以太坊区块链如何与Nethereum互动

最近,我有时间在以太坊区块链上玩智能合约。此示例将重点关注使用Nethereum库与智能合约进行交互。

最初我想看看Eth Gas Station上发现的合约0x2a0c0dbecc7e4d658f48e01e3fa353f44050c208中发生的事件,但是在轻模式下获得geth同步被证明是一个非常大的挑战。在快速模式下同步也很慢:几个小时取决于你的连接速度。由于我希望我的示例尽可能无缝地工作,因此在测试区块链上部署起来更容易:ganache-cli

因此,示例的第一部分是使用ganache-cli本地区块链,并从Nethereum文档部署示例合约。

ganache-cli

Ganache-cli将在每次运行时生成测试帐户。为了确保它们不会更改(更容易进行测试,但从不在生产中使用这些帐户!),使用助记符参数。不要忘记映射用于连接节点的端口8545。

1
docker run --rm -ti -p 8545:8545 trufflesuite/ganache-cli --mnemonic "johnny mnemonic"

这个命令的结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Ganache CLI v6.1.0 (ganache-core: 2.1.0)

Available Accounts
==================
(0) 0x4efd4ab8293b3b8179d9dbf9ade1ae00d83eb314
(1) 0xaffe3d426b8517b17b54290c882f0827f65ec187
(2) 0x6824385051e746ef4c1c6b4ae7e56a381a95d54a
(3) 0x338da826cf7a3c9a68f00a9e922eeed5ca1e8211
(4) 0x8dcc6e12c380a80329e6108ad9b04b78e561d65a
(5) 0xcee6938394b0fa55c45d08ad588cd84af89a14df
(6) 0x70ab1d88d6980b0d192f3521f8862ac4dca68567
(7) 0xe20547f96055fbd2c3a2263e71cd4adb74b69349
(8) 0x79bef342f6bc8e0b34bcf51e55bf73611aeeb2c4
(9) 0xa24982b1e3c6be086465971c9e7e7e8ad44fdf48

Private Keys
==================
(0) 3f22cc3e1757c4a69de7e249c99e4217d4a0017157247a863cc7fb61e5a16ec8
(1) 8cfce94fa87c2e937d2c901b6193802900e3a9b15bdfe9aaeb1cbb9e9b46d485
(2) 3b9f3f9087260beb3c81a7fa105e0c0714cf30964d726a25cafb883bf3589c2e
(3) 14886ce9c977b5b181cfc01ded5a9f4753f4340623bed643cd7ea89a777e36e7
(4) c8486cd25cb5278481eef49cb689905511f0ebd77101c3f87bb25c152d8a248a
(5) 6ba903be3121fdacb40b677f8f5c0a400e9ff06d0632f4f9c0fcaf5ef4cf989e
(6) 3141fae5ba12e4a00260f9aec8fafa0d60e0339a4d68145c4950eaab67e55e79
(7) cb3a94619a4ced15e0efea940e74c8b5c45b4af7dddc38ad50a0b474cc633ed1
(8) a3b3c325cb77497c5f6ac65a169aa9bdbdc1387d9367f5ab4d83c76b18ed2651
(9) 59b034e79634893393a58ed2be861c459c200be8622a04c267f90ad7a44607ca

HD Wallet
==================
Mnemonic: johnny mnemonic
Base HD Path: m/44'/60'/0'/0/{account_index}

Listening on localhost:8545

现在我们已准备好本地测试区块链并等待合约。

Nethereum客户端

与以太坊区块链交互涉及几个步骤。

  • 创建合约代码
  • 编译二进制文件
  • 解锁帐户以发送要处理的交易
  • 部署二进制文件
  • 与合约互动

合约代码

我们将使用Nethereum文档中的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
contract test {
uint _multiplier;

event Multiplied(uint indexed a, address indexed sender, uint result);

function test(uint multiplier){
_multiplier = multiplier;
}

function multiply(uint a) returns(uint r) {
r = a * _multiplier;
emit Multiplied(a, msg.sender, r);
return r;
}
}

代码编译将成为下一篇文章的一部分。目前我只需复制并粘贴应用程序二进制接口(ABI)和字节码:)

解锁帐户

如果你要发送需要支付费用的交易,则需要解锁该帐户。这笔费用是以gas支付的,gas价格各不相同。

在此示例中,帐户已解锁30分钟,但在现实生活中,这应该更少:)

1
2
3
4
5
6
7
8
9
Log($"Using geth node {node}");
var web3 = new Web3(node);

Log($"Unlocking account {senderAddress}");
var unlockAccountResult = await web3.Personal.UnlockAccount.SendRequestAsync(senderAddress, senderPassword, 1200).ConfigureAwait(false);
Log($"-> Success: {unlockAccountResult}");

var funds = await web3.Eth.GetBalance.SendRequestAsync(senderAddress).ConfigureAwait(false);
Log($"Account {senderAddress} has {UnitConversion.Convert.FromWei(funds.Value)} eth");

gas估算和部署

Nethereum提供了一种方便的功能来估算函数和合约部署的gas成本。否则你需要提供任意金额(希望足够高)。

发送交易后,我们将等待它被挖掘:然后我们可以获得包含交易信息的收据:

  • 区块号
  • 合约地址
  • 用过的gas
1
2
3
4
5
6
7
8
9
10
var gasPrice = await web3.Eth.GasPrice.SendRequestAsync().ConfigureAwait(false);
Log($"Gas price is {gasPrice.Value} wei");

var multiplier = 7;
var gasDeploy = await web3.Eth.DeployContract.EstimateGasAsync(abi, contractByteCode, senderAddress, multiplier).ConfigureAwait(false);

Log($"Deploying contract with multiplier {multiplier} using {gasDeploy.Value} gas");
var receipt = await web3.Eth.DeployContract.SendRequestAndWaitForReceiptAsync(abi, contractByteCode, senderAddress, gasDeploy, null, multiplier).ConfigureAwait(false);
Log($"-> Done at block {receipt.BlockNumber.Value} using {receipt.CumulativeGasUsed.Value} gas");
Log($"-> Contract address is {receipt.ContractAddress}");

调用函数

函数调用遵循相同的模式:估计gas,发送交易并等待接收。

1
2
3
4
5
6
7
8
var contract = web3.Eth.GetContract(abi, receipt.ContractAddress);

var multiplyFunction = contract.GetFunction("multiply");

var gas7 = await multiplyFunction.EstimateGasAsync(7).ConfigureAwait(false);
Log($"Multiply 7 by {multiplier} using {gas7.Value} gas");
var receipt7 = await multiplyFunction.SendTransactionAndWaitForReceiptAsync(senderAddress, gas7, null, null, 7).ConfigureAwait(false);
Log($"-> Done at block {receipt7.BlockNumber.Value} using {receipt7.CumulativeGasUsed.Value} gas");

监听事件

在监听事件之前,我们需要为它创建一个过滤器。之后,将检索在创建过滤器之后(或在最后一次调用GetFilterChanges之后)发生的事件。

1
2
3
4
5
6
7
8
9
10
11
Log($"Creating filter for all events");
var filterAll = await multiplyEvent.CreateFilterAsync().ConfigureAwait(false);

Log("Get all events");
var log = await multiplyEvent.GetFilterChanges<MultipliedEvent>(filterAll).ConfigureAwait(false);
Log($"-> Got {log.Count}");

foreach (var evt in log)
{
Log($"-> Block {evt.Log.BlockNumber.Value} : {evt.Event.MultiplicationInput} * {multiplier} = {evt.Event.Result}");
}

运行客户端和节点

运行docker-compose up --build --abort-on-container-exit将启动两个容器,并在客户端完成后停止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
Attaching to samplenethereumtruffle_geth_1, samplenethereumtruffle_client_1
client_1 | Waiting 5 seconds.
geth_1 | Ganache CLI v6.1.0 (ganache-core: 2.1.0)
geth_1 |
geth_1 | Available Accounts
geth_1 | ==================
geth_1 | (0) 0x4efd4ab8293b3b8179d9dbf9ade1ae00d83eb314
geth_1 | (1) 0xaffe3d426b8517b17b54290c882f0827f65ec187
geth_1 | (2) 0x6824385051e746ef4c1c6b4ae7e56a381a95d54a
geth_1 | (3) 0x338da826cf7a3c9a68f00a9e922eeed5ca1e8211
geth_1 | (4) 0x8dcc6e12c380a80329e6108ad9b04b78e561d65a
geth_1 | (5) 0xcee6938394b0fa55c45d08ad588cd84af89a14df
geth_1 | (6) 0x70ab1d88d6980b0d192f3521f8862ac4dca68567
geth_1 | (7) 0xe20547f96055fbd2c3a2263e71cd4adb74b69349
geth_1 | (8) 0x79bef342f6bc8e0b34bcf51e55bf73611aeeb2c4
geth_1 | (9) 0xa24982b1e3c6be086465971c9e7e7e8ad44fdf48
geth_1 |
geth_1 | Private Keys
geth_1 | ==================
geth_1 | (0) 3f22cc3e1757c4a69de7e249c99e4217d4a0017157247a863cc7fb61e5a16ec8
geth_1 | (1) 8cfce94fa87c2e937d2c901b6193802900e3a9b15bdfe9aaeb1cbb9e9b46d485
geth_1 | (2) 3b9f3f9087260beb3c81a7fa105e0c0714cf30964d726a25cafb883bf3589c2e
geth_1 | (3) 14886ce9c977b5b181cfc01ded5a9f4753f4340623bed643cd7ea89a777e36e7
geth_1 | (4) c8486cd25cb5278481eef49cb689905511f0ebd77101c3f87bb25c152d8a248a
geth_1 | (5) 6ba903be3121fdacb40b677f8f5c0a400e9ff06d0632f4f9c0fcaf5ef4cf989e
geth_1 | (6) 3141fae5ba12e4a00260f9aec8fafa0d60e0339a4d68145c4950eaab67e55e79
geth_1 | (7) cb3a94619a4ced15e0efea940e74c8b5c45b4af7dddc38ad50a0b474cc633ed1
geth_1 | (8) a3b3c325cb77497c5f6ac65a169aa9bdbdc1387d9367f5ab4d83c76b18ed2651
geth_1 | (9) 59b034e79634893393a58ed2be861c459c200be8622a04c267f90ad7a44607ca
geth_1 |
geth_1 | HD Wallet
geth_1 | ==================
geth_1 | Mnemonic: johnny mnemonic
geth_1 | Base HD Path: m/44'/60'/0'/0/{account_index}
geth_1 |
geth_1 | Listening on localhost:8545
client_1 | Using geth node http://geth:8545
client_1 | Unlocking account 0xaffe3d426b8517b17b54290c882f0827f65ec187
geth_1 | personal_unlockAccount
client_1 | -> Success: True
geth_1 | eth_getBalance
client_1 | Account 0xaffe3d426b8517b17b54290c882f0827f65ec187 has 100 eth
geth_1 | eth_gasPrice
client_1 | Gas price is 20000000000 wei
geth_1 | eth_estimateGas
client_1 | Deploying contract with multiplier 7 using 128999 gas
geth_1 | eth_sendTransaction
geth_1 |
geth_1 | Transaction: 0xd22f0cca420a4fb1771f800e143aec97792e71d4b3fba2b35b428bac86746c0e
geth_1 | Contract created: 0xc080107e84a8bc84c914cd738f2c280dd3bdf693
geth_1 | Gas usage: 128999
geth_1 | Block Number: 1
geth_1 | Block Time: Wed Apr 25 2018 21:38:55 GMT+0000 (UTC)
geth_1 |
geth_1 | eth_getTransactionReceipt
geth_1 | eth_getCode
client_1 | -> Done at block 1 using 128999 gas
client_1 | -> Contract address is 0xc080107e84a8bc84c914cd738f2c280dd3bdf693
client_1 | Creating filter for all events
geth_1 | eth_newFilter
geth_1 | eth_estimateGas
client_1 | Multiply 7 by 7 using 23711 gas
geth_1 | eth_sendTransaction
geth_1 |
geth_1 | Transaction: 0x01f20d02da08cb41db016d7247e26b5bfde5908cd1d9e77634aff590b4189fd5
geth_1 | Gas usage: 23711
geth_1 | Block Number: 2
geth_1 | Block Time: Wed Apr 25 2018 21:38:56 GMT+0000 (UTC)
geth_1 |
geth_1 | eth_getTransactionReceipt
client_1 | -> Done at block 2 using 23711 gas
geth_1 | eth_estimateGas
client_1 | Multiply 8 by 7 using 23711 gas
geth_1 | eth_sendTransaction
geth_1 |
geth_1 | Transaction: 0x976f1812f5adc0c16e9625535eded5ad5ef1d396d7c99963cd138bf19d9af421
geth_1 | Gas usage: 23711
geth_1 | Block Number: 3
geth_1 | Block Time: Wed Apr 25 2018 21:38:56 GMT+0000 (UTC)
geth_1 |
geth_1 | eth_getTransactionReceipt
client_1 | -> Done at block 2 using 23711 gas
client_1 | Get all events
client_1 | -> No event received
geth_1 | eth_getFilterChanges
client_1 | Done. Exiting.

没有收到任何事件……看起来像正在实施的功能。虽然我不想等待它,但我决定看一下运行私有Geth节点。

私有geth节点

根据client-go Docker中心映像上的说明,设置更复杂一些:

第1步:创建genesis文件

虽然ganache-cli默认提供100eth,但是在私有Geth节点中为帐户提供资金是通过在genesis.json文件中添加它们来完成的。为简单起见,我们将重用ganache帐户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"config": {
"chainId": 0,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00",
"alloc": {
"0xaffe3d426b8517b17b54290c882f0827f65ec187": {
"balance": "0xF00000000000000000"
}
}
}

第2步:初始化geth节点

然后需要使用geth init命令初始化节点。如果你的网络中还有其他节点,则还需要初始化它们。

1
RUN geth init data/genesis_clique.json

第3步:导入帐户

我们需要使用geth account import命令导入帐户,帐户私钥和密码。

1
RUN geth account import data/account1.key --password data/account1.pass

第4步:使用挖掘运行geth

该节点以--maxpeers = 0--nodiscover启动,以确保没有人可以连接到它,并且它不会分别尝试发现。

1
ENTRYPOINT [ "geth", "--nodiscover", "--maxpeers=0", "--rpc", "--rpcapi=eth,web3,personal,net,miner,admin,debug", "--rpcvhosts=geth", "--rpcaddr=0.0.0.0", "--mine"

现在我们可以构建并启动docker镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
INFO [04-25|21:44:28] Maximum peer count                       ETH=0 LES=0 total=0
INFO [04-25|21:44:28] Starting peer-to-peer node instance=Geth/v1.8.6-stable/linux-amd64/go1.10.1
INFO [04-25|21:44:28] Allocated cache and file handles database=/root/.ethereum/geth/chaindata cache=768 handles=1024
WARN [04-25|21:44:28] Upgrading database to use lookup entries
INFO [04-25|21:44:28] Initialised chain configuration config="{ChainID: 0 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Constantinople: <nil> Engine: unknown}"
INFO [04-25|21:44:28] Database deduplication successful deduped=0
INFO [04-25|21:44:28] Disk storage enabled for ethash caches dir=/root/.ethereum/geth/ethash count=3
INFO [04-25|21:44:28] Disk storage enabled for ethash DAGs dir=/root/.ethash count=2
INFO [04-25|21:44:28] Initialising Ethereum protocol versions="[63 62]" network=1
INFO [04-25|21:44:28] Loaded most recent local header number=0 hash=1092ae…35e2af td=131072
INFO [04-25|21:44:28] Loaded most recent local full block number=0 hash=1092ae…35e2af td=131072
INFO [04-25|21:44:28] Loaded most recent local fast block number=0 hash=1092ae…35e2af td=131072
INFO [04-25|21:44:28] Regenerated local transaction journal transactions=0 accounts=0
INFO [04-25|21:44:28] Starting P2P networking
INFO [04-25|21:44:28] RLPx listener up self="enode://2c62fe87d0f270b5fe143235b471d224ad59859ba8ede6272c183f13f168014f935f4209b98c1a97bf753aad350e1096fcff663496c07f970f7c6573a19527bc@[::]:30303?discport=0"
INFO [04-25|21:44:28] IPC endpoint opened url=/root/.ethereum/geth.ipc
INFO [04-25|21:44:28] HTTP endpoint opened url=http://0.0.0.0:8545 cors= vhosts=geth
INFO [04-25|21:44:30] Unlocked account address=0x4EFD4Ab8293b3B8179d9DBF9Ade1Ae00D83EB314
INFO [04-25|21:44:30] Transaction pool price threshold updated price=18000000000
INFO [04-25|21:44:30] Etherbase automatically configured address=0x4EFD4Ab8293b3B8179d9DBF9Ade1Ae00D83EB314
INFO [04-25|21:44:30] Starting mining operation
INFO [04-25|21:44:30] Commit new mining work number=1 txs=0 uncles=0 elapsed=1.633ms
INFO [04-25|21:44:33] Generating ethash verification cache epoch=0 percentage=34 elapsed=3.025s
INFO [04-25|21:44:36] Generated ethash verification cache epoch=0 elapsed=5.832s
INFO [04-25|21:44:41] Generating DAG in progress epoch=0 percentage=0 elapsed=4.700s
INFO [04-25|21:44:45] Generating DAG in progress epoch=0 percentage=1 elapsed=9.534s
INFO [04-25|21:44:50] Generating DAG in progress epoch=0 percentage=2 elapsed=14.181s
INFO [04-25|21:44:55] Generating DAG in progress epoch=0 percentage=3 elapsed=18.879s
INFO [04-25|21:45:00] Generating DAG in progress epoch=0 percentage=4 elapsed=23.663s
INFO [04-25|21:45:04] Generating DAG in progress epoch=0 percentage=5 elapsed=28.397s
INFO [04-25|21:45:11] Generating DAG in progress epoch=0 percentage=6 elapsed=34.842s

看起来需要花一些时间……

准备以太坊DAG(定向非循环图)需要花费大量时间。当然,不是我的样本开始时我愿意等待的。希望有另一种共识算法可用!

用geth进行权限挖掘的证明

这种设置更复杂,但是由于这篇很棒的文章,它也被记录下来了。

第1步:更新genesis文件

最简单的是使用puppeth创建genesis.json文件。我们将使用PoA和两个帐户。其中一个将是用于验证块的1个帐户。

client-go Docker hub image不包含puppeth。希望提供包含所有工具的dockerfile,我们可以从中构建一镜像。镜像在这里:geth-alltools docker image

不带参数运行会打开一个shell,我们就可以开始玩弄了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
$ docker run -ti mathieubrun/geth-alltools
/ # puppeth
+-----------------------------------------------------------+
| Welcome to puppeth, your Ethereum private network manager |
| |
| This tool lets you create a new Ethereum network down to |
| the genesis block, bootnodes, miners and ethstats servers |
| without the hassle that it would normally entail. |
| |
| Puppeth uses SSH to dial in to remote servers, and builds |
| its network components out of Docker containers using the |
| docker-compose toolset. |
+-----------------------------------------------------------+

Please specify a network name to administer (no spaces or hyphens, please)
> SampleNet

Sweet, you can set this via --network=SampleNet next time!

INFO [04-26|22:59:43] Administering Ethereum network name=SampleNet
WARN [04-26|22:59:43] No previous configurations found path=/root/.puppeth/SampleNet

What would you like to do? (default = stats)
1. Show network stats
2. Configure new genesis
3. Track new remote server
4. Deploy network components
> 2

Which consensus engine to use? (default = clique)
1. Ethash - proof-of-work
2. Clique - proof-of-authority
> 2

How many seconds should blocks take? (default = 15)
> 5

Which accounts are allowed to seal? (mandatory at least one)
> 0x4efd4ab8293b3b8179d9dbf9ade1ae00d83eb314
> 0xaffe3d426b8517b17b54290c882f0827f65ec187
> 0x

Which accounts should be pre-funded? (advisable at least one)
> 0xaffe3d426b8517b17b54290c882f0827f65ec187
> 0x

Specify your chain/network ID if you want an explicit one (default = random)
>
INFO [04-26|23:00:44] Configured new genesis block

What would you like to do? (default = stats)
1. Show network stats
2. Manage existing genesis
3. Track new remote server
4. Deploy network components
> ^C
/ #

创建的genesis文件将位于~/.puppeth文件夹中。你可以注意到帐户是在extradata字段中设置的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"config": {
"chainId": 26341,
"homesteadBlock": 1,
"eip150Block": 2,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 3,
"eip158Block": 3,
"byzantiumBlock": 4,
"clique": {
"period": 5,
"epoch": 30000
}
},
"nonce": "0x0",
"timestamp": "0x5ae0e24c",
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000004efd4ab8293b3b8179d9dbf9ade1ae00d83eb3140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x47b760",
"difficulty": "0x1",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"0x4efd4ab8293b3b8179d9dbf9ade1ae00d83eb314": {
"balance": "0x1"
},
"0xaffe3d426b8517b17b54290c882f0827f65ec187": {
"balance": "0xF00000000000000000"
}
}
}

第2步:导入帐户

要重新使用帐户,我们需要使用geth account import命令导入帐户,并使用帐户私钥和密码。

1
2
RUN geth account import data/account1.key --password data/account1.pass
RUN geth account import data/account2.key --password data/account2.pass

第3步:使用挖掘运行geth

在运行geth时必须解锁用于块的帐户,因此我们将其添加到geth参数中。

1
ENTRYPOINT [ "geth", "--nodiscover", "-unlock=4efd4ab8293b3b8179d9dbf9ade1ae00d83eb314", "--password=data/account1.pass", "--maxpeers=0", "--rpc", "--rpcapi=eth,web3,personal,net,miner,admin,debug", "--rpcvhosts=geth", "--rpcaddr=0.0.0.0", "--mine" ]

封装

再次运行客户端和节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
Attaching to samplenethereumtruffle_client_1, samplenethereumtruffle_geth_1
geth_1 | INFO [04-25|22:01:06] Maximum peer count ETH=0 LES=0 total=0
geth_1 | INFO [04-25|22:01:06] Starting peer-to-peer node instance=Geth/v1.8.6-stable/linux-amd64/go1.10.1
geth_1 | INFO [04-25|22:01:06] Allocated cache and file handles database=/root/.ethereum/geth/chaindata cache=768 handles=1024
geth_1 | WARN [04-25|22:01:06] Upgrading database to use lookup entries
geth_1 | INFO [04-25|22:01:06] Initialised chain configuration config="{ChainID: 26341 Homestead: 1 DAO: <nil> DAOSupport: false EIP150: 2 EIP155: 3 EIP158: 3 Byzantium: 4 Constantinople: <nil> Engine: clique}"
geth_1 | INFO [04-25|22:01:06] Initialising Ethereum protocol versions="[63 62]" network=1
geth_1 | INFO [04-25|22:01:06] Loaded most recent local header number=0 hash=030bd8…18932b td=1
geth_1 | INFO [04-25|22:01:06] Loaded most recent local full block number=0 hash=030bd8…18932b td=1
geth_1 | INFO [04-25|22:01:06] Loaded most recent local fast block number=0 hash=030bd8…18932b td=1
geth_1 | INFO [04-25|22:01:06] Database deduplication successful deduped=0
geth_1 | INFO [04-25|22:01:06] Regenerated local transaction journal transactions=0 accounts=0
geth_1 | INFO [04-25|22:01:06] Starting P2P networking
geth_1 | INFO [04-25|22:01:06] RLPx listener up self="enode://2ffed0c407c0e73cfd16379cb74acb022848079bde49102abff6359466fbf416c8eed8729b6746def180aa543f616b427d0a92b83d50aa281ae170b241f8b10d@[::]:30303?discport=0"
geth_1 | INFO [04-25|22:01:06] IPC endpoint opened url=/root/.ethereum/geth.ipc
geth_1 | INFO [04-25|22:01:06] HTTP endpoint opened url=http://0.0.0.0:8545 cors= vhosts=geth
client_1 | Waiting 5 seconds.
geth_1 | INFO [04-25|22:01:08] Unlocked account address=0x4EFD4Ab8293b3B8179d9DBF9Ade1Ae00D83EB314
geth_1 | INFO [04-25|22:01:08] Transaction pool price threshold updated price=18000000000
geth_1 | INFO [04-25|22:01:08] Etherbase automatically configured address=0x4EFD4Ab8293b3B8179d9DBF9Ade1Ae00D83EB314
geth_1 | INFO [04-25|22:01:08] Starting mining operation
geth_1 | INFO [04-25|22:01:08] Commit new mining work number=1 txs=0 uncles=0 elapsed=883.6µs
geth_1 | INFO [04-25|22:01:08] Successfully sealed new block number=1 hash=bfacd2…60b0f4
geth_1 | INFO [04-25|22:01:08] 🔨 mined potential block number=1 hash=bfacd2…60b0f4
geth_1 | INFO [04-25|22:01:08] Commit new mining work number=2 txs=0 uncles=0 elapsed=1.900ms
client_1 | Using geth node http://geth:8545
client_1 | Unlocking account 0xaffe3d426b8517b17b54290c882f0827f65ec187
geth_1 | INFO [04-25|22:01:13] Successfully sealed new block number=2 hash=4848c2…ac8e4c
geth_1 | INFO [04-25|22:01:13] 🔨 mined potential block number=2 hash=4848c2…ac8e4c
geth_1 | INFO [04-25|22:01:13] Commit new mining work number=3 txs=0 uncles=0 elapsed=1.515ms
client_1 | -> Success: True
client_1 | Account 0xaffe3d426b8517b17b54290c882f0827f65ec187 has 4427.21857769029238784 eth
client_1 | Gas price is 18000000000 wei
geth_1 | INFO [04-25|22:01:18] Successfully sealed new block number=3 hash=83444a…1d4845
geth_1 | INFO [04-25|22:01:18] 🔨 mined potential block number=3 hash=83444a…1d4845
geth_1 | INFO [04-25|22:01:18] Commit new mining work number=4 txs=0 uncles=0 elapsed=1.38ms
client_1 | Deploying contract with multiplier 7 using 128999 gas
geth_1 | INFO [04-25|22:01:18] Submitted contract creation fullhash=0xd76e791c4e2066b84a2786a392859575d32ca7075019ed54e5179f79236cb3dc contract=0xc080107e84a8bc84C914cd738f2c280dd3Bdf693
geth_1 | INFO [04-25|22:01:23] Successfully sealed new block number=4 hash=5447bc…dc83df
geth_1 | INFO [04-25|22:01:23] 🔨 mined potential block number=4 hash=5447bc…dc83df
geth_1 | INFO [04-25|22:01:23] Commit new mining work number=5 txs=1 uncles=0 elapsed=3.755ms
geth_1 | INFO [04-25|22:01:28] Successfully sealed new block number=5 hash=630233…aadcd8
geth_1 | INFO [04-25|22:01:28] 🔨 mined potential block number=5 hash=630233…aadcd8
geth_1 | INFO [04-25|22:01:28] Commit new mining work number=6 txs=0 uncles=0 elapsed=2.605ms
client_1 | -> Done at block 5 using 128999 gas
client_1 | -> Contract address is 0xc080107e84a8bc84c914cd738f2c280dd3bdf693
client_1 | Creating filter for all events
client_1 | Multiply 7 by 7 using 23711 gas
geth_1 | INFO [04-25|22:01:28] Submitted transaction fullhash=0x4bfe9e2b033709a2d0738a79915debd3434f0c19acc004111e6b57bb3ea2aa6b recipient=0xc080107e84a8bc84C914cd738f2c280dd3Bdf693
geth_1 | INFO [04-25|22:01:33] Successfully sealed new block number=6 hash=5bec46…9c0871
geth_1 | INFO [04-25|22:01:33] 🔗 block reached canonical chain number=1 hash=bfacd2…60b0f4
geth_1 | INFO [04-25|22:01:33] 🔨 mined potential block number=6 hash=5bec46…9c0871
geth_1 | INFO [04-25|22:01:33] Commit new mining work number=7 txs=1 uncles=0 elapsed=3.344ms
geth_1 | INFO [04-25|22:01:38] Successfully sealed new block number=7 hash=82325a…b6dfaa
geth_1 | INFO [04-25|22:01:38] 🔗 block reached canonical chain number=2 hash=4848c2…ac8e4c
geth_1 | INFO [04-25|22:01:38] 🔨 mined potential block number=7 hash=82325a…b6dfaa
geth_1 | INFO [04-25|22:01:38] Commit new mining work number=8 txs=0 uncles=0 elapsed=3.350ms
client_1 | -> Done at block 7 using 23711 gas
client_1 | Multiply 8 by 7 using 23711 gas
geth_1 | INFO [04-25|22:01:38] Submitted transaction fullhash=0x41c620c8003cfe15054b061e6178241bf3478fb5ac0ece2d9b1b4afea8d597ce recipient=0xc080107e84a8bc84C914cd738f2c280dd3Bdf693
geth_1 | INFO [04-25|22:01:43] Successfully sealed new block number=8 hash=ce5a93…c20a2d
geth_1 | INFO [04-25|22:01:43] 🔗 block reached canonical chain number=3 hash=83444a…1d4845
geth_1 | INFO [04-25|22:01:43] 🔨 mined potential block number=8 hash=ce5a93…c20a2d
geth_1 | INFO [04-25|22:01:43] Commit new mining work number=9 txs=1 uncles=0 elapsed=1.869ms
geth_1 | INFO [04-25|22:01:48] Successfully sealed new block number=9 hash=96fc79…d8a93e
geth_1 | INFO [04-25|22:01:48] 🔗 block reached canonical chain number=4 hash=5447bc…dc83df
geth_1 | INFO [04-25|22:01:48] 🔨 mined potential block number=9 hash=96fc79…d8a93e
geth_1 | INFO [04-25|22:01:48] Commit new mining work number=10 txs=0 uncles=0 elapsed=1.492ms
client_1 | -> Done at block 7 using 23711 gas
client_1 | Get all events
client_1 | -> Block 7 : 7 * 7 = 49
client_1 | -> Block 9 : 8 * 7 = 56
client_1 | Done. Exiting.

最后!我们现在有一个非常简单的项目,它可以部署合约,与之交互,并监听事件!

本文的源代码库位于Github上。

如果希望快速进行以太坊开发,那请看我们精心打造的教程:

C#以太坊

其他区块链教程如下:

  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和事件等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和事件等。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • EOS入门教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。

汇智网原创翻译,转载请标明出处。这里是原文