以太坊:通过Web3实现智能合约交互
以太坊:通过Web3实现智能合约交互
1. 环境准备
1.1 安装相关依赖包
安装pip3
sudo apt install python3-pip -y
使用pip3安装web3 python包
pip3 install web3
安装ipython3
sudo apt install ipython3 -y
1.2 安装ganache
下载
输入以下命令,运行ganache(./后的内容视具体版本而定)
./ganache-2.5.4-linux-x86_64.AppImage &
1.3 测试
进入Python交互环境
ipython3
输入以下代码测试连接情况
from web3 import Web3 w3 = Web3(Web3.HTTPProvider("http://localhost:7545")) w3.isConnected()
2. 新建一个student合约
2.1 配置合约信息
在contracts文件夹中新建Student.sol并输入以下内容:
// SPDX-License-Identifier: MIT pragma solidity >=0.4.16 <0.9.0; contract Student{ string name; constructor() { // name = _name; name = "Tom"; } function getName() public view returns (string memory) { return name; } }
2.2 编写web3脚本
2.2.1新建一个Student.py文件
导入库
from web3 import Web3 import os import sys import getopt import uuid
声明一些全局变量
url = "http://localhost:7545" # 以太坊测试链 rpc 连接端口 contract_address_file = contract_student.txt # 合约地址保存文件 abi_file = "Student/Student.abi" # abi 文件 bytecode_file = "Student/Student.bin" # 字节码文件 account_id = 0 # 默认账户
连接测试链
# 连接测试链 w3 = Web3(Web3.HTTPProvider(url)) eth = w3.eth print("eth connect:", w3.isConnected())
设置默认账户
def set_default_account(): """ 设置调用合约、发送交易的账户 """ global account_id eth.defaultAccount = eth.accounts[account_id]
获取abi和bytecode
def get_abi_from_file(file): """ 从文件中获取abi """ with open(file, r) as f: return f.read() def get_bytecode_from_file(file): """ 从文件中获取字节码 """ with open(file, r) as f: return "0x" + f.read()
部署合约、获取合约地址
def deploy_contract(abi, bytecode): """ 部署合约 """ contract = eth.contract(abi=abi, bytecode=bytecode) # 创建合约 tx_hash = contract.constructor().transact() # 部署合约(发送构造函数的交易,需相对应合约中的参数) tx_receipt = eth.waitForTransactionReceipt(tx_hash) # 等待交易回执 print("contract address:", tx_receipt.contractAddress) # 合约地址 # 保存合约 global contract_address_file with open(contract_address_file, "w") as f: f.write(tx_receipt.contractAddress) # 通过地址获取已部署合约 deployed_contract = eth.contract(address=tx_receipt.contractAddress, abi=abi) return deployed_contract def get_deployed_contract(abi, bytecode): """ 获取部署合约,如果本地已保存合约地址,则调用该地址的合约,否则重新创建一个新的合约 """ try: # 尝试获取已有合约 with open(contract_address_file, "r") as f: contract_address = f.read() print("contract address:", contract_address) deployed_contract = eth.contract(address=contract_address, abi=abi) return deployed_contract except IOError: # 获取已有合约失败则重新部署新合约 return deploy_contract(abi, bytecode)
main方法
if __name__ == __main__: set_default_account() abi = get_abi_from_file(abi_file) bytecode = get_bytecode_from_file(bytecode_file) deployed_contract = get_deployed_contract(abi, bytecode) print(deployed_contract.functions.getName().call())
2.2.2 编译合约与运行
编译
solc --abi --bin --overwrite -o Student Student.sol
运行
python3 Student.py