🐯
Web3.py でスマートコントラクトに値を渡してみる
はじめに
前回はweb3.pyを使って簡単なスマートコントラクトの実行を行い pythonの素晴らしさを、またしても再認識した。
今回は続きとして、前回のコードを改修し、スマートコントラクトに好きな挨拶を渡して表示できるようにしてみる。
参考サイト
公式ドキュメント
こつこつイーサリアムpythonスクリプト
今回もわかりやすいように、スマートコントラクトを作成しブロックチェーンに展開するスクリプトと、値を渡して呼び出すスクリプトを分けて作ることにした。
スマートコントラクト作成スクリプト
contract_set.py
# ライブラリの読み込み
from web3 import Web3
from solcx import compile_source
# ローカルのイーサリアム環境(Basu)に接続
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
# アカウントと秘密鍵の設定
account_0 = w3.toChecksumAddress('0xfe3b557e8fb62b89f4916b721be55ceb828dbd73')
private_key = '0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63'
# Solidity のソースをコンパイル
compiled_sol = compile_source(
'''
pragma solidity >0.5.0;
contract Greeter {
string public greeting;
constructor() public {
greeting = 'Hogetaro';
}
function setGreeting(string memory _greeting) public {
greeting = _greeting;
}
function greet() view public returns (string memory) {
return greeting;
}
}
''',
output_values=['abi', 'bin']
)
# コントラクトインターフェイスの取得
contract_id, contract_interface = compiled_sol.popitem()
# print(contract_interface)
# バイトコードとABI
bytecode = contract_interface['bin']
abi = contract_interface['abi']
# ABIの表示
print(abi)
# コントラクトの作成
contract = w3.eth.contract(abi=abi, bytecode=bytecode)
# トランザクションの生成
tx = contract.constructor().buildTransaction({
'from': account_0,
'nonce': w3.eth.getTransactionCount(account_0),
'gas': 1728712,
'gasPrice': w3.toWei('21', 'gwei')})
# トランザクションに署名
signed_tx = w3.eth.account.signTransaction(tx, private_key)
# トランザクションの送信
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
# トランザクションレシート?
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
# コントラクトアドレスの表示
print(tx_receipt.contractAddress)
中身はほとんど前回と同じで、setGreeting という関数を追加しただけである。
これを実行すると、ABIとコントラクトアドレスが表示される。
$ python3 contract_set.py
[{'inputs': [], 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'inputs': [], 'name': 'greet', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [], 'name': 'greeting', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'string', 'name': '_greeting', 'type': 'string'}], 'name': 'setGreeting', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}]
0xfeae27388A65eE984F452f86efFEd42AaBD438FD
スマートコントラクトへの値の設定および呼び出しスクリプト
set_call.py
さきほど表示されたABIとコントラクトアドレスを使って、値を渡したあとに呼び出すスクリプトを作成。
今回は新たなトランザクションを生成、実行する必要があるため前回より複雑になっている。
# ライブラリのインポート
from web3 import Web3
# 接続
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
account_0 = w3.toChecksumAddress('0xfe3b557e8fb62b89f4916b721be55ceb828dbd73')
private_key = '0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63'
# ABI
abi = [{'inputs': [], 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'inputs': [], 'name': 'greet', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [], 'name': 'greeting', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'string', 'name': '_greeting', 'type': 'string'}], 'name': 'setGreeting', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}]
# コントラクトアドレス
contractAddress = '0xfeae27388A65eE984F452f86efFEd42AaBD438FD'
# コントラクトオブジェクト
contract = w3.eth.contract(address=contractAddress, abi=abi)
# 呼び出しと表示
tx = contract.functions.setGreeting('KONNICHIWA!!!!!').buildTransaction({'nonce': w3.eth.getTransactionCount(account_0)})
signed_tx = w3.eth.account.signTransaction(tx, private_key)
# トランザクションの送信
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
print(contract.functions.greet().call())
これを実行すると、元のコントラクトの挨拶を上書きして、設定した挨拶が返される。
$ python3 set_call.py
KONNICHIWA!!!!!
素晴らしい!さすが python!!
挨拶をハードコーディングしてしまってるのを引数で渡すようにすれば、もっと前回との違いがわかりやすい気がするが、とりあえずこれで満足しました。
Discussion