Lightning Network
ビットコインのマイクロペイメントに対応したオフチェーンネットワークLightning Networkを試してみました。
https://github.com/lightningnetwork/lnd/tree/master/docker
現在のブロックチェーンはスケーラビリティなど今後問題になってくる技術的な課題があり、それを克服するために(メインチェーン/オンチェーンに負担をかけないような)様々な工夫が用意されています。そのアプローチの仕方が各ブロックチェーンごとに個性的(Layer2、クロスチェーンなどなど)で、技術的好奇心が掻き立てられます。ビットコインではオンチェーンとは独自のしくみのオフチェーンでペイメントチャンネルを経由してコインの売買ができるようです。(ノード構築のインセンティブは手数料)
簡単に言えば取引ごとにオンチェーンに書き込むのではなく、まとまった取引の開始(チャンネルを開く)と終了(チャンネルを閉じる)のみとし、取引自体はオフチェーンで実行されることのようです。
ここでは上記サイトのdockerによる実装を試しました。3つのコンソールを開きメインコンソールではbitcoinデーモン、アリス用のコンソールではdockerで実装されたアリスノード、もう一つはボブ用です。アリスからボブへの送金を試みます。ちょっと長いため最後にまとめて配置しました。
ここ最近、にわかですがブロックチェーンの情報収集をしていて思うことは、ちょっと大げさですが人類があらゆる知恵を絞り出してこの分野に取り組んでいるような気がしてしまいます。ビットコインとならぶ存在のイーサリアム、新しい存在の、ポルカドット、カルダノ、ソラナ、コスモス、ニア、フローなど、様々な背景のある人たちが入り混じって取り組んでいます。エンジニアとして感じたことは暗号通貨のチャートにオープンソースのリンクがあることに、なんという時代になってきたんだ、と思ってしまいます。(資金調達・取引のメカニズムがコードになっていて、バーチャルだけでなくリアルの世界で通用してしまっている) またそれぞれのBlockchainには思想があり、それを支持する人の主義主張をきくのも興味深いです。ネットワークの安定維持(ノード構築のインセンティブ)、分散化(特定の人の影響力が大きくならないようなしくみ)、TPSのような性能をバランスよく最大化させるアイディアは、暗号通貨のことだけでなく、次世代の社会インフラを考える際のヒントになります。次世代ブロックチェーンの議論については、現在のしくみを生かして改善する考え方と、新しいしくみを根本から作ってしまう考え方とわかれる傾向にあるのかなと感じます。(Lightning Networkは前者)
かつてパソコンの黎明期国内外様々なメーカが独自規格のハード、OSを作っていましたが、今のブロックチェーンの規格は、なんかそのころに似ている気がしています。(とても活気があってエキサイティング) そこから思うことは、決してエンジニア目線で良いと思ったものが必ずしも強くないことです。WINTELが勝ち取ってきたようにユーザに近いところが充実しているものが強いのかもしれません。
とはいってもSolidity、Cadence、SimplicityといったBlockchainならではのキーワード、従来のキーワードでもあまり表に出てこなかった、Rust、WebAssembly、Haskellがクローズアップされており、反応してしまいます。今回もdockerが多用されていますが、これまでもテストしたWeb3, React / Node などもあわせて最近のフロントエンドからバックエンドまであらゆるものが活用されているのがわかります。こういったことからも世界中のエンジニアが総力戦で取り組んでいる気がして、前の大げさな表現になりました。
Blockchain、面白すぎです。
環境) Ubuntu20.4/WSL/Windows11
Main Console
$ export NETWORK="simnet"
$ docker volume create simnet_lnd_alice
simnet_lnd_alice
$ docker volume create simnet_lnd_bob
simnet_lnd_bob
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1dd1039ed38b lnd "./start-lnd.sh" 12 seconds ago Up 11 seconds 9735/tcp, 10009/tcp alice
e4fc59546fff btcd "./start-btcd.sh" 15 seconds ago Up 12 seconds 8333-8334/tcp, 18333-18334/tcp, 18555-18556/tcp, 28901-28902/tcp btcd
(alice console)
$ MINING_ADDRESS=rX6B5SfUFCeCDi8mei55RVctaLh8nJUXEX docker-compose up -d btcd
Recreating btcd ... done
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
900848493f15 btcd "./start-btcd.sh" 5 seconds ago Up 4 seconds 8333-8334/tcp, 18333-18334/tcp, 18555-18556/tcp, 28901-28902/tcp btcd
1dd1039ed38b lnd "./start-lnd.sh" 4 minutes ago Up 4 minutes 9735/tcp, 10009/tcp alice
$ docker exec -it btcd /start-btcctl.sh generate 400
[
"30513adbb2ea06a2f41ff6e820f28c0541f74add61db7221288695ca0fedfdf0",
"63e8712d9c82c85c3420747b9d0c2dcb0830054154f39fbbd69b650d6a08d335",
"5d63dd30dba612b8fcb98583439a278b3189240064366c2943fcb5acab7710a4",
"5440ecd7403fd4cbafc54cf2463dc970c774b6cc42a8fd7c3aa7bb511a9937c9",
"60730b05b5ad1b420ed8423a4ba399cf673e1dde3dbb0158558a92424f28f7f7",
"403844d8e249f4977d143dc60ba8bd4954f98e1ef75ec81c2b0650201928cc86",
"78ca8280c6a6de6e18122759459a7f385f290c48d99cfee6a5314fc36508cb6f",
"413968a4d9a6377b8fe791aa3168778ac2525f162078124a0b25423259afdf9c",
"5e4b2583234d35c0669418546593325f08efe450fc469691831aea84c1983ac0",
"19d4d6ec5229152e3b95e0b65d4db5ed3c75dcee23a75c9159025813a490b8dd",
"77d779970fc355f5f6820710907433570a1e9e47e68262a1f280f5913213bcbd",
"781d8f2adc43261023e45562b169a9e3a60d08f68cf858f8ea5afd7e8f804844",
"363204521e8f8e36e0a6be1428958c1a2f43a875156e6623fd60612b99588f76",
"6ae88c7fbe26730e5590df3785ac6758c999a696fa8b1268b828550bf6727a8b",
"1ad55b323913f41fe25d8dd5c284526a446192d43710e3fd4bfe2e1a71920ccd",
...
$ docker exec -it btcd /start-btcctl.sh getblockchaininfo | grep -A 1 segwit
"segwit": {
"status": "active",
$
(bob console)
$ docker inspect bob | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.20.0.4",
(alice consolからbob-nodeに接続addressddress)
(alice でoepnchannelel)
$ docker exec -it btcd /start-btcctl.sh generate 3
[
"04a28809c867e71fa0c70630cf81885fadddafc2a9759588e5d6dfcdea07a424",
"6e121d9e71bb4ad2e5f35d14bbf3f00e7a943cd18c87b3a4cc531421308a9fb5",
"4c4e90c4e94321fe425d6280535cb26c2068e367577ef3f3acec9507c76bcce6"
]
(alice でclosechannelel)
$ docker exec -it btcd /start-btcctl.sh generate 3
[
"62dab67d832a50f2d69c3f86e88eea425fae796100751e3554845271542001d9",
"7f58bd2257d43be5f4853d73bcf220f2ef6bf65c2a703d6fa9961cd41c81b014",
"538ae071300bfa5f437ccd815d737812d4753dd2bd6cf7b0484b4d6d042362e6"
]
Code language: JavaScript (javascript)
Alice Console
$ docker-compose run -d --name alice --volume simnet_lnd_alice:/root/.lnd lnd
Creating btcd ... done
alice
$ docker exec -i -t alice bash
bash-5.1#
bash-5.1# lncli --network=simnet walletbalance
{
"total_balance": "0",
"confirmed_balance": "0",
"unconfirmed_balance": "0",
"account_balance": {
"default": {
"confirmed_balance": "0",
"unconfirmed_balance": "0"
}
}
}
bash-5.1# lncli --network=simnet channelbalance
{
"balance": "0",
"pending_open_balance": "0",
"local_balance": {
"sat": "0",
"msat": "0"
},
"remote_balance": {
"sat": "0",
"msat": "0"
},
"unsettled_local_balance": {
"sat": "0",
"msat": "0"
},
"unsettled_remote_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_local_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_remote_balance": {
"sat": "0",
"msat": "0"
}
}
bash-5.1# lncli --network=simnet newaddress np2wkh
{
"address": "rX6B5SfUFCeCDi8mei55RVctaLh8nJUXEX"
}
(addressをmainin colsoleのMINING_ADDRESSSS.Recreating btcdするとwalletbalanceが変化nceが変化変化-5.1# lncli --network=simnet walletbalance
{
"total_balance": "1505000000000",
"confirmed_balance": "1505000000000",
"unconfirmed_balance": "0",
"account_balance": {
"default": {
"confirmed_balance": "1505000000000",
"unconfirmed_balance": "0"
}
}
}
(main consoleからaddressress,bob consoleからpubkey所得してbob得してbobてbobob nodeに接続接続-5.1#
bash-5.1# lncli --network=simnet connect 0204e6918ae3239cc8da262715e5ada2d3540cc9fec6db7d6b72e544e2c77f6cac@172.20.0.4
{
}
bash-5.1# lncli --network=simnet listpeers
{
"peers": [
{
"pub_key": "0204e6918ae3239cc8da262715e5ada2d3540cc9fec6db7d6b72e544e2c77f6cac",
"address": "172.20.0.4:9735",
"bytes_sent": "391",
"bytes_recv": "391",
"sat_sent": "0",
"sat_recv": "0",
"inbound": false,
"ping_time": "0",
"sync_type": "ACTIVE_SYNC",
"features": {
"0": {
"name": "data-loss-protect",
"is_required": true,
"is_known": true
},
"5": {
"name": "upfront-shutdown-script",
"is_required": false,
"is_known": true
},
"7": {
"name": "gossip-queries",
"is_required": false,
"is_known": true
},
"9": {
"name": "tlv-onion",
"is_required": false,
"is_known": true
},
"12": {
"name": "static-remote-key",
"is_required": true,
"is_known": true
},
"14": {
"name": "payment-addr",
"is_required": true,
"is_known": true
},
"17": {
"name": "multi-path-payments",
"is_required": false,
"is_known": true
},
"23": {
"name": "anchors-zero-fee-htlc-tx",
"is_required": false,
"is_known": true
},
"31": {
"name": "amp",
"is_required": false,
"is_known": true
},
"45": {
"name": "explicit-commitment-type",
"is_required": false,
"is_known": true
},
"2023": {
"name": "script-enforced-lease",
"is_required": false,
"is_known": true
}
},
"errors": [
],
"flap_count": 1,
"last_flap_ns": "1642158005985969341",
"last_ping_payload": null
}
]
}
bash-5.1#
bash-5.1# lncli --network=simnet openchannel --node_key=0204e6918ae3239cc8da262715e5ada2d3540cc9fec6db7d6b72e544e2c77f6cac --local_amt=1234567
{
"funding_txid": "05b707addfd5aae36fdf62610376e45d4d6859f9e559a5e24957ce173e1a284b"
}
(main coloseでfundingng transaction)
bash-5.1# lncli --network=simnet listchannels
{
"channels": [
{
"active": true,
"remote_pubkey": "0204e6918ae3239cc8da262715e5ada2d3540cc9fec6db7d6b72e544e2c77f6cac",
"channel_point": "05b707addfd5aae36fdf62610376e45d4d6859f9e559a5e24957ce173e1a284b:0",
"chan_id": "887305883680768",
"capacity": "1234567",
"local_balance": "1231097",
"remote_balance": "0",
"commit_fee": "3140",
"commit_weight": "772",
"fee_per_kw": "2500",
"unsettled_balance": "0",
"total_satoshis_sent": "0",
"total_satoshis_received": "0",
"num_updates": "0",
"pending_htlcs": [
],
"csv_delay": 148,
"private": false,
"initiator": true,
"chan_status_flags": "ChanStatusDefault",
"local_chan_reserve_sat": "12345",
"remote_chan_reserve_sat": "12345",
"static_remote_key": false,
"commitment_type": "ANCHORS",
"lifetime": "38",
"uptime": "38",
"close_address": "",
"push_amount_sat": "0",
"thaw_height": 0,
"local_constraints": {
"csv_delay": 148,
"chan_reserve_sat": "12345",
"dust_limit_sat": "354",
"max_pending_amt_msat": "1222222000",
"min_htlc_msat": "1",
"max_accepted_htlcs": 483
},
"remote_constraints": {
"csv_delay": 148,
"chan_reserve_sat": "12345",
"dust_limit_sat": "354",
"max_pending_amt_msat": "1222222000",
"min_htlc_msat": "1",
"max_accepted_htlcs": 483
}
}
]
}
(bob consoleで-5.1# lncli --network=simnet sendpayment --pay_req=lnsb555550n1ps7zkvupp5fd6kx42j5dgd2dc0znmev8et60vqnkcl09nt4al48sjeelf4d76qdqqcqzpgxqyz5vqsp5atu4jx427nlgrwmchg32scz2e3qjdflrxjswcynee34vp3rh3c8s9qyyssqlqfdy6ncp6lm8fs6uyec0yyrqz5aazcum9ehq355x4qpl5c36tj88u5mc636w7aw7n8xjetcgek47hh3u4qp3nprj8k5r6k0cpp837gqusyazn
Payment hash: 4b75635552a350d5370f14f7961f2bd3d809db1f7966baf7f53c259cfd356fb4
Description:
Amount (in satoshis): 55555
Fee limit (in satoshis): 55555
Destination: 0204e6918ae3239cc8da262715e5ada2d3540cc9fec6db7d6b72e544e2c77f6cac
Confirm payment (yes/no): yes
+------------+--------------+--------------+--------------+-----+----------+-----------------+-------+
| HTLC_STATE | ATTEMPT_TIME | RESOLVE_TIME | RECEIVER_AMT | FEE | TIMELOCK | CHAN_OUT | ROUTE |
+------------+--------------+--------------+--------------+-----+----------+-----------------+-------+
| SUCCEEDED | 0.025 | 0.227 | 55555 | 0 | 852 | 887305883680768 | |
+------------+--------------+--------------+--------------+-----+----------+-----------------+-------+
Amount + fee: 55555 + 0 sat
Payment hash: 4b75635552a350d5370f14f7961f2bd3d809db1f7966baf7f53c259cfd356fb4
Payment status: SUCCEEDED, preimage: 2cf46eed79d3aa72f942ea8a2eeb4f7aa50c437670d51e9e98d350fd232ba8ab
bash-5.1#
bash-5.1# lncli --network=simnet channelbalance
{
"balance": "1175542",
"pending_open_balance": "0",
"local_balance": {
"sat": "1175542",
"msat": "1175542000"
},
"remote_balance": {
"sat": "55555",
"msat": "55555000"
},
"unsettled_local_balance": {
"sat": "0",
"msat": "0"
},
"unsettled_remote_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_local_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_remote_balance": {
"sat": "0",
"msat": "0"
}
}
bash-5.1# lncli --network=simnet listchannels
{
"channels": [
{
"active": true,
"remote_pubkey": "0204e6918ae3239cc8da262715e5ada2d3540cc9fec6db7d6b72e544e2c77f6cac",
"channel_point": "05b707addfd5aae36fdf62610376e45d4d6859f9e559a5e24957ce173e1a284b:0",
"chan_id": "887305883680768",
"capacity": "1234567",
"local_balance": "1175542",
"remote_balance": "55555",
"commit_fee": "2810",
"commit_weight": "1116",
"fee_per_kw": "2500",
"unsettled_balance": "0",
"total_satoshis_sent": "55555",
"total_satoshis_received": "0",
"num_updates": "2",
"pending_htlcs": [
],
"csv_delay": 148,
"private": false,
"initiator": true,
"chan_status_flags": "ChanStatusDefault",
"local_chan_reserve_sat": "12345",
"remote_chan_reserve_sat": "12345",
"static_remote_key": false,
"commitment_type": "ANCHORS",
"lifetime": "438",
"uptime": "438",
"close_address": "",
"push_amount_sat": "0",
"thaw_height": 0,
"local_constraints": {
"csv_delay": 148,
"chan_reserve_sat": "12345",
"dust_limit_sat": "354",
"max_pending_amt_msat": "1222222000",
"min_htlc_msat": "1",
"max_accepted_htlcs": 483
},
"remote_constraints": {
"csv_delay": 148,
"chan_reserve_sat": "12345",
"dust_limit_sat": "354",
"max_pending_amt_msat": "1222222000",
"min_htlc_msat": "1",
"max_accepted_htlcs": 483
}
}
]
}
(上記-5.1# lncli --network=simnet closechannel --funding_txid=05b707addfd5aae36fdf62610376e45d4d6859f9e559a5e24957ce173e1a284b --output_index=0
{
"closing_txid": "1b8f588256cedc8e31ed5818bdcd1edc5deff96ced9bfebe59acfc3fca8f7629"
}
(main coloseでfundingng transaction)
bash-5.1# lncli --network=simnet walletbalance
{
"total_balance": "1534999932848",
"confirmed_balance": "1534999932848",
"unconfirmed_balance": "0",
"account_balance": {
"default": {
"confirmed_balance": "1534999932848",
"unconfirmed_balance": "0"
}
}
}
bash-5.1#
Code language: PHP (php)
Bob Console
$ docker-compose run -d --name bob --volume simnet_lnd_bob:/root/.lnd lnd
Starting btcd ... done
bob
$ docker exec -i -t bob bash
bash-5.1# lncli --network=simnet walletbalance
{
"total_balance": "2029999990000",
"confirmed_balance": "2029999990000",
"unconfirmed_balance": "0",
"account_balance": {
"default": {
"confirmed_balance": "2029999990000",
"unconfirmed_balance": "0"
}
}
}
bash-5.1# lncli --network=simnet channelbalance
{
"balance": "0",
"pending_open_balance": "0",
"local_balance": {
"sat": "0",
"msat": "0"
},
"remote_balance": {
"sat": "0",
"msat": "0"
},
"unsettled_local_balance": {
"sat": "0",
"msat": "0"
},
"unsettled_remote_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_local_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_remote_balance": {
"sat": "0",
"msat": "0"
}
}
bash-5.1# lncli --network=simnet getinfo
{
"version": "0.14.1-beta commit=v0.14.1-beta-dirty",
"commit_hash": "6042004edaaa5b3cad0a0808ff23dba4716f7178",
"identity_pubkey": "0204e6918ae3239cc8da262715e5ada2d3540cc9fec6db7d6b72e544e2c77f6cac",
"alias": "0204e6918ae3239cc8da",
"color": "#3399ff",
"num_pending_channels": 0,
"num_active_channels": 0,
"num_inactive_channels": 0,
"num_peers": 0,
"block_height": 806,
"block_hash": "56e1d3d993da053d4b50cdd08b8101f72d91fac1a42845cef06eebc3a4293d2d",
"best_header_timestamp": "1642157626",
"synced_to_chain": true,
"synced_to_graph": false,
"testnet": false,
"chains": [
{
"chain": "bitcoin",
"network": "simnet"
}
],
"uris": [
],
"features": {
"0": {
"name": "data-loss-protect",
"is_required": true,
"is_known": true
},
"5": {
"name": "upfront-shutdown-script",
"is_required": false,
"is_known": true
},
"7": {
"name": "gossip-queries",
"is_required": false,
"is_known": true
},
"9": {
"name": "tlv-onion",
"is_required": false,
"is_known": true
},
"12": {
"name": "static-remote-key",
"is_required": true,
"is_known": true
},
"14": {
"name": "payment-addr",
"is_required": true,
"is_known": true
},
"17": {
"name": "multi-path-payments",
"is_required": false,
"is_known": true
},
"23": {
"name": "anchors-zero-fee-htlc-tx",
"is_required": false,
"is_known": true
},
"30": {
"name": "amp",
"is_required": true,
"is_known": true
},
"31": {
"name": "amp",
"is_required": false,
"is_known": true
},
"45": {
"name": "explicit-commitment-type",
"is_required": false,
"is_known": true
},
"2023": {
"name": "script-enforced-lease",
"is_required": false,
"is_known": true
}
}
}
(pubkey->alice console)
bash-5.1#
bash-5.1# lncli --network=simnet listpeers
{
"peers": [
{
"pub_key": "035a928e2fdb16f8356735d189028bd2a424f10d6dea8b997b66ac27811c6e996a",
"address": "172.20.0.3:44330",
"bytes_sent": "391",
"bytes_recv": "391",
"sat_sent": "0",
"sat_recv": "0",
"inbound": true,
"ping_time": "0",
"sync_type": "ACTIVE_SYNC",
"features": {
"0": {
"name": "data-loss-protect",
"is_required": true,
"is_known": true
},
"5": {
"name": "upfront-shutdown-script",
"is_required": false,
"is_known": true
},
"7": {
"name": "gossip-queries",
"is_required": false,
"is_known": true
},
"9": {
"name": "tlv-onion",
"is_required": false,
"is_known": true
},
"12": {
"name": "static-remote-key",
"is_required": true,
"is_known": true
},
"14": {
"name": "payment-addr",
"is_required": true,
"is_known": true
},
"17": {
"name": "multi-path-payments",
"is_required": false,
"is_known": true
},
"23": {
"name": "anchors-zero-fee-htlc-tx",
"is_required": false,
"is_known": true
},
"31": {
"name": "amp",
"is_required": false,
"is_known": true
},
"45": {
"name": "explicit-commitment-type",
"is_required": false,
"is_known": true
},
"2023": {
"name": "script-enforced-lease",
"is_required": false,
"is_known": true
}
},
"errors": [
],
"flap_count": 1,
"last_flap_ns": "1642158005986281830",
"last_ping_payload": null
}
]
}
(alice consoleでopenen channel)
bash-5.1#
bash-5.1# lncli --network=simnet addinvoice --amt=55555
{
"r_hash": "4b75635552a350d5370f14f7961f2bd3d809db1f7966baf7f53c259cfd356fb4",
"payment_request": "lnsb555550n1ps7zkvupp5fd6kx42j5dgd2dc0znmev8et60vqnkcl09nt4al48sjeelf4d76qdqqcqzpgxqyz5vqsp5atu4jx427nlgrwmchg32scz2e3qjdflrxjswcynee34vp3rh3c8s9qyyssqlqfdy6ncp6lm8fs6uyec0yyrqz5aazcum9ehq355x4qpl5c36tj88u5mc636w7aw7n8xjetcgek47hh3u4qp3nprj8k5r6k0cpp837gqusyazn",
"add_index": "1",
"payment_addr": "eaf9591aaaf4fe81bb78ba22a8604acc4126a7e334a0ec1279cc6ac0c4778e0f"
}
(payment_request->alice console.alice console: send payment from alice to bob)
bash-5.1# lncli --network=simnet channelbalance
{
"balance": "55555",
"pending_open_balance": "0",
"local_balance": {
"sat": "55555",
"msat": "55555000"
},
"remote_balance": {
"sat": "1175542",
"msat": "1175542000"
},
"unsettled_local_balance": {
"sat": "0",
"msat": "0"
},
"unsettled_remote_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_local_balance": {
"sat": "0",
"msat": "0"
},
"pending_open_remote_balance": {
"sat": "0",
"msat": "0"
}
}
bash-5.1#
bash-5.1# lncli --network=simnet walletbalance
{
"total_balance": "2030000045555",
"confirmed_balance": "2030000045555",
"unconfirmed_balance": "0",
"account_balance": {
"default": {
"confirmed_balance": "2030000045555",
"unconfirmed_balance": "0"
}
}
}
bash-5.1#
Code language: PHP (php)
※code中、漢字がまざると文字化けが・・まだこのテーマになれない・・
Web3.js + React.js
ユーザが使うDapps(Decentralized Applications)という形にするにはUIが必要で、Webブラウザを使う方法は代表的な形になるのでしょう。
フロントエンドでよく使われるweb3.js と react.jsを、ここまで作ったしくみに追加してみました。
https://zenn.dev/shunp110/articles/630a0166f468e4
上記、参考にさせていただきました。
環境) Ubuntu20.04/WSL/Windows11
$ node -v
v16.13.1
$ npm -v
8.1.2
$ npx -v
8.1.2
$ npm install web3
$ npm install -g serve
$ npx clear-npx-cache
$ npx create-react-app my-app
$ cd my-app
$ export NODE_OPTIONS=”–max-old-space-size=1024″
src/App.js
import "./App.css";
import Web3 from "web3/dist/web3.min.js"
import ABI from "./contracts/Hello.json";
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
const address = "0x482a64967a50076C6F00b0bD859F56514eA07402";
const abi = ABI.abi;
const contract = new web3.eth.Contract(abi, address);
function App() {
const handleCall = async () => {
const msg = await contract.methods.get().call();
alert(msg);
};
return (
<div className="App">
<h1>web3.js + react.js DEMO</h1>
<button onClick={handleCall}>Call</button>
</div>
);
}
export default App;
Code language: JavaScript (javascript)
contracts/Hello.json は下記でコンパイルした結果のbuildディレクトリのものを使用します。
http://bitlife.me/bc/2022/01/08/
また、上記で実行したように、Ganache-cliを立ち上げ、Deployをしたものとします。(conract address使用)
ビルド・実行
$ npm run build
$ serve -s build
rpm startでは、javascript heap out of memoryとなったため、このようにしました。
“scripts”: {
“start”: “react-scripts start”,
“build”: “GENERATE_SOURCEMAP=false react-scripts build”,
“test”: “react-scripts test”,
“eject”: “react-scripts eject”
},
不要かもしれませんが、package.jsonもこのようにしました。(-max-old-spaceも同様、いろいろ試行錯誤した結果なのでのこしておきます)
Call ボタンをクリックすると、上記Alertが表示されました。
何気ない画面ですが、いろんなものが詰まっています。ここまで効率的に開発できるのもやはりフロントエンド、バックエンドのJavaScript環境が強力だからでしょう。この充実ぶりはホットであることの証明ですね。
(web3.js という名前自体が、Web3.0の時代もJSだよね、と)
モダンなJavaScriptをためした記事のリンクを下記に参考まで
Ethereum IDE (Remix) & MetaMask
いよいよGUIツールを使って送金やコントラクトの動作確認をしてみました。
ベースとなる環境は前回のGanacheでデフォルトのID二つ使います。
Ganache-cli立ち上げ時に表示されるPrivateKeyをMetaMaskにインポートしてアカウントを作成します。(デフォルトでアカウントはアンロックされている) ネットワークはGanacheをdevelopmentとして追加します。(127.0.0.1:8545にRPC接続。いろいろと調べてチェーンIDは1337とした)
MetaMaskでは、0x827..がAccount3、0xA28…がAccount4で最初は同じ100ETHの画面。
Account4にはアクティビティがありませんでした。
次に、Remixを試してみます。
自動的に関数のボタンが作成され、デバッグ体制を作ってくれます。
inc,decで値を増減させ、getまたはcount(変数)で数値を表示します。(上記incを一回押し、getを押した様子)
他にもいろいろと動かしみましたが、まだエラー解決に時間がかかります。(ネットの記事、YouTube動画などで動作確認済のはずのものが思い通り動かせないなど・・書籍などでも古めで、2018年くらいの情報が多い。。しかしブロックチェーンの本質はかわらないので、対応していくのみ)
これらのツールを使って効率よく開発をすすめていきたいと思います。(Ganache便利! これもGUI版あるみたいなのでまた)
Truffle.js Framework
Ethereum 環境の理解を深めるために、以前フレームワークやツールを使わずテストをしましたが、今回はTruffle.jsフレームワークを使って構築・テストをしたいと思います。
参考: https://zenn.dev/shunp110/articles/0080928ab43289
: https://qiita.com/toshiok/items/12b47b28e5fb6c5909b1
以前Gethで作ったブロックチェーンのローカル環境は、Ganacheを使います。
環境: Ubuntu20.04/WSL/Windows11
$ node -v
v16.13.1
$ npm -v
8.1.2
インストール
$ sudo npm install -g truffle
$ sudo npm install -g ganache-cli
ネットワーク起動
$ ganache-cli
Ganache CLI v6.12.2 (ganache-core: 2.13.2)
Available Accounts
(0) 0x6Adc538Ed8526217B04354DDF6E15dF53039B986 (100 ETH)
(1) 0xcB2289aAa662eadFDCB5c0655E88B6a44dc11FaD (100 ETH)
(2) 0x85B350bC7c0c75D70EE9FE5e3d20c5Ead091F8dA (100 ETH)
(3) 0x3CC61a4a4E70Ae097390f6d0DfC8c56c9555EFD9 (100 ETH)
(4) 0x12099D695cc5526D9A71944F3b551b03b25A3Fee (100 ETH)
….
アカウントやETHがあらかじめ用意されています。
次に、別コンソールでコードの作成、configの編集、コンパイル、デプロイ、コンソールの実行をします。
$ truffle init
contracts/Hello.sol
pragma solidity >=0.4.22 <0.9.0;
contract Hello {
function get() public pure returns (string memory) {
return "Hello!";
}
}
Code language: JavaScript (javascript)
migrations/2_hello.js
const Hello = artifacts.require("Hello");
module.exports = function (deployer) {
deployer.deploy(Hello);
};
Code language: JavaScript (javascript)
(デフォルトで生成される、1_initial_migrations.js をそのままにしたため2_という名前にする)
truffle_config.js
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
Code language: CSS (css)
上記部分のコメントをはずす。
$ truffle compile
$ truffle migrate –network development
Compiling your contracts... =========================== > Everything is up to date, there is nothing to compile. Starting migrations... ====================== > Network name: 'development' > Network id: 1641626547449 > Block gas limit: 6721975 (0x6691b7) 1_initial_migration.js ====================== Deploying 'Migrations' ---------------------- > transaction hash: 0xaf7dc12859e4a1275e2daa1710c2ce7673652a7da394f395435fad33879c84f1 > Blocks: 0 Seconds: 0 > contract address: 0x67cD5Bee85BBbFFF12F8482711fB8649F506a4e5 > block number: 1 > block timestamp: 1641626555 > account: 0x6Adc538Ed8526217B04354DDF6E15dF53039B986 > balance: 99.99502292 > gas used: 248854 (0x3cc16) > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.00497708 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00497708 ETH 2_hello.js ========== Deploying 'Hello' ----------------- > transaction hash: 0xad64a961af2ce0ccab6901c45fd7030c2fe8a91cc480ac996267c508ef3a3081 > Blocks: 0 Seconds: 0 > contract address: 0x0A551aEF4c63f9a77eC2f307D9e99878C7c32Ee6 > block number: 3 > block timestamp: 1641626555 > account: 0x6Adc538Ed8526217B04354DDF6E15dF53039B986 > balance: 99.99147276 > gas used: 134995 (0x20f53) > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.0026999 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.0026999 ETH Summary ======= > Total deployments: 2 > Final cost: 0.00767698 ETH
$ truffle console –network development
truffle(development)> web3.eth.getAccounts(function(err, data){accounts = data });
[
‘0x6Adc538Ed8526217B04354DDF6E15dF53039B986’,
‘0xcB2289aAa662eadFDCB5c0655E88B6a44dc11FaD’,
‘0x85B350bC7c0c75D70EE9FE5e3d20c5Ead091F8dA’,
‘0x3CC61a4a4E70Ae097390f6d0DfC8c56c9555EFD9’,
‘0x12099D695cc5526D9A71944F3b551b03b25A3Fee’,
‘0x3Ff15F4c7EEC3338104645780D6c78C6ca9103A7’,
‘0x2095e763CD5bD681308d259905D4eDCE0e7f9Af3’,
‘0xcFAd6063c4B5FF7233950Ca55f34Aa56eF72175a’,
‘0xA0BA9eB80Bd62D0c56CAe6311Cb8C7482F21523f’,
‘0xa4188D85d855bD1837e31C9EA5251bC75c650014’
]
truffle(development)> web3.eth.getBalance(accounts[0]);
‘99990922500000000000’
truffle(development)> web3.eth.getBalance(accounts[1]);
‘100000000000000000000’
truffle(development)> web3.eth.sendTransaction({from: accounts[0], to: accounts[1], value: web3.utils.toWei(’20’,’ether’)});
{
transactionHash: ‘0x4e040a381ba1bae54f090b0b60e723b5f0c0e0fed2fab660e925cd7ecc040d72’,
transactionIndex: 0,
blockHash: ‘0x975091b47f1343022343bc87c4880b64328d79117a457891a7f7bb62049ca10b’,
blockNumber: 5,
from: ‘0x6adc538ed8526217b04354ddf6e15df53039b986’,
to: ‘0xcb2289aaa662eadfdcb5c0655e88b6a44dc11fad’,
gasUsed: 21000,
cumulativeGasUsed: 21000,
….
truffle(development)> web3.eth.getBalance(accounts[0]);
‘79990502500000000000’
truffle(development)> web3.eth.getBalance(accounts[1]);
‘120000000000000000000’
truffle(development)> web3.eth.getTransaction(‘0x4e040a381ba1bae54f090b0b60e723b5f0c0e0fed2fab660e925cd7ecc040d72’);
{
hash: ‘0x4e040a381ba1bae54f090b0b60e723b5f0c0e0fed2fab660e925cd7ecc040d72’,
nonce: 4,
blockHash: ‘0x975091b47f1343022343bc87c4880b64328d79117a457891a7f7bb62049ca10b’,
blockNumber: 5,
transactionIndex: 0,
from: ‘0x6Adc538Ed8526217B04354DDF6E15dF53039B986’,
to: ‘0xcB2289aAa662eadFDCB5c0655E88B6a44dc11FaD’,
value: ‘20000000000000000000’,
gas: ‘0x15f90’,
gasPrice: ‘20000000000’,
input: ‘0x’,
v: ‘0x25’,
r: ‘0xae5a478f99b3a927b949957b50f7a11d063a342f10cd19350f4032d2d5474e30’,
s: ‘0x4f25702b2eba9d2aa51cd895f013848c0afdc00f56d5e5c8b8d9e700c06b6222’
}
truffle(development)> Hello.deployed().then( c => instance = c );
TruffleContract {
constructor: [Function: TruffleContract] {
_constructorMethods: {
configureNetwork: [Function: configureNetwork],
setProvider: [Function: setProvider],
….
truffle(development)> instance.get()
‘Hello!’
コンソールでは、ETHの送金、確認、それからコントラクトの関数の実行をしています。accounts[0]のETHが最初から少ないのは、デプロイのときにGAS代がひかれています。
この組み合わせは、gethで構築したことを考えると本当にありがたく感じます。IDEとかはまた試す予定です。
※まだこのブログテーマの使い方になれていないせいで、表示が見づらい点がありますが、改善していきます。
Bitcoin Core
ここまでEthereumやSymbolをさわってきましたが、やはり基本はBitcoinということでこのブログの開始にあたり、環境を整えました。
bitcoin-cliを使っていろいろとテストしようと、最初はdockerとか使った簡単な(と思われる)やり方を試しましたが、情報が古かったりうまく動作しなかったため、やはりソースから実装することにしました。
環境) Ubuntu20.4/WSL/ Windows 11
git clone https://github.com/bitcoin/bitcoin.git
cd bitcoinsudo apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils python3
sudo apt install libevent-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev
./contrib/install_db4.sh
pwd
export BDB_PREFIX=’/home/k/work1/bitcoin/db4′
./autogen.sh
./configure BDB_LIBS=”-L${BDB_PREFIX}/lib” BDB_CFLAGS=”-I${BDB_PREFIX}/include” –disable-tests –disable-bench –without-gui –without-miniupnpc –with-utils –with-sqlite=yes –without-bdb
make
sudo make install
walletを作成するときにsqliteが使えるようにする必要があるため上記のようにconfigureオプションに加えました。
signetの起動
$ bitcoind -signet
Walletの作成
$ bitcoin-cli -signet createwallet testwallet
{
“name”: “testwallet”,
“warning”: “”
}
アドレス取得
$ bitcoin-cli -signet getnewaddress
tb1qw8k2tutz36qpfmtes2jny2wcmavh0mt2edvt96
情報取得
$ bitcoin-cli -signet getblockchaininfo
{
“chain”: “signet”,
“blocks”: 71428,
“headers”: 71428,
“bestblockhash”: “000000dc046a49f82b6bb65633ba4650e093f7fd2e7956efa65304c0a545fbdd”,
“difficulty”: 0.002700124394835933,
“time”: 1641274764,
“mediantime”: 1641272545,
“verificationprogress”: 0.9999990656266684,
“initialblockdownload”: false,
“chainwork”: “000000000000000000000000000000000000000000000000000000c98018dd0a”,
“size_on_disk”: 231372553,
“pruned”: false,
“softforks”: {
“bip34”: {
“type”: “buried”,
“active”: true,
“height”: 1 ………
以下サイトでも確認。
次はフォーセットからコインの取得です。
bitcoind では以下のようにtestwalletへの入金のトランザクションが表示され、(フォーセットのページのtxidの値 1e4645….)
2022-01-04T05:17:57Z UpdateTip: new best=000000b99486707164e3ebb0ae6e7a4ab0e63872b79c54a13fa716a3602a3b67 height=71424 version=0x20000000 log2_work=39.654561 tx=734111 date=’2022-01-04T05:17:56Z’ progress=1.000000 cache=0.0MiB(25txo)
2022-01-04T05:22:17Z [testwallet] AddToWallet 1e4645cdc4c9ce729f4b809668ea8ca16071a8b1b82db28372c9f18de3d97698 new
2022-01-04T05:22:30Z UpdateTip: new best=0000001f59a29230b5dc275f6b311ba506e1505d39f01c98ae5d59ada0155d31 height=71425 version=0x20000000 log2_work=39.654581 tx=734223 date=’2022-01-04T05:22:27Z’ progress=1.000000 cache=0.0MiB(192txo)
2022-01-04T05:22:30Z [testwallet] AddToWallet 1e4645cdc4c9ce729f4b809668ea8ca16071a8b1b82db28372c9f18de3d97698 update
コンソールでは、下記のように変化があることを確認できました。
$ bitcoin-cli -signet getbalance
0.00000000
$ bitcoin-cli -signet getbalance
0.01000000
結局、ソースからの構築の方が簡単でした。signetはブロック数がテストネットに比べて少ないので同期がはやく容量も少なく済むため使いやすいです。
まずは環境構築でした。
参考書籍) 「ビットコインとブロックチェーン(Mastering Bitcoin)」(NTT出版)
The First Post !
これまでBlockchain関連の記事を下記のように別のブログで書いてきましたが、もっと深く学習したいという思いから専用のブログを立ち上げました。(ハードフォーク?)
追記(このブログをはじめてから他で扱ったもの)