Skip to content

使用Python调用Solidity合约

这里使用的合约来自于这里中的一个布尔可满性证明电路生成的Verify合约,于Sepolia 0xbEA8E0F363b1B8469f7971ED157Ec262232D293e部署。

1. 安装依赖

bash
pip install web3 eth-account

2. 准备一个RPC节点

这里使用GetBlock

3. Python代码示例

CAUTION

💀孩子们注意资金账户和测试账户要分开

abi
json
[
	{
		"inputs": [
			{
				"internalType": "uint256[24]",
				"name": "_proof",
				"type": "uint256[24]"
			},
			{
				"internalType": "uint256[1]",
				"name": "_pubSignals",
				"type": "uint256[1]"
			}
		],
		"name": "verifyProof",
		"outputs": [
			{
				"internalType": "bool",
				"name": "",
				"type": "bool"
			}
		],
		"stateMutability": "view",
		"type": "function"
	}
]
proof & public signals
json
{
 "A": [
  "21860314311648082144119237428816522776534861044712670798123111267113298541167",
  "19011679756522918214237064326901138170560812587127533776215776713105468145442",
  "1"
 ],
 "B": [
  "2646133980078131914507857200375469679789286844739432355665346314081704361405",
  "13889943492831913834804319683000878079205443507567487900890258196931968130509",
  "1"
 ],
 "C": [
  "20734773724461417395552182055150709243833045882953469179956611527056271446574",
  "15710414592920317320293397423703814362719064144494256946181196800938530500676",
  "1"
 ],
 "Z": [
  "20561852897234688380979919287282767037959010378165596947607724154483951499424",
  "6122232522674985727127284478945366168578755086215148093727377800176422633844",
  "1"
 ],
 "T1": [
  "10279993713664578652579403551153368710861572383797672368464388728714854594501",
  "1830766094772175078090411988565165501599780889650679924865351804915463619009",
  "1"
 ],
 "T2": [
  "13453339944260436603772379655045194567668841305436667299518131720401799197975",
  "1878530269448865558885111361698648918780579563213553034619643588870422013925",
  "1"
 ],
 "T3": [
  "7968522597035204585552688871740125090430156719632864203269035766618172641619",
  "19811461066576534307499218737564249038349645264023711514858145683802009720956",
  "1"
 ],
 "Wxi": [
  "15987522046720054484294109486076710847215230863461852476975806408814593489310",
  "15454317329417224539157853572276874240734848836935342309579771138054229033523",
  "1"
 ],
 "Wxiw": [
  "951930434873131110350320837324908721786699471414385262506203998832780237941",
  "17429286652635776304236385674029337426996094203091753535498904364644818323108",
  "1"
 ],
 "eval_a": "15004998984254783864940761541262947912840270622227584000019303298477580325070",
 "eval_b": "1947081577872201452693962008974639354754250794733650209506327813702580206940",
 "eval_c": "21521658401977056321791152224833831920988055092058296503354379010082682876287",
 "eval_s1": "21173748067731374811694638079145976040116673746120251365684325858495049672557",
 "eval_s2": "17743678266096230707311925318440497524696014329588703355930383513494505328606",
 "eval_zw": "10543756018853707613533778080554550059272691861721761775521367027104610102236",
 "protocol": "plonk",
 "curve": "bn128"
}
json
[
 "1"
]

:::

python
# type: ignore
import os
from dotenv import load_dotenv

load_dotenv()

from web3 import Web3
from eth_account import Account

RPC_URL = os.getenv("RPC_URL")
# 使用 HTTPProvider 创建 Web3 实例
w3 = Web3(Web3.HTTPProvider(RPC_URL))

# 导入账户
account = Account.from_key(os.getenv("PRIVATE_KEY"))
w3.eth.default_account = account.address

# 合约地址
contract_addr = "0xbEA8E0F363b1B8469f7971ED157Ec262232D293e"

# 导入abi
with open("abi.json", "r") as f:
    import json
    abi = json.load(f)

# 创建合约实例
contract = w3.eth.contract(address=contract_addr, abi=abi)

# 导入proof中的24个uint256
with open("proof_plonk.json", "r") as f:
    proof_data = json.load(f)
    
# 导入public_signals
with open("public_plonk.json", "r") as f:
    public_signals = json.load(f)
    
proof = [
    int(proof_data["A"][0]),
    int(proof_data["A"][1]),
    int(proof_data["B"][0]),
    int(proof_data["B"][1]),
    int(proof_data["C"][0]),
    int(proof_data["C"][1]),
    int(proof_data["Z"][0]),
    int(proof_data["Z"][1]),
    int(proof_data["T1"][0]),
    int(proof_data["T1"][1]),
    int(proof_data["T2"][0]),
    int(proof_data["T2"][1]),
    int(proof_data["T3"][0]),
    int(proof_data["T3"][1]),
    int(proof_data["Wxi"][0]),
    int(proof_data["Wxi"][1]),
    int(proof_data["Wxiw"][0]),
    int(proof_data["Wxiw"][1]),
    int(proof_data["eval_a"]),
    int(proof_data["eval_b"]),
    int(proof_data["eval_c"]),
    int(proof_data["eval_s1"]),
    int(proof_data["eval_s2"]),
    int(proof_data["eval_zw"])
]

public = [int(x) for x in public_signals]

# 调用合约方法创建交易
tx = contract.functions.verifyProof(proof, public).build_transaction({
    'from': w3.eth.default_account,
    'nonce': w3.eth.get_transaction_count(w3.eth.default_account),
    'gas': 500000,
    'gasPrice': w3.to_wei('20', 'gwei')
})

# 签名
signed = account.sign_transaction(tx)

# 发送交易
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print("tx hash:", tx_hash.hex())

# 等待状态确认
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print("Transaction receipt:", receipt)

# 对于一个不涉及交易的函数返回值也可以直接call来验证(不会产生交易记录和gas fee)
result = contract.functions.verifyProof(proof, public).call()
print("Result", result)