运行环境

测试环境
OS: Ubuntu 18.04
Go: go1.15.6 linux/amd64

源代码

git clone https://github.com/HuobiGroup/huobi-eco-chain.git

当前测试 master 分支

编译

cd huobi-eco-chain/
make geth

编译完成后,生成文件在./build/bin/geth

创建 geth.toml

参考 https://github.com/HuobiGroup/huobi-eco-chain-docs/blob/master/dev/deploy.md

[Eth]
SyncMode = "fast"
DiscoveryURLs = []
TrieCleanCacheRejournal= 300000000000

[Eth.Miner]
GasFloor = 8000000
GasCeil = 8000000
GasPrice = 0
Recommit = 3000000000
Noverify = false

[Eth.Ethash]
CacheDir = "ethash"
CachesInMem = 2
CachesOnDisk = 3
CachesLockMmap = false
DatasetDir = "/data/heco/data/.ethash"
DatasetsInMem = 1
DatasetsOnDisk = 2
DatasetsLockMmap = false
PowMode = 0

[Eth.TxPool]
Locals = []
NoLocals = false
Journal = "transactions.rlp"
Rejournal = 3600000000000
PriceLimit = 1
PriceBump = 10
AccountSlots = 16
GlobalSlots = 4096
AccountQueue = 64
GlobalQueue = 1024
Lifetime = 10800000000000

[Node]
DataDir = "/data/heco/data"
InsecureUnlockAllowed = true
NoUSB = true
IPCPath = "geth.ipc"
HTTPHost = "0.0.0.0"
HTTPPort = 8545
HTTPCors = ["*"]
HTTPVirtualHosts = ["*"]
HTTPModules = ['eth', 'net', 'web3']

WSHost = "0.0.0.0"
WSPort = 8546
WSModules = ['eth', 'net', 'web3']

GraphQLVirtualHosts = ["localhost"]


[Node.P2P]
MaxPeers = 50
NoDiscovery = false

ListenAddr = ":32668"
EnableMsgEvents = false

[Node.HTTPTimeouts]
ReadTimeout = 30000000000
WriteTimeout = 30000000000
IdleTimeout = 120000000000

预先创建一个账户地址

使用MetaMask或者其他工具预先创建一个账户地址,并保存好私钥,后面这个地址会配置在初始的Validators中,并用做boot节点启动挖矿coinbase地址

创建genesis.json

参考https://docs.hecochain.com/#/genesis
根据需要修改特定的字段,常规的比如

  • chainId 修改为自己的独有链id
  • extraData 修改为预先创建的地址
  • alloc中的0xdaf88b74fca1246c6144bc846aaa3441ed095191修改为初始资金接收地址,balance根据业务需要,计算相应预先发行数量(精度18位)的16进制

对于共识参数,根据需要再做修改吧

"congress": {
    "period": 3, // 出块间隔(秒)
    "epoch": 200 // 出块顺序刷新间隔(块数)
}

初始化并启动geth

将上面修改好的geth.tomlgenesis.json放到规划好的位置,我们此时假设为/data/heco

初始化geth

在上面目录/data/heco中执行数据初始化

./geth --datadir ./data init genesis.json

我们将链相关数据保存在/data/heco/data下,方便磁盘数据管理,以及后期磁盘空间升级及其迁移

首次启动geth

./geth --config geth.toml --nodiscover

启动后,进入ipc导入我们预先生成的地址私钥,作为此节点的coinbase
从另一个终端进入

./geth attach ipc:/data/heco/data/geth.ipc

在geth命令行中导入预先生成地址的私钥,123456为钱包密码,在此目录创建password文件,并将密码保存在该文件,后面后台启动会需要

personal.importRawKey("e9bc9ae610535514。。。56a272f69fd59d7986b9f4f49c025cc","123456")

并设置该地址为无限期解锁,因为后面需要使用该私钥进行出块签名。0为无限期

personal.unlockAccount("0x48F155527f2。。。7e84692AA0025C0","123456",0)

此时geth命令行中输入eth,查看

> eth
{
  accounts: ["0x48F155527f2。。。7e84692AA0025C0"],
  blockNumber: 4412,
  coinbase: "0x48F155527f2。。。7e84692AA0025C0",

accountscoinbase都为预先生成的地址

后台运行geth

此时关闭前面运行的geth,重新后台运行

nohup ./geth --config geth.toml --networkid 65525 --unlock "0x48F155527f2。。。7e84692AA0025C0" --password ./password --mine --nodiscover --etherbase 0 2>> ./geth.log &

此时查看geth.log文件

tail -f geth.log

即可看到geth 已经正常单节点出块

测试查询

查看前面预先设置的初始资金接收地址

eth.getBalance("0x48F155527。。。。692AA0025C0")

可查看到,该地址已经存入了balance设置对应的代币

测试转账

eth.sendTransaction({from: "0x48F155527f25EB1。。。。4692AA0025C0" , to: "0x5849cce8b6ea2。。。。7436b628df34217", value: web3.toWei(10,"ether")})

执行完,查看from和to双方账户资金转移正常

MetaMask扩展配置

Chrome浏览器安装好扩展后,进入设置->网络->添加网络,输入相关信息

  • 网络名称 -> 任意信息,只是本地备注
  • 新增 RPC URL -> 该geth运行所在服务器访问地址+端口(端口是上面geth.toml配置的Node->HTTPPort)
  • 链ID -> 上面genesis.json中配置的chainId
  • 符号(选填)-> 该节点的系统代币的符号
  • 屏蔽管理器 URL(选填)-> 汉化翻译不准确,其实就是区块浏览器的地址,后期可以自己拿Etherscan自己部署一套

此时就可以通过MetaMask扩展进行地址代币管理了

多节点部署

如果只是本地测试,单点足以满足需求的话,可以不必继续部署
在其他需要部署节点的服务器上准备好geth节点程序以及上面同样的geth.toml和genesis.json文件,(同一机器多个geth运行实例,修改对应端口和data目录,流程同理)
然后照搬上面的流程的初始化并启动geth后台运行geth
执行完成后会报

WARN [02-24|15:35:05.457] Block sealing failed                     err="unauthorized validator"

是因为此节点的coinbase并不在初始的Validators中,先忽略,等下后面跟进合约动态添加到Validators

数据链接

由于节点启动时关闭了自发现,所以需要我们主动去连接下
两边节点分别查下节点信息

admin.nodeInfo

将enode存下来,将ip地址127.0.0.1修改为当前节点对应的可其他节点访问的地址
节点A

enode://219a81569be3b9f3e261f40e0edbf4893ccde5bc94df6525135eacc337122ef060bad7f220d90622349ab189b87106f26637520f272e5ae73f9797cd6506ddd4@172.17.116.158:32668?discport=0

节点B

enode://425ef46887ac2cb08076bc78e54ba11fb280c9cb2ff6a7bc173001933cfcd2b98b9f49afa3ac3857cc5e49ad01e64595a07c8c2053416390459409da7920a1c9@172.17.116.159:32668?discport=0

然后分别再对方节点上增加自己的节点
节点A执行

admin.addPeer("enode://425ef46887ac2cb08076bc78e54ba11fb280c9cb2ff6a7bc173001933cfcd2b98b9f49afa3ac3857cc5e49ad01e64595a07c8c2053416390459409da7920a1c9@172.17.116.159:32668?discport=0")

节点B执行

admin.addPeer("enode://219a81569be3b9f3e261f40e0edbf4893ccde5bc94df6525135eacc337122ef060bad7f220d90622349ab189b87106f26637520f272e5ae73f9797cd6506ddd4@172.17.116.158:32668?discport=0")

此时A节点正常出块,B节点正常从A节点同步区块,其他节点同理加入

编译合约

修改solc的依赖版本

 // Configure your compilers
  compilers: {
    solc: {
      version: "^0.6.1", // 修改为该版本以上,不然会报找不到对应的版本,此时会下载0.6.12版本

编译合约

truffle compile

此时会在./build/contracts下生成各个合约对应的abi json文件
其中的"abi"节点的内容,就是下面myetherwallet要用到的abi

合约设置

经过上面的操作,多节点网络已经运行了,下一步进行系统合约设置
以下合约操作通过https://www.myetherwallet.com/interface/interact-with-contract 工具进行交互

申请成为出块节点

选择执行createProposal
参数

  • dst 需要申请添加的地址
  • details 附加信息(选填)

对于genesis的预设地址,默认会在系统初始化时,自动添加到审核通过

审核出块申请

选择执行voteProposal,当前设计,合约签名地址需要为已经通过申请的用户,赞同总数或者拒绝总数,哪个先超过当前正在出块人数的 1/2+1,就执行对应的决定。这个不合理,应该是需要正在出块人中的1/2+1赞同才有效,那些之前通过审核,但不是正在出块的地址,没有审核资格。
参数

取消出块资质

选择执行setUnpassed,目前合约需要当前合约权限才能禁止掉其他人,不合理,后面进行合约修改,同样需要发起申请,通过1/2+1人通过,才会取消对应地址的资格。

创建validator地址

选择执行createOrEditValidator,需要先申请,通过后才允许创建
参数

  • feeAddr 该矿工领取奖励时的接收地址
  • moniker 昵称(选填)
  • identity 身份(选填)
  • website 网址(选填)
  • email 邮箱(选填)
  • details 附加信息(选填)

抵押系统代币

选择执行stake,需要创建完validator,才能进行抵押,抵押量不小于32 ether,后面挖矿奖励会根据当前用户抵押量所占总比例进行分配。

矿工主动提交所得,进行分配

链程序出块后,自动执行distributeBlockReward将打包所得手续费转到合约进行池分配(后期排查,节点程序是否可作恶,抽水),代币总量到合约后,合约根据currentValidatorSet中各自地址抵押总额,以及各自占比进行分配记账(validatorInfo[地址].hbIncoming),(对于合约分配逻辑,后面单独写文章讲解)

领取出块奖励

选择执行 withdrawProfits,参数validator为矿工地址,执行签名地址需要与创建时设置的feeAddr一致,领取时间间隔24小时(28800块)

参考

https://github.com/sigp/lighthouse/issues/2115