こんな人に向けた記事
難しい説明は抜きにして手順やTIPSだけ簡潔にまとめた記事を見ながらポチポチ試しながら理解したい人向け。
前提
この記事を読む前にWin10のBash on Windows をインストールを先にどうぞ。
Ethreumと関連ツールのインストール、各種設定
インストール
$ sudo add-apt-repository -y ppa:ethereum/ethereum
$ sudo apt update
$ sudo apt install ethereum
$ sudo apt install solc
Dir準備
$ sudo mkdir /private_eth
$ sudo chmod 777 /private_eth/
初期化用ファイル準備
C:\work\genesis.json
をWindowsのディレクトリにUTF8で用意してください。とりあえず開発用なので内容は適当でOK。(viエディタ等で用意するよりWindowsのディレクトリに用意する方が楽だろうという意味合いでこっちに作成する例にしました。手順確認のため、何度もrmでディレクトリごと消して確認していた、という理由もあります。)
{
"config": {
"chainId": 123456789,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}
genesisブロックの初期化
$ geth --datadir /private_eth init /mnt/c/work/genesis.json
geth の起動
$ geth --nodiscover --datadir /private_eth
gethを操作する(アカウント作成~採掘)
先ほど起動したgethを動かしたまま、別ウインドウを開いてコンソールを起動してください。
gethコンソールを別で立ち上げる
$ geth attach /private_eth/geth.ipc
アカウントがないことを確認する
ここからはgethコンソールの操作を>で説明します。
> eth.account
[]
新規アカウントを作成する
> personal.newAccount("アカウントのpassword")
アカウントが作成されたことを確認する
> eth.account
アカウントをアンロックする
採掘するためにアンロックする必要があります。パスワード聞かれますので上記で設定した"1つ目のアカウントのpassword"を入力してください。
> personal.unlockAccount(eth.accounts[0])
開発で使う分の採掘をする
開発用途なので必要な時だけ採掘してください。
> miner.start()
別ウインドウ側を見ましょう。実際にマイニングが開始されます。
INFO [04-27|13:26:24] Commit new mining work number=20 txs=0 uncles=0 elapsed=2.001s
INFO [04-27|13:26:24] Successfully sealed new block number=20 hash=0fe44d…b26983
INFO [04-27|13:26:24] 🔗 block reached canonical chain number=15 hash=c6a2b0…c88282
INFO [04-27|13:26:24] 🔨 mined potential block number=20 hash=0fe44d…b26983
INFO [04-27|13:26:24] Commit new mining work number=21 txs=0 uncles=0 elapsed=151µs
INFO [04-27|13:26:24] Successfully sealed new block number=21 hash=b95c29…6fd59d
INFO [04-27|13:26:24] 🔗 block reached canonical chain number=16 hash=8fcab0…0ceeb9
INFO [04-27|13:26:24] 🔨 mined potential block number=21 hash=b95c29…6fd59d
INFO [04-27|13:26:24] Mining too far in the future wait=2s
採掘できているか残高を確認する
> eth.getBalance(eth.accounts[0])
必要ないときは採掘を止めます
後述のContractを扱うときはマイニングしている必要あるので、適宜Start、Stopしてください。
> miner.stop()
Contractを動かす
ここからが本題。
solファイルを用意する
C:\work\HelloWorld.sol をUTF8で作成する
pragma solidity ^0.4.13;
contract HelloWorld {
string _message;
function setMessage(string message) {
_message = message;
}
function getMessage() returns (string) {
return _message;
}
}
solをコンパイルする
テキストに出す必要は無いのですが、ファイルに残った方が便利そうなので。
$ solc --bin --abi /mnt/c/work/HelloWorld.sol >> /mnt/c/work/HelloWorld.sol.txt
以下の内容のテキストが出力されます
======= /mnt/c/work/HelloWorld.sol:HelloWorld =======
Binary:
608060405234801561001057600080fd5b506102d7806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063368b877214610051578063ce6d41de146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610206565b5050565b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fc5780601f106101d1576101008083540402835291602001916101fc565b820191906000526020600020905b8154815290600101906020018083116101df57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a723058207d10a97dd1ad400deeda71921fe9e414d354b320436b6951314567971dfc9ffc0029
Contract JSON ABI
[{"constant":false,"inputs":[{"name":"message","type":"string"}],"name":"setMessage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"getMessage","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contractをデプロイする
gethコンソールで以下コマンドを実行します。
> bin = "0x608060405234801561001057600080fd5b506102d7806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063368b877214610051578063ce6d41de146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610206565b5050565b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fc5780601f106101d1576101008083540402835291602001916101fc565b820191906000526020600020905b8154815290600101906020018083116101df57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a723058207d10a97dd1ad400deeda71921fe9e414d354b320436b6951314567971dfc9ffc0029"
> abi = [{"constant":false,"inputs":[{"name":"message","type":"string"}],"name":"setMessage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"getMessage","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
> contract = eth.contract(abi)
> HelloWorld = contract.new({ from: eth.accounts[0], data: bin, gas: 1000000 })
アンロックしていないとこのようなメッセージが出ます。採掘を止めてからしばらくするとロックされていると思いますので再度アンロックしてから実施してください。
> HelloWorld = contract.new({ from: eth.accounts[0], data: bin, gas: 1000000 })
Error: authentication needed: password or unlock
at web3.js:3143:20
at web3.js:6347:15
at web3.js:5081:36
at web3.js:3021:24
at <anonymous>:1:14
またこのとき、マイニングしていないとブロックチェーンにとりこまれません。
> HelloWorld = contract.new({ from: eth.accounts[0], data: bin, gas: 1000000 })
{
abi: [{
constant: false,
inputs: [{...}],
name: "setMessage",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [],
name: "getMessage",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
address: undefined,
transactionHash: "0x2471e25618efc5c18a80537abaa939e620737301152422cfad32cda8d019d80b"
}
> HelloWorld.getMessage.call()
TypeError: Cannot access member 'call' of undefined
at <anonymous>:1:1
デプロイされたかどうかはコントラクト名をタイプすればわかります。
取り込み前
> HelloWorld
{
abi: [{
constant: false,
inputs: [{...}],
name: "setMessage",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [],
name: "getMessage",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
address: undefined,
transactionHash: "0xfb92336e24422be457bf4f0ac6bb7d2dfa1337554cb782e359898d9ec2630c78"
}
>
address: undefined の場合、取り込まれていません。
マイニングを再度再開して様子をみてから確認しましょう。
取り込み後
> HelloWorld
{
abi: [{
constant: false,
inputs: [{...}],
name: "setMessage",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [],
name: "getMessage",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
address: "0x2158e824b2f706f4047802d1e80740f059e1506c",
transactionHash: "0xfb92336e24422be457bf4f0ac6bb7d2dfa1337554cb782e359898d9ec2630c78",
allEvents: function(),
getMessage: function(),
setMessage: function()
}
それではコントラクトを動かしてみましょう。
> HelloWorld.setMessage.sendTransaction("test123", { from: eth.accounts[0] })
Error: authentication needed: password or unlock
at web3.js:3143:20
at web3.js:6347:15
at web3.js:5081:36
at web3.js:4137:16
at <anonymous>:1:1
またもアンロックしろということで、おまじないのようにアンロックを書きたくなってきたので引数にパスワードつきで。
> personal.unlockAccount(eth.accounts[0], "password")
true
> HelloWorld.setMessage.sendTransaction("test123", { from: eth.accounts[0] })
"0x9a4743fa6636924c77069c1b56fe9fcea813550f05c6a609747d422da4644f70"
> HelloWorld.getMessage.call()
""
>
あえてこの状態はマイニング止めて行いました。マイニングを開始し、再度Getしてみます。
> miner.start()
> HelloWorld.getMessage.call()
"test123"
>
> miner.stop()
> personal.unlockAccount(eth.accounts[0], "password")
true
> HelloWorld.setMessage.sendTransaction("test456", { from: eth.accounts[0] })
"0x5c3218ed780130525a623a2893169e30b9f2936b2afe264ba542829ef9ce309d"
>
> HelloWorld.getMessage.call()
"test123"
>
はい、このようにマイニング中のみコントラクトの中に"test123"が書き込まれていました。再開すると、また内容が変わります。
> HelloWorld.getMessage.call()
"test123"
> miner.start()
null
> HelloWorld.getMessage.call()
"test456"
sendTransactionはマイニング必要、Getする(コントラクトの中の変数が書き換わらない処理)だけであればマイニング不要とわかりました。
例えばログ専用のコントラクトを作りたい場合、年ごとにプライベートノードわけておくと低負荷で参照系を運用できるなぁ、とか考えてしまいます。
長くなりましたがネットの記事を色々見て試しはしたものの随所に落とし穴があることがわかり、引っかかった部分のTIPSも含めて記載しています。
次回は実際にログ蓄積するI/FをもったContractを作成してみようと思います。