Ethereum (2) – dapp

5年以上前に、Bitcoinのしくみに興味をもち論文にあるコードを実行しました。

Block Chain
http://decode.red/blog/20160409562/

それからNEMの盗難でBlockChain Explorerで追跡したり、

BlockChain Explorer

イーサリアムの通貨でけだない、スマートコントラクトのしくみに興味を持ち、Solidity言語のテストをしました。

Ethereum

Ethereum

以前から、音楽などの著作権や発明の特許といったものを登録するのに面倒な手続きや長年維持管理するコストに不満があり、
発明した人がきちんと証明され利益を得られるしくみはないだろうかと考えていたことがあります。(タイムスタンプと著作物のハッシュを登録できるようなサイト。ブログみたいなものが改竄不可能で証明されればいい)

最近NFTが話題になっていますが、これがそのものズバリだったためBlockChainについてもっと深く関与するために、復習する意味で今の自分の環境で動かしてみました。

参考)「ブロックチェーンdapp&ゲーム開発入門」(翔泳社)

dapp(decentralized application=分散型アプリケーション)と最近は呼ばれているようですね。

現在の最新のもので動かそうとしたところ、Solidity、Go言語、Gethのバージョンの組み合わせによって思ったように動作しないため、前回と今回の参考書籍、ネットの情報をいったりきたりして、
自分の実行したい環境で動作させました。前回のものはとてもわかりやすいのですが古すぎ、ネットの情報は新しすぎるため、その中間のやり方にしました。

dappゲームを開発できるオンラインレッスンのサイト、CryptoZombiesでもSolidityのバージョンと、
https://cryptozombies.io/jp/

Remix IDEサイトなどので使われるバージョンとはかなり差がありますが、

https://docs.soliditylang.org/en/v0.8.11/
https://remix.ethereum.org/

CryptoZombiesが0.4.19、前回参考書籍は 0.4.8 ということを考えれば、今回の0.4.15はまあまあ良いかもと思っています。

次に環境をどのように整えるかですが、ねらったバージョンを使うため、dockerを使った仮想環境でubuntuを作成し、それぞれバージョンを考慮したダウロード、git cloneをしました。
Remixなどの周辺ツールはまた次の機会にトライすることとし、ここではGethにRPC接続して動かします(フロントエンド開発を考慮)。

試す処理は、コインの送金と、コントラクトの実行です。

環境) docker / WSL / Windows 11

docker起動:

PS> docker pull ubuntu:16.04
PS> docker images
PS> docker run -it -d –name ubuntu1604 ubuntu:16.04
PS> docker exec -it ubuntu1604 /bin/bash

linux環境 インストール:

sudo apt-get install build-essential libgmp3-dev git tree
cd /root
wget https://go.dev/dl/go1.8.1.linux-amd64.tar.gz
tar zxvf go1.8.1.linux-amd64.tar.gz
export GOROOT=/root/go
git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum
git checkout refs/tags/v1.6.7
cd /root
wget https://nodejs.org/dist/v16.13.1/node-v16.13.1-linux-x64.tar.gz
tar zxvf node-v16.13.1.tar.gz
export PATH=/root/go/bin:/root/go-ethereum/build/bin:/root/node-v16.13.1-linux-x64/bin:$PATH
npm install -g solc@0.4.21

初期化:

gexport PATH=/root/go/bin:/root/go-ethereum/build/bin:/root/node-v16.13.1-linux-x64/bin:$PATH
gexport GOROOT=/root/go

geth init –datadir /root/work/testnet /root/work/testnet/genesis.json

ネットワーク起動:

geth –datadir /root/work/testnet console –rpc –rpcapi=”admin,db,eth,miner,net,personal,web3″

別コンソールでdocker exec shell で操作(要環境変数設定)

geth attach rpc:http://localhost:8545

以下、実際に操作した結果です。
長いので説明を先に書きます。

最初は、送金のテストをします。
まず、送金元と送金先に使うアカウントを二つ作成します。コインベースはaccounts[0]です。
それぞれ報酬がゼロ、ブロック数もゼロであることを確認します。
マイニングをすると報酬とブロックが増えたので、これをaccounts[0]からaccounts[1]に送金します。
送金操作をするとき送金元のアカウントをアンロックします。
そしてまたマイニングし、送金処理は保留状態でなくなると完了します。
accounts[1]に10ether増加していることが確認できました。
次に、コントラクトをデプロイするテストをします。
Solidityのソースコードをあらかじめコンパイルをして、バイナリとABIの二つを作成しておきます。
そのぞれの内容をcode,apiという変数に格納するため、コンソールにコピペします。(codeには先頭に0xが必要です)
再びアンロックをして、トランザクションを送信します。
web3.eth.getTransactionReceipt(tx)がnullでなくなるまでマイニングをします。
できたらコントラクトのアドレスを取得して、プログラムを呼び出します。

root@:~# geth attach rpc:http://localhost:8545
Welcome to the Geth JavaScript console!

instance: Geth/v1.6.7-stable-ab5646c5/linux-amd64/go1.8.1
modules: admin:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 web3:1.0

> eth.accounts
[]
> personal.newAccount()
Passphrase:
Repeat passphrase:
“0x0a1778382898465130e30cf18789c26b3981f936”
> personal.newAccount()
Passphrase:
Repeat passphrase:
“0xb27ad16aca47abd23afbe8b8404b8a2cf78a2a7d”
> eth.coinbase
“0x0a1778382898465130e30cf18789c26b3981f936”
> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0
> eth.blockNumber
0
> miner.start(1)
null
> eth.mining
true
> miner.stop()
true
> eth.mining
false
> eth.getBalance(eth.accounts[0])
60000000000000000000
> eth.blockNumber
12
> personal.unlockAccount(eth.accounts[0])
Unlock account 0x0a1778382898465130e30cf18789c26b3981f936
Passphrase:
true
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(10, “ether”)})
“0x74b642012ac18ae48b04b1a0fc93ceab635fca4c46b4520d9ec9cbae9137395d”
> eth.getBalance(eth.accounts[1])
0
> eth.pendingTransactions
[{
blockHash: null,
blockNumber: null,
from: “0x0a1778382898465130e30cf18789c26b3981f936”,
gas: 90000,
gasPrice: 18000000000,
hash: “0x74b642012ac18ae48b04b1a0fc93ceab635fca4c46b4520d9ec9cbae9137395d”,
input: “0x”,
nonce: 0,
r: “0xb339a8717c3bec88c8eceb52cd580f7c31b32683178187acc7ed7ebfeb2ed25”,
s: “0x285cbb59f4ba8f3c17e1aa35043a3f8f9993efac473899e7b81f75f37e5ab1c0”,
to: “0xb27ad16aca47abd23afbe8b8404b8a2cf78a2a7d”,
transactionIndex: 0,
v: “0x65″,
value: 10000000000000000000
}]
> eth.blockNumber
12
> miner.start(1)
null
> miner.stop()
true
> eth.pendingTransactions
[]
> eth.blockNumber
16
> eth.getBalance(eth.accounts[1])
10000000000000000000
> eth.getBalance(eth.accounts[0])
70000000000000000000
> code=”0x60606040526040805190810160405280600681526020017f48656c6c6f2100000000000000000000000000000000000000000000000000008152506001908051906020019061004f9291906100a0565b50341561005b57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610145565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e157805160ff191683800117855561010f565b8280016001018555821561010f579182015b8281111561010e5782518255916020019190600101906100f3565b5b50905061011c9190610120565b5090565b61014291905b8082111561013e576000816000905550600101610126565b5090565b90565b610271806101546000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610066575b600080fd5b341561005c57600080fd5b6100646100f4565b005b341561007157600080fd5b610079610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b957808201518184015260208101905061009e565b50505050905090810190601f1680156100e65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561014f57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b610191610231565b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102275780601f106101fc57610100808354040283529160200191610227565b820191906000526020600020905b81548152906001019060200180831161020a57829003601f168201915b5050505050905090565b6020604051908101604052806000815250905600a165627a7a723058203b2ee67d0dff9694121d5b0f7f16856cd028501ffc528c88b83d62287142ab640029”
“0x60606040526040805190810160405280600681526020017f48656c6c6f2100000000000000000000000000000000000000000000000000008152506001908051906020019061004f9291906100a0565b50341561005b57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610145565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e157805160ff191683800117855561010f565b8280016001018555821561010f579182015b8281111561010e5782518255916020019190600101906100f3565b5b50905061011c9190610120565b5090565b61014291905b8082111561013e576000816000905550600101610126565b5090565b90565b610271806101546000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610066575b600080fd5b341561005c57600080fd5b6100646100f4565b005b341561007157600080fd5b610079610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b957808201518184015260208101905061009e565b50505050905090810190601f1680156100e65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561014f57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b610191610231565b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102275780601f106101fc57610100808354040283529160200191610227565b820191906000526020600020905b81548152906001019060200180831161020a57829003601f168201915b5050505050905090565b6020604051908101604052806000815250905600a165627a7a723058203b2ee67d0dff9694121d5b0f7f16856cd028501ffc528c88b83d62287142ab640029”
> abi=[{“constant”:false,”inputs”:[],”name”:”kill”,”outputs”:[],”payable”:false,”stateMutability”:”nonpayable”,”type”:”function”},{“constant”:true,”inputs”:[],”name”:”greet”,”outputs”:[{“name”:””,”type”:”string”}],”payable”:false,”stateMutability”:”view”,”type”:”function”},{“inputs”:[],”payable”:false,”stateMutability”:”nonpayable”,”type”:”constructor”}]
[{
constant: false,
inputs: [],
name: “kill”,
outputs: [],
payable: false,
stateMutability: “nonpayable”,
type: “function”
}, {
constant: true,
inputs: [],
name: “greet”,
outputs: [{
name: “”,
type: “string”
}],
payable: false,
stateMutability: “view”,
type: “function”
}, {
inputs: [],
payable: false,
stateMutability: “nonpayable”,
type: “constructor”
}]
> personal.unlockAccount(eth.accounts[0])
Unlock account 0x0a1778382898465130e30cf18789c26b3981f936
Passphrase:
true
> tx=eth.sendTransaction({from:eth.accounts[0],data:code, gas:500e3})
“0x349f3de96e2a7148faa352e6fdcfcd8e7a16cf3ee098f0334d7e5864abae3b7c”
> web3.eth.getTransactionReceipt(tx)
null
> miner.start(1)
null
> miner.stop()
true
> web3.eth.getTransactionReceipt(tx)
{
blockHash: “0x578c9de53a4be6429e2094a082ab383b9953d2954e278b8cb35cfbd46b5b7e7d”,
blockNumber: 17,
contractAddress: “0x2d16473ba640f18869286e6b7a5ad503b834cc0d”,
cumulativeGasUsed: 278197,
from: “0x0a1778382898465130e30cf18789c26b3981f936”,
gasUsed: 278197,
logs: [],
logsBloom: “0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000”,
root: “0xa2d2fbac7d142e478646bb34bf8450779263d219996b6499323057c96a349188”,
to: null,
transactionHash: “0x349f3de96e2a7148faa352e6fdcfcd8e7a16cf3ee098f0334d7e5864abae3b7c”,
transactionIndex: 0
}
> addr = web3.eth.getTransactionReceipt(tx).contractAddress
“0x2d16473ba640f18869286e6b7a5ad503b834cc0d”
> Hello = web3.eth.contract(abi).at(addr)
{
abi: [{
constant: false,
inputs: [],
name: “kill”,
outputs: [],
payable: false,
stateMutability: “nonpayable”,
type: “function”
}, {
constant: true,
inputs: [],
name: “greet”,
outputs: [{…}],
payable: false,
stateMutability: “view”,
type: “function”
}, {
inputs: [],
payable: false,
stateMutability: “nonpayable”,
type: “constructor”
}],
address: “0x2d16473ba640f18869286e6b7a5ad503b834cc0d”,
transactionHash: null,
allEvents: function(),
greet: function(),
kill: function()
}
> Hello.greet()
“Hello!”
>
>

実体がない空気のようなP2Pネットワークのメソッドを呼び出してい感覚がいい。

Hello.sol

コンパイル:

solcjs –bin –abi Hello.sol

かなり面倒のようにも見えますが、コンソールでの実行の方がブロックチェーンのしくみをわかりやすく理解できます。ツールとか使ってしまうと、そのあたりが見えなくなるので、今回の目的である復習、実行環境の構築、備忘録としては、うまくいきました。(実用ではやはりツールを使うことになります)

あと最近注目の技術として、Symbolプラットホームがあります。XYMというコインで知られていますが、SDKのドキュメントが豊富で、また試してみたいと思っています。

https://docs.symbolplatform.com/ja/concepts/overview.html

社会インフラとして、様々な問題解決手段として、ブロックチェーンは、面白い!