以太坊入门三 Web3j.py 与节点交互

以太坊 geth 客户端提供自带的交互接口即 web3j ,来控制节点的信息操作。到实际开发中,不论是采用 Java 版的 web3j,还是 Python 版的 web3j,其实关系就不是很大了。

web3 js :https://web3js.readthedocs.io/en/v2.0.0-alpha/

java-web3j:https://docs.web3j.io/getting_started/

python-web3j:https://web3py.readthedocs.io/en/latest/index.html

Tips:<对应的可自行搜索中文相关文档,这里就不一一列出,英语文档想对详细些。中文看过后,开发过程中遇到问题,查看英语文档可了解更多相关信息。>

下面主要列举些 web3.py 里面的常用语句。这里我是写了一个关于节点的类,常用的语句单独写为一个方法。

1. 连接节点

def start_node(db='D:/eth-test/db/', port='30303', rpcport='8545'):
    cmdOrder = 'geth --datadir ' + db + ' --rpc --rpcapi "eth,net,web3,personal,admin,txpool,debug,miner"' \
              ' --port ' + port + ' --rpcport ' + rpcport + ' --nodiscover --rpccorsdomain "*" --allow-insecure-unlock' \
              ' --ipcdisable'
    os.system(cmdOrder)

2. 生成 web3 实例

def __init__(self, ip, rpcport):
    # 连接本地以太坊节点
    self.w3 = Web3(Web3.HTTPProvider('http://' + ip + ':' + rpcport, request_kwargs={'timeout': 60}))

3. 返回当前的账户列表

# 返回当前所有账户
def getAddrs(self):
    return self.w3.eth.accounts

4. 返回指定账户余额

# 返回指定地址的余额
def getBalance(self, addr):
    balance = self.w3.fromWei(self.w3.eth.getBalance(addr), 'ether')
    return balance

5. 返回当前节点的 enode

此作用用来添加节点

# 返回当前节点的 enode 信息
def getEnode(self):
    return self.w3.geth.admin.node_info()['enode']

6. 返回节点个数

# 返回当前节点数
def peers(self):
    return self.w3.geth.admin.peers()

7. 添加节点

# 当前节点添加节点
def addPeer(self, enode):
    return self.w3.geth.admin.add_peer(enode)

8. 挖矿、停止挖矿

# 开始挖矿
def minerStart(self):
    self.w3.geth.miner.start(1)
# 结束挖矿
def minerStop(self):
    self.w3.geth.miner.stop()

9. 部署智能合约

部署合约以及对智能合约的调用(改变合约状态时),都需要设置节点默认账户,并解锁该账户。此外还需要 引入 solc.exe 文件(放在同级目录)

from web3 import Web3
from solc import compile_standard

personal.unlockAccount(ins.getAddrs()[2], 'sophia', 300) # 参数分别为 账户地址、私匙、解锁时间(秒)
def contractCompile(ins):
    compiledSol = compile_standard({
        'language': 'Solidity',
        'sources': {'UserInfo.sol': {
                        'content': '''
                            pragma solidity ^0.6.0;

                            contract UserInfo {
                                 string name;
                                 uint age;
                                 bool gender = true;
                                 constructor() public{
                                     name = 'junweiJun';
                                     age = 18;
                                     gender = true;
                                 }
                                 function setAttr(string memory _name, uint _age, bool _gender) public{
                                     name = _name;
                                     age = _age;
                                     gender = _gender;
                                 }
            
                                 function getAttr() public view returns (string memory, uint, bool) {
                                     return (name, age, gender);
                                 }
                             }
                        
                        '''
                    }
        },
        "settings":
            {
                "outputSelection": {
                    "*": {
                        "*": [
                            "metadata", "evm.bytecode"
                            , "evm.bytecode.sourceMap"
                        ]
                    }
                }
            }
    })
    # 设置默认账户
    # ins.w3.eth.coinbase = ins.getAddrs()[1]
    # 获取 bytecode
    bytecode = compiledSol['contracts']['UserInfo.sol']['UserInfo']['evm']['bytecode']['object']
    # 获取 abi
    abi = json.loads(compiledSol['contracts']['UserInfo.sol']['UserInfo']['metadata'])['output']['abi']
    print("abi:", abi)
    # 生成合约
    UserInfo = ins.w3.eth.contract(abi=abi, bytecode=bytecode)
    # # 部署合约
    print(ins.w3.eth.defaultAccount)
    ins.w3.eth.defaultAccount = ins.getAddrs()[1]
    print(ins.w3.eth.defaultAccount)
    # 解锁账户
    ins.w3.geth.personal.unlockAccount(ins.getAddrs()[1], 'xsmile', 300)
    # 设置 defaultAccount 并解锁账户,否则会出现 ValueError: {'code': -32000, 'message': 'unknown account'}
    txHash = UserInfo.constructor().transact()
    try:
        ins.minerStart()
        # # 等待合约被挖掘
        txReceipt = ins.w3.eth.waitForTransactionReceipt(txHash)
        print('txReceipt:', txReceipt)
        # ins.minerStop()
        userInfo = ins.w3.eth.contract(address=txReceipt.contractAddress, abi=abi)
        user = userInfo.functions.getAttr().call()
        print('init: ', user)
    except Exception:
        pass
    finally:
        ins.minerStop()
    pass
合约部署

10. 调用智能合约

def updateContract(ins):
    # 解锁账户
    ins.w3.eth.defaultAccount = ins.getAddrs()[2]
    ins.w3.geth.personal.unlockAccount(ins.getAddrs()[2], 'sophia', 300)
    abi = [{'inputs': [], 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'inputs': [], 'name': 'getAttr', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}, {'internalType': 'uint256', 'name': '', 'type': 'uint256'}, {'internalType': 'bool', 'name': '', 'type': 'bool'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'string', 'name': '_name', 'type': 'string'}, {'internalType': 'uint256', 'name': '_age', 'type': 'uint256'}, {'internalType': 'bool', 'name': '_gender', 'type': 'bool'}], 'name': 'setAttr', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}]
    contractAddress = '0x9DBF7256f54Eefe99Aa1f9436921F0F0e13147Ff'
    userInfo = ins.w3.eth.contract(address=contractAddress, abi=abi)
    user = userInfo.functions.getAttr().call()
    print(user)
    try:
        ins.minerStart()
        uName = 'jerry'
        uAge = 20
        uGender = True
        txHash = userInfo.functions.setAttr(uName, uAge, uGender).transact()
        print("txHash:", txHash)
        txReceipt = ins.w3.eth.waitForTransactionReceipt(txHash)
        print("******************************************")
        print('txReceipt:', txReceipt)
        user1 = userInfo.functions.getAttr().call()
        print('after: ', user1)
    except Exception:
        print(Exception)
    finally:
        ins.minerStop()
调用合约

11. 查询区块中存储的信息

这里指调用智能合约,并改变合约状态后,存储到区块中合约内的信息。

打印信息时,如区块地址为类型为:Hexbytes 类型的,我们需要的是字符串类型的一串16进制字符。

参考:https://web3py.readthedocs.io/en/latest/contracts.html#web3.contract.ContractFunction.call

block.hash.hex()  # 转换输出字符串地址
def searchContract(ins):
    abi = [{'inputs': [], 'name': 'getAttr', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}, {'internalType': 'string', 'name': '', 'type': 'string'}, {'internalType': 'string', 'name': '', 'type': 'string'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'string', 'name': '_number', 'type': 'string'}, {'internalType': 'string', 'name': '_batch', 'type': 'string'}, {'internalType': 'string', 'name': '_createTime', 'type': 'string'}], 'name': 'setAttr', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}]
    contractAddress = '0xb27a8caeAeE69B17d377a889246DA5112c9e14b8'
    userInfo = ins.w3.eth.contract(address=contractAddress, abi=abi)
    print("****************区块 Hash 值查询******************")
    blockHash = '0x627b561fe9d60ec6e6b392a4361340ed009df2c37497d4a343e172c96da1552d'
    info = userInfo.functions.getAttr().call(block_identifier=blockHash)
    print(info)
查询合约内容

 

原创不易,尊重版权。转载请注明出处:http://www.cnblogs.com/xsmile/

 

posted @ 2020-03-29 11:11  x_smile  阅读(1417)  评论(0编辑  收藏  举报