Debug以太坊go-ethereum实战

软硬件环境

OS:macOS amd64
geth version:go-ethereum v1.6.7
IDE:goland
go version:go1.10.1 darwin/amd64

搭建go-ethereum本地化开发环境

搭建过程这里不细讲,具体可以参考Windows下搭建btcd本地化开发环境。只不过本文使用goland作为IDE。

安装geth

$ go install ./cmd/geth

命令执行完毕,会在$GOPATH/bin下面生成一个geth可执行文件。

自定义genesis.json

本文采用Ethash引擎,下面是genesis.json文件。为了演示效果,难度可以设置的低一点。

{
  "config": {
        "chainId": 1314,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
    "coinbase" : "0x0000000000000000000000000000000000000000",
    "difficulty" : "0x200",
    "extraData" : "",
    "gasLimit" : "0xffffffff",
    "nonce" : "0x0000000000000042",
    "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp" : "0x00",
    "alloc": { }
}

初始化节点

打开一个终端,切换到$GOPATH/bin目录下面,执行下面的命令:

$  ./geth --datadir ./geth-data0 init genesis.json
$  ./geth --datadir ./geth-data1 init genesis.json

配置程序参数

具体是【Run】——【Edit Configurations…】,下图是一个配置参考图:

Debug以太坊go-ethereum实战_第1张图片

程序参数的通用格式是:

--datadir "/Users/data/gobin/geth-dataX" --networkid 1314 --nodiscover --rpcport 600X --port 3000X --ipcpath /Users/data/go/bin/gethX.ipc console

【注1】上面的命令还不完备,但基本够能够满足我们的需求。
【注2】错误的命令行参数:

./geth --datadir "/Users/data/go/bin/geth-data0" --networkid 1314 --nodiscover --rpcport 6001 --port 30001 --ipcpath /Users/data/Library/Ethereum/geth1.ipc console

这个参数传进去,直接连到以太坊主网了。不要加./geth。

对应到本文,我们需要启动2个node,node1负责mining,node2负责同步。当然你可以两个node都mining。

我们node1的程序参数是:

 --datadir "/Users/data/go/bin/geth-data0" --networkid 1314 --nodiscover --rpcport 6001 --port 30001 --ipcpath /Users/data/go/bin/geth1.ipc console

我们node2的程序参数是:

--datadir "/Users/data/go/bin/geth-data1" --networkid 1314 --nodiscover --rpcport 6002 --port 30002 --ipcpath /Users/data/go/bin/geth2.ipc console

【注3】因为在一台机器上启多个进程,所以数据目录,rpc端口,以及udp端口都得不一样才行。

启动node1

点击工具栏中的运行三角图标。运行界面如下图:

Debug以太坊go-ethereum实战_第2张图片

接下来,我们创建账户,设置coinbase,开始挖矿。下面是要执行的一些命令:

> personal.newAccount("pwd")
//eth.coinbase 查看是否有coinbase,若存在,则不用在设置了。
> miner.setEtherbase(eth.accounts[0])
> admin.nodeInfo.enode    //保存下node1的网络ID

启动node2

点击工具栏的调试图标。

我们重新开一个终端,执行下面的命令,该命令会启动一个连到node2的交互式JS控制台,便于我们输命令:

$ ./geth attach ipc:/Users/data/go/bin/geth2.ipc

命令执行成功,会进入控制台,我们在其中输入下面的命令用于创建2个地址:

> personal.newAccount("pwd1")
> personal.newAccount("pwd2")

我们也可以重新开一个终端关联到node1。但这里我们直接在控制台上输入下面的命令,用于向node2的eth.accounts[0]中转10ETH:

personal.unlockAccount(eth.accounts[0]) //转账之前先解锁
eth.sendTransaction({from:eth.accounts[0],to:"0xa94d69aaa3f4ba948f10aef1c9e746b9b69685cf",value:web3.toWei(10,"ether")})

其中”0xa94d69aaa3f4ba948f10aef1c9e746b9b69685cf”为node2的eth.accounts[0]。

好,准备工作完备。

需求1

现在开始debug,如果我们想知道从node2的console上发送一条交易(从eth.accounts[0]转5ETH到eth.accounts[1]),背后都发生了什么,怎么办?

我们需要在/internal/ethapi/api.go的(s *PublicTransactionPoolAPI) SendTransaction方法上打上断点【注意:打上断点以后,直接debug你会发现程序并没有在断点出停。只有当你在控制台发送一条交易或者本地通过rpc发交易才会触发程序在断点处停掉】。

然后在控制台输入以下命令:

> personal.unlockAccount(eth.accounts[0]) //转账之前先解锁
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(10,"ether")})

回车过后,我们的代码就从Console跳到Debugger。下面是函数的调用堆栈:

Debug以太坊go-ethereum实战_第3张图片

【注3】如果我们不想单步调试,直接点击上图左侧的绿色小三角,继续运行程序直到下一个断点。

根据调用堆栈,这下我们就知道在控制台点击回车键之后,都发生了什么。下面的信息是node2的日志里面出现的,其实这条信息的背后还是有一些故事的。

INFO [07-18|18:45:15] Submitted transaction                    fullhash=0x21d1e3f8d0cc2eada9cbfd7113ea5d5543eb5bd82da4d54db16632afda6be9f6 recipient=0xeed9d944214aed8898c20888ed100adc306714fb

需求2

我们想知道node2同步node1时,都发生了什么?怎么办?

我们在/core/blockchain.go的(st *insertStats) report方法上添加断点【注意:打上断点还不够,需要事件去触发程序在断点处停掉】。

Debug以太坊go-ethereum实战_第4张图片

接着我们在关联node2的控制台上执行添加peer的命令:

admin.addPeer("enode://fc4eb108d62dc8d9fe1133557eafc106682c3652f5edb222342da9613befefdaeed22cf2883a1cba7ecb765abe92d753e18f73b72a3250e9e7788b4eca89c539@127.0.0.1:30001?discport=0")

回车后,我们就能看到node2的console将打印下面的日志信息,表明开始同步。

 INFO [07-18|18:58:37] Block synchronisation started 

但“同步”二字背后都经过了哪些逻辑呢?显然,我们刚刚打断点的地方是有参与的,否则程序不会走到那里停掉。
Debug以太坊go-ethereum实战_第5张图片

注意

重新启动Debug功能,需重新geth attach,有关geth的attach命令用法,可以参见以太坊实战-attach命令。

总结

上面对debug以太坊geth给出了初步的思路,掌握这些方法有利于我们洞悉以太坊geth的内部工作原理。调试过程辅以日志信息就可以相对清楚的了解geth背后的逻辑。

你可能感兴趣的:(Ethereum)