🦅

web3.py でスマートコントラクトを実行してみる

2022/03/03に公開

はじめに

前回はweb3.pyを使って Hyperledger Besu上で送金テストを行い、pythonの素晴らしさを勝手に再認識した。

Web3.py をさわってみる

今回は続きとして、web3.pyでスマートコントラクトを実行してみる。

参考サイト

公式ドキュメント
https://web3py.readthedocs.io/en/stable/contracts.html#contracts
こつこつイーサリアム
https://k2k2-ethereum.com/programming/python/273/

事前準備

python用Solc の準備

pythonスクリプトの中でSolidity をコンパイルできるようにするために、以下をインストールする。

py-solc-x のインストール

$ pip install py-solc-x

CLIでの確認

>>> from solcx import install_solc
>>> install_solc(version='latest')
Version('0.8.12')

HyperLedger Besuの起動

省略。

pythonスクリプト

今回は素人の自分でもわかりやすいように、スマートコントラクトを作成しブロックチェーンに展開するスクリプトと、それを呼び出すスクリプトを分けて作ることにした。

スマートコントラクト作成スクリプト

contract.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 = 'Hello';
	}

	function greet() view public returns (string memory) {
	    return greeting;
	}
    }
    ''',
    output_values=['abi', 'bin']
)

# コントラクトインターフェイス
contract_id, contract_interface = compiled_sol.popitem()

# バイトコードと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)

これを実行すると、ABIとコントラクトアドレスが表示される。ABIというのはよくわかっていないが、呼び出し時にも必要みたい。

$ python3 contract.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'}]
0x3F0BE59Bc74c7368Aa049a0B064ce9Dc32890669

これでJavaScriptのJaの字も使わずに、ブロックチェーン上にスマートコントラクトが実装された。素晴らしい!

スマートコントラクト呼び出しスクリプト

call.py

さきほど表示されたABIとコントラクトアドレスを使って呼び出しスクリプトを作成。実質6行しかない。

# ライブラリのインポート
from web3 import Web3

# 接続
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))

# 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'}]

# コントラクトアドレス
contractAddress = '0x3F0BE59Bc74c7368Aa049a0B064ce9Dc32890669'

# コントラクトオブジェクト
greeter = w3.eth.contract(address=contractAddress, abi=abi)

# 呼び出しと表示
print(greeter.functions.greet().call())

これを実行すると、スマートコントラクトを呼び出した結果が表示される。

$ python3 call.py 
Hello

なるほどー。つまり関数を呼び出すだけであれば新たにトランザクションを生成する必要がないということですかね。ガス代もかからないと。

ここまではなんとなく理解できたので、次はスマートコントラクトに値を渡すやりかたを試してみたいと思います。

Discussion