以太坊入門三 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/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM