PolarSPARC |
Hyperledger Besu Private Network using Docker
Bhaskar S | *UPDATED*10/22/2022 |
Overview
Hyperledger Besu is a Java-based, open source Ethereum client (formerly called Pantheon) that is designed for the Enterprise use-cases and can be run in both the public (permissionless) and the private (permissioned) scenarios.
Hyperledger Besu includes the following capabilities:
Execution Environment :: The Ethereum Virtual Machine (EVM) that is responsible for the processing of transactions and the execution of contracts that are coded as business logic (Smart Contracts)
Persistence Storage :: The blockchain store for persisting the state of the blockchain (account balances, etc) as well as the immutable blocks of transactions that led to the current state. Under the hood, it uses RocksDB (a key-value database) for storage of data on each Ethereum node
Consensus Algorithms :: The mechanism used by the Ethereum nodes distributed across the network to achieve agreement on the current state of the blockchain as well as the validity of the transactions. For the public (permissionless) network, it uses the Proof of Work (PoW) algorithm, and for the private (permissioned) network, it uses the Proof of Authority (PoA) algorithm. Currently, there are two PoA algorithms supported - Clique and Istanbul Byzantine Fault Tolerance (IBFT2)
Peer-2-Peer Networking :: The nodes in the for Ethereum network communicate with each other to discover other nodes in the network and to synchronize the state of the blockchain on each node
Application Connectivity :: The use of JSON based messages over HTTP to allow business applications to interact with the Ethereum blockchain
Monitoring :: The mechanism to monitor the health and performance of the nodes in the Ethereum network
The following diagram illustrates the high-level architecture of Hyperledger Besu:
In the article Introduction to Ethereum - Part 1, we introduced some basic concepts of Ethereum, got our hands dirty in setting up a private network with 4 accounts (one for each of the entities - the bank, the buyer, the dealer, & the dmv), and demonstrated sending a sample transaction between two of the accounts.
In this article, we will demonstrate the same transaction behavior, but with a different setup using the official Docker image for Hyperledger Besu.
Installation
The setup will be on a Ubuntu 22.04 LTS based Linux desktop.
Ensure Docker is installed and setup. Else, refer to the article Introduction to Docker for help.
Also, ensure the Python programming language (version 3.7 or above) is installed.
Assuming that we are logged in as polarsparc and the current working directory is the home directory /home/polarsparc, we will setup a directory structure by executing the following commands in a terminal window:
$ mkdir -p HyperledgerBesu/conf
$ mkdir -p HyperledgerBesu/data/bank/keystore
$ mkdir -p HyperledgerBesu/data/buyer/keystore
$ mkdir -p HyperledgerBesu/data/dealer/keystore
$ mkdir -p HyperledgerBesu/data/dmv/keystore
Now, change the current working directory to the directory /home/polarsparc/HyperledgerBesu. In the following paragraphs we will refer to this location as $BESU_HOME.
Visit the site Hyperledger Besu to determine the current stable version. At the time of this article, the current stable version is 22.7.7.
For our exploration, we will be downloading and using the official docker image hyperledger/besu:22.7.7 for Hyperledger Besu.
To pull and download the docker image for Hyperledger Besu, execute the following command:
docker pull hyperledger/besu:22.7.7
The following should be the typical output:
22.7.7: Pulling from hyperledger/besu fb0b3276a519: Already exists 252b0b1a7bd8: Pull complete 15f44a07bce1: Pull complete Digest: sha256:f76cee87b8a2024e9e031baf48396798e443dbf06d1f4382819f39d80f35ddd2 Status: Downloaded newer image for hyperledger/besu:22.7.7 docker.io/hyperledger/besu:22.7.7
Once the download is complete, execute the following command to check everything was ok with the image for Hyperledger Besu:
$ docker run --rm --name besu hyperledger/besu:22.7.7 --version
The following would be the typical output:
besu/v22.7.7/linux-x86_64/openjdk-java-11 2022-10-22 14:24:38.396+00:00 | main | INFO | Besu | Using jemalloc
Next step is to download and install the Python module for Web3. Execute the following command:
python -m pip install web3
This completes the installation part. Moving on to setup the private network.
Private Network Setup
For this demonstration, we will need 4 accounts, one for each of the entities - the bank, the buyer, the dealer, and the dmv.
We will create the 4 accounts using MyEtherWallet.
First, we will create an account for the entity bank. Click on Create a new wallet as shown in the illustration below:
Next, click on Software as shown in the illustration below:
Next, click on Keystore File as shown in the illustration below:
Next, enter a secure password in the text box Password, re-enter the same password in the text box Confirm Password, and then click on Create Wallet as shown in the illustration below:
Next, click on Acknowledge & Download as shown in the illustration below:
This action will take a few seconds and the keystore file with the name in the form UTC--{timestamp}--{address} will be downloaded to the directory $HOME/Downloads.
Move the keystore file we just created for the bank to the appropriate directory by executing the following command:
$ mv $HOME/Downloads/UTC--* $BESU_HOME/data/bank/keystore
Perform the above steps for creating a new keystore for each of the remaining entities - the buyer, the dealer, and the dmv by clicking on Create Another Wallet each time as shown in the illustration below:.
Once the 4 keystore files are created and moved to the appropriate location, execute the following command at the location $BESU_HOME:
$ tree ./data
The following would be the typical output:
./data |-- bank | |-- keystore | |-- UTC--2022-10-22T13-02-38.299Z--f1da86e0f5288f0537865e7b51edd302089ae06f |-- buyer | |-- keystore | |-- UTC--2022-10-22T13-13-58.581Z--760ee653f93dca288fe6f9a39b2ed54ed4be0226 |-- dealer | |-- keystore | |-- UTC--2022-10-22T13-15-26.669Z--658ba9305cb0de275e55ccfff396446bf7add077 |-- dmv |-- keystore |-- UTC--2022-10-22T13-16-24.965Z--41c6f1783161c92d4bdfe1f901bc2e9a1c80aa8d 8 directories, 8 files
From the Output.3 above, we have the 4 accounts and their respective addresses as follows:
bank :: f1da86e0f5288f0537865e7b51edd302089ae06f
buyer :: 760ee653f93dca288fe6f9a39b2ed54ed4be0226
dealer :: 658ba9305cb0de275e55ccfff396446bf7add077
dmv :: 41c6f1783161c92d4bdfe1f901bc2e9a1c80aa8d
In order to setup a private Ethereum blockchain network, we need to initialize and create the Genesis block. The Genesis block is the first block of the blockchain that has no previous block. We will use the following template to create the genesis file:
{ "config":{ "chainId": 21, "berlinBlock": 0, "clique":{ "blockperiodseconds": 10, "epochlength": 30000 } }, "coinbase":"0x0000000000000000000000000000000000000000", "difficulty":"0x1", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000bank-address0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit":"0xa00000", "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", "nonce":"0x0", "timestamp":"0x5c51a607", "alloc": { "bank-address": { "balance": "20000000000000000000" }, "buyer-address": { "balance": "10000000000000000000" }, "dealer-address": { "balance": "5000000000000000000" }, "dmv-address": { "balance": "3000000000000000000" } } }
Create a file called genesis.json with above contents in the directory $BESU_HOME/conf.
For this demonstration, we will be using the Clique algorithm, which is one of the supported Proof of Authority (PoA) consensus algorithm.
The PoA is most suitable for Enterprise scenarios where the participants know and trust each other. As a result, the PoA consensus algorithms have faster block creation times and higher transaction throughput.
Clique is a reputation-based algorithm in which only approved and trusted accounts (known as the Signers) can validate transactions and create blocks. If there are more than one Signers, they take turns to create the next block.
We will use the bank as the trusted Signers in our private Ethereum network. The address of the Signers is specified in the extraData field.
The following illustration shows the template for the extraData field:
Using the bank's address as the Signer (which is a 40 character hex string) f1da86e0f5288f0537865e7b51edd302089ae06f, the following illustration shows the final extraData field:
After modifying the contents of the file genesis.json (located in the directory $BESU_HOME/conf) with the Signer and the 4 account addresses, the following would be the contents of the genesis file:
{ "config":{ "chainId": 21, "berlinBlock": 0, "clique":{ "blockperiodseconds": 10, "epochlength": 30000 } }, "coinbase":"0x0000000000000000000000000000000000000000", "difficulty":"0x1", "extraData":"0x0000000000000000000000000000000000000000000000000000000000000000f1da86e0f5288f0537865e7b51edd302089ae06f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit":"0xa00000", "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", "nonce":"0x0", "timestamp":"0x5c51a607", "alloc": { "f1da86e0f5288f0537865e7b51edd302089ae06f": { "balance": "20000000000000000000" }, "760ee653f93dca288fe6f9a39b2ed54ed4be0226": { "balance": "10000000000000000000" }, "658ba9305cb0de275e55ccfff396446bf7add077": { "balance": "5000000000000000000" }, "41c6f1783161c92d4bdfe1f901bc2e9a1c80aa8d": { "balance": "3000000000000000000" } } }
In the following section, we will explain some of the important parameters used in the genysis file shown above:
config :: Describes this private blockchain in terms of the network identifier, the milestone block number, and the consensus engine used
chainId :: It specifies the blockchain network identifier. A value of 1, 2, 3, or 4 refer to the real-world public Ethereum networks currently in use. Since we desire a private network, we will choose an arbitrary value of 21 for our network
berlinBlock :: It specifies the block at which the network changed protocols. Since our network is private and we are starting from scratch, we set the value to 0 (zero) indicating no hard fork
clique :: Indicates we are using the specified PoA consensus algorithm
blockperiodseconds :: Indicates the time interval between the creation of the next block
epochlength :: Indicates the number of blocks after which to checkpoint and reset the pending votes
coinbase :: Indicates the address of the account that will receive the rewards for successful mining of a block
difficulty :: Indicates the level of effort before generating a new block. Higher value indicates more effort on the part of the miner nodes. For our private network, we will keep this value low
extraData :: Indicates the concatenated list of authorized signers. At least one initial signer MUST be specified
gasLimit :: Indicates the limit of the gas fees that will be charged for processing a block
nonce :: Indicates the 64-bit hash corresponding to amount of mining computation effort performed on a block
mixHash :: Indicates the 256-bit hash, that combined with nonce, indicates the amount of computation performed to generate a block
timestamp :: Indicates the creation date and time of the block
alloc :: Indicates the accounts with pre-allocated ethers in our private network. At least one account MUST be specified
Moving along, the next step is to extract the private key for the 4 accounts. For this, we will leverage the web3 module we installed for Python.
Open a new terminal window, change the current directory to $BESU_HOME, and launch the Python interpreter.
To extract the private key for bank, execute the following commands at the Python interpreter prompt:
>>> from web3.auto import w3
>>> with open("./data/bank/keystore/UTC--2022-10-22T13-02-38.299Z--f1da86e0f5288f0537865e7b51edd302089ae06f") as key_file:
... encrypted_key = key_file.read()
... bank_priv_key = w3.eth.account.decrypt(encrypted_key, 'Bank_Secret')
>>> bank_priv_key
The following would be the typical output:
HexBytes('0xa0d12aee64cecaf6af78a2594263f123b35ecf2fb3c76f88b662cbcb7207b348')
Copy the private key a0d12aee64cecaf6af78a2594263f123b35ecf2fb3c76f88b662cbcb7207b348 (without the 0x) and save it to a file called key in the directory $BESU_HOME/data/bank.
We will repeat the above steps for each of the other accounts buyer, dealer , and dmv.
To extract the private key for buyer, execute the following commands at the Python interpreter prompt:
>>> with open("./data/buyer/keystore/UTC--2022-10-22T13-13-58.581Z--760ee653f93dca288fe6f9a39b2ed54ed4be0226") as key_file:
... encrypted_key = key_file.read()
... buyer_priv_key = w3.eth.account.decrypt(encrypted_key, 'Buyer_Secret')
>>> buyer_priv_key
The following would be the typical output:
HexBytes('0xabe351ed564b301bfbfc6e0e69a23720fc3bc40405f164188c88dbed548f60b1')
Copy the private key abe351ed564b301bfbfc6e0e69a23720fc3bc40405f164188c88dbed548f60b1 (without the 0x) and save it to a file called key in the directory $BESU_HOME/data/buyer.
To extract the private key for dealer, execute the following commands at the Python interpreter prompt:
>>> with open("./data/dealer/keystore/UTC--2022-10-22T13-15-26.669Z--658ba9305cb0de275e55ccfff396446bf7add077") as key_file:
... encrypted_key = key_file.read()
... dealer_priv_key = w3.eth.account.decrypt(encrypted_key, 'Dealer_Secret')
>>> dealer_priv_key
The following would be the typical output:
HexBytes('0xa8fdf591c01c215140d1a3e614148e2d20ee162b10fe1dbce5db639f03024efc')
Copy the private key a8fdf591c01c215140d1a3e614148e2d20ee162b10fe1dbce5db639f03024efc (without the 0x) and save it to a file called key in the directory $BESU_HOME/data/dealer.
Finally, to extract the private key for dmv, execute the following commands at the Python interpreter prompt:
>>> with open("./data/dmv/keystore/UTC--2022-10-22T13-16-24.965Z--41c6f1783161c92d4bdfe1f901bc2e9a1c80aa8d") as key_file:
... encrypted_key = key_file.read()
... dmv_priv_key = w3.eth.account.decrypt(encrypted_key, 'Dmv_Secret')
>>> dmv_priv_key
The following would be the typical output:
HexBytes('0x0a6b5fbe7c08d63b47ba7c051b27a5c773afd3d565660355355092ff14b8b1f3')
Copy the private key 0a6b5fbe7c08d63b47ba7c051b27a5c773afd3d565660355355092ff14b8b1f3 (without the 0x) and save it to a file called key in the directory $BESU_HOME/data/dmv.
The next step is to extract the public address of the bootnode and store it in a file named bootnode_pubkey that will be located at $BESU_HOME/data/bank. A bootnode is used for initial discovery of the nodes (peers) in the network. We will designate the node running the bank as the bootnode.
To extract the public address for bank, execute the following command in the terminal prompt:
$ docker run --rm --name bank -u $(id -u $USER):$(id -g $USER) -v $BESU_HOME/root hyperledger/besu:22.7.7 --data-path=/root/data/bank --node-private-key-file=/root/data/bank/key public-key export-address --to=/root/data/bank/bootnode_pubkey
The following would be the typical output:
2022-10-22 18:33:31.630+00:00 | main | INFO | KeyPairUtil | Loaded public key 0x8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963 from /root/data/bank/key
For simplicity, the nodes of our Hyperledger Besu based private Ethereum network will on localhost 127.0.0.1 on different ports.
The next step is to create a configuration file with various options for the bank node. The configuration file will be used by Hyperledger Besu to start the Ethereum node.
The following will be the contents of the configuration file bank-config.toml (located in the directory $BESU_HOME/conf):
logging="INFO" identity="bank" data-path="/opt/besu/data" genesis-file="/config/genesis.json" node-private-key-file="/opt/besu/keys/key" nat-method="DOCKER" host-whitelist=["*"] # P2P related p2p-host="127.0.0.1" p2p-port=30303 # RPC related rpc-http-enabled=true rpc-http-host="127.0.0.1" rpc-http-port=8545 rpc-http-api=["ADMIN", "CLIQUE", "ETH", "NET", "TXPOOL", "WEB3"] rpc-http-cors-origins=["*"]
In the following section, we will explain some of the configuration options used above:
identity :: Indicates the name of the Ethereum node
data-path :: Specifies the path to the data directory used by Hyperledger Besu
genesis-file :: Specifies the genesis file to be used for the private Ethereum network
node-private-key-file :: Specifies the private key file for the Ethereum node
nat-method :: Specifies the method to be used in a NAT environment so other nodes can discovery each other
host-whitelist :: Specifies a comma-separated list of host addresses to make API calls. The "*" (asterisk) here means allow all hosts
p2p-host :: Specifies the host on which to listen for peer-2-peer discovery
p2p-port :: Specifies the network port on which to listen for peer-2-peer discovery
rpc-http-enabled :: If true, enables API access via HTTP
rpc-http-host :: Specifies the host on which to listen for API request(s)
rpc-http-port :: Specifies the network port on which to listen for API request(s)
rpc-http-api :: Specifies a comma-separated list of APIs enabled for access
rpc-http-cors-origins :: Specifies a comma-separated list of domains allowed for CORS validation. The "*" (asterisk) here means accept request(s) from all domains
Open 4 terminal windows, each representing the 4 entities, namely, the bank, the buyer, the dealer, and the dmv. We will refer to these 4 windows corresponding to the entity they refer. For example, the first terminal will be referred to as the bank , the second terminal as the buyer, the third terminal as the dealer and the fourth terminal as the dmv.
In each of the 4 windows, change the current working directory to $BESU_HOME.
In the bank terminal, start the Ethereum node by executing the following command:
$ docker run --rm --name bank --network host -e BESU_OPTS="--add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true" -u $(id -u $USER):$(id -g $USER) -v $BESU_HOME/data/bank:/opt/besu/data -v $BESU_HOME/data/bank:/opt/besu/keys -v $BESU_HOME/data/bank:/opt/besu/public-keys -v $BESU_HOME/conf/bank-config.toml:/config/config.toml -v $BESU_HOME/conf/genesis.json:/config/genesis.json hyperledger/besu:22.7.7 --config-file=/config/config.toml
The following would be the typical output:
Setting logging level to INFO 2022-10-22 19:06:49.002+00:00 | main | INFO | Besu | Using LibEthPairings native alt bn128 2022-10-22 19:06:49.004+00:00 | main | INFO | Besu | Using the native implementation of the signature algorithm 2022-10-22 19:06:49.007+00:00 | main | INFO | Besu | Using the native implementation of the blake2bf algorithm 2022-10-22 19:06:49.011+00:00 | main | INFO | Besu | Starting Besu version: besu/bank/v22.7.7/linux-x86_64/openjdk-java-11 2022-10-22 19:06:49.455+00:00 | main | WARN | Besu | --graphql-http-host has been ignored because --graphql-http-enabled was not defined on the command line. 2022-10-22 19:06:49.457+00:00 | main | WARN | Besu | --rpc-ws-host has been ignored because --rpc-ws-enabled was not defined on the command line. 2022-10-22 19:06:49.459+00:00 | main | INFO | Besu | Static Nodes file = /opt/besu/data/static-nodes.json 2022-10-22 19:06:49.460+00:00 | main | INFO | StaticNodesParser | StaticNodes file /opt/besu/data/static-nodes.json does not exist, no static connections will be created. 2022-10-22 19:06:49.460+00:00 | main | INFO | Besu | Connecting to 0 static nodes. 2022-10-22 19:06:49.463+00:00 | main | INFO | Besu | Security Module: localfile 2022-10-22 19:06:49.479+00:00 | main | INFO | RocksDBKeyValueStorageFactory | No existing database detected at /opt/besu/data. Using version 1 2022-10-22 19:06:49.931+00:00 | main | WARN | Besu | --tx-pool-future-max-by-account has been deprecated, use --tx-pool-limit-by-account-percentage instead. 2022-10-22 19:06:49.950+00:00 | main | INFO | KeyPairUtil | Loaded public key 0x8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963 from /opt/besu/keys/key 2022-10-22 19:06:50.077+00:00 | main | INFO | ProtocolScheduleBuilder | Protocol schedule created with milestones: [Berlin: 0] 2022-10-22 19:06:50.154+00:00 | main | INFO | TransactionPoolFactory | Enabling transaction pool 2022-10-22 19:06:50.166+00:00 | main | INFO | BesuControllerBuilder | TTD difficulty is not present, creating initial sync phase for PoW 2022-10-22 19:06:50.190+00:00 | main | INFO | RunnerBuilder | Detecting NAT service. 2022-10-22 19:06:50.297+00:00 | main | INFO | Runner | Starting external services ... 2022-10-22 19:06:50.297+00:00 | main | INFO | JsonRpcHttpService | Starting JSON-RPC service on 0.0.0.0:8545 2022-10-22 19:06:50.417+00:00 | vert.x-eventloop-thread-1 | INFO | JsonRpcHttpService | JSON-RPC service started and listening on 0.0.0.0:8545 2022-10-22 19:06:50.422+00:00 | main | INFO | AutoTransactionLogBloomCachingService | Starting auto transaction log bloom caching service. 2022-10-22 19:06:50.423+00:00 | main | INFO | LogBloomCacheMetadata | Lookup cache metadata file in data directory: /opt/besu/data/caches 2022-10-22 19:06:50.432+00:00 | main | INFO | Runner | Starting Ethereum main loop ... 2022-10-22 19:06:50.432+00:00 | main | INFO | DockerNatManager | Starting docker NAT manager. 2022-10-22 19:06:50.441+00:00 | main | INFO | NetworkRunner | Starting Network. 2022-10-22 19:06:50.456+00:00 | nioEventLoopGroup-2-1 | INFO | RlpxAgent | P2P RLPx agent started and listening on /0:0:0:0:0:0:0:0:30303. 2022-10-22 19:06:50.457+00:00 | main | INFO | PeerDiscoveryAgent | Starting peer discovery agent on host=0.0.0.0, port=30303 2022-10-22 19:06:50.490+00:00 | vert.x-eventloop-thread-1 | INFO | VertxPeerDiscoveryAgent | Started peer discovery agent successfully, on effective host=0:0:0:0:0:0:0:0%0 and port=30303 2022-10-22 19:06:50.495+00:00 | vert.x-eventloop-thread-1 | INFO | PeerDiscoveryAgent | P2P peer discovery agent started and listening on /0:0:0:0:0:0:0:0%0:30303 2022-10-22 19:06:50.589+00:00 | vert.x-eventloop-thread-1 | INFO | PeerDiscoveryAgent | Writing node record to disk. NodeRecord{seq=1, publicKey=0x038be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b024134393, udpAddress=Optional[/127.0.0.1:30303], tcpAddress=Optional[/127.0.0.1:30303], asBase64=-Je4QEk8ycQ0VBvQz1nvA3E3BtbGW132qt9DW_S07t6ZSaCqIY4TUJ8AsrV_czNMRAxPj3bhzDgrqBec6C530D6h2rYBg2V0aMfGhOOh5SSAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQOL4oPxVQqFuO1G-4BSeszga1WYU3e3Ybt3AbGwJBNDk4N0Y3CCdl-DdWRwgnZf, nodeId=0x2ec606ee8985c1a3e070f8e5f1da86e0f5288f0537865e7b51edd302089ae06f, customFields={tcp=30303, udp=30303, ip=0x7f000001, eth=[[0xe3a1e524, 0x]], id=V4, secp256k1=0x038be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b024134393}} 2022-10-22 19:06:50.611+00:00 | main | INFO | DefaultP2PNetwork | Enode URL enode://8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963@127.0.0.1:30303 2022-10-22 19:06:50.612+00:00 | main | INFO | DefaultP2PNetwork | Node address 0xf1da86e0f5288f0537865e7b51edd302089ae06f 2022-10-22 19:06:50.615+00:00 | main | INFO | DefaultSynchronizer | Starting synchronizer. 2022-10-22 19:06:50.621+00:00 | main | INFO | FullSyncDownloader | Starting full sync. 2022-10-22 19:06:50.622+00:00 | main | INFO | FullSyncTargetManager | No sync target, waiting for peers. Current peers: 0 2022-10-22 19:06:50.641+00:00 | main | INFO | Runner | Ethereum main loop is up. 2022-10-22 19:06:50.705+00:00 | pool-7-thread-1 | INFO | BlockMiner | Produced #1 / 0 tx / 0 om / 0 (0.0%) gas / (0x8b55187027adb584f4304481a5c4891cfa3342aaa0af3c85edbc81ff91773bf7) in 0.047s 2022-10-22 19:06:55.637+00:00 | EthScheduler-Timer-0 | INFO | FullSyncTargetManager | No sync target, waiting for peers. Current peers: 0
From the Output.8 above, we need to make a note of the bootnode address from the line that contains the sub-string Enode URL.
We will now create the configuration files (with various options including the address of the bootnode) for the remaining 3 entities.
The docker option --network host was the *ONLY* way to get the Ethereum private network work, with all the nodes discovered and connected.
The following will be the contents of the configuration file buyer-config.toml (located in the directory $BESU_HOME/conf):
logging="INFO" identity="buyer" data-path="/opt/besu/data" genesis-file="/config/genesis.json" node-private-key-file="/opt/besu/keys/key" nat-method="DOCKER" host-whitelist=["*"] bootnodes=["enode://8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963@127.0.0.1:30303"] # P2P related p2p-host="127.0.0.1" p2p-port=30304 # RPC related rpc-http-enabled=false rpc-http-host="127.0.0.1" rpc-http-port=8546 rpc-http-api=["ADMIN", "CLIQUE", "ETH", "NET", "TXPOOL", "WEB3"] rpc-http-cors-origins=["*"]
The following will be the contents of the configuration file dealer-config.toml (located in the directory $BESU_HOME/conf):
logging="INFO" identity="dealer" data-path="/opt/besu/data" genesis-file="/config/genesis.json" node-private-key-file="/opt/besu/keys/key" nat-method="DOCKER" host-whitelist=["*"] bootnodes=["enode://8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963@127.0.0.1:30303"] # P2P related p2p-host="127.0.0.1" p2p-port=30305 # RPC related rpc-http-enabled=false rpc-http-host="127.0.0.1" rpc-http-port=8547 rpc-http-api=["ADMIN", "CLIQUE", "ETH", "NET", "TXPOOL", "WEB3"] rpc-http-cors-origins=["*"]
The following will be the contents of the configuration file dmv-config.toml (located in the directory $BESU_HOME/conf):
logging="INFO" identity="dmv" data-path="/opt/besu/data" genesis-file="/config/genesis.json" node-private-key-file="/opt/besu/keys/key" nat-method="DOCKER" host-whitelist=["*"] bootnodes=["enode://8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963@127.0.0.1:30303"] # P2P related p2p-host="127.0.0.1" p2p-port=30306 # RPC related rpc-http-enabled=false rpc-http-host="127.0.0.1" rpc-http-port=8548 rpc-http-api=["ADMIN", "CLIQUE", "ETH", "NET", "TXPOOL", "WEB3"] rpc-http-cors-origins=["*"]
The values for the configuration options p2p-port and the rpc-http-port have to be unique for every Ethereum node in the private network.
In the buyer terminal, start the Ethereum node by executing the following command:
$ docker run --rm --name buyer --network host -e BESU_OPTS="--add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true" -u $(id -u $USER):$(id -g $USER) -v $BESU_HOME/data/buyer:/opt/besu/data -v $BESU_HOME/data/buyer:/opt/besu/keys -v $BESU_HOME/conf/buyer-config.toml:/config/config.toml -v $BESU_HOME/conf/genesis.json:/config/genesis.json hyperledger/besu:22.7.7 --config-file=/config/config.toml
The following would be the typical output:
Setting logging level to INFO 2022-10-22 19:29:37.228+00:00 | main | INFO | Besu | Using LibEthPairings native alt bn128 2022-10-22 19:29:37.230+00:00 | main | INFO | Besu | Using the native implementation of the signature algorithm 2022-10-22 19:29:37.234+00:00 | main | INFO | Besu | Using the native implementation of the blake2bf algorithm 2022-10-22 19:29:37.238+00:00 | main | INFO | Besu | Starting Besu version: besu/buyer/v22.7.7/linux-x86_64/openjdk-java-11 2022-10-22 19:29:37.656+00:00 | main | WARN | Besu | --rpc-http-host, --rpc-http-port, --rpc-http-cors-origins and --rpc-http-api has been ignored because --rpc-http-enabled was not defined on the command line. 2022-10-22 19:29:37.658+00:00 | main | WARN | Besu | --graphql-http-host has been ignored because --graphql-http-enabled was not defined on the command line. 2022-10-22 19:29:37.661+00:00 | main | WARN | Besu | --rpc-ws-host has been ignored because --rpc-ws-enabled was not defined on the command line. 2022-10-22 19:29:37.663+00:00 | main | INFO | Besu | Static Nodes file = /opt/besu/data/static-nodes.json 2022-10-22 19:29:37.664+00:00 | main | INFO | StaticNodesParser | StaticNodes file /opt/besu/data/static-nodes.json does not exist, no static connections will be created. 2022-10-22 19:29:37.664+00:00 | main | INFO | Besu | Connecting to 0 static nodes. 2022-10-22 19:29:37.667+00:00 | main | INFO | Besu | Security Module: localfile 2022-10-22 19:29:37.683+00:00 | main | INFO | RocksDBKeyValueStorageFactory | No existing database detected at /opt/besu/data. Using version 1 2022-10-22 19:29:38.152+00:00 | main | WARN | Besu | --tx-pool-future-max-by-account has been deprecated, use --tx-pool-limit-by-account-percentage instead. 2022-10-22 19:29:38.170+00:00 | main | INFO | KeyPairUtil | Loaded public key 0x0854eb4540a40bce1853040037df18eea7f5234f9c958664bbafb412159be681c44b0da24fc36805fc9d3da9741eae8a6226ab89e8af458f67d1d5454a3e049d from /opt/besu/keys/key 2022-10-22 19:29:38.296+00:00 | main | INFO | ProtocolScheduleBuilder | Protocol schedule created with milestones: [Berlin: 0] 2022-10-22 19:29:38.370+00:00 | main | INFO | TransactionPoolFactory | Enabling transaction pool 2022-10-22 19:29:38.381+00:00 | main | INFO | BesuControllerBuilder | TTD difficulty is not present, creating initial sync phase for PoW 2022-10-22 19:29:38.406+00:00 | main | INFO | RunnerBuilder | Detecting NAT service. 2022-10-22 19:29:38.470+00:00 | main | INFO | Runner | Starting external services ... 2022-10-22 19:29:38.475+00:00 | main | INFO | AutoTransactionLogBloomCachingService | Starting auto transaction log bloom caching service. 2022-10-22 19:29:38.476+00:00 | main | INFO | LogBloomCacheMetadata | Lookup cache metadata file in data directory: /opt/besu/data/caches 2022-10-22 19:29:38.485+00:00 | main | INFO | Runner | Starting Ethereum main loop ... 2022-10-22 19:29:38.485+00:00 | main | INFO | DockerNatManager | Starting docker NAT manager. 2022-10-22 19:29:38.490+00:00 | main | INFO | NetworkRunner | Starting Network. 2022-10-22 19:29:38.569+00:00 | nioEventLoopGroup-2-1 | INFO | RlpxAgent | P2P RLPx agent started and listening on /0:0:0:0:0:0:0:0:30304. 2022-10-22 19:29:38.570+00:00 | main | INFO | PeerDiscoveryAgent | Starting peer discovery agent on host=0.0.0.0, port=30304 2022-10-22 19:29:38.611+00:00 | vert.x-eventloop-thread-1 | INFO | VertxPeerDiscoveryAgent | Started peer discovery agent successfully, on effective host=0:0:0:0:0:0:0:0%0 and port=30304 2022-10-22 19:29:38.614+00:00 | vert.x-eventloop-thread-1 | INFO | PeerDiscoveryAgent | P2P peer discovery agent started and listening on /0:0:0:0:0:0:0:0%0:30304 2022-10-22 19:29:38.701+00:00 | vert.x-eventloop-thread-1 | INFO | PeerDiscoveryAgent | Writing node record to disk. NodeRecord{seq=1, publicKey=0x030854eb4540a40bce1853040037df18eea7f5234f9c958664bbafb412159be681, udpAddress=Optional[/127.0.0.1:30304], tcpAddress=Optional[/127.0.0.1:30304], asBase64=-Je4QJAo0BPrj_yLqNigrRsR3raxl4FGi8320LbNBUj8GFDvNL_cT3sKc5PBlzEP0Z2Qr4cHIL_lET-wcwZl2kcHN1EBg2V0aMfGhOOh5SSAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQMIVOtFQKQLzhhTBAA33xjup_UjT5yVhmS7r7QSFZvmgYN0Y3CCdmCDdWRwgnZg, nodeId=0x6a509e9a68bb306420dec9b5760ee653f93dca288fe6f9a39b2ed54ed4be0226, customFields={tcp=30304, udp=30304, ip=0x7f000001, eth=[[0xe3a1e524, 0x]], id=V4, secp256k1=0x030854eb4540a40bce1853040037df18eea7f5234f9c958664bbafb412159be681}} 2022-10-22 19:29:38.744+00:00 | main | INFO | DefaultP2PNetwork | Enode URL enode://0854eb4540a40bce1853040037df18eea7f5234f9c958664bbafb412159be681c44b0da24fc36805fc9d3da9741eae8a6226ab89e8af458f67d1d5454a3e049d@127.0.0.1:30304 2022-10-22 19:29:38.744+00:00 | main | INFO | DefaultP2PNetwork | Node address 0x760ee653f93dca288fe6f9a39b2ed54ed4be0226 2022-10-22 19:29:38.747+00:00 | main | INFO | DefaultSynchronizer | Starting synchronizer. 2022-10-22 19:29:38.751+00:00 | main | INFO | FullSyncDownloader | Starting full sync. 2022-10-22 19:29:38.754+00:00 | main | INFO | FullSyncTargetManager | No sync target, waiting for peers. Current peers: 0 2022-10-22 19:29:38.775+00:00 | main | INFO | Runner | Ethereum main loop is up. 2022-10-22 19:29:39.132+00:00 | nioEventLoopGroup-3-1 | INFO | FullSyncTargetManager | No sync target, waiting for peers. Current peers: 1 2022-10-22 19:29:42.016+00:00 | nioEventLoopGroup-3-1 | INFO | BlockPropagationManager | Saved announced block for future import 13 (0xb03db618ad8ce1dea634b7e466d68704d3e85767a005f4cca08a23704ffb4076) - 1 saved block(s) 2022-10-22 19:29:42.017+00:00 | nioEventLoopGroup-3-1 | INFO | BlockPropagationManager | Retrieving parent 0xff19e9950977249f7e7a170222802da512e274cee9cd19823358c5e7ba77f9c4 of block 13 (0xb03db618ad8ce1dea634b7e466d68704d3e85767a005f4cca08a23704ffb4076) 2022-10-22 19:29:42.051+00:00 | nioEventLoopGroup-3-1 | INFO | BlockPropagationManager | Saved announced block for future import 12 (0xff19e9950977249f7e7a170222802da512e274cee9cd19823358c5e7ba77f9c4) - 2 saved block(s) ..... SNIP ..... 2022-10-22 19:29:42.223+00:00 | nioEventLoopGroup-3-1 | INFO | BlockPropagationManager | Saved announced block for future import 2 (0xfa032005a838a9da0518dd637d8e12d1767cf556ebec127c9a87ecb6a82c03bb) - 12 saved block(s) 2022-10-22 19:29:42.224+00:00 | nioEventLoopGroup-3-1 | INFO | BlockPropagationManager | Retrieving parent 0x8b55187027adb584f4304481a5c4891cfa3342aaa0af3c85edbc81ff91773bf7 of block 2 (0xfa032005a838a9da0518dd637d8e12d1767cf556ebec127c9a87ecb6a82c03bb) 2022-10-22 19:29:42.281+00:00 | EthScheduler-Workers-0 | INFO | PersistBlockTask | Imported #1 / 0 tx / 0 om / 0 (0.0%) gas / (0x8b55187027adb584f4304481a5c4891cfa3342aaa0af3c85edbc81ff91773bf7) in 0.022s. Peers: 1 ..... SNIP ..... 2022-10-22 19:31:02.011+00:00 | EthScheduler-Workers-0 | INFO | PersistBlockTask | Imported #21 / 0 tx / 0 om / 0 (0.0%) gas / (0x76ec46e8f9266633fda6dc32176f2c6b22096603473d65f345667be2339f7288) in 0.002s. Peers: 3 ^C2022-10-22 19:31:11.115+00:00 | BesuCommand-Shutdown-Hook | INFO | DefaultSynchronizer | Stopping synchronizer 2022-10-22 19:31:11.118+00:00 | BesuCommand-Shutdown-Hook | INFO | NetworkRunner | Stopping Network. 2022-10-22 19:31:11.130+00:00 | BesuCommand-Shutdown-Hook | INFO | EthProtocolManager | Stopping eth Subprotocol. 2022-10-22 19:31:11.227+00:00 | BesuCommand-Shutdown-Hook | INFO | EthProtocolManager | eth Subprotocol stopped. 2022-10-22 19:31:11.227+00:00 | BesuCommand-Shutdown-Hook | INFO | NetworkRunner | Network stopped. 2022-10-22 19:31:11.228+00:00 | BesuCommand-Shutdown-Hook | INFO | AutoTransactionLogBloomCachingService | Shutting down Auto transaction logs caching service. 2022-10-22 19:31:11.229+00:00 | BesuCommand-Shutdown-Hook | INFO | DockerNatManager | Stopping docker NAT manager.
In the dealer terminal, start the Ethereum node by executing the following command:
$ docker run --rm --name dealer --network host -e BESU_OPTS="--add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true" -u $(id -u $USER):$(id -g $USER) -v $BESU_HOME/data/dealer:/opt/besu/data -v $BESU_HOME/data/dealer:/opt/besu/keys -v $BESU_HOME/conf/dealer-config.toml:/config/config.toml -v $BESU_HOME/conf/genesis.json:/config/genesis.json hyperledger/besu:22.7.7 --config-file=/config/config.toml
In the dmv terminal, start the Ethereum node by executing the following command:
$ docker run --rm --name dmv --network host -e BESU_OPTS="--add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true" -u $(id -u $USER):$(id -g $USER) -v $BESU_HOME/data/dmv:/opt/besu/data -v $BESU_HOME/data/dmv:/opt/besu/keys -v $BESU_HOME/conf/dmv-config.toml:/config/config.toml -v $BESU_HOME/conf/genesis.json:/config/genesis.json hyperledger/besu:22.7.7 --config-file=/config/config.toml
To make API requests on our private blockchain network, we will issue the following commands at the Python interpreter prompt:
>>> import web3
>>> from web3 import Web3
>>> from web3.middleware import geth_poa_middleware
>>> provider = Web3.HTTPProvider('http://127.0.0.1:8545')
>>> w3 = Web3(provider)
>>> w3.middleware_onion.inject(geth_poa_middleware, layer=0)
To check if we have successfully connected to the bank node, execute the following command at the Python interpreter prompt:
>>> w3.isConnected()
The following would be the typical output:
True
To get information about the bank node, execute the following command at the Python interpreter prompt:
>>> w3.geth.admin.nodeInfo()
The following would be the typical output:
AttributeDict({'enode': 'enode://8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963@127.0.0.1:30303', 'listenAddr': '127.0.0.1:30303', 'ip': '127.0.0.1', 'name': 'besu/bank/v22.7.7/linux-x86_64/openjdk-java-11', 'id': '8be283f1550a85b8ed46fb80527acce06b55985377b761bb7701b1b0241343937fc46bc08dd96a26ef20dcc37c6df8c79edf7a2a0e86828cc6ce1e07e5f5a963', 'ports': AttributeDict({'discovery': 30303, 'listener': 30303}), 'protocols': AttributeDict({'eth': AttributeDict({'config': AttributeDict({'chainId': 21, 'berlinBlock': 0, 'clique': AttributeDict({'epochLength': 30000, 'blockPeriodSeconds': 10})}), 'difficulty': 11, 'genesis': '0x8a6b044d304cf5fba6bd7855ca8c38226a55e9bf39ab8182244cc613d225846e', 'head': '0xf1b4be8b6116aa6623292961ae15a3ac6abbfbbb3790a85cf47cf4e1680c333a', 'network': 21})})})
The trimmed string value enode://8be283f...@127.0.0.1:30001 is the endpoint address for the bank node.
To verify the peers connected to the bank node, execute the following command at the Python interpreter prompt:
>>> w3.geth.admin.peers()
The following would be the typical output:
[AttributeDict({'version': '0x5', 'name': 'besu/dealer/v22.7.7/linux-x86_64/openjdk-java-11', 'caps': ['eth/62', 'eth/63', 'eth/64', 'eth/65', 'eth/66', 'snap/1'], 'network': AttributeDict({'localAddress': '127.0.0.1:30303', 'remoteAddress': '127.0.0.1:33896'}), 'port': '0x7661', 'id': '0x2a9e0e41e30a838075511189d211e6c992f774bde95277c786075693de5a5fda8b1d6cc2e8aabf4686a59f79208de647d50b15ff9fea9feedd689b9a23846759', 'protocols': AttributeDict({'eth': AttributeDict({'difficulty': '0x9', 'head': '0x9dfa85e80c4717be05c2703f98c7a88cb3c1090dd43a9cdf7324801513d62f3d', 'version': 66})}), 'enode': 'enode://2a9e0e41e30a838075511189d211e6c992f774bde95277c786075693de5a5fda8b1d6cc2e8aabf4686a59f79208de647d50b15ff9fea9feedd689b9a23846759@127.0.0.1:30305?discport=0'}), AttributeDict({'version': '0x5', 'name': 'besu/buyer/v22.7.7/linux-x86_64/openjdk-java-11', 'caps': ['eth/62', 'eth/63', 'eth/64', 'eth/65', 'eth/66', 'snap/1'], 'network': AttributeDict({'localAddress': '127.0.0.1:30303', 'remoteAddress': '127.0.0.1:33888'}), 'port': '0x7660', 'id': '0x0854eb4540a40bce1853040037df18eea7f5234f9c958664bbafb412159be681c44b0da24fc36805fc9d3da9741eae8a6226ab89e8af458f67d1d5454a3e049d', 'protocols': AttributeDict({'eth': AttributeDict({'difficulty': '0x9', 'head': '0x9dfa85e80c4717be05c2703f98c7a88cb3c1090dd43a9cdf7324801513d62f3d', 'version': 66})}), 'enode': 'enode://0854eb4540a40bce1853040037df18eea7f5234f9c958664bbafb412159be681c44b0da24fc36805fc9d3da9741eae8a6226ab89e8af458f67d1d5454a3e049d@127.0.0.1:30304?discport=0'}), AttributeDict({'version': '0x5', 'name': 'besu/dmv/v22.7.7/linux-x86_64/openjdk-java-11', 'caps': ['eth/62', 'eth/63', 'eth/64', 'eth/65', 'eth/66', 'snap/1'], 'network': AttributeDict({'localAddress': '127.0.0.1:30303', 'remoteAddress': '127.0.0.1:59406'}), 'port': '0x7662', 'id': '0x8642e38feb3bb6080bbd868f40f2c2751c0df2704de178f22cad1af31bbd53b5841ccd800c139ea0344784e7c757f3d31f09a657d65ad3e34f83c12f31cc66ce', 'protocols': AttributeDict({'eth': AttributeDict({'difficulty': '0x9', 'head': '0x9dfa85e80c4717be05c2703f98c7a88cb3c1090dd43a9cdf7324801513d62f3d', 'version': 66})}), 'enode': 'enode://8642e38feb3bb6080bbd868f40f2c2751c0df2704de178f22cad1af31bbd53b5841ccd800c139ea0344784e7c757f3d31f09a657d65ad3e34f83c12f31cc66ce@127.0.0.1:30306?discport=0'})]
To retrieve the details of a block by the block number 0 (zero), execute the following command at the Python interpreter prompt:
>>> w3.eth.getBlock(0)
The following would be the typical output:
AttributeDict({"number": 0, "hash": "0x8a6b044d304cf5fba6bd7855ca8c38226a55e9bf39ab8182244cc613d225846e", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "nonce": "0x0000000000000000", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "stateRoot": "0xb3962f7878e5846c8cf7630d651b2b904d23b8ecbb5e2a49a5021d32b860a404", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "miner": "0x0000000000000000000000000000000000000000", "difficulty": 1, "totalDifficulty": 1, "proofOfAuthorityData": "0x0000000000000000000000000000000000000000000000000000000000000000f1da86e0f5288f0537865e7b51edd302089ae06f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "size": 626, "gasLimit": 10485760, "gasUsed": 0, "timestamp": 1548854791, "uncles": [], "transactions": []})
To display account balance for the buyer account, execute the following command at the Python interpreter prompt:
>>> w3.eth.getBalance(Web3.toChecksumAddress('0x760ee653f93dca288fe6f9a39b2ed54ed4be0226'))
The following would be the typical output:
10000000000000000000
If we do not use Web3.toChecksumAddress on the address to get the account balance, we will encounter an error
Similarly, to display account balance for the dealer account, execute the following command at the Python interpreter prompt:
>>> w3.eth.getBalance(Web3.toChecksumAddress('0x658ba9305cb0de275e55ccfff396446bf7add077'))
The following would be the typical output:
5000000000000000000
We will now send a transaction to transfer 1 ether from the buyer to the dealer. For this we will need to create a send transaction message. Enter the following data at the Python interpreter prompt to create the message structure called buyer_dealer_txn:
>>> buyer_dealer_txn = {
... 'from': Web3.toChecksumAddress('0x760ee653f93dca288fe6f9a39b2ed54ed4be0226'),
... 'to': Web3.toChecksumAddress('0x658ba9305cb0de275e55ccfff396446bf7add077'),
... 'value': w3.toWei(1, 'ether'),
... 'gas': 90000,
... 'gasPrice': 18000000000,
... 'nonce': 0,
... 'chainId': 21
...}
Before sending the transaction message buyer_dealer_txn, it needs to be digitally signed using the private key of the buyer. To do that, execute the following commands at the Python interpreter prompt:
>>> buyer_priv_key = '0xabe351ed564b301bfbfc6e0e69a23720fc3bc40405f164188c88dbed548f60b1'
>>> signed_txn = w3.eth.account.sign_transaction(buyer_dealer_txn, buyer_priv_key)
To send the signed transaction to transfer 1 ether from the buyer to the dealer, execute the following command at the Python interpreter prompt:
>>> w3.eth.sendRawTransaction(signed_txn.rawTransaction)
The following would be the typical output:
HexBytes('0x0be38c14e1e23665970c115517d1c318ed3ab5b0395992ada7d656d1e5485544')
The w3.eth.sendRawTransaction method will return a transaction hash as a hex string (similar to a transaction id).
To display all the details of a transaction on this private network, execute the following command at the Python interpreter prompt:
>>> w3.eth.getTransaction('0x0be38c14e1e23665970c115517d1c318ed3ab5b0395992ada7d656d1e5485544')
The following would be the typical output:
AttributeDict({"blockHash": "0x70475aeb066ea503c90eb78958ee68db164dc6ca21900359157fec8ccb376116", "blockNumber": 12, "chainId": "0x15", "from": "0x760eE653f93DcA288Fe6f9a39b2ed54Ed4bE0226", "gas": 90000, "gasPrice": 18000000000, "hash": "0x0be38c14e1e23665970c115517d1c318ed3ab5b0395992ada7d656d1e5485544", "input": "0x", "nonce": 0, "publicKey": "0x0854eb4540a40bce1853040037df18eea7f5234f9c958664bbafb412159be681c44b0da24fc36805fc9d3da9741eae8a6226ab89e8af458f67d1d5454a3e049d", "raw": "0xf86d80850430e2340083015f9094658ba9305cb0de275e55ccfff396446bf7add077880de0b6b3a7640000804da0a75c0c26ca2bca4a41cd1b953adbd9e01db831c8a1a2a22266ae7704b47f25bba0295a04aeba95b5c0abb3fea62f5958b6c41588e6c86965ac0055f054b2505fc8", "to": "0x658ba9305Cb0dE275E55CcfFf396446bF7Add077", "transactionIndex": 0, "type": "0x0", "value": 1000000000000000000, "v": 77, "r": "0xa75c0c26ca2bca4a41cd1b953adbd9e01db831c8a1a2a22266ae7704b47f25bb", "s": "0x295a04aeba95b5c0abb3fea62f5958b6c41588e6c86965ac0055f054b2505fc8"})
From the Output.18 above, we see that transaction is processed in block number 12.
To display account balance for the buyer account, execute the following command at the Python interpreter prompt:
>>> w3.fromWei(w3.eth.getBalance(Web3.toChecksumAddress('0x760ee653f93dca288fe6f9a39b2ed54ed4be0226')), 'ether')
The following would be the typical output:
8.999622
Similarly, to display account balance for the dealer account, execute the following command at the Python interpreter prompt:
>>> w3.fromWei(w3.eth.getBalance(Web3.toChecksumAddress('0x658ba9305cb0de275e55ccfff396446bf7add077')), 'ether')
The following would be the typical output:
6
As is evident from the Output.19 and Output.20 above, the account balance for the buyer has decreased, while the account balance for the dealer has increased.
YAAAHOOO !!! We have successfully demonstrated a 4-node Hyperledger Besu based private Ethereum network using Docker.
The following is the link to the Github Repo that provides the config and wallet account files (with the directory structure) used in this article for a quickstart:
References
Hyperledger Besu Enterprise Ethereum Client
Hyperledger Besu Command Line Options