基于以太坊dpos实现

GitHub地址 https://github.com/TTCECO/gttc
基于以太坊go-ethereum的DPOS实现

一 构建以太坊

1 git clone https://github.com/TTCECO/gttc.git
  • 目录结构为~/github.com/TTCECO/gttc
2 在根目录make gttc(make all)

二.构建有多个节点的以太坊链

Before read this instruction, please make sure the gttc, bootnode 
and puppeth already compiled and installed correctly in your server.

1 在目录 gttc/build/bin下创建节点目录

$ mkdir node1 node2

2 生成超级节点账号

$ gttc --datadir node1/ account new
$ gttc --datadir node2/ account new
  • 输入密码后会显示生成的地址node1_address和node2_address

3 把账号信息写入文件来启动节点

$ echo 'node1_address' >> account.txt
$ echo 'node2_address' >> account.txt
$ echo 'password1' >> node1/password.txt
$ echo 'password2' >> node2/password.txt

4 通过puppeth来构建创世配置文件

$ puppeth

+-----------------------------------------------------------+
| Welcome to puppeth, your 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)
> devnet

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

INFO [06-04|12:33:34] Administering Ethereum network           name=devnet
WARN [06-04|12:33:34] No previous configurations found         path=/Users/tataufo/.puppeth/devnet

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 = alien)
 1. Ethash - proof-of-work
 2. Clique - proof-of-authority
 3. Alien  - delegated-proof-of-stake
> 3

How many seconds should blocks take? (default = 3)
> 4

How many blocks create for one epoch? (default = 30000)
> 30

What is the max number of signers? (default = 21)
> 3

What is the minimize balance for valid voter ? (default = 10000TTC)
> 100

How many minutes delay to create first block ? (default = 5 minutes)
> 5

Which accounts are vote by themselves to seal the block?(least one, those accounts will be auto pre-funded)
(The follow two address can be found in account.txt)
> 0xfa846876ef5ed3826e483303f42d987a66af8e15 
> 0x62739566c666df9a057d7e7c92898511d4e64c07
> 0x

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

Specify your chain/network ID if you want an explicit one (default = random)
>
INFO [06-04|12:35:27] 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
> 2

 1. Modify existing fork rules
 2. Export genesis configuration
 3. Remove genesis configuration
> 2

Which file to save the genesis into? (default = devnet.json)
> genesis.json
INFO [06-04|12:35:45] Exported existing 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

5 初始化节点数据

$ gttc --datadir node1/ init genesis.json
$ gttc --datadir node2/ init genesis.json

if old data in node folder, please remove them before initialize.

6 生成bootnode

$ bootnode -genkey boot.key

bootnode简化了Ethereum客户端实现,它只参与网络节点发现协议,但不运行任何高级应用程序协议。它可以用作轻量级的引导节点,以帮助在私有网络中找到对等点。
总而言之,就是一个用于节点发现或者说节点引导的轻量节点,方便联盟链的搭建~

7 运行bootnode

$ bootnode -nodekey boot.key -verbosity 9 -addr 127.0.0.1:30310

上面命令运行完,会打印类似下面的log

 enode://20940eac58b9e615706ea3c357c409aecbb44998d1388db49a8df61e727f92029019708b2ad69467f94eef9a49b5d4ffb2cc1e71bb06addeb134fe8bdbc62153@127.0.0.1:30310

encode后面的这么一长串东西,就是这个节点的ID信息,下面启动geth节点的时候要指定连接这个bootnode~

8 运行节点1和节点2

  • 下面命令中 unlock后面的地址为之前写入account.txt文件中的地址,以挖矿的形式启动
  • enode地址为上面第7步生成的encode。 (也可以不用第七步生成的encode节点地址作为下面的启动参数,后续直接将节点进行关联即可(第九步))
  • networkid 为genesis.json中的 ChinaId
$ gttc --datadir node1/ --syncmode 'full' --port 30311 --rpc --rpcaddr 'localhost' --rpcport 8501 --rpcapi 'personal,db,eth,net,web3,txpool,miner,alien,admin' --bootnodes 'enode://20940eac58b9e615706ea3c357c409aecbb44998d1388db49a8df61e727f92029019708b2ad69467f94eef9a49b5d4ffb2cc1e71bb06addeb134fe8bdbc62153@127.0.0.1:30310' --networkid 1014 --gasprice '1' -unlock 'fa846876ef5ed3826e483303f42d987a66af8e15' --password node1/password.txt --mine
后台启动方式:
nohup ./gwsc --datadir node1/ --syncmode 'full' --port 30311 --rpc --rpcaddr '127.0.0.1' --rpcport 8501 --rpcapi 'personal,db,eth,net,web3,txpool,miner,alien,admin' --networkid 1001 --gasprice '1' -unlock '6672c4a5d01751e92f86e5d0393feceb1513481b' --password node1/password.txt --mine >/dev/null 2>log & 
$ gttc --datadir node2/ --syncmode 'full' --port 30312 --rpc --rpcaddr 'localhost' --rpcport 8502 --rpcapi 'personal,db,eth,net,web3,txpool,miner,alien,admin' --bootnodes 'enode://20940eac58b9e615706ea3c357c409aecbb44998d1388db49a8df61e727f92029019708b2ad69467f94eef9a49b5d4ffb2cc1e71bb06addeb134fe8bdbc62153@127.0.0.1:30310' --networkid 1014 --gasprice '1' -unlock '62739566c666df9a057d7e7c92898511d4e64c07' --password node2/password.txt --mine
不用第七步生成的encode节点地址作为下面的启动参数
gttc --datadir node1/ --syncmode 'full' --port 30311 --rpc --rpcaddr 'localhost' --rpcport 8501 --rpcapi 'personal,db,eth,net,web3,txpool,miner,alien,admin' --networkid 1001 --gasprice '1' -unlock 'e363576de44cc5ca22fd96b49daa0724a3d4f6e4' --password node1/password.txt --mine

9 节点互联
1 进入geth JavaScript控制台

 ./gttc attach rpc:http://127.0.0.1:8501
 ./gttc attach rpc:http://127.0.0.1:8502

2 查看节点是否互联

admin.peers
[]

返回数据为[] 说明节点之间没有互相发现。
3 设置节点互联

admin.nodeInfo

记录下enode

"enode://7f2f1a5818b4bb7e756036ab08834386534807bbf5c5a305ddcbefa1ff9ea99028feb00cb78322ac39340501d5b7c6147e169aadbb028daf20f8d73dbdfea98e@[::]:30311"
"enode://6ab4f74058b9c1e43d2d0c6f55f538ea7f2f366dd9f8f560024f14603333f017d3404b9c9711538289fa76504fecf33cf0e36cce7b0414604f673abe93012413@[::]:30312"

4 进入node1 geth控制台

#添加节点2的监视器
admin.addPeer("enode://7f2f1a5818b4bb7e756036ab08834386534807bbf5c5a305ddcbefa1ff9ea99028feb00cb78322ac39340501d5b7c6147e169aadbb028daf20f8d73dbdfea98e@[::]:30311")

addPeer的时候注意如果节点不是在同一台服务器上,需要把@后面[::]换成当前节点所在机器的ip地址。

  • 进入node2 geth控制台 添加节点1的监视器

三 进行投票

投票操作也属于一笔交易,是从投票人给候选者进行投票。投票人的金额必须大于投票最小金额,否则投票无效。参数为:genesis.json中的minVoterBalance

  • ufo : prefix of custom data
  • 1 : custom info version
  • event : category of info (event, oplog …)
  • vote : vote event

The sample vote in console is like this

personal.sendTransaction({from:"t07544bf9c90d175da395b8d08fcaf34da0a3e0688",to:"t0aafeaaf6111762fea733ff7b4c8b59ac69316385",value:0,data:web3.toHex("ufo:1:event:vote")})

从A地址向B地址转移数量为0的代币,代表A投*票给B地址,而票数的计算则是A地址当前拥有货币的数量。

四 生成新的超级节点地址进行挖矿(方式跟node1和node2类似)

1 创建超级节点账户

./gttc --datadir super_node/ account new
  • 输入密码后会显示生成的地址暂且把地址记为:super_node_address

2 把密码写入super_node文件下

$ echo 'password' >> super_node/password.txt

3 初始化超级节点

$ gttc --datadir super_node/ init genesis.json

4 Run bootnode

$ bootnode -nodekey boot.key -verbosity 9 -addr 127.0.0.1:30310
  • boot.key使用之前运行node1生成的就可以了

5 运行超级节点进行挖矿(同理也可以不用第4步生成的encode地址参数)

$ gttc --datadir super_node/ --syncmode 'full' --port 30313 --rpc --rpcaddr 'localhost' --rpcport 8503 --rpcapi 'personal,db,eth,net,web3,txpool,miner,net' --bootnodes 'enode://20940eac58b9e615706ea3c357c409aecbb44998d1388db49a8df61e727f92029019708b2ad69467f94eef9a49b5d4ffb2cc1e71bb06addeb134fe8bdbc62153@127.0.0.1:30310' --networkid 1014 --gasprice '1' -unlock '62739566c666df9a057d7e7c92898511d4e64c07' --password super_node/password.txt --mine

6 节点互联

  • 进入node1的geth控制台 添加super_node的监视器(addPeer) 。node2 同理
  • 进入super_node的geth控制台 添加node1和node2的监视器。进行节点之间互联。
  • 超级节点地址需要有人投票并且成为有效见证人后才能挖矿。
    用户投票是有最小投票金额限制的,否则无效。
    参数为:genesis.json中的minVoterBalance

参数:

 alien.getSnapshotAtNumber(48)
  {
    confirmedNumber: 44,
    confirms: {
      41: ["t08feba63259ef7e79da13246dc20ff79fe446a478", "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1", "t07c352585cd7549bfbc0a7e88bf820fa574174598"],
      42: ["t07c352585cd7549bfbc0a7e88bf820fa574174598", "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1", "t08feba63259ef7e79da13246dc20ff79fe446a478"],
      43: ["t0cc9c08721c7d8a792e238e80f6c20cb066e919a1", "t07c352585cd7549bfbc0a7e88bf820fa574174598", "t08feba63259ef7e79da13246dc20ff79fe446a478"],
      44: ["t07c352585cd7549bfbc0a7e88bf820fa574174598", "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1", "t08feba63259ef7e79da13246dc20ff79fe446a478"],
      45: ["t08feba63259ef7e79da13246dc20ff79fe446a478", "t07c352585cd7549bfbc0a7e88bf820fa574174598", "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1"],
      46: ["t08feba63259ef7e79da13246dc20ff79fe446a478", "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1", "t07c352585cd7549bfbc0a7e88bf820fa574174598"]
    },
    hash: "t027009a5d7480cb2802e45b9d0ef2547ce7ad5e720d9281b0d628f314998a6416",
    headerTime: 1533341653,
    historyHash: ["t0fb741ff569db0a9277111285d157a0412c4dc6e30509834e7e87ce84755db336", "t0855589fcf6fb8157b29df69cba0393737a1c15a7427666f5e84b34c8a5680523", "t07b37e235e0686c8defaa0068b0508fe55921bd5e27bf0f1ee3e6909184dc74f4", "t0664bb4e6889acfd8bd4c277ba109cd9fbaf1366ce8472761b050451c01cf1a04", "t0d3d64b715e8568be7d86a82dbfd9a801013132d4229d96963f3869b584426f7a", "t068a1241b27c209ab584155a670a0473f29ae302eb2fe47d1a75b1eea45898ab2", "t04c8e6e969c950810c2acf128866f2aa416dc56b1ef2987281de4812622ebb44f", "t03c7047ba4574bf1e49c9e068d82e1b2c3f59e958658d897f4836db23f6ffcc3c", "t0c05b07cb1c00be507742bd9de8702a42d8cf77f43c566f52196f5b0bc47d084c", "t0d1f96774a2feb4c21add4aeb14ac0d92d5357b1cdc53cead0ed9df459ce308ac", "t0c95bd9b4fd9f9d4ca5a38d2433f6f9d6f48027098316d8b9d95fa1436639338d", "t0300addbe720652487d69c62b37d7281298200b2c7c68170a24dad8503c73940e", "t06ede482139d9a8f5a7bc385b16c5d3c59ad11715091ad1609aa451f605fcc633", "t027009a5d7480cb2802e45b9d0ef2547ce7ad5e720d9281b0d628f314998a6416"],
    loopStartTime: 1533341639,
    number: 48,
    period: 4,
    punished: {
      t07c352585cd7549bfbc0a7e88bf820fa574174598: 880,
      t08feba63259ef7e79da13246dc20ff79fe446a478: 950,
      t0cc9c08721c7d8a792e238e80f6c20cb066e919a1: 1370
    },
    signers: ["t07c352585cd7549bfbc0a7e88bf820fa574174598", "t08feba63259ef7e79da13246dc20ff79fe446a478", "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1", "t07c352585cd7549bfbc0a7e88bf820fa574174598", "t08feba63259ef7e79da13246dc20ff79fe446a478", "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1", "t07c352585cd7549bfbc0a7e88bf820fa574174598"],
    tally: {
      t07c352585cd7549bfbc0a7e88bf820fa574174598: 9.046256971665328e+74,
      t08feba63259ef7e79da13246dc20ff79fe446a478: 9.046256971665328e+74,
      t0cc9c08721c7d8a792e238e80f6c20cb066e919a1: 9.046256971665328e+74
    },
    voters: {
      t07c352585cd7549bfbc0a7e88bf820fa574174598: 0,
      t08feba63259ef7e79da13246dc20ff79fe446a478: 0,
      t0cc9c08721c7d8a792e238e80f6c20cb066e919a1: 0
    },
    votes: {
      t07c352585cd7549bfbc0a7e88bf820fa574174598: {
        Candidate: "t07c352585cd7549bfbc0a7e88bf820fa574174598",
        Stake: 9.046256971665328e+74,
        Voter: "t07c352585cd7549bfbc0a7e88bf820fa574174598"
      },
      t08feba63259ef7e79da13246dc20ff79fe446a478: {
        Candidate: "t08feba63259ef7e79da13246dc20ff79fe446a478",
        Stake: 9.046256971665328e+74,
        Voter: "t08feba63259ef7e79da13246dc20ff79fe446a478"
      },
      t0cc9c08721c7d8a792e238e80f6c20cb066e919a1: {
        Candidate: "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1",
        Stake: 9.046256971665328e+74,
        Voter: "t0cc9c08721c7d8a792e238e80f6c20cb066e919a1"
      }
    }
  }

  • signers : Signers queue in current loop (每一轮的超级节点队列)
  • loopStartTime: Start Time of the current loop, used to calculate the right miner(signer) by time(每一轮的开始时间)
  • 重新选取超级节点时间:当出块数=节点数*轮数时,会重重选一次超级节点。
    轮数参数:consensus/alien/alien.go文件中的defauleLoopCntRecalculateSigners = 10(默认为10轮)
  • period: 4 每4秒出一个块

> 投票规则: 假如超级节点为3个。则每出30个块(10轮)signers中的节点会重新选取3个超级节点。每出三个块(一轮12秒),loopStartTime会变一次,同时signers的顺序也会变一次。但是不换出块节点,只有当出了30个块则更换节点

> 超级节点挖矿的收益
go-ethereum consensus/alien/alien.go中方法accumulateRewards

主要代码如下:
	secondsPerYear     = 365 * 24 * 3600
	//config.Alien.Period:为多少秒出一次块
	blockNumPerYear := secondsPerYear / config.Alien.Period
	initSignerBlockReward := new(big.Int).Div(totalBlockReward, big.NewInt(int64(2*blockNumPerYear)))
	yearCount := header.Number.Uint64() / blockNumPerYear
	//根据块数计算当前年数  再进行右位移运算  得到当前挖出一块的总收益
	blockReward := new(big.Int).Rsh(initSignerBlockReward, uint(yearCount))

	minerReward := new(big.Int).Set(blockReward)
	minerReward.Mul(minerReward, new(big.Int).SetUint64(snap.MinerReward))
	//minerReward为挖矿人的收益。
	minerReward.Div(minerReward, big.NewInt(1000)) // cause the reward is calculate by cnt per thousand
	//votersReward 投票人获得的返佣收益(投票人平分)
	votersReward := blockReward.Sub(blockReward, minerReward)

blockReward = minerReward + votersReward。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值