記事の内容
この記事ではHyperledger Sawtooth-Sethの環境構築を行います。
基本的には公式のドキュメントに書いてある内容になりますが、分かりづらい部分などを少し補足したいと思います。
Hyperledger Sawtooth-Seth?
SethはSawtooth-Ethereumプロジェクトのことで、Hyperledger-SawtoothプラットフォームにEthereumのEVM(Ethereum Virtual Machine)をサポートするためのプロジェクトになります。
つまり、Sawtoothプラットフォーム上でEthereumのcontractを実行することが出来るようになります。
このEVMを動かす仕組みの部分についてはHyperledger-Burrowが使われています。
注意すべき点は3点
- Blockの識別は32バイトのブロックハッシュではなく、64バイトのヘッダー署名で識別される。ブロックハッシュを使用するスマートコントラクトはヘッダー署名の最初の32バイトが使用される
- 実行リソースの制限は権限で行われるので実質Gasは不要
- Sawtooth内でのトランザクション実行はモジュール化されているため、トランザクションはブロックチェーンのコンテキスト内で実行されていることを知ることができません。
この3番目についてはまだ理解しきれておらず、どう注意すべきなのかを理解できてません。
Sawtooth-Sethの環境構築
早速環境構築を行っていきます。
1.Sawtooth-SethのSetup
gitのリポジトリから最新のソースをcloneする
git clone https://github.com/hyperledger/sawtooth-seth.git
cd sawtooth-seth
docker-compose up --build
buildはかなり時間がかかります。
私の環境では1時間30分ほどかかりました。
dockerの起動が完了するとサービスが以下のポートで公開される。
Host | Port Service |
---|---|
8080 | Sawtooth REST API Server |
3030 | Seth-RPC Server |
buildが終わると以下のとおりコンテナが起動します。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
81ec0d06335e sawtooth-seth-cli-go:latest "bash -c '\n seth in…" 3 hours ago Up 3 hours seth-cli-go
b95be9c606f0 hyperledger/sawtooth-rest-api:nightly "sawtooth-rest-api -…" 3 hours ago Up 3 hours 4004/tcp, 8008/tcp, 0.0.0.0:8080->8080/tcp rest-api
9f8f4953f169 sawtooth-seth-rpc:latest "bash -c '\n seth-rp…" 3 hours ago Up 3 hours 0.0.0.0:3030->3030/tcp seth-rpc
de45cd7836b4 hyperledger/sawtooth-block-info-tp:nightly "block-info-tp -vv -…" 3 hours ago Up 3 hours 4004/tcp block-info-tp
ab8c34b768a9 sawtooth-seth-cli:latest "bash -c '\n seth co…" 3 hours ago Up 3 hours seth-cli
8ac0407ffdad sawtooth-seth-tp:latest "bash -c '\n seth-tp…" 3 hours ago Up 3 hours seth-tp
0ab8b272c365 hyperledger/sawtooth-devmode-engine-rust:nightly "devmode-engine-rust…" 3 hours ago Up 3 hours devmode-engine-rust
d6674dd15fed hyperledger/sawtooth-settings-tp:nightly "settings-tp -vv --c…" 3 hours ago Up 3 hours 4004/tcp settings-tp
d7fcffbdce72 hyperledger/sawtooth-validator:nightly "bash -c '\n if [ ! …" 3 hours ago Up 3 hours 0.0.0.0:4004->4004/tcp, 0.0.0.0:32768->8800/tcp sawtooth-validator
buildが終わって環境が正しく出来ているか確認するためブロックの情報を取得してみます。
curl http://0.0.0.0:8080/blocks
{
"data": [
{
"batches": [
{
"header": {
"signer_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e",
"transaction_ids": [
"34b485ec53289df6c8818113ffc297167720fc6c5c0fc75489d9ecd487ffd7fb44faab5a2c3c227252a8ec3bdf542d88ae940aedf8356a339a628dda44231bf1"
]
},
"header_signature": "c58dfa9aade0c15b02ec80295dd9a77697f025415c54a7e4d9a7299559bf6a8e17dfc4daf4c7b96ddc71f4af96f521ef2f87ef3129cced6d4d87fb904cc24ebf",
"trace": false,
"transactions": [
{
"header": {
"batcher_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e",
"dependencies": [],
"family_name": "sawtooth_settings",
"family_version": "1.0",
"inputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c12840f169a04216b7",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1918142591ba4e8a7",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c12840f169a04216b7"
],
"nonce": "",
"outputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c12840f169a04216b7"
],
"payload_sha512": "ed55267439d5d1259c19a14d5fc29a3e398416e4be76af698253c75594d731823b25d5aefb5e77ba0f4232aef8189b3bb716dfcba84705cb204c672e03631a16",
"signer_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e"
},
"header_signature": "34b485ec53289df6c8818113ffc297167720fc6c5c0fc75489d9ecd487ffd7fb44faab5a2c3c227252a8ec3bdf542d88ae940aedf8356a339a628dda44231bf1",
"payload": "CAESgAEKJnNhd3Rvb3RoLnNldHRpbmdzLnZvdGUuYXV0aG9yaXplZF9rZXlzEkIwMzlkY2E3NjIyNDc5N2Y0MDQwZjg1NzBiM2FkYzdhMWYxN2EzMDU1YWM0YzFmYWMxMDM0YTkxNWRiMDEyY2RkM2UaEjB4ODU0YjliNzk3MzJlMWE4MA=="
}
]
},
{
"header": {
"signer_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e",
"transaction_ids": [
"16effac10b7c2dca490d1ff83982611bc1fcb4570d8f30b61382de3d5a4843575a2d165724e86fce7519c3b0e129229e35b8e021bca38c8a01e943725c582ec0",
"ab88dc2f1d9b6c9196087f2713afa3b742623aa7a8a172f53730b0997ff801483c438fe7d8e9126aa4ef3742ff4c9db319500139a144f05d0a93cafdc39678e1",
"e824e60479c42353f0a5e20e3b7cf1e6621e5a93faacbf65800006c8c34970943c9dcfe326e4fd43a39f2f7fe250fab152288866b6b7423d25d320d53da56e13"
]
},
"header_signature": "2c9b0d89d1c3aad0f9763668de53d555ad48ab72f98ec5d12b4a3300ed57918c20435c18c3304f609831b85f24ae88912914ad5ead95b2fbfa9eb5cfa21ae5bd",
"trace": false,
"transactions": [
{
"header": {
"batcher_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e",
"dependencies": [],
"family_name": "sawtooth_settings",
"family_version": "1.0",
"inputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c12840f169a04216b7",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1918142591ba4e8a7",
"000000a87cb5eafdcca6a8c983c585ac3c40d9b1eb2ec8ac9f31ff82a3537ff0dbce7e"
],
"nonce": "",
"outputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8c983c585ac3c40d9b1eb2ec8ac9f31ff82a3537ff0dbce7e"
],
"payload_sha512": "0df17cc8cf7e37cba6dcd8b76142d67cc23eff56c7fc521857101e928c728c81d3ef1dfaa78b651743bddebad922e258525ae96c0b1915e564d99aa94b40f3a4",
"signer_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e"
},
"header_signature": "16effac10b7c2dca490d1ff83982611bc1fcb4570d8f30b61382de3d5a4843575a2d165724e86fce7519c3b0e129229e35b8e021bca38c8a01e943725c582ec0",
"payload": "CAESQAohc2F3dG9vdGguY29uc2Vuc3VzLmFsZ29yaXRobS5uYW1lEgdEZXZtb2RlGhIweDY4OGFjMGJjNTNkN2E4Njc="
},
{
"header": {
"batcher_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e",
"dependencies": [],
"family_name": "sawtooth_settings",
"family_version": "1.0",
"inputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c12840f169a04216b7",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1918142591ba4e8a7",
"000000a87cb5eafdcca6a8c983c585ac3c40d9b1eb2ec8ac9f31ff5ca4f3850ccc331a"
],
"nonce": "",
"outputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8c983c585ac3c40d9b1eb2ec8ac9f31ff5ca4f3850ccc331a"
],
"payload_sha512": "9f99ada845678a382e339b07466b9ba3a527ee445db227c16b3f123a5942ea572a4cae88d8ac6382eb3dea8a9c5c2b2ba1e09970cc29f0e4ad79f8379e67b73e",
"signer_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e"
},
"header_signature": "ab88dc2f1d9b6c9196087f2713afa3b742623aa7a8a172f53730b0997ff801483c438fe7d8e9126aa4ef3742ff4c9db319500139a144f05d0a93cafdc39678e1",
"payload": "CAESPwokc2F3dG9vdGguY29uc2Vuc3VzLmFsZ29yaXRobS52ZXJzaW9uEgMwLjEaEjB4NGFjMDQ0YWY4NjE4NjZmZQ=="
},
{
"header": {
"batcher_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e",
"dependencies": [],
"family_name": "sawtooth_settings",
"family_version": "1.0",
"inputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c12840f169a04216b7",
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1918142591ba4e8a7",
"000000a87cb5eafdcca6a8f82af32160bc5311783bdad381ea57b4e3b0c44298fc1c14"
],
"nonce": "",
"outputs": [
"000000a87cb5eafdcca6a8cde0fb0dec1400c5ab274474a6aa82c1c0cbf0fbcaf64c0b",
"000000a87cb5eafdcca6a8f82af32160bc5311783bdad381ea57b4e3b0c44298fc1c14"
],
"payload_sha512": "2cd9ec5b11ddd5a1d4df7219b6fc1f97a3c5189f22877660e1914abd30d383f3383c7ed22f41e1ccf967a50ac32af5ae19db63029b83ac3d9a849eed1ea2ee60",
"signer_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e"
},
"header_signature": "e824e60479c42353f0a5e20e3b7cf1e6621e5a93faacbf65800006c8c34970943c9dcfe326e4fd43a39f2f7fe250fab152288866b6b7423d25d320d53da56e13",
"payload": "CAESRAoic2F3dG9vdGgudmFsaWRhdG9yLmJhdGNoX2luamVjdG9ycxIKYmxvY2tfaW5mbxoSMHhiNTExYTRjZGZhMTkzOGFl"
}
]
}
],
"header": {
"batch_ids": [
"c58dfa9aade0c15b02ec80295dd9a77697f025415c54a7e4d9a7299559bf6a8e17dfc4daf4c7b96ddc71f4af96f521ef2f87ef3129cced6d4d87fb904cc24ebf",
"2c9b0d89d1c3aad0f9763668de53d555ad48ab72f98ec5d12b4a3300ed57918c20435c18c3304f609831b85f24ae88912914ad5ead95b2fbfa9eb5cfa21ae5bd"
],
"block_num": "0",
"consensus": "R2VuZXNpcw==",
"previous_block_id": "0000000000000000",
"signer_public_key": "039dca76224797f4040f8570b3adc7a1f17a3055ac4c1fac1034a915db012cdd3e",
"state_root_hash": "fb8a0fa36c1f26ad3066189059d763af26a601e11acd151ddc9ee18ca1147bc7"
},
"header_signature": "de3fd9095eca3be3651de7eefc96f244cee5e5c136f8d99d28a3a982071fb9d618c59bc0a6fa8e2287392c85dfbf1775afbf0b0f1776fb8a39e53d48eedfc438"
}
],
"head": "de3fd9095eca3be3651de7eefc96f244cee5e5c136f8d99d28a3a982071fb9d618c59bc0a6fa8e2287392c85dfbf1775afbf0b0f1776fb8a39e53d48eedfc438",
"link": "http://0.0.0.0:8080/blocks?head=de3fd9095eca3be3651de7eefc96f244cee5e5c136f8d99d28a3a982071fb9d618c59bc0a6fa8e2287392c85dfbf1775afbf0b0f1776fb8a39e53d48eedfc438&start=0x0000000000000000&limit=100",
"paging": {
"limit": null,
"start": null
}
}
##2.アカウントを作成する
アカウントはキー情報を作成して、そのキー情報をインポートする形で作成します。
$ openssl ecparam -genkey -name secp256k1 | openssl ec -out key-file.pem -aes128
$ seth account import key-file.pem myalias
このコマンドを実行するとパスワードの設定を求められるのでパスワードを設定します。
次のコマンドでアカウントを作成します。
$ seth account create --nonce=0 --wait myalias
実行に成功するとアカウント作成のトランザクションとアカウントのAddressが結果として返ってきます。
Enter Password to unlock myalias:
Account created
Transaction Receipt: {
"TransactionID": "22ce6936ed4dc4ad80eade096569ff8c704391e9147500184aece60a5a14ba441bb970dcd17d04af24a22812f42ef36e34d5a537f0dcc53d0678c1b06f248482",
"Address": "b9919d7959f11155d74d105299c97af3f6e72a6e"
}
アカウントの情報を確認します。
$ seth show account {address}
コマンドの{address}にはアカウントのアドレスがはいります。
$ seth show account b9919d7959f11155d74d105299c97af3f6e72a6e
Address: b9919d7959f11155d74d105299c97af3f6e72a6e
Balance: 0
Code :
Nonce : 1
Perms : +root,+send,+call,+contract,+account
(No Storage Set)
##3.コントラクトのデプロイ
次はsolidityで書かれたコントラクトをデプロイします。
サンプルのコードはリポジトリに用意されているものを使用します。
cd sawtooth-seth/
cp contracts/examples/simple_intkey/simple_intkey.sol contracts/contract.sol
このコントラクトですが、solidityコンパイラの0.4.0で作られています。
現時点(2019/11/02)では、この記事の手順でインストールされているsolcのバージョンが0.5.12のためうまく動きません。
以下、0.5.12用に修正したものです。
pragma solidity ^0.5.12;
contract intkey {
mapping (uint => uint) intmap;
event Set(uint key, uint value);
function set(uint key, uint value) public {
intmap[key] = value;
emit Set(key, value);
}
function inc(uint key) public {
intmap[key] = intmap[key] + 1;
}
function dec(uint key) public {
intmap[key] = intmap[key] - 1;
}
function get(uint key) public view returns (uint retVal) {
return intmap[key];
}
}
修正したのはバージョンとget関数の定義だけです。
次はコンパイルします。
solcがインストールされているコンテナに入ります。
$ docker exec -it seth-cli-go bash
次にコンパイルします。
$ cd contracts
$ solc --bin contract.sol
======= contract.sol:intkey =======
Binary:
608060405234801561001057600080fd5b50610230806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631ab06ee514610051578063812600df146100895780639507d39a146100b7578063c20efb90146100f9575b600080fd5b6100876004803603604081101561006757600080fd5b810190808035906020019092919080359060200190929190505050610127565b005b6100b56004803603602081101561009f57600080fd5b8101908080359060200190929190505050610181565b005b6100e3600480360360208110156100cd57600080fd5b81019080803590602001909291905050506101b0565b6040518082815260200191505060405180910390f35b6101256004803603602081101561010f57600080fd5b81019080803590602001909291905050506101cc565b005b80600080848152602001908152602001600020819055507f545b620a3000f6303b158b321f06b4e95e28a27d70aecac8c6bdac4f48a9f6b38282604051808381526020018281526020019250505060405180910390a15050565b600160008083815260200190815260200160002054016000808381526020019081526020016000208190555050565b6000806000838152602001908152602001600020549050919050565b60016000808381526020019081526020016000205403600080838152602001908152602001600020819055505056fea265627a7a72315820394bd55d5ddc51241a351b007ca05e01f86d35aaca9b99b1b2053687f5836e2864736f6c634300050c0032
次はコントラクトをデプロイします。
デプロイは以下のコマンドで実行します。
{alias}にはアカウントの情報、{contract}にはコンパイルしたバイナリデータが入ります。
$ seth contract create --wait {alias} {contract}
この手順では以下のようになります。
$ seth contract create --wait myalias 608060405234801561001057600080fd5b50610230806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631ab06ee514610051578063812600df146100895780639507d39a146100b7578063c20efb90146100f9575b600080fd5b6100876004803603604081101561006757600080fd5b810190808035906020019092919080359060200190929190505050610127565b005b6100b56004803603602081101561009f57600080fd5b8101908080359060200190929190505050610181565b005b6100e3600480360360208110156100cd57600080fd5b81019080803590602001909291905050506101b0565b6040518082815260200191505060405180910390f35b6101256004803603602081101561010f57600080fd5b81019080803590602001909291905050506101cc565b005b80600080848152602001908152602001600020819055507f545b620a3000f6303b158b321f06b4e95e28a27d70aecac8c6bdac4f48a9f6b38282604051808381526020018281526020019250505060405180910390a15050565b600160008083815260200190815260200160002054016000808381526020019081526020016000208190555050565b6000806000838152602001908152602001600020549050919050565b60016000808381526020019081526020016000205403600080838152602001908152602001600020819055505056fea265627a7a72315820394bd55d5ddc51241a351b007ca05e01f86d35aaca9b99b1b2053687f5836e2864736f6c634300050c0032
Enter Password to unlock myalias:
Contract created
Transaction Receipt: {
"TransactionID": "80955167079971c1701ec8edebc51e04ac931d7bf814535a614e39eef39ee5066432f95342c0022a1370e5de62884cbcb52ebbeb908075dc185ab521ac66966d",
"GasUsed": 24,
"Address": "93864c71b24054105adfc067ed63cc75d557ca70",
"ReturnValue": "608060405234801561001057600080fd5b506004361061004c5760003560e01c80631ab06ee514610051578063812600df146100895780639507d39a146100b7578063c20efb90146100f9575b600080fd5b6100876004803603604081101561006757600080fd5b810190808035906020019092919080359060200190929190505050610127565b005b6100b56004803603602081101561009f57600080fd5b8101908080359060200190929190505050610181565b005b6100e3600480360360208110156100cd57600080fd5b81019080803590602001909291905050506101b0565b6040518082815260200191505060405180910390f35b6101256004803603602081101561010f57600080fd5b81019080803590602001909291905050506101cc565b005b80600080848152602001908152602001600020819055507f545b620a3000f6303b158b321f06b4e95e28a27d70aecac8c6bdac4f48a9f6b38282604051808381526020018281526020019250505060405180910390a15050565b600160008083815260200190815260200160002054016000808381526020019081526020016000208190555050565b6000806000838152602001908152602001600020549050919050565b60016000808381526020019081526020016000205403600080838152602001908152602001600020819055505056fea265627a7a72315820394bd55d5ddc51241a351b007ca05e01f86d35aaca9b99b1b2053687f5836e2864736f6c634300050c0032"
}
コントラクトがデプロイできました。
##4.コントラクトを実行する
コントラクトの実行はseth-cliコンテナで実行します。
$ docker exec -it seth-cli bash
コンテナ内でnodejsのライブラリを使用してコントラクト実行に使用する関数名、引数の情報を作成します。
$ node
> var abi = require('ethereumjs-abi')
undefined
> abi.simpleEncode("set(uint,uint)", "0x13", "0x2a").toString("hex")
'1ab06ee50000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000002a'
次のコマンドでコントラクトをデプロイします。
{alias}にはアカウント名、{address}にはコントラクトをデプロイした時のコントラクトのアドレス、{input}にはnodejsで作った文字列が入ります。
$ seth contract call --wait {alias} {address} {input}
この手順だと以下のようになります。
$ seth contract call --wait myalias 93864c71b24054105adfc067ed63cc75d557ca70 1ab06ee50000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000002a
Enter Password to unlock myalias:
Contract called
Transaction Receipt: {
"TransactionID": "4a3e35ad4f1eb75b6278f974a50afced32e504927914eb41811f7d212a81d24a7a9a029edb194ee78ccde1748258bc5095815a043b304738f2b686ef95167fd6",
"GasUsed": 181,
"Events": [
{
"event_type": "seth_log_event",
"Attributes": [
{
"Key": "address",
"Value": "93864c71b24054105adfc067ed63cc75d557ca70"
},
{
"Key": "eventID",
"Value": "93864C71B24054105ADFC067ED63CC75D557CA70"
},
{
"Key": "topic1",
"Value": "545b620a3000f6303b158b321f06b4e95e28a27d70aecac8c6bdac4f48a9f6b3"
}
],
"Data": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKg=="
}
]
}
実行が出来ました。
最後にこのコントラクト実行で作成されたトランザクションの情報を取得します。
$ seth show receipt {transaction-id}
{transaction-id}にはコントラクト実行の結果で返ってきたTransactionIDを設定します。
この手順では以下のようになります。
$ seth show receipt 4a3e35ad4f1eb75b6278f974a50afced32e504927914eb41811f7d212a81d24a7a9a029edb194ee78ccde1748258bc5095815a043b304738f2b686ef95167fd6
Seth Transaction Receipt: {
"GasUsed": 181
}
終わりです。
#所感
一旦、コントラクト実行までは出来たもののSawtoothとの繋がりがあまり分からないですね。
gethでコントラクト実行と同じような感じで使えるのはありがたいなと感じました。