上一篇说到在外网服务器上安装好了btcd和btcwallet,且编译了btcd和btcwallet的相关组件,现在我们运行比特币节点所需要的软件已经安装好了,接下来就是使用和运行了。
由于Btcd网上的资料不多,和以太坊相比简直差远了,Bitcoin的资料也不多,但至少比Btcd还是要完善的,文档也还齐全,Btcd有一些细节功能甚至还没开发完全。所以当初倒腾这个启动和交互式环境确实花了较多时间。看了很多国外的博客,也和他们有过一些交流,但很多东西自己运行起来就不是那么回事,总是踩了很多坑,以前弄以太坊私链的时候一个下午就全部搞定了,这个btcd足足弄了我一天半。
本文我会介绍btcd在simnet即模拟环境下的启动和运行方法,其中包括钱包的使用和btcctl交互式rpc命令的使用。最后我会简单介绍一下simnet环境下多节点的连接。
这里我简单介绍一下btcd的四种运行模式,分别有Mainnet,Regression,Testnet和Simnet四种
先给出源码中参数设置部分的代码
Mainnet就是比特币主网,连入这个网就是正儿八经地玩比特币了,你可能需要同步主网区块,维护区块链信息,然后在主网挖矿等等。我们仅做测试和实验,故不选择连入主网。
Testnet是一个公开的测试网,所有开发者都可以访问这个网络。为了避免有人恶意囤积上面的Testnet bitcoin,这个testnet每隔一段时期就会清空并以新的创始块重新开始。任何打算在比特币主干网上用于生产的软件开发都应该首先在testnet上用测试币进行测试。这样可以保护开发人员免受由于软件错误而导致的金钱损失,也可以保护网络免受由于软件错误导致的意外攻击。
Regression代表“回归测试”,允许用户创建本地区块链以进行测试。 与testnet3(它是一个公共和共享的测试区块链)不同,Regressiont区块链旨在作为本地测试的封闭系统运行。 用户从头开始启动regtest区块链,创建一个本地的创世区块。 可以将其他节点添加到网络中,或者使用单个节点运行它来测试Bitcoin Core软件
至于Simnet,也是本地测试的一种网络,源码中它的配置参数和Regression还是有一些不同的,比如端口号,和一些分叉的参数,细节我也没有深入挖掘,大家可以去源码看一看不同的参数是不是影响你的需求。
我把Regression和Simnet配置的细节放在下面以便对比
var RegressionNetParams = Params{
Name: "regtest",
Net: wire.TestNet,
DefaultPort: "18444",
DNSSeeds: []DNSSeed{},
// Chain parameters
GenesisBlock: ®TestGenesisBlock,
GenesisHash: ®TestGenesisHash,
PowLimit: regressionPowLimit,
PowLimitBits: 0x207fffff,
CoinbaseMaturity: 100,
BIP0034Height: 100000000, // Not active - Permit ver 1 blocks
BIP0065Height: 1351, // Used by regression tests
BIP0066Height: 1251, // Used by regression tests
SubsidyReductionInterval: 150,
TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
ReduceMinDifficulty: true,
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
GenerateSupported: true,
// Checkpoints ordered from oldest to newest.
Checkpoints: nil,
// Consensus rule change deployments.
//
// The miner confirmation window is defined as:
// target proof of work timespan / target proof of work spacing
RuleChangeActivationThreshold: 108, // 75% of MinerConfirmationWindow
MinerConfirmationWindow: 144,
Deployments: [DefinedDeployments]ConsensusDeployment{
DeploymentTestDummy: {
BitNumber: 28,
StartTime: 0, // Always available for vote
ExpireTime: math.MaxInt64, // Never expires
},
DeploymentCSV: {
BitNumber: 0,
StartTime: 0, // Always available for vote
ExpireTime: math.MaxInt64, // Never expires
},
DeploymentSegwit: {
BitNumber: 1,
StartTime: 0, // Always available for vote
ExpireTime: math.MaxInt64, // Never expires.
},
},
// Mempool parameters
RelayNonStdTxs: true,
// Human-readable part for Bech32 encoded segwit addresses, as defined in
// BIP 173.
Bech32HRPSegwit: "bcrt", // always bcrt for reg test net
// Address encoding magics
PubKeyHashAddrID: 0x6f, // starts with m or n
ScriptHashAddrID: 0xc4, // starts with 2
PrivateKeyID: 0xef, // starts with 9 (uncompressed) or c (compressed)
// BIP32 hierarchical deterministic extended key magics
HDPrivateKeyID: [4]byte{0x04, 0x35, 0x83, 0x94}, // starts with tprv
HDPublicKeyID: [4]byte{0x04, 0x35, 0x87, 0xcf}, // starts with tpub
// BIP44 coin type used in the hierarchical deterministic path for
// address generation.
HDCoinType: 1,
}
var SimNetParams = Params{
Name: "simnet",
Net: wire.SimNet,
DefaultPort: "18555",
DNSSeeds: []DNSSeed{}, // NOTE: There must NOT be any seeds.
// Chain parameters
GenesisBlock: &simNetGenesisBlock,
GenesisHash: &simNetGenesisHash,
PowLimit: simNetPowLimit,
PowLimitBits: 0x207fffff,
BIP0034Height: 0, // Always active on simnet
BIP0065Height: 0, // Always active on simnet
BIP0066Height: 0, // Always active on simnet
CoinbaseMaturity: 100,
SubsidyReductionInterval: 210000,
TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
ReduceMinDifficulty: true,
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
GenerateSupported: true,
// Checkpoints ordered from oldest to newest.
Checkpoints: nil,
// Consensus rule change deployments.
//
// The miner confirmation window is defined as:
// target proof of work timespan / target proof of work spacing
RuleChangeActivationThreshold: 75, // 75% of MinerConfirmationWindow
MinerConfirmationWindow: 100,
Deployments: [DefinedDeployments]ConsensusDeployment{
DeploymentTestDummy: {
BitNumber: 28,
StartTime: 0, // Always available for vote
ExpireTime: math.MaxInt64, // Never expires
},
DeploymentCSV: {
BitNumber: 0,
StartTime: 0, // Always available for vote
ExpireTime: math.MaxInt64, // Never expires
},
DeploymentSegwit: {
BitNumber: 1,
StartTime: 0, // Always available for vote
ExpireTime: math.MaxInt64, // Never expires.
},
},
// Mempool parameters
RelayNonStdTxs: true,
// Human-readable part for Bech32 encoded segwit addresses, as defined in
// BIP 173.
Bech32HRPSegwit: "sb", // always sb for sim net
// Address encoding magics
PubKeyHashAddrID: 0x3f, // starts with S
ScriptHashAddrID: 0x7b, // starts with s
PrivateKeyID: 0x64, // starts with 4 (uncompressed) or F (compressed)
WitnessPubKeyHashAddrID: 0x19, // starts with Gg
WitnessScriptHashAddrID: 0x28, // starts with ?
// BIP32 hierarchical deterministic extended key magics
HDPrivateKeyID: [4]byte{0x04, 0x20, 0xb9, 0x00}, // starts with sprv
HDPublicKeyID: [4]byte{0x04, 0x20, 0xbd, 0x3a}, // starts with spub
// BIP44 coin type used in the hierarchical deterministic path for
// address generation.
HDCoinType: 115, // ASCII for s
}
首先,模拟环境下也是需要一个钱包的,钱包里面可以有多个本地的账户,一个账户也可以有多个地址
btcwallet --simnet --create
创建一个simnet模式下的钱包
运行如下:
要求输入private passphrase,这个passphrase一定要记住,后续解锁钱包的时候需要用到
后面问你是不是需要多一层的加密或者是否有本地钱包种子可以加载,我们第一次启动,这些都不需要指定
钱包生成之后,~/.btcwallet文件夹下面就有logs和simnnet文件夹了
生成钱包之后,准备工作就算全部完成了,我们来启动btcd服务
btcd --simnet --rpcuser=rpcuser --rpcpass=rpcpass --rpclisten=0.0.0.0:18556 --listen=0.0.0.0:18555
命令解释如下:
然后我们需要再打开一个窗口,上面的btcd命令让它在原来的窗口进行运行
运行指令
btcwallet --simnet --username=rpcuser --password=rpcpass
命令解释如下:
上面两步运行情况如下
上面是btcwallet的运行窗口,下面是btcd运行窗口。
因为我之前调试代码的时候加了一些输出,所以下面的窗口可能有一些输出和你不一样。
可以看到当btcwallet打开之后,btcd会显示 New websocket client 127.0.0.1:50754 这就是钱包客户端的socket接入
到这里 btcd和btcwallet开启了之后,服务就算启动完了。接下来我们需要再打开一个窗口,使用btcctl命令操作区块链,注意,btcd和btcwallet的窗口别关,所以,完整操作一共需要开三个窗口。btcd和btcwallet一般是不需要动的,我们在btcctl的窗口进行交互即可。
我这里截一个屏幕,后续讲解命令的时候就不截图了
接下来的操作都是一些常用的操作,后面我会写一篇博客把btcctl常用的命令进行简单叙述
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet listaccounts
命令解释如下:
默认情况下里面只有两个账户default和imported
为了后面转账功能更加便于观察,我们创建一个账户
创建账户之前,需要先对钱包解锁,这里用到walletpassphrase即前面建立钱包的时候输入的passphrase。我这里是"hht"
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet walletpassphrase "hht" 600
解锁命令后面跟着一个数字,意思是解锁多久,单位是秒,600s即解锁十分钟
解锁命令输入完成之后,可以在btcwallet界面看到消息 “The wallet has been temporarily unlocked”
解锁之后,即可创建账户了
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet createnewaccount kingsley
这里通过createnewaccount建立一个账户kingsley。
我的服务器运行这步命令之后,btcctl界面会卡死。我当时卡在这好久好久,找卡死的解决办法。但是,后来偶然发现,只需要将钱包ctrl+c关闭一下(btcctl也就被停了),再重启一下钱包,就发现kingsley账户已经创建好了。
也许你不会遇到和我一样的问题,因为这个问题我在网上找了很久都没有找到解决办法,也许是wallet的bug吧。如果你知道原因也欢迎在评论留下您的观点,谢谢。
此时再listaccounts可以看到有三个用户了:default、imported、kingsley
钱包里面有账户是不够的,比特币之间转账都是基于地址来进行,所以我们要使用后续功能,必须给账户分配一个地址。账户可以有多个地址。
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet getaddressesbyaccount default
可以看到default账户和kingsley账户都是没有地址的,接下来给他们生成地址
用getnewaddress命令给default分配一个地址
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet getnewaddress default
和创建账户一样,我的服务器运行这步命令之后,btcctl界面会卡死。解决办法也是一样的,只需要将钱包ctrl+c关闭一下(btcctl也就被停了),再重启一下钱包就可以了。
用getnewaddress命令给kingsley分配一个地址
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet getnewaddress kingsley
通过getaddressesbyaccount命令看default和kingsley下的地址
上面 -4: the client has been shutdown就是我将btcwallet杀死之后btcctl的回显,可以看到default和kingsley已经分配好了地址
现在我们在本地创建好了两个账户,每个账户下都有地址了。我们就可以做一些和区块链有关的操作了。
现在区块链上只有一个btcd启动时初始化的创世区块。我们来手动生成一些区块。
在挖矿之前,需要重启btcd,并给btcd指定一个矿工地址,这样后面挖出来的区块奖励就会给这个地址的账户了
重启btcd,指定矿工地址,随意指定,我就用上面的default的地址 SX5uJ3YGgYBQ7iCkjWmZ4hGvsTuE7PvJgk
btcd --simnet --rpcuser=rpcuser --rpcpass=rpcpass --rpclisten=0.0.0.0:18556 --listen=0.0.0.0:18555 --miningaddr=SX5uJ3YGgYBQ7iCkjWmZ4hGvsTuE7PvJgk --txindex
命令解释如下
重新打开btcwallet
btcwallet --simnet --username=rpcuser --password=rpcpass
通过generate命令手动生成区块
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass generate 300
该指令可以在区块链中手动生成300个区块,由于全网没有交易数据,所以这些生成的区块都只有一个coinbase交易。
指令运行成功之后可以看到btcd和btcwallet和btcctl三个窗口都有回显,表示已经生成了区块
此时再用listaccounts命令即可以看到刚刚挖出区块的奖励已经进入矿工地址了
这里注意,如果生成的区块量很少的话,可能矿工账户里会没有钱。这大概类似以太坊gas的存在类似吧。具体原因我也没有深究,如有知道的朋友欢迎留言交流。
这里再提一点,关于这个generate手动生成区块。有人会问不能让他自动进行挖矿嘛。
这是可以的,但是在源码里面做了一个约束,必须还要有另外一个节点连到本btcd客户端,才会进行自动挖矿,并且想要自动挖矿,必须更改源代码config.go中的defaultGenerate参数,将其从默认的false改为true。这样当有另外一个节点连接进来时,就会自动执行挖矿。同理,在我们的测试网络,暂时还没有交易数据,不管是手动挖的区块还是自动挖的区块,都只有coinbase交易。
并且,当把defaultGenerate参数改为true的时候
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet setgenerate 0
才行我们的default账户现在已经有很多比特币了,我们可以尝试进行转账。此处使用命令sendtoaddress命令,这个命令默认是从default账户下转账出去的。也有从指定账户转到指定账户的命令,不过我没怎么用过
转账之前必须先对账户进行解锁
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet walletpassphrase "hht" 600
从default账户转账100比特币给kingsley账户
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass --wallet sendtoaddress SYaDYKqmywEGNUvVtCdnCdD2GpvSAWYBmn 100
这里可能会出现错误 -32603:insufficient funds available to construct transaction
原因就是没有足够的funds,如果我们遇到这个问题,多generate一点区块多拿一点钱就可以了。
可以看到转账成功之后 会把这条交易的hash显示出来。
现在我们listaccounts是看不到kingsley收到了钱的,因为这条交易虽然已经验证,但还没有被写入区块链,所以我们需要手动生成一个块来将这条命令包含进区块链
btcctl --simnet --rpcuser=rpcuser --rpcpass=rpcpass generate 1
当有新的区块生成后,刚刚的那条交易就写入了区块链,这是listaccounts就可以看到Kingsley账户下已经有刚刚转来的100比特币了。
上述描述的是只有本地一个btcd客户端和一个btcwallet客户端的环境,称作机器A。在simnet环境下,可以有任意个节点进行相连组成p2p网络。
在本文的最后,我简单介绍一下,其他节点怎么连入该测试网络。
我们开启另一台服务器,称作机器B,配置好同A一样的btcd和btcwallet等软件。
A机器按照上述方法进行启动,不需要作更改。
B机器如果想要练到A机器所在的网络,如下操作
启动btcd客户端
btcd --simnet -u rpcuser -P rpcpass --rpclisten=0.0.0.0:18556 --listen=0.0.0.0:18555 --simnet --connect=X.X.X.X --miningaddr=XXXXXX
可以看到和之前启动Btcd命令一样,只需要多加一个connect参数,指定A机器的IP地址就好了,这个miningaddr同理也是B机器挖矿成功后的矿工地址,这里指定一个A机器default地址也是可以的,那B挖出来钱就给A中的defaulta吧。
我这么解释应该很清楚了
启动btcwallet客户端
这里就和A机器完全一样了,因为btcwallet操作的是本地的钱包账户。所以正常启动就好。
当B机器加入之后,可以在A机器btcd窗口看到有新节点加入,这样两个节点就连在一起了。一笔跨机器的转账也可以正常进行。
通过此方法可以连入无数个节点。方法类似,这里就不再赘述
下篇博客我会介绍一下btcctl常用的命令,当然不一定常用,只不过是我实验经常用的到的命令。