0%

Python Web3实用代码入门

推荐编程语言:Python

推荐编辑器:Pycharm & VSCode

推荐类库:Web3

推荐辅助AI:GPT & Deepseek & Claude & Grok

推荐翻译软件:沉浸式翻译 (推荐搭配gpt兼顾质量和价格)

本轮教程由AI编写,经过测试可以使用。

安装依赖:

1
pip install web3==7.10.0

阅读文档:

https://web3py.readthedocs.io/en/v7.10.0/quickstart.html

连接Web3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from web3 import Web3

# 使用 Hoodi 测试网的 RPC
rpc_url = "https://rpc.hoodi.ethpandaops.io"

# 创建 Web3 实例
w3 = Web3(Web3.HTTPProvider(rpc_url))

# 检查连接状态
if w3.is_connected():
print("成功连接到网络!")
# 获取当前区块号
block_number = w3.eth.block_number
print(f"当前区块号: {block_number}")

# 获取链ID
chain_id = w3.eth.chain_id
print(f"链 ID: {chain_id}")
else:
print("连接失败!")

创建帐号:

1
2
3
4
5
from web3 import Web3
# 创建账号无需连接到节点
w3 = Web3()
acc = w3.eth.account.create()
print(f'private key={w3.to_hex(acc.key)}, account={acc.address}')

领取测试币:

本文所有的代码接下来均使用Hoodi测试网来进行:

1:Sepolia将于2026年9月关闭,Hoodi预计将运行到2028年

2:Hoodi测试币获取较为容易

本文的测试账号:

1
0xCE9E102c0090033221DbE9ffd43E134f0275E74E

pk910水龙头:https://hoodi-faucet.pk910.de/ POW 单次0.1-33个

GHOST水龙头:https://ghostchain.io/faucet/ethereum-hoodi/ 单次1

Automata水龙头:https://www.hoodifaucet.io/ 机器验证0.01

QuickNode水龙头:https://faucet.quicknode.com/ethereum/hoodi 主网0.001余额验证

RockX水龙头:https://access.rockx.com/faucet-hoodi 任务验证0.03-1

Stakely水龙头:https://stakely.io/faucet/ethereum-hoodi-testnet-eth 社交验证

请优先使用pk910,因为这是一家知名的反女巫水龙头,拥有大量的测试代币和有效的限制手段,使得测试币可以长久的供应。

这次我分别使用了前3种验证方式给这个初始号获得了2**.**27625 ETH测试币,我想着应该够我这次教程所使用的。

查询余额:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 导入 Web3.py 库,用于与以太坊网络交互
from web3 import Web3

# Hoodi 测试网的 RPC 地址(官方提供的公共节点)
rpc_url = 'https://rpc.hoodi.ethpandaops.io'

# 创建 Web3 实例,连接到 Hoodi 测试网
w3 = Web3(Web3.HTTPProvider(rpc_url))

# 检查是否成功连接到节点
if not w3.is_connected():
print("连接 Hoodi 测试网 RPC 失败,请检查网络或 RPC 地址。")
else:
print("成功连接到 Hoodi 测试网!")

# 要查询余额的目标钱包地址
address = '0xCE9E102c0090033221DbE9ffd43E134f0275E74E'

# 获取该地址在 Hoodi 测试网上的余额(单位:Wei)
balance_wei = w3.eth.get_balance(address)

# 将余额从 Wei 转换为 Ether(1 ETH = 10^18 Wei)
balance_ether = w3.from_wei(balance_wei, 'ether')

# 输出余额结果
print(f"地址 {address} 的余额为:{balance_ether} Hoodi ETH")

输出结果:

成功连接到 Hoodi 测试网!
地址 0xCE9E102c0090033221DbE9ffd43E134f0275E74E 的余额为:2.27625 Hoodi ETH

与浏览器查询结果一致!

发送交易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from web3 import Web3

# 连接以太坊测试网络
w3 = Web3(Web3.HTTPProvider('https://rpc.hoodi.ethpandaops.io'))
if not w3.is_connected():
raise Exception("无法连接到以太坊网络")

# 从私钥获取钱包地址
private_key = '你的私钥' # 请替换为实际的私钥,开头不要带0x
sender_account = w3.eth.account.from_key(private_key)
sender_address = sender_account.address

# 设置接收地址和转账金额
receiver_address = '0x0000000000000000000000000000000000000000' # 默认为零地址
amount = w3.to_wei(0.001, 'ether') # 转换为wei单位

# 从RPC获取链ID
chain_id = w3.eth.chain_id

# 获取当前nonce值
nonce = w3.eth.get_transaction_count(sender_address)

# 获取当前gas价格
gas_price = w3.eth.gas_price

# 构建交易对象
transaction = {
'nonce': nonce,
'to': receiver_address,
'value': amo
'gas': 21000, # 标准ETH转账的gas限制
'gasPrice': gas_price,
'chainId': chain_id
}

# 使用私钥签名交易
signed_txn = w3.eth.account.sign_transaction(transaction, private_key)

# 发送交易到网络
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

print(f"交易已发送!")
print(f"发送方: {sender_address}")
print(f"接收方: {receiver_address}")
print(f"金额: {w3.from_wei(amount, 'ether')} ETH")
print(f"交易哈希: {tx_hash.hex()}")

输出结果:

交易已发送!
发送方: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
接收方: 0x0000000000000000000000000000000000000000
金额: 0.001 ETH
交易哈希: 2e3bbbbaf1d47b1b7ac5c17a6ade5ecb65932981d96c16c21190ae3ee21409e2

发送EIP1559交易:

简单来说,发送EIP1559交易可以更加优雅的使用手续费,使得交易更加流畅。

主要差异:

  1. 费用结构不同:

普通交易:单一的gasPrice,用户支付固定价格
EIP1559交易:采用双层费用结构
baseFee:由网络自动计算并销毁
priorityFee:给矿工的小费,决定交易优先级
2. 交易类型标识:

普通交易:type: 0或无type字段
EIP1559交易:明确标识type: 2
3. 费用字段:

普通交易:只有gasPrice
EIP1559交易:
maxFeePerGas:用户愿意支付的最高总费用
maxPriorityFeePerGas:给矿工的小费上限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from web3 import Web3

# 连接以太坊测试网络
w3 = Web3(Web3.HTTPProvider('https://rpc.hoodi.ethpandaops.io'))
if not w3.is_connected():
raise Exception("无法连接到以太坊网络")

# 从私钥获取钱包地址
private_key = '你的私钥' # 请替换为实际的私钥,开头不要带0x
sender_account = w3.eth.account.from_key(private_key)
sender_address = sender_account.address

# 设置接收地址和转账金额
receiver_address = '0x0000000000000000000000000000000000000000' # 默认为零地址
amount = w3.to_wei(0.001, 'ether') # 转换为wei单位

# 从RPC获取链ID
chain_id = w3.eth.chain_id

# 获取当前nonce值
nonce = w3.eth.get_transaction_count(sender_address)

# 构建EIP1559交易对象
transaction = {
'nonce': nonce,
'to': receiver_address,
'value': amount,
'gas': 21000, # 标准ETH转账的gas限制
'maxFeePerGas': w3.to_wei(5, 'gwei'), # 最大gas费用
'maxPriorityFeePerGas': w3.to_wei(1, 'gwei'), # 优先费用
'chainId': chain_id,
'type': 2 # EIP1559交易类型
}

# 使用私钥签名交易
signed_txn = w3.eth.account.sign_transaction(transaction, private_key)

# 发送交易到网络
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

print(f"交易已发送!")
print(f"发送方: {sender_address}")
print(f"接收方: {receiver_address}")
print(f"金额: {w3.from_wei(amount, 'ether')} ETH")
print(f"交易哈希: {tx_hash.hex()}")

输出结果:

交易已发送!
发送方: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
接收方: 0x0000000000000000000000000000000000000000
金额: 0.001 ETH
交易哈希: 49820a896d0bf44be94866d4c787d838a821690d00935cf2cea0609a54731ac1

循环:

基础循环示范:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1. for循环 - 遍历固定次数
print("=== for循环示例 ===")
for i in range(5): # 循环5次,i从0到4
print(f"这是第 {i+1} 次循环")

# 2. while循环 - 根据条件循环
print("\n=== while循环示例 ===")
count = 1
while count <= 3: # 当count小于等于3时继续循环
print(f"while循环第 {count} 次")
count += 1 # 每次循环count加1

# 3. 遍历列表
print("\n=== 遍历列表示例 ===")
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
print(f"我喜欢吃 {fruit}")

这是最基础的三种循环,一般情况下多数使用第一种。

当你想要重复某部分代码的时候,就可以使用循环,让机器重复操作,这也是计算机的伟大之处。

循环发送10次EIP1559操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from web3 import Web3
import time

# 连接以太坊测试网络
w3 = Web3(Web3.HTTPProvider('https://rpc.hoodi.ethpandaops.io'))
if not w3.is_connected():
raise Exception("无法连接到以太坊网络")

# 从私钥获取钱包地址
private_key = '你的私钥' # 请替换为实际的私钥
sender_account = w3.eth.account.from_key(private_key)
sender_address = sender_account.address

# 设置接收地址和转账金额
receiver_address = '0x0000000000000000000000000000000000000000'
amount = w3.to_wei(0.001, 'ether')

# 从RPC获取链ID
chain_id = w3.eth.chain_id

print(f"开始连续发送10笔EIP1559交易...")
print(f"发送方: {sender_address}")
print(f"接收方: {receiver_address}")
print(f"每笔金额: {w3.from_wei(amount, 'ether')} ETH\n")

# 使用for循环发送10次交易
for i in range(10):
try:
# 获取当前nonce值(每次循环都要重新获取)
nonce = w3.eth.get_transaction_count(sender_address)

# 构建EIP1559交易
transaction = {
'nonce': nonce,
'to': receiver_address,
'value': amount,
'gas': 21000,
'maxFeePerGas': w3.to_wei(5, 'gwei'),
'maxPriorityFeePerGas': w3.to_wei(1, 'gwei'),
'chainId': chain_id,
'type': 2
}

# 签名并发送交易
signed_txn = w3.eth.account.sign_transaction(transaction, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

print(f"✅ 第 {i+1} 笔交易发送成功!")
print(f" 交易哈希: {tx_hash.hex()}")
print(f" nonce: {nonce}")

# 在交易之间添加短暂延迟,避免nonce冲突
if i < 9: # 最后一笔交易后不需要等待
print(" 等待2秒...\n")
time.sleep(2)

except Exception as e:
print(f"❌ 第 {i+1} 笔交易失败: {str(e)}")
break # 如果失败就停止循环

print(f"\n交易发送完成! 共发送 {i+1} 笔交易")

值得注意的是,一次操作不容易出现问题,但是多次操作容易出现问题。

上面代码引入了两个新特性:

1:异常 Exception

在多次执行中,容易遇到异常问题,使用try来捕获异常,except Exception as e:里面只打印了异常的信息,这样做是当遇到异常的时候就停止代码,查找原因。当然,你也可以直接跳过异常让代码继续运行(一般不推荐)。

2:等待 Sleep

在调用RPC时会遇到频率的问题,一般免费的RPC是有限制的。如每分钟50次之类的,所以需要等待来防止RPC调用错误。当然你也可以选择高频的付费RPC。

输出结果:

开始连续发送10笔EIP1559交易…
发送方: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
接收方: 0x0000000000000000000000000000000000000008
每笔金额: 0.001 ETH

✅ 第 1 笔交易发送成功!
交易哈希: bb3946e9fa78aa0fe1b9a71db9867b2cf9e60728469a4bc9d2d717592e91cf05
nonce: 2
等待2秒…

❌ 第 2 笔交易失败: 500 Server Error: Internal Server Error for url: https://rpc.hoodi.ethpandaops.io/

交易发送完成! 共发送 2 笔交易

解决问题:

这种情况解决方法有2个:

1:切换1个更加稳定,且性能更加的RPC

2:增加重试次数,1次不行2次,3次,总能成功

方法2的问题在于不能无限重试,不然程序会陷入死循环,但是最大重试次数依旧有概率失败。

个人推荐换1个私有的RPC即使部署付费的,效果也会比公开的强。

如果使用方法2,那么代码改良如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from web3 import Web3
import time
import requests

# 连接以太坊测试网络
w3 = Web3(Web3.HTTPProvider('https://rpc.hoodi.ethpandaops.io'))
if not w3.is_connected():
raise Exception("无法连接到以太坊网络")

# 从私钥获取钱包地址
private_key = '你的私钥'
sender_account = w3.eth.account.from_key(private_key)
sender_address = sender_account.address

# 设置接收地址和转账金额
receiver_address = '0x0000000000000000000000000000000000000000' # 注意:应该是全零地址
amount = w3.to_wei(0.001, 'ether')

# 从RPC获取链ID
chain_id = w3.eth.chain_id

print(f"开始连续发送10笔EIP1559交易...")
print(f"发送方: {sender_address}")
print(f"接收方: {receiver_address}")
print(f"每笔金额: {w3.from_wei(amount, 'ether')} ETH\n")

def send_transaction_with_retry(max_retries=3):
"""带重试机制的交易发送函数"""
for retry in range(max_retries):
try:
# 获取当前nonce值
nonce = w3.eth.get_transaction_count(sender_address)

# 构建EIP1559交易
transaction = {
'nonce': nonce,
'to': receiver_address,
'value': amount,
'gas': 21000,
'maxFeePerGas': w3.to_wei(5, 'gwei'),
'maxPriorityFeePerGas': w3.to_wei(1, 'gwei'),
'chainId': chain_id,
'type': 2
}

# 签名并发送交易
signed_txn = w3.eth.account.sign_transaction(transaction, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

return tx_hash, nonce, True # 成功标志

except Exception as e:
error_msg = str(e)
print(f" 第 {retry+1} 次重试失败: {error_msg}")

if retry < max_retries - 1:
wait_time = 2 * (retry + 1) # 指数退避:2, 4, 6秒
print(f" 等待 {wait_time} 秒后重试...")
time.sleep(wait_time)
else:
return None, None, False # 失败标志

# 使用for循环发送10次交易
success_count = 0
target_count = 10

for i in range(target_count):
attempt_count = i + 1

print(f"正在发送第 {attempt_count} 笔交易...")

tx_hash, nonce, success = send_transaction_with_retry(max_retries=3)

if success:
success_count += 1
print(f"✅ 第 {attempt_count} 笔交易发送成功!")
print(f" 交易哈希: {tx_hash.hex()}")
print(f" nonce: {nonce}")

if attempt_count < target_count:
print(" 等待3秒...\n")
time.sleep(3)
else:
print(f"❌ 第 {attempt_count} 笔交易所有重试都失败,跳过继续下一笔")
print(" 等待5秒后继续下一笔交易...\n")
time.sleep(5)

print(f"\n=== 交易统计 ===")
print(f"目标发送: {target_count} 笔")
print(f"成功发送: {success_count} 笔")
print(f"失败次数: {target_count - success_count} 笔")

if success_count < target_count:
print(f"\n注意:有 {target_count - success_count} 笔交易发送失败")
print("可能原因:")
print("1. RPC节点不稳定")
print("2. 网络连接问题")
print("3. 账户余额不足")
print("4. 交易频率过高被限制")

最后的结果:

=== 交易统计 ===
目标发送: 10 笔
成功发送: 9 笔
失败次数: 1 笔

该代码不仅增加了重试机制,还增加失败继续运行的机制,最大的3次重试下,依旧有1笔交易未能完成。

所以推荐注册私有的RPC!

注册私有RPC:

https://www.ankr.com/

你也可以使用其他的服务商,这家可以直接使用钱包登录注册使用。

点击projects,你可以将自己的IP添加到白名单里面,我就不添加了。

然后在去寻找链条,点开ETH,切换到testnet,再点击Hoodi,你就会得到RPC:

https://rpc.ankr.com/eth_hoodi/bebd9bac7f3e5181e4c5da8777fbb74e36627180a0a9372bf53b902f2e485b5e

但是我使用新的RPC还是遇到了问题:{‘code’: -32000, ‘message’: ‘ALREADY_EXISTS: already known’, ‘data’: {‘trace_id’: ‘b3fca2d9bb3a02633947556b1548478e’}}

这个问题表示你发送了相同的nonce值,产生这个的原因在于,你再循环里面获取nonce值,而RPC还没有来得及更新最新数据。解决办法也简单,nonce值只在循环外面获取一次,循环内nonce值递增即可。

原版循环发送代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from web3 import Web3
import time

# 连接以太坊测试网络
w3 = Web3(Web3.HTTPProvider('https://rpc.ankr.com/eth_hoodi/bebd9bac7f3e5181e4c5da8777fbb74e36627180a0a9372bf53b902f2e485b5e'))
if not w3.is_connected():
raise Exception("无法连接到以太坊网络")

# 从私钥获取钱包地址
private_key = '0x你的私钥' # 请替换为实际的私钥
sender_account = w3.eth.account.from_key(private_key)
sender_address = sender_account.address

# 设置接收地址和转账金额
receiver_address = '0x0000000000000000000000000000000000000088'
amount = w3.to_wei(0.0001, 'ether')

# 从RPC获取链ID
chain_id = w3.eth.chain_id

print(f"开始连续发送10笔EIP1559交易...")
print(f"发送方: {sender_address}")
print(f"接收方: {receiver_address}")
print(f"每笔金额: {w3.from_wei(amount, 'ether')} ETH\n")

# 获取当前nonce值(每次循环都要重新获取)
nonce = w3.eth.get_transaction_count(sender_address)
# 使用for循环发送10次交易
for i in range(10):
try:
# 构建EIP1559交易
transaction = {
'nonce': nonce,
'to': receiver_address,
'value': amount,
'gas': 1000000,
'maxFeePerGas': w3.to_wei(5, 'gwei'),
'maxPriorityFeePerGas': w3.to_wei(1, 'gwei'),
'chainId': chain_id,
'type': 2
}

# 签名并发送交易
signed_txn = w3.eth.account.sign_transaction(transaction, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

print(f"✅ 第 {i + 1} 笔交易发送成功!")
print(f" 交易哈希: {tx_hash.hex()}")
print(f" nonce: {nonce}")
nonce+=1

# 在交易之间添加短暂延迟,避免nonce冲突
# if i < 9: # 最后一笔交易后不需要等待
# print(" 等待2秒...\n")
# time.sleep(2)

except Exception as e:
print(f"❌ 第 {i + 1} 笔交易失败: {str(e)}")
break # 如果失败就停止循环

print(f"\n交易发送完成! 共发送 {i + 1} 笔交易")

甚至将等待时间都给注释掉了,结果还是成功了。

这说明就是nonce值的问题。

开始连续发送10笔EIP1559交易…
发送方: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
接收方: 0x0000000000000000000000000000000000000088
每笔金额: 0.0001 ETH

✅ 第 1 笔交易发送成功!
交易哈希: 880ce2ec27d41cf58b3241d2723d8311bfec5a4c90d2b108e517aa60d7dfb366
nonce: 41
✅ 第 2 笔交易发送成功!
交易哈希: ac1b8713dba996bcc6a4d7a964eb0ad79bbcf3606da33f9afff48b96836d8d00
nonce: 42
✅ 第 3 笔交易发送成功!
交易哈希: 0d946c244c7cd18d3384cd06744c1dfc9b5873e3ed0942960066b97dba8a76b4
nonce: 43
✅ 第 4 笔交易发送成功!
交易哈希: a1eac59909fd5c8a7218091bcb1207f8a3c4fea8be3b64d603513f1051581544
nonce: 44
✅ 第 5 笔交易发送成功!
交易哈希: a6410292924cc64535363272125b2ff2c80bf86db9b01c519f99c011f172b0ff
nonce: 45
✅ 第 6 笔交易发送成功!
交易哈希: 5054263308f4ad5c8ca32ce2874947bd36f2ed039dfd67b0b914560d8c7f8bd6
nonce: 46
✅ 第 7 笔交易发送成功!
交易哈希: b6282a2eb82f33f5ba512f2ed7dd82316e989cff41a070bf37743b22ea7d7674
nonce: 47
✅ 第 8 笔交易发送成功!
交易哈希: e8c7b21f04add05b633f0a4980f498e0e795b750df1c3d345e5c3e0478cea725
nonce: 48
✅ 第 9 笔交易发送成功!
交易哈希: e594be7c6672d0003a3d53aa34ac95d2e3102d31271bd367c5e0c2b92ada22af
nonce: 49
✅ 第 10 笔交易发送成功!
交易哈希: b2ae8aea170adad6d8c1b4d9c9743a84461c74d7790137b6c0172734f9c4e50b
nonce: 50

交易发送完成! 共发送 10 笔交易

发送中文信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from web3 import Web3

# 连接以太坊测试网络
w3 = Web3(Web3.HTTPProvider('https://rpc.hoodi.ethpandaops.io'))
if not w3.is_connected():
raise Exception("无法连接到以太坊网络")

# 从私钥获取钱包地址
private_key = '你的私钥' # 请替换为实际的私钥
sender_account = w3.eth.account.from_key(private_key)
sender_address = sender_account.address

# 设置接收地址
receiver_address = '0x0000000000000000000000000000000000000000'

# 将中文"我爱中国"转换为16进制
chinese_text = "我爱中国"
hex_data = '0x' + chinese_text.encode('utf-8').hex()
amount = w3.to_wei(0.001, 'ether')

print("=== EIP1559交易 - 附带中文数据 ===")
print(f"发送方: {sender_address}")
print(f"接收方: {receiver_address}")
print(f"转账金额: {w3.from_wei(amount, 'ether')} ETH")
print(f"附加数据: {chinese_text}")
print(f"16进制数据: {hex_data}")

def send_transaction_with_data():
try:
# 获取当前nonce值
nonce = w3.eth.get_transaction_count(sender_address)

# 构建EIP1559交易,附加数据会增加gas消耗
transaction = {
'nonce': nonce,
'to': receiver_address,
'value': amount,
'gas': 25000, # 因为有数据,gas限制需要增加
'maxFeePerGas': w3.to_wei(5, 'gwei'),
'maxPriorityFeePerGas': w3.to_wei(1, 'gwei'),
'data': hex_data, # 这里是附加的数据
'chainId': w3.eth.chain_id,
'type': 2 # EIP1559交易类型
}

# 估算实际需要的gas
try:
estimated_gas = w3.eth.estimate_gas(transaction)
transaction['gas'] = estimated_gas
print(f"估算gas: {estimated_gas}")
except Exception as e:
print(f"Gas估算失败,使用默认值: {e}")

# 使用私钥签名交易
signed_txn = w3.eth.account.sign_transaction(transaction, private_key)

# 发送交易到网络
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

# 获取带0x前缀的交易哈希
tx_hash_with_0x = '0x' + tx_hash.hex()

# 拼接浏览器地址
explorer_url = f"https://hoodi.etherscan.io/tx/{tx_hash_with_0x}"

return tx_hash_with_0x, explorer_url, True

except Exception as e:
print(f"交易失败: {str(e)}")
return None, None, False

# 发送交易
tx_hash, explorer_url, success = send_transaction_with_data()

if success:
print(f"\n✅ 交易发送成功!")
print(f"交易哈希: {tx_hash}")
print(f"区块链浏览器: {explorer_url}")

# 等待交易确认(可选)
print("\n等待交易确认中...")
try:
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
if receipt.status == 1:
print("✅ 交易已确认!")
else:
print("❌ 交易失败!")
except Exception as e:
print(f"等待确认超时: {e}")
else:
print("❌ 交易发送失败,请检查网络和余额")

输出结果:

=== EIP1559交易 - 附带中文数据 ===
发送方: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
接收方: 0x0000000000000000000000000000000000000000
转账金额: 0.001 ETH
附加数据: 我爱中国
16进制数据: 0xe68891e788b1e4b8ade59bbd
Gas估算失败,使用默认值: 400 Client Error: Bad Request for url: https://rpc.hoodi.ethpandaops.io/

✅ 交易发送成功!
交易哈希: 0x60db0a623e5889f64ad96fd2e85d0e6d2555b023076dca9fa9ac7ca0f907efde
区块链浏览器: https://hoodi.etherscan.io/tx/0x60db0a623e5889f64ad96fd2e85d0e6d2555b023076dca9fa9ac7ca0f907efde

等待交易确认中…
✅ 交易已确认!

你可以在浏览器里面打开这个链接地址,然后在Input Data:里面看到16进制数:0xe68891e788b1e4b8ade59bbd

和上面生成的一样,你可以点击UTF-8,里面的数据就会变成四个大字“我爱中国”。

这次去浏览器才注意到之前的循环交易都失败了,原因的gas不够,所以我建议接下来的所有操作默认gas都改成100万(用不了的又不扣除)。

代码没问题,只是遇到了预编译地址:不要向 0x000…0009 或其他预编译地址(0x1~0x9)发送 ETH。它们只用于合约内部计算。

铭文:

这个可能已经不流行了,但还是要说1下。在2023年掀起了一股铭文风潮,很快就席卷到了EVM链上。

大致是这样的,自己给自己发送金额为0的交易,然后在data数据里面填写需要的字符。

如部署1个代币,假设为 HOODIS:

1
2
3
4
5
6
7
{
"p": "brc-20",
"op": "deploy",
"tick": "HOODIS",
"max": "21000",
"lim": "1"
}

该协议名称brc-20可以随便改,op操作一般只有部署和mint,转账3种,然后是名称,总量,单次mint数量。

1
2
3
4
5
6
{
"p": "brc-20",
"op": "mint",
"tick": "HOODIS",
"amt": "1"
}

这就是单次mint的内容,每次获取1个代币。

你简单修改下代码,将接受者改成发送者地址,将金额改为0,将Data数据改为上面的json数据,使用’’’来引用多行内容。

先部署之后才可以mint,而且得按照lim限制数量mint,否则就是无效内容。

铭文讲究先到先得,当总数满了之后的所有mint操作都作废。

铭文部署操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from web3 import Web3

# 连接以太坊测试网络
w3 = Web3(Web3.HTTPProvider('https://rpc.hoodi.ethpandaops.io'))
if not w3.is_connected():
raise Exception("无法连接到以太坊网络")

# 从私钥获取钱包地址
private_key = '0x你的私钥' # 请替换为实际的私钥
sender_account = w3.eth.account.from_key(private_key)
sender_address = sender_account.address

# 设置接收地址
receiver_address = sender_address

# 将中文"我爱中国"转换为16进制
chinese_text = '''{
"p": "brc-20",
"op": "deploy",
"tick": "HOODIS",
"max": "21000",
"lim": "1"
}'''

hex_data = '0x' + chinese_text.encode('utf-8').hex()
amount = w3.to_wei(0, 'ether')

print("=== EIP1559交易 - 附带中文数据 ===")
print(f"发送方: {sender_address}")
print(f"接收方: {receiver_address}")
print(f"转账金额: {w3.from_wei(amount, 'ether')} ETH")
print(f"附加数据: {chinese_text}")
print(f"16进制数据: {hex_data}")


def send_transaction_with_data():
try:
# 获取当前nonce值
nonce = w3.eth.get_transaction_count(sender_address)

# 构建EIP1559交易,附加数据会增加gas消耗
transaction = {
'nonce': nonce,
'to': receiver_address,
'value': amount,
'gas': 1000000, # 因为有数据,gas限制需要增加
'maxFeePerGas': w3.to_wei(5, 'gwei'),
'maxPriorityFeePerGas': w3.to_wei(1, 'gwei'),
'data': hex_data, # 这里是附加的数据
'chainId': w3.eth.chain_id,
'type': 2 # EIP1559交易类型
}

# 估算实际需要的gas
try:
estimated_gas = w3.eth.estimate_gas(transaction)
transaction['gas'] = estimated_gas
print(f"估算gas: {estimated_gas}")
except Exception as e:
print(f"Gas估算失败,使用默认值: {e}")

# 使用私钥签名交易
signed_txn = w3.eth.account.sign_transaction(transaction, private_key)

# 发送交易到网络
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

# 获取带0x前缀的交易哈希
tx_hash_with_0x = '0x' + tx_hash.hex()

# 拼接浏览器地址
explorer_url = f"https://hoodi.etherscan.io/tx/{tx_hash_with_0x}"

return tx_hash_with_0x, explorer_url, True

except Exception as e:
print(f"交易失败: {str(e)}")
return None, None, False


# 发送交易
tx_hash, explorer_url, success = send_transaction_with_data()

if success:
print(f"\n✅ 交易发送成功!")
print(f"交易哈希: {tx_hash}")
print(f"区块链浏览器: {explorer_url}")

# 等待交易确认(可选)
print("\n等待交易确认中...")
try:
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
if receipt.status == 1:
print("✅ 交易已确认!")
else:
print("❌ 交易失败!")
except Exception as e:
print(f"等待确认超时: {e}")
else:
print("❌ 交易发送失败,请检查网络和余额")

输出结果:

=== EIP1559交易 - 附带中文数据 ===
发送方: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
接收方: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
转账金额: 0 ETH
附加数据: {
“p”: “brc-20”,
“op”: “deploy”,
“tick”: “HOODIS”,
“max”: “21000”,
“lim”: “1”
}
16进制数据: 0x7b0a20202270223a20226272632d3230222c0a2020226f70223a20226465706c6f79222c0a2020227469636b223a2022484f4f444953222c0a2020226d6178223a20223231303030222c0a2020226c696d223a202231220a7d
Gas估算失败,使用默认值: 400 Client Error: Bad Request for url: https://rpc.hoodi.ethpandaops.io/

✅ 交易发送成功!
交易哈希: 0x57920446e56ae4dff1b99594b1cd87e114d232b5d29e4bdf705d49cc4a7a6c0b
区块链浏览器: https://hoodi.etherscan.io/tx/0x57920446e56ae4dff1b99594b1cd87e114d232b5d29e4bdf705d49cc4a7a6c0b

等待交易确认中…
✅ 交易已确认!

mint操作只需要将里面的数据字符串修改1下即可。

铭文唯一的成本就只有手续费了,所以这股操作风潮很快就过去了,凭空产生的代币终究没有太多价值。

合约部署:

这次你需要使用到solcx库,建议安装0.8版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import solcx
from web3 import Web3
import json # 方便打印ABI

# --- 1. 定义合约和网络信息 ---

# Hoodi 测试网的 RPC URL
# 这是你提供的 Ankr 公共 RPC
RPC_URL = "https://rpc.ankr.com/eth_hoodi/bebd9bac7f3e5181e4c5da8777fbb74e36627180a0a9372bf53b902f2e485b5e"

# 你的测试账户私钥 (请务必使用测试账户,不要泄露任何有真实资产的私钥!)
# 将 "0x..." 替换为你的私钥
# 示例: PRIVATE_KEY = "0xabcdef123456..."
PRIVATE_KEY = "0x你的私钥"

# 合约源代码 (Solidity)
# 这是一个非常简单的合约:
# - 有一个公开的字符串变量 `message`
# - 构造函数在部署时将 message 初始化为 "Hello, Hoodi!"
# - 有一个 `sayHello` 函数可以读取 message
# - 有一个 `updateMessage` 函数可以修改 message
hello_contract_source_code = """
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Hello {
string public message;

constructor() {
message = "Hello, Hoodi!";
}

function sayHello() public view returns (string memory) {
return message;
}

function updateMessage(string memory newMessage) public {
message = newMessage;
}
}
"""

# --- 2. 编译 Solidity 合约 ---

print("正在安装 Solidity 编译器 0.8.0 版本 (如果尚未安装)...")
# 安装指定版本的 Solidity 编译器
# solcx 会自动下载并管理编译器,这非常方便
solcx.install_solc('0.8.0')

print("开始编译合约...")
# 使用 solcx.compile_source 来编译源代码字符串
# solc_version 指定了我们想用的编译器版本
compiled_sol = solcx.compile_source(
hello_contract_source_code,
output_values=['abi', 'bin'], # 我们需要 ABI 和 Bytecode (bin)
solc_version='0.8.0'
)

# 编译结果是一个字典,我们需要从中提取出合约的 ABI 和 Bytecode
# key 的格式通常是 '<stdin>:合约名'
contract_id, contract_interface = compiled_sol.popitem()
bytecode = contract_interface['bin']
abi = contract_interface['abi']

print("合约编译成功!")
# print("\n合约 ABI:")
# print(json.dumps(abi, indent=2)) # 打印格式化的 ABI,方便查看
# print("\n合约 Bytecode (部分):")
# print(bytecode[:100] + "...") # 只打印部分字节码

# --- 3. 连接到 Hoodi 测试网并设置账户 ---

print(f"\n正在连接到 Hoodi 测试网: {RPC_URL}")
# 使用 Web3.py 连接到 RPC 节点
w3 = Web3(Web3.HTTPProvider(RPC_URL))

# 检查是否连接成功
if not w3.is_connected():
print("错误:无法连接到 Hoodi 测试网!请检查 RPC URL。")
exit()

print("连接成功!")
print(f"当前区块号: {w3.eth.block_number}")

# 从私钥加载你的账户
# 这是部署合约和发送交易的主体
if PRIVATE_KEY == "YOUR_PRIVATE_KEY":
print("\n错误:请在代码中设置你的测试账户私钥 (PRIVATE_KEY)!")
exit()

my_account = w3.eth.account.from_key(PRIVATE_KEY)
my_address = my_account.address
print(f"使用的账户地址: {my_address}")

# 检查账户余额
balance_wei = w3.eth.get_balance(my_address)
balance_eth = w3.from_wei(balance_wei, 'ether')
print(f"账户余额: {balance_eth} Hoodi ETH")

if balance_wei == 0:
print("警告:账户余额为 0,你可能无法支付部署合约所需的 Gas 费用。")


# --- 4. 部署合约 ---

print("\n准备部署合约...")
# 使用 ABI 和 Bytecode 创建一个合约对象
# 这还不是部署后的合约,只是一个可以用于部署的 "模板"
HelloContract = w3.eth.contract(abi=abi, bytecode=bytecode)

# 获取 nonce。Nonce 是每个账户发出的交易计数,用于防止重放攻击
nonce = w3.eth.get_transaction_count(my_address)

# 1. 构建部署交易
# .constructor() 表示我们正在调用合约的构造函数 (即部署操作)
# .build_transaction() 会估算 Gas 并填充交易字段
transaction = HelloContract.constructor().build_transaction({
'from': my_address,
'nonce': nonce,
# 你也可以手动设置 gas 和 gasPrice
# 'gas': 2000000,
# 'gasPrice': w3.eth.gas_price,
})

# 2. 使用你的私钥对交易进行签名
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY)

print("正在发送部署交易...")
# 3. 发送已签名的交易到网络
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

print(f"交易已发送,交易哈希 (TxHash): {w3.to_hex(tx_hash)}")
print("正在等待交易被矿工打包...")

# 4. 等待交易完成
# 这会阻塞程序,直到交易被确认
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

# 从交易回执中获取新部署的合约地址
deployed_contract_address = tx_receipt.contractAddress
print("\n🎉 合约部署成功!🎉")
print(f"合约地址: {deployed_contract_address}")
print(f"区块号: {tx_receipt.blockNumber}")
# 你可以在 Hoodi 测试网的区块浏览器上查看这个地址和交易

# --- 5. 与已部署的合约进行交互 ---

print("\n与已部署的合约进行交互...")

# 使用合约地址和 ABI 创建一个合约实例
deployed_hello_contract = w3.eth.contract(
address=deployed_contract_address,
abi=abi
)

# 调用 `sayHello()` view 函数 (只读,不消耗 Gas)
# .call() 用于执行只读操作
initial_message = deployed_hello_contract.functions.sayHello().call()
print(f"调用 sayHello() 函数,读取到的初始消息: '{initial_message}'")

# 接下来,我们将尝试发送一个交易来修改消息
print("\n准备发送一个交易来调用 updateMessage() 函数...")

# 构建调用 updateMessage 的交易
update_nonce = w3.eth.get_transaction_count(my_address)
update_tx = deployed_hello_contract.functions.updateMessage("Hello, Python and Web3!").build_transaction({
'from': my_address,
'nonce': update_nonce
})

# 签名并发送交易
signed_update_tx = w3.eth.account.sign_transaction(update_tx, private_key=PRIVATE_KEY)
update_tx_hash = w3.eth.send_raw_transaction(signed_update_tx.raw_transaction)
print(f"更新消息的交易已发送, TxHash: {w3.to_hex(update_tx_hash)}")
print("等待交易完成...")
w3.eth.wait_for_transaction_receipt(update_tx_hash)
print("消息更新成功!")

# 再次调用 sayHello() 函数,检查消息是否已更新
updated_message = deployed_hello_contract.functions.sayHello().call()
print(f"再次调用 sayHello(),读取到的新消息: '{updated_message}'")

print("\n所有测试完成!")

输出结果:

正在安装 Solidity 编译器 0.8.0 版本 (如果尚未安装)…
开始编译合约…
合约编译成功!

正在连接到 Hoodi 测试网: https://rpc.ankr.com/eth_hoodi/bebd9bac7f3e5181e4c5da8777fbb74e36627180a0a9372bf53b902f2e485b5e
连接成功!
当前区块号: 1505378
使用的账户地址: 0xCE9E102c0090033221DbE9ffd43E134f0275E74E
账户余额: 2.24206576464945356 Hoodi ETH

准备部署合约…
正在发送部署交易…
交易已发送,交易哈希 (TxHash): 0x844ac9c7320fe84b536dc897fd5f26a25b8e0ac22a6ed32b4b4914f09ea75938
正在等待交易被矿工打包…

🎉 合约部署成功!🎉
合约地址: 0x005bb21AF26C9c6c58911dD564A33Ac251720986
区块号: 1505379

与已部署的合约进行交互…
调用 sayHello() 函数,读取到的初始消息: ‘Hello, Hoodi!’

准备发送一个交易来调用 updateMessage() 函数…
更新消息的交易已发送, TxHash: 0xdeee572c98443b88eb59b1d6cd97a378913bdc291cf500b63554233ba59ee874
等待交易完成…
消息更新成功!
再次调用 sayHello(),读取到的新消息: ‘Hello, Python and Web3!’

所有测试完成!