Closed2

GoでEthereumに接続する

sey323sey323

こちらのチュートリアルの実行メモです。

環境

  • MacOs v10.15.7

Gethのインストールと環境構築

はじめにGoでEthereumに接続できるGethをインストールする。

brew tap ethereum/ethereum
brew install ethereum
brew install geth

必須ではないがデフォルトの設定だとINFOログが大量に出力されるので、--verbosityのオプションを付与することで抑制することができる。本手順は下記のログ抑制をしていないログを表示している。

alias geth="geth --verbosity 1"

ローカルにEthereumネットワークを構築する。

Gethには、開発者向けにローカルにethereumのネットワークを構築する機能があるのでそれを利用する。下記のコマンドを実行する。

$ geth --dev --http --http.api eth,web3,personal,net --http.corsdomain "http://remix.ethereum.org"
INFO [07-09|10:32:22.866] Starting Geth in ephemeral dev mode...
WARN [07-09|10:32:22.866] You are running Geth in --dev mode. Please note the following:

  1. This mode is only intended for fast, iterative development without assumptions on
     security or persistence.
  2. The database is created in memory unless specified otherwise. Therefore, shutting down
     your computer or losing power will wipe your entire block data and chain state for
     your dev environment.
  3. A random, pre-allocated developer account will be available and unlocked as
     eth.coinbase, which can be used for testing. The random dev account is temporary,
     stored on a ramdisk, and will be lost if your machine is restarted.
  4. Mining is enabled by default. However, the client will only seal blocks if transactions
     are pending in the mempool. The miner's minimum accepted gas price is 1.
  5. Networking is disabled; there is no listen-address, the maximum number of peers is set
     to 0, and discovery is disabled.

INFO [07-09|10:32:22.868] Maximum peer count                       ETH=50 LES=0 total=50
INFO [07-09|10:32:22.872] Set global gas cap                       cap=50,000,000
INFO [07-09|10:32:23.108] Using developer account                  address=0xcbb926247e7dc92d63F141B6c228c2F2838B7926
INFO [07-09|10:32:23.110] Allocated trie memory caches             clean=154.00MiB dirty=256.00MiB
INFO [07-09|10:32:23.110] Writing custom genesis block
INFO [07-09|10:32:23.111] Persisted trie from memory database      nodes=12 size=1.82KiB time="50.033µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [07-09|10:32:23.111]
INFO [07-09|10:32:23.111] ---------------------------------------------------------------------------------------------------------------------------------------------------------
INFO [07-09|10:32:23.111] Chain ID:  1337 (unknown)
INFO [07-09|10:32:23.111] Consensus: Clique (proof-of-authority)
INFO [07-09|10:32:23.111]
INFO [07-09|10:32:23.111] Pre-Merge hard forks:
INFO [07-09|10:32:23.111]  - Homestead:                   0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md)
INFO [07-09|10:32:23.111]  - Tangerine Whistle (EIP 150): 0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md)
INFO [07-09|10:32:23.111]  - Spurious Dragon/1 (EIP 155): 0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)
INFO [07-09|10:32:23.111]  - Spurious Dragon/2 (EIP 158): 0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)
INFO [07-09|10:32:23.111]  - Byzantium:                   0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md)
INFO [07-09|10:32:23.111]  - Constantinople:              0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md)
INFO [07-09|10:32:23.111]  - Petersburg:                  0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md)
INFO [07-09|10:32:23.111]  - Istanbul:                    0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md)
INFO [07-09|10:32:23.111]  - Muir Glacier:                0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md)
INFO [07-09|10:32:23.111]  - Berlin:                      0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md)
INFO [07-09|10:32:23.111]  - London:                      0        (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md)
INFO [07-09|10:32:23.111]
INFO [07-09|10:32:23.111] Merge not configured!
INFO [07-09|10:32:23.111]  - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)
INFO [07-09|10:32:23.111] ---------------------------------------------------------------------------------------------------------------------------------------------------------
INFO [07-09|10:32:23.111]
INFO [07-09|10:32:23.111] Initialising Ethereum protocol           network=1337 dbversion=<nil>
INFO [07-09|10:32:23.112] Loaded most recent local header          number=0 hash=0d73ec..437b61 td=1 age=53y3mo1w
INFO [07-09|10:32:23.112] Loaded most recent local full block      number=0 hash=0d73ec..437b61 td=1 age=53y3mo1w
INFO [07-09|10:32:23.112] Loaded most recent local fast block      number=0 hash=0d73ec..437b61 td=1 age=53y3mo1w
WARN [07-09|10:32:23.112] Failed to load snapshot, regenerating    err="missing or corrupted snapshot"
INFO [07-09|10:32:23.112] Rebuilding state snapshot
INFO [07-09|10:32:23.112] Resuming state snapshot generation       root=965080..1f3d6e accounts=0 slots=0 storage=0.00B dangling=0 elapsed="346.067µs"
INFO [07-09|10:32:23.113] Gasprice oracle is ignoring threshold set threshold=2
WARN [07-09|10:32:23.113] Error reading unclean shutdown markers   error="not found"
INFO [07-09|10:32:23.113] Generated state snapshot                 accounts=10 slots=0 storage=412.00B dangling=0 elapsed="791.957µs"
INFO [07-09|10:32:23.113] Stored checkpoint snapshot to disk       number=0 hash=0d73ec..437b61
ERROR[07-09|10:32:23.113] Failed to check db for legacy receipts   err="this operation is not supported"
INFO [07-09|10:32:23.113] Starting peer-to-peer node               instance=Geth/v1.10.20-stable/darwin-amd64/go1.18.3
WARN [07-09|10:32:23.113] P2P server will be useless, neither dialing nor listening
INFO [07-09|10:32:23.116] New local node record                    seq=1,657,330,343,115 id=5088a84a6c1f732c ip=127.0.0.1 udp=0 tcp=0
INFO [07-09|10:32:23.116] Started P2P networking                   self=enode://d3b5391cb1e27ef357cd26960c88b90774da295ef3c2993dabef7c84270a808f1802ac5d30a85ebef76687d6e4a716a6ebc1934ebbfb601639194e37927afaa5@127.0.0.1:0
INFO [07-09|10:32:23.116] IPC endpoint opened                      url=/var/folders/1c/tkr84d1j6ql32nmyqsp4qgth0000gn/T/geth.ipc
INFO [07-09|10:32:23.116] HTTP server started                      endpoint=127.0.0.1:8545 auth=false prefix= cors=http://remix.ethereum.org vhosts=localhost
INFO [07-09|10:32:23.116] Transaction pool price threshold updated price=0
INFO [07-09|10:32:23.117] Updated mining threads                   threads=0
INFO [07-09|10:32:23.117] Transaction pool price threshold updated price=1
INFO [07-09|10:32:23.117] Etherbase automatically configured       address=0xcbb926247e7dc92d63F141B6c228c2F2838B7926
INFO [07-09|10:32:23.117] Commit new sealing work                  number=1 sealhash=e5aab8..0f390f uncles=0 txs=0 gas=0 fees=0 elapsed="70.578µs"
WARN [07-09|10:32:23.117] Block sealing failed                     err="sealing paused while waiting for transactions"
WARN [07-09|10:32:23.117] Failed to get free disk space            path= err="failed to call Statfs: no such file or directory"
INFO [07-09|10:32:23.117] Commit new sealing work                  number=1 sealhash=e5aab8..0f390f uncles=0 txs=0 gas=0 fees=0 elapsed="198.82µs"

上記のようなログ出力されれば問題なく構築されたこととなる。

クライアント起動

別のターミナルを開いて、上記の手順で構築したテスト用のEthereumネットワークに接続する。メッセージが表示され、コンソールが表示される。

$ geth attach http://127.0.0.1:8545
Welcome to the Geth Javascript console!

instance: Geth/v1.10.18-unstable-8d84a701-20220503/linux-amd64/go.1.18.1
coinbase: 0x540dbaeb2390f2eb005f7a6dbf3436a0959197a9
at block: 0 (Thu Jan 01 1970 01:00:00 GMT+0100 (BST))
 modules: eth:1.0 personal:1.0 rpc:1.0 web3:1.0

To exit, press ctrl-d or type exit
>

以降の手順はこのコンソール上で実行する。

Ethereumの送信処理

アカウント

Ethereumに参加するアカウントを確認する。本来であればClefを利用してアカウントを作成するが、ここではGethの組込アカウントを利用する。既存のアカウントは下記のコマンドで確認できる。

> eth.accounts
["${ハッシュ値(環境によって異なる)}"]

コインベースに、上記のアカウントを紐づける。コインベースとは、Ethereumがマイニングよって生まれた時の最初のトランザクションである。

> eth.coinbase==eth.accounts[0]
true

送信先のアカウントを作成する。

> personal.newAccount()
Passphrase:
Repeat passphrase:
"${ハッシュ値}"

下記のコマンドでアカウントが作成されたことを確認する。ハッシュ値が前回実行した時より1つ増えていればOK。

> eth.accounts
["${ハッシュ値}", "${ハッシュ値}"]

Ethereumの送信

ブロックチェーンは、トランザクションが行われたタイミングで初めてブロックチェーン上に存在が記録され、存在が認められる。なのでEthereumもトランザクション(送信処理)を行う必要がある。

送信処理を行う場合は、sendTransactonを利用する。Gethのデフォルトのアカウントから、上の手順で新規作成したユーザにEthereumを送信する。

> eth.sendTransaction({from: eth.coinbase, to: eth.accounts[1], value: web3.toWei(50, "ether")})
"0x993f9b784d6f3b55971b5d8d2f5998fadcc71a373cbce8e6abadc63576d6c2e6"

sendTransaction実行時に出力されたハッシュを引数にし、下記のコマンドでtransactionの中身を確認できる。

> eth.getTransaction("0x993f9b784d6f3b55971b5d8d2f5998fadcc71a373cbce8e6abadc63576d6c2e6")
{
  accessList: [],
  blockHash: "0x1b4ce74aff658281648d1628bfcae61800c14fe1289db5155cb839ad8a09be8b",
  blockNumber: 1,
  chainId: "0x539",
  from: "0x829a91bc4650607c5983ab4a1acc024c06ec07c1",
  gas: 21000,
  gasPrice: 875000001,
  hash: "0x993f9b784d6f3b55971b5d8d2f5998fadcc71a373cbce8e6abadc63576d6c2e6",
  input: "0x",
  maxFeePerGas: 2000000001,
  maxPriorityFeePerGas: 1,
  nonce: 0,
  r: "0xe01e961774358e404de5a8c5c69928ee7039f938e460bd615bcd3e10b4cf4766",
  s: "0x608afd5f99d973eabdf2f18dea291a6b7575d7ee03721d98c7c77343578ad0f7",
  to: "0x78716e0e4c894700550bf385b64ea0307ebcb063",
  transactionIndex: 0,
  type: "0x2",
  v: "0x0",
  value: 50000000000000000000
}

この処理によりEthereumが発行されたことが確認できた。

sey323sey323

概要

自分でGenesisファイルを作成し、Ethereumのネットワークを構築する。最終的にEthereumの送金処理を行い、マイニングによってその処理が実行されることを確認する。

ネットワークの構築

Genesisファイルを作成

ブロックチェーン上の最初のブロックを示す、Genesisブロックを記述する。

vi myGenesis.json

下記の内容を記載する。

{
  "config": {
    "chainId": 15,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0
  },
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "",
  "gasLimit": "0x8000000",
  "difficulty": "0x4000",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}

下記のコマンドで初期化する。

$ geth --datadir eth_private_net/ init eth_private_net/myGenesis.json
INFO [07-10|17:47:05.278] Maximum peer count                       ETH=50 LES=0 total=50
INFO [07-10|17:47:05.283] Set global gas cap                       cap=50,000,000
INFO [07-10|17:47:05.285] Allocated cache and file handles         database=/Users/sey323/Workspace/tmp/go-ethereum-sample/eth_private_net/geth/chaindata cache=16.00MiB handles=16
INFO [07-10|17:47:05.412] Opened ancient database                  database=/Users/sey323/Workspace/tmp/go-ethereum-sample/eth_private_net/geth/chaindata/ancient readonly=false
INFO [07-10|17:47:05.413] Writing custom genesis block
INFO [07-10|17:47:05.413] Persisted trie from memory database      nodes=0 size=0.00B time="10.545µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [07-10|17:47:05.414] Successfully wrote genesis state         database=chaindata hash=7b2e8b..7e0432
INFO [07-10|17:47:05.415] Allocated cache and file handles         database=/Users/sey323/Workspace/tmp/go-ethereum-sample/eth_private_net/geth/lightchaindata cache=16.00MiB handles=16
INFO [07-10|17:47:05.560] Opened ancient database                  database=/Users/sey323/Workspace/tmp/go-ethereum-sample/eth_private_net/geth/lightchaindata/ancient readonly=false
INFO [07-10|17:47:05.560] Writing custom genesis block
INFO [07-10|17:47:05.561] Persisted trie from memory database      nodes=0 size=0.00B time="3.723µs"  gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [07-10|17:47:05.561] Successfully wrote genesis state         database=lightchaindata hash=7b2e8b..7e0432

ネットワークの起動

上記のGenesisブロックを利用し、プライベート・ネットで起動する。

geth --networkid "15" --nodiscover --datadir "./eth_private_net" console 2>> ./eth_private_net/geth_err.logget
Welcome to the Geth JavaScript console!

instance: Geth/v1.10.20-stable/darwin-amd64/go1.18.3
at block: 0 (Thu Jan 01 1970 09:00:00 GMT+0900 (JST))
 datadir: /Users/sey323/Workspace/tmp/go-ethereum-sample/eth_private_net
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

To exit, press ctrl-d or type exit
>

上記のメッセージが表示され、コンソールにログインができれば、プライベート・ネットの構築が完了したこととなる。consoleオプションを付与することで、ネットワークの起動と、コンソールのログインを同時に行うことができる。

アカウントの作成

上記のコンソール上で、下記のコマンドを実行し、アカウントを2つ作成する。 personal.newAccount(${アカウントのパスワード})となる。今回はわかりやすいように、送金者のパスワードをsender、受信者のパスワードをreceiverとする。

> personal.newAccount("sender") # sender
"0x256049a16743cd53c9a5c87260f4029e5fb8543b"
> personal.newAccount("receiver")
"0x5016f5da222c0d681540a4a93341821ce86d2808"

名前の通り、senderで送信し、receiverで受け取る。

senderをマイニングをするときにマイニング報酬を受け取るアカウントとして紐付けを行う。

> miner.setEtherbase(eth.accounts[0])
true
> eth.coinbase
"0x256049a16743cd53c9a5c87260f4029e5fb8543b" ←senderのパスワードと一致していればOK

マイニング

作成したEthereumのブロックチェーン 上でマイニングを行う。マイニングを実施し、報酬が取得できていることを確認する。

マイニングの開始

マイニングはminer.start()コマンドにより行う。引数に数字を指定することで、指定した数字数だけCPUのコアを利用する。

> miner.start(1)

停止は下記のコマンドで行う

> miner.stop()

マイニング状態の確認

現在いくつのブロックチェーンがマイニングできているかを下記のコマンドで確認する。

> eth.blockNumber
3

何回か時間を開けて実行すると、マイニングされたブロックチェーン の数が増えていくことが確認できる。

> eth.blockNumber
26

10番目にマイニングされた内容を確認する場合、下記のコマンドを実行する。

> eth.getBlock(10)
{
  difficulty: 131264,
  extraData: "0xd983010a14846765746888676f312e31382e338664617277696e",
  gasLimit: 132912767,
  gasUsed: 0,
  hash: "0x16d0b5283bb1c27ed8e4e2716f2de876f41b32d179686309415e5f0cfff818be",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x256049a16743cd53c9a5c87260f4029e5fb8543b", # 発掘者の情報。先ほど指定したsender
  mixHash: "0xda08b63f24843580b91e9985e3c34799bd97ba8cc7ae0d5614f91ee8d4f5ff3a",
  nonce: "0x4551a9f0ddab8683",
  number: 10,
  parentHash: "0xe222146a7803943a45177a22593ffa55fc20a711d60d995f0203cba5d3088ea3",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 538,
  stateRoot: "0x389d7b60d6ec8dc385e05a39fc7284b68dee61403ebfca3b9065abaa8251e5a0",
  timestamp: 1657443671,
  totalDifficulty: 1327872,
  transactions: [], # ブロックチェーン上で行われたトランザクションが記載される。まだトランザクションを行っていないので何もない。
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

マイニング報酬の確認

下記のコマンドでマイニング報酬を確認する。

> eth.getBalance(eth.accounts[0])
52000000000000000000
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
52

52ETH獲得できたことを確認できた。

Weiとは

イーサリアムの最小単位。1 wei = 0.000000000000000001 ETHとなる。

送金

確認のため一度マイニング処理を停止する。

> miner.stop()

先ほどマイニングしsenderが獲得したEthereumをreceiverに送金する。sender(account[0])はEthereumを獲得していて、receiver(account[1])は所持数が0であることを確認する。

> eth.getBalance(eth.accounts[0])
52000000000000000000
> eth.getBalance(eth.accounts[1])
0

まず送金者のアカウントをアンロック状態にする。

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x256049a16743cd53c9a5c87260f4029e5fb8543b
Passphrase: # 「sender」と入力
true

その後下記のコマンドで送金処理を行う。実行後、トランザクションIDが発行される。

> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(5, "ether")})
"0x1de0364dae1a75508a34083c743e8c24ed5f45a7773ff038cda7ba1d91d58531"

マイニング処理を先の処理で停止したため、上記の送金処理が検証されておらず、まだEthereumの移動が起きていない。

> eth.getBalance(eth.accounts[0])
52000000000000000000
> eth.getBalance(eth.accounts[1])
0

マイニングを再度実行し、その後しばらくして送金処理が行われていることを確認する。

> miner.start(1)
null

数秒待つと、receiver(account[1])に送金されたことが確認できる。

> eth.getBalance(eth.accounts[1])
0
> eth.getBalance(eth.accounts[1])
5000000000000000000

トランザクションの内容確認

下記のコマンドでトランザクションの内容を確認する。

> eth.getTransaction("0x1de0364dae1a75508a34083c743e8c24ed5f45a7773ff038cda7ba1d91d58531")
{
  blockHash: "0xc20daf211903cde4866444133e4788e47b11e56c361271e329a18a4a0f4adf62",
  blockNumber: 27,
  from: "0x256049a16743cd53c9a5c87260f4029e5fb8543b", # 送金者
  gas: 21000, # gasの最大値
  gasPrice: 1000000000, # マイニング手数料
  hash: "0x1de0364dae1a75508a34083c743e8c24ed5f45a7773ff038cda7ba1d91d58531",
  input: "0x",
  nonce: 0,
  r: "0xd048cc4684a1e6f6bf90f9c470490f10f2131f4e43c49dbc5d4e13dfb8c32277",
  s: "0xce0277c95337a22d8ea5523f75781892acf03f8ddfe6fa6873b1924be25def5",
  to: "0x5016f5da222c0d681540a4a93341821ce86d2808",
  transactionIndex: 0,
  type: "0x0",
  v: "0x41",
  value: 5000000000000000000 # 送金金額
}
このスクラップは2023/05/05にクローズされました