Commit 2cb03695 authored by 张振华's avatar 张振华

update

parent 0ef31ffb
......@@ -17,6 +17,7 @@ import (
"sync/atomic"
"time"
"github.com/33cn/chain33/common/crypto"
dpostype "github.com/33cn/plugin/plugin/consensus/dpos/types"
ttypes "github.com/33cn/plugin/plugin/consensus/dpos/types"
dty "github.com/33cn/plugin/plugin/dapp/dposvote/types"
......@@ -30,6 +31,9 @@ const (
continueToVote = 0
voteSuccess = 1
voteFail = 2
VrfQueryTypeM = 0
VrfQueryTypeRP = 1
)
// Errors define
......@@ -55,11 +59,15 @@ func (ti *timeoutInfo) String() string {
return fmt.Sprintf("%v", ti.Duration)
}
/*
type vrfStatusInfo struct {
Cycle int64
VrfStatus int64 //0:初始状态,1:未注册M状态,2:已发起M注册状态,3:已注册M状态,4:已发起RP注册状态,5:已注册RP状态,6:已过cycle一半但未发起M注册,7.cycle周期已过,未注册RP状态
M []byte
R []byte
P []byte
}
*/
// ConsensusState handles execution of the consensus algorithm.
// It processes votes and proposals, and upon reaching agreement,
// commits blocks to the chain and executes them against the application.
......@@ -108,6 +116,9 @@ type ConsensusState struct {
cachedNotify *dpostype.DPosNotify
cycleBoundaryMap map[int64] *dty.DposCBInfo
vrfInfoMap map[int64] *dty.VrfInfo
vrfInfosMap map[int64] []*dty.VrfInfo
}
// NewConsensusState returns a new ConsensusState.
......@@ -122,6 +133,8 @@ func NewConsensusState(client *Client, valMgr ValidatorMgr) *ConsensusState {
dposState: InitStateObj,
dposVotes: nil,
cycleBoundaryMap: make(map[int64] *dty.DposCBInfo),
vrfInfoMap: make(map[int64]*dty.VrfInfo),
vrfInfosMap: make(map[int64] []*dty.VrfInfo),
}
cs.updateToValMgr(valMgr)
......@@ -578,11 +591,17 @@ func (cs *ConsensusState) QueryCycleBoundaryInfo(cycle int64)(*dty.DposCBInfo, e
return msg.GetData().(types.Message).(*dty.DposCBInfo), nil
}
// InitCycleBoundaryInfo method
func (cs *ConsensusState) InitCycleBoundaryInfo(){
// Init method
func (cs *ConsensusState) Init() {
now := time.Now().Unix()
task := DecideTaskByTime(now)
cs.InitCycleBoundaryInfo(task)
cs.InitCycleVrfInfo(task)
cs.InitCycleVrfInfos(task)
}
// InitCycleBoundaryInfo method
func (cs *ConsensusState) InitCycleBoundaryInfo(task Task){
info, err := cs.QueryCycleBoundaryInfo(task.cycle)
if err == nil && info != nil {
//cs.cycleBoundaryMap[task.cycle] = info
......@@ -599,6 +618,7 @@ func (cs *ConsensusState) InitCycleBoundaryInfo(){
return
}
// UpdateCBInfo method
func (cs *ConsensusState) UpdateCBInfo(info *dty.DposCBInfo) {
valueNumber := len(cs.cycleBoundaryMap)
if valueNumber == 0 {
......@@ -627,16 +647,23 @@ func (cs *ConsensusState) UpdateCBInfo(info *dty.DposCBInfo) {
cs.cycleBoundaryMap[info.Cycle] = info
}
// GetCBInfoByCircle method
func (cs *ConsensusState) GetCBInfoByCircle(cycle int64) (info *dty.DposCBInfo) {
if v, ok := cs.cycleBoundaryMap[cycle];ok {
info = v
return info
}
info, err := cs.QueryCycleBoundaryInfo(cycle)
if err == nil && info != nil {
cs.UpdateCBInfo(info)
return info
}
return nil
}
// VerifyNotify method
// VerifyCBInfo method
func (cs *ConsensusState) VerifyCBInfo(info *dty.DposCBInfo) bool {
// Verify signature
bPubkey, err := hex.DecodeString(info.Pubkey)
......@@ -690,12 +717,27 @@ func (cs *ConsensusState) VerifyCBInfo(info *dty.DposCBInfo) bool {
return true
}
// SendCBTx method
func (cs *ConsensusState) SendCBTx(info *dty.DposCBInfo) bool {
err := cs.privValidator.SignCBInfo(info)
info.Pubkey = hex.EncodeToString(cs.privValidator.GetPubKey().Bytes())
canonical := dty.CanonicalOnceCBInfo{
Cycle: info.Cycle,
StopHeight: info.StopHeight,
StopHash: info.StopHash,
Pubkey: info.Pubkey,
}
byteCB, err := json.Marshal(&canonical)
if err != nil {
dposlog.Error("marshal CanonicalOnceCBInfo failed", "err", err)
}
sig, err := cs.privValidator.SignMsg(byteCB)
if err != nil {
dposlog.Error("SignCBInfo failed.", "err", err)
return false
} else {
info.Signature = sig
tx, err := cs.client.CreateRecordCBTx(info)
if err != nil {
dposlog.Error("CreateRecordCBTx failed.", "err", err)
......@@ -718,6 +760,7 @@ func (cs *ConsensusState) SendCBTx(info *dty.DposCBInfo) bool {
return true
}
// SendRegistVrfMTx method
func (cs *ConsensusState) SendRegistVrfMTx(info *dty.DposVrfMRegist) bool {
tx, err := cs.client.CreateRegVrfMTx(info)
if err != nil {
......@@ -740,6 +783,7 @@ func (cs *ConsensusState) SendRegistVrfMTx(info *dty.DposVrfMRegist) bool {
return true
}
// SendRegistVrfRPTx method
func (cs *ConsensusState) SendRegistVrfRPTx(info *dty.DposVrfRPRegist) bool {
tx, err := cs.client.CreateRegVrfRPTx(info)
if err != nil {
......@@ -762,4 +806,272 @@ func (cs *ConsensusState) SendRegistVrfRPTx(info *dty.DposVrfRPRegist) bool {
return true
}
func (cs *ConsensusState) QueryVrf(info *dty.DposCBInfo) bool {
// QueryVrf method
func (cs *ConsensusState) QueryVrf(pubkey []byte, cycle int64) (info *dty.VrfInfo, err error) {
var pubkeys [][]byte
pubkeys = append(pubkeys, pubkey)
infos, err := cs.client.QueryVrfInfos(pubkeys, cycle)
if err != nil {
return nil, err
}
if len(infos) > 0 {
info = infos[0]
}
return info, nil
}
// InitCycleVrfInfo method
func (cs *ConsensusState) InitCycleVrfInfo(task Task){
info, err := cs.QueryVrf(cs.privValidator.GetPubKey().Bytes(), task.cycle)
if err == nil && info != nil {
//cs.cycleBoundaryMap[task.cycle] = info
cs.UpdateVrfInfo(info)
return
}
info, err = cs.QueryVrf(cs.privValidator.GetPubKey().Bytes(), task.cycle - 1)
if err == nil && info != nil {
//cs.cycleBoundaryMap[task.cycle] = info
cs.UpdateVrfInfo(info)
}
return
}
// UpdateCBInfo method
func (cs *ConsensusState) UpdateVrfInfo(info *dty.VrfInfo) {
valueNumber := len(cs.vrfInfoMap)
if valueNumber == 0 {
cs.vrfInfoMap[info.Cycle] = info
return
}
oldestCycle := int64(0)
for k, _ := range cs.vrfInfoMap {
if k == info.Cycle {
cs.vrfInfoMap[info.Cycle] = info
return
} else {
if oldestCycle == 0 {
oldestCycle = k
} else if oldestCycle > k {
oldestCycle = k
}
}
}
if valueNumber >= 5 {
delete(cs.vrfInfoMap, oldestCycle)
}
cs.vrfInfoMap[info.Cycle] = info
}
// GetCBInfoByCircle method
func (cs *ConsensusState) GetVrfInfoByCircle(cycle int64, ty int) (info *dty.VrfInfo) {
if v, ok := cs.vrfInfoMap[cycle];ok {
info = v
if VrfQueryTypeM == ty && len(info.M) > 0 {
return info
} else if VrfQueryTypeRP == ty && len(info.M) > 0 && len(info.R) >0 && len(info.P) > 0 {
return info
}
}
info, err := cs.QueryVrf(cs.privValidator.GetPubKey().Bytes(), cycle)
if err == nil && info != nil {
cs.UpdateVrfInfo(info)
return info
}
return nil
}
// QueryVrfs method
func (cs *ConsensusState) QueryVrfs(set *ttypes.ValidatorSet, cycle int64) (infos []*dty.VrfInfo, err error) {
var pubkeys [][]byte
for i := 0; i < set.Size(); i++ {
pubkeys = append(pubkeys, set.Validators[i].PubKey)
}
infos, err = cs.client.QueryVrfInfos(pubkeys, cycle)
if err != nil {
return nil, err
}
return infos, nil
}
// InitCycleVrfInfo method
func (cs *ConsensusState) InitCycleVrfInfos(task Task){
infos, err := cs.QueryVrfs(cs.validatorMgr.Validators, task.cycle - 1)
if err == nil && infos != nil {
//cs.cycleBoundaryMap[task.cycle] = info
cs.UpdateVrfInfos(task.cycle, infos)
}
return
}
// UpdateCBInfo method
func (cs *ConsensusState) UpdateVrfInfos(cycle int64, infos []*dty.VrfInfo) {
if len(cs.validatorMgr.Validators.Validators) != len(infos) {
return
}
for i := 0; i < len(infos); i++ {
if len(infos[i].M) == 0 || len(infos[i].R) == 0 || len(infos[i].P) == 0 {
return
}
}
valueNumber := len(cs.vrfInfosMap)
if valueNumber == 0 {
cs.vrfInfosMap[cycle] = infos
return
}
oldestCycle := int64(0)
for k, _ := range cs.vrfInfosMap {
if k == cycle {
cs.vrfInfosMap[cycle] = infos
return
} else {
if oldestCycle == 0 {
oldestCycle = k
} else if oldestCycle > k {
oldestCycle = k
}
}
}
if valueNumber >= 5 {
delete(cs.vrfInfosMap, oldestCycle)
}
cs.vrfInfosMap[cycle] = infos
}
// GetVrfInfosByCircle method
func (cs *ConsensusState) GetVrfInfosByCircle(cycle int64) (info []*dty.VrfInfo) {
if v, ok := cs.vrfInfosMap[cycle];ok {
info = v
return info
}
infos, err := cs.QueryVrfs(cs.validatorMgr.Validators, cycle)
if err == nil && infos != nil {
cs.UpdateVrfInfos(cycle, infos)
return info
}
return nil
}
// ShuffleValidators method
func (cs *ConsensusState) ShuffleValidators(cycle int64){
if cycle == cs.validatorMgr.ShuffleCycle {
//如果已经洗过牌,则直接返回,不重复洗牌
return
}
infos := cs.GetVrfInfosByCircle(cycle - 1)
if infos == nil {
cs.validatorMgr.VrfValidators = nil
cs.validatorMgr.NoVrfValidators = nil
cs.validatorMgr.ShuffleCycle = cycle
cs.validatorMgr.ShuffleType = ShuffleTypeNoVrf
return
}
cbInfo := cs.GetCBInfoByCircle(cycle - 1)
if cbInfo == nil {
cs.validatorMgr.VrfValidators = nil
cs.validatorMgr.NoVrfValidators = nil
cs.validatorMgr.ShuffleCycle = cycle
cs.validatorMgr.ShuffleType = ShuffleTypeNoVrf
return
}
cs.validatorMgr.LastCycleBoundaryInfo = cbInfo
var vrfValidators []*ttypes.Validator
var noVrfValidators []*ttypes.Validator
for i := 0; i < len(infos); i++ {
if isValidVrfInfo(infos[i]) {
var vrfBytes []byte
vrfBytes = append(vrfBytes, []byte(cbInfo.StopHash)...)
vrfBytes = append(vrfBytes, infos[i].R...)
item := &ttypes.Validator{
PubKey: infos[i].Pubkey,
}
item.Address = crypto.Ripemd160(vrfBytes)
vrfValidators = append(vrfValidators, item)
}
}
set := cs.validatorMgr.Validators.Validators
if len(vrfValidators) == 0 {
cs.validatorMgr.ShuffleCycle = cycle
cs.validatorMgr.ShuffleType = ShuffleTypeNoVrf
return
} else if len(vrfValidators) == len(set) {
cs.validatorMgr.ShuffleCycle = cycle
cs.validatorMgr.ShuffleType = ShuffleTypeVrf
cs.validatorMgr.VrfValidators = ttypes.NewValidatorSet(vrfValidators)
return
}
cs.validatorMgr.ShuffleCycle = cycle
cs.validatorMgr.ShuffleType = ShuffleTypePartVrf
for i := 0; i < len(set); i ++ {
//如果节点信息不在VrfValidators,则说明没有完整的VRF信息,将被放入NoVrfValidators中
if !isValidatorExist(set[i].PubKey, vrfValidators) {
item := &ttypes.Validator{
PubKey: set[i].PubKey,
Address: set[i].Address,
}
noVrfValidators = append(noVrfValidators, item)
}
}
cs.validatorMgr.VrfValidators = ttypes.NewValidatorSet(vrfValidators)
cs.validatorMgr.NoVrfValidators = ttypes.NewValidatorSet(noVrfValidators)
}
func isValidVrfInfo(info *dty.VrfInfo) bool {
if info != nil && len(info.M) > 0 || len(info.R) > 0 || len(info.P) > 0 {
return true
}
return false
}
func isValidatorExist(pubkey []byte ,set []*ttypes.Validator) bool {
for i := 0; i < len(set); i++ {
if bytes.Equal(pubkey, set[i].PubKey) {
return true
}
}
return false
}
// VrfEvaluate method
func (cs *ConsensusState) VrfEvaluate(input []byte)(hash [32]byte, proof []byte) {
return cs.privValidator.VrfEvaluate(input)
}
// VrfEvaluate method
func (cs *ConsensusState) VrfProof(pubkey []byte, input []byte, hash [32]byte, proof []byte) bool{
return cs.privValidator.VrfProof(pubkey, input, hash, proof)
}
\ No newline at end of file
......@@ -325,7 +325,7 @@ OuterLoop:
// 对于受托节点,才需要初始化区块,启动共识相关程序等,后续支持投票要做成动态切换的。
if client.isDelegator {
client.InitBlock()
client.csState.InitCycleBoundaryInfo()
client.csState.Init()
node.Start()
}
......
......@@ -3,6 +3,16 @@ syntax = "proto3";
package types;
message CycleBoundaryInfo{
int64 cycle = 1;
int64 stopHeight = 2;
string stopHash = 3;
}
message SuperNode{
bytes address = 1;
bytes pubKey = 2;
}
message VoteItem {
int32 votedNodeIndex = 1; //被投票的节点索引
bytes votedNodeAddress = 2; //被投票的节点地址
......@@ -13,6 +23,11 @@ message VoteItem {
int64 periodStop = 7; //新节点负责出块的终止时间
int64 height = 8; //新节点负责出块的起始高度
bytes voteID = 9; //选票ID
CycleBoundaryInfo lastCBInfo = 10;
int64 shuffleType = 11;
repeated SuperNode validators = 12;
repeated SuperNode vrfValidators = 13;
repeated SuperNode noVrfValidators = 14;
}
//DPosVote Dpos共识的节点投票,为达成共识用。
......
......@@ -76,49 +76,23 @@ func DecideTaskByTime(now int64) (task Task) {
return task
}
// State is the base class of dpos state machine, it defines some interfaces.
type State interface {
timeOut(cs *ConsensusState)
sendVote(cs *ConsensusState, vote *dpostype.DPosVote)
recvVote(cs *ConsensusState, vote *dpostype.DPosVote)
sendVoteReply(cs *ConsensusState, reply *dpostype.DPosVoteReply)
recvVoteReply(cs *ConsensusState, reply *dpostype.DPosVoteReply)
sendNotify(cs *ConsensusState, notify *dpostype.DPosNotify)
recvNotify(cs *ConsensusState, notify *dpostype.DPosNotify)
//sendCBInfo(cs *ConsensusState, info *dty.DposCBInfo)
recvCBInfo(cs *ConsensusState, info *dty.DposCBInfo)
}
// InitState is the initial state of dpos state machine
type InitState struct {
}
func (init *InitState) timeOut(cs *ConsensusState) {
//if available noes < 2/3, don't change the state to voting.
connections := cs.client.node.peerSet.Size()
validators := cs.validatorMgr.Validators.Size()
if connections == 0 || connections < (validators*2/3-1) {
dposlog.Error("InitState timeout but available nodes less than 2/3,waiting for more connections", "connections", connections, "validators", validators)
cs.ClearVotes()
//设定超时时间,超时后再检查链接数量
cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
} else {
func generateVote(cs *ConsensusState) *dpostype.Vote {
//获得当前高度
height := cs.client.GetCurrentHeight()
now := time.Now().Unix()
if cs.lastMyVote != nil && math.Abs(float64(now-cs.lastMyVote.VoteItem.PeriodStop)) <= 1 {
if cs.lastMyVote != nil && math.Abs(float64(now - cs.lastMyVote.VoteItem.PeriodStop)) <= 1 {
now += 2
}
//计算当前时间,属于哪一个周期,应该哪一个节点出块,应该出块的高度
task := DecideTaskByTime(now)
addr, validator := cs.validatorMgr.Validators.GetByIndex(int(task.nodeID))
cs.ShuffleValidators(task.cycle)
addr, validator := cs.validatorMgr.GetValidatorByIndex(int(task.nodeID))
if addr == nil && validator == nil {
dposlog.Error("Address and Validator is nil", "node index", task.nodeID, "now", now, "cycle", dposCycle, "period", dposPeriod)
//cs.SetState(InitStateObj)
cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
return
//cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
return nil
}
//生成vote, 对于vote进行签名
......@@ -132,29 +106,23 @@ func (init *InitState) timeOut(cs *ConsensusState) {
PeriodStop: task.periodStop,
Height: height + 1,
}
cs.validatorMgr.FillVoteItem(voteItem)
encode, err := json.Marshal(voteItem)
if err != nil {
panic("Marshal vote failed.")
//cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
//return
}
voteItem.VoteID = crypto.Ripemd160(encode)
index := -1
for i := 0; i < cs.validatorMgr.Validators.Size(); i++ {
if bytes.Equal(cs.validatorMgr.Validators.Validators[i].Address, cs.privValidator.GetAddress()) {
index = i
break
}
}
index := cs.validatorMgr.GetIndexByPubKey(cs.privValidator.GetPubKey().Bytes())
if index == -1 {
panic("This node's address is not exist in Validators.")
}
vote := &dpostype.Vote{DPosVote: &dpostype.DPosVote{
vote := &dpostype.Vote{
DPosVote: &dpostype.DPosVote{
VoteItem: voteItem,
VoteTimestamp: now,
VoterNodeAddress: cs.privValidator.GetAddress(),
......@@ -162,9 +130,79 @@ func (init *InitState) timeOut(cs *ConsensusState) {
},
}
return vote
}
func checkVrf(cs *ConsensusState) {
now := time.Now().Unix()
task := DecideTaskByTime(now)
middleTime := task.cycleStart + (task.cycleStop - task.cycleStart) / 2
if now < middleTime {
info := cs.GetVrfInfoByCircle(task.cycle, VrfQueryTypeM)
if info == nil {
vrfM := &dty.DposVrfMRegist{
Pubkey: hex.EncodeToString(cs.privValidator.GetPubKey().Bytes()),
Cycle: task.cycle,
M: cs.currentVote.LastCBInfo.StopHash,
}
cs.SendRegistVrfMTx(vrfM)
}
} else {
info := cs.GetVrfInfoByCircle(task.cycle, VrfQueryTypeRP)
if info != nil && len(info.M) > 0 && (len(info.R) == 0 || len(info.P) == 0){
hash, proof := cs.VrfEvaluate(info.M)
vrfRP := &dty.DposVrfRPRegist{
Pubkey: hex.EncodeToString(cs.privValidator.GetPubKey().Bytes()),
Cycle: task.cycle,
R: hex.EncodeToString(hash[:]),
P: hex.EncodeToString(proof),
}
cs.SendRegistVrfRPTx(vrfRP)
}
}
}
// State is the base class of dpos state machine, it defines some interfaces.
type State interface {
timeOut(cs *ConsensusState)
sendVote(cs *ConsensusState, vote *dpostype.DPosVote)
recvVote(cs *ConsensusState, vote *dpostype.DPosVote)
sendVoteReply(cs *ConsensusState, reply *dpostype.DPosVoteReply)
recvVoteReply(cs *ConsensusState, reply *dpostype.DPosVoteReply)
sendNotify(cs *ConsensusState, notify *dpostype.DPosNotify)
recvNotify(cs *ConsensusState, notify *dpostype.DPosNotify)
//sendCBInfo(cs *ConsensusState, info *dty.DposCBInfo)
recvCBInfo(cs *ConsensusState, info *dty.DposCBInfo)
}
// InitState is the initial state of dpos state machine
type InitState struct {
}
func (init *InitState) timeOut(cs *ConsensusState) {
//if available noes < 2/3, don't change the state to voting.
connections := cs.client.node.peerSet.Size()
validators := cs.validatorMgr.Validators.Size()
if connections == 0 || connections < (validators*2/3-1) {
dposlog.Error("InitState timeout but available nodes less than 2/3,waiting for more connections", "connections", connections, "validators", validators)
cs.ClearVotes()
//设定超时时间,超时后再检查链接数量
cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
} else {
vote := generateVote(cs)
if nil == vote {
cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
return
}
if err := cs.privValidator.SignVote(cs.validatorMgr.ChainID, vote); err != nil {
dposlog.Error("SignVote failed", "vote", vote.String())
//cs.SetState(InitStateObj)
cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
return
}
......@@ -279,6 +317,14 @@ func (voting *VotingState) recvVote(cs *ConsensusState, vote *dpostype.DPosVote)
cs.SetCurrentVote(voteItem)
//检查最终投票是否与自己的投票一致,如果不一致,需要更新本地的信息,保证各节点共识结果执行一致。
if !bytes.Equal(cs.myVote.VoteItem.VoteID, voteItem.VoteID) {
if !cs.validatorMgr.UpdateFromVoteItem(voteItem) {
panic("This node's validators are not the same with final vote, please check")
}
}
//进行VRF相关处理
checkVrf(cs)
//1s后检查是否出块,是否需要重新投票
cs.scheduleDPosTimeout(time.Millisecond*500, VotedStateType)
} else if result == continueToVote {
......@@ -330,6 +376,15 @@ func (voted *VotedState) timeOut(cs *ConsensusState) {
if bytes.Equal(cs.privValidator.GetAddress(), cs.currentVote.VotedNodeAddress) {
//当前节点为出块节点
//如果区块未同步,则等待;如果区块已同步,则进行后续正常出块的判断和处理。
if block.Height + 1 < cs.currentVote.Height {
dposlog.Info("VotedState timeOut but block is not sync,wait...", "localHeight", block.Height, "vote height", cs.currentVote.Height)
cs.scheduleDPosTimeout(time.Second*1, VotedStateType)
return
}
//时间到了节点切换时刻
if now >= cs.currentVote.PeriodStop {
//当前时间超过了节点切换时间,需要进行重新投票
dposlog.Info("VotedState timeOut over periodStop.", "periodStop", cs.currentVote.PeriodStop)
......@@ -344,28 +399,7 @@ func (voted *VotedState) timeOut(cs *ConsensusState) {
StopHash: hex.EncodeToString(block.Hash()),
Pubkey: hex.EncodeToString(cs.privValidator.GetPubKey().Bytes()),
}
/*
err := cs.privValidator.SignCBInfo(info)
if err != nil {
dposlog.Error("SignCBInfo failed.", "err", err)
} else {
tx, err := cs.client.CreateRecordCBTx(info)
if err != nil {
dposlog.Error("CreateRecordCBTx failed.", "err", err)
}else {
cs.privValidator.SignTx(tx)
dposlog.Info("Sign RecordCBTx.")
//将交易发往交易池中,方便后续重启或者新加入的超级节点查询
msg := cs.client.GetQueueClient().NewMessage("mempool", types.EventTx, tx)
err = cs.client.GetQueueClient().Send(msg, false)
if err != nil {
dposlog.Error("Send RecordCBTx to mempool failed.", "err", err)
} else {
dposlog.Error("Send RecordCBTx to mempool ok.", "err", err)
}
}
}
*/
cs.SendCBTx(info)
info2 := &dty.DposCBInfo{
Cycle: info.Cycle,
......@@ -417,12 +451,6 @@ func (voted *VotedState) timeOut(cs *ConsensusState) {
cs.scheduleDPosTimeout(time.Duration(timeoutCheckConnections)*time.Millisecond, InitStateType)
return
}
//如果区块未同步,则等待;如果区块已同步,则进行后续正常出块的判断和处理。
if block.Height + 1 < cs.currentVote.Height {
dposlog.Info("VotedState timeOut but block is not sync,wait...", "localHeight", block.Height, "vote height", cs.currentVote.Height)
cs.scheduleDPosTimeout(time.Second*1, VotedStateType)
return
}
//当前时间未到节点切换时间,则继续进行出块判断
if block.BlockTime >= task.blockStop {
......@@ -457,6 +485,8 @@ func (voted *VotedState) timeOut(cs *ConsensusState) {
} else {
dposlog.Info("This node is not current owner.", "current owner index", cs.currentVote.VotedNodeIndex, "this node index", cs.client.ValidatorIndex())
//根据时间进行vrf相关处理,如果在(cyclestart,middle)之间,发布M,如果在(middle,cyclestop)之间,发布R、P
checkVrf(cs)
//非当前出块节点,如果到了切换出块节点的时间,则进行状态切换,进行投票
if now >= cs.currentVote.PeriodStop {
//当前时间超过了节点切换时间,需要进行重新投票
......
......@@ -8,6 +8,8 @@ It is generated from these files:
dpos_msg.proto
It has these top-level messages:
CycleBoundaryInfo
SuperNode
VoteItem
DPosVote
DPosVoteReply
......@@ -30,6 +32,62 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type CycleBoundaryInfo struct {
Cycle int64 `protobuf:"varint,1,opt,name=cycle" json:"cycle,omitempty"`
StopHeight int64 `protobuf:"varint,2,opt,name=stopHeight" json:"stopHeight,omitempty"`
StopHash string `protobuf:"bytes,3,opt,name=stopHash" json:"stopHash,omitempty"`
}
func (m *CycleBoundaryInfo) Reset() { *m = CycleBoundaryInfo{} }
func (m *CycleBoundaryInfo) String() string { return proto.CompactTextString(m) }
func (*CycleBoundaryInfo) ProtoMessage() {}
func (*CycleBoundaryInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *CycleBoundaryInfo) GetCycle() int64 {
if m != nil {
return m.Cycle
}
return 0
}
func (m *CycleBoundaryInfo) GetStopHeight() int64 {
if m != nil {
return m.StopHeight
}
return 0
}
func (m *CycleBoundaryInfo) GetStopHash() string {
if m != nil {
return m.StopHash
}
return ""
}
type SuperNode struct {
Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
PubKey []byte `protobuf:"bytes,2,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
}
func (m *SuperNode) Reset() { *m = SuperNode{} }
func (m *SuperNode) String() string { return proto.CompactTextString(m) }
func (*SuperNode) ProtoMessage() {}
func (*SuperNode) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *SuperNode) GetAddress() []byte {
if m != nil {
return m.Address
}
return nil
}
func (m *SuperNode) GetPubKey() []byte {
if m != nil {
return m.PubKey
}
return nil
}
type VoteItem struct {
VotedNodeIndex int32 `protobuf:"varint,1,opt,name=votedNodeIndex" json:"votedNodeIndex,omitempty"`
VotedNodeAddress []byte `protobuf:"bytes,2,opt,name=votedNodeAddress,proto3" json:"votedNodeAddress,omitempty"`
......@@ -40,12 +98,17 @@ type VoteItem struct {
PeriodStop int64 `protobuf:"varint,7,opt,name=periodStop" json:"periodStop,omitempty"`
Height int64 `protobuf:"varint,8,opt,name=height" json:"height,omitempty"`
VoteID []byte `protobuf:"bytes,9,opt,name=voteID,proto3" json:"voteID,omitempty"`
LastCBInfo *CycleBoundaryInfo `protobuf:"bytes,10,opt,name=lastCBInfo" json:"lastCBInfo,omitempty"`
ShuffleType int64 `protobuf:"varint,11,opt,name=shuffleType" json:"shuffleType,omitempty"`
Validators []*SuperNode `protobuf:"bytes,12,rep,name=validators" json:"validators,omitempty"`
VrfValidators []*SuperNode `protobuf:"bytes,13,rep,name=vrfValidators" json:"vrfValidators,omitempty"`
NoVrfValidators []*SuperNode `protobuf:"bytes,14,rep,name=noVrfValidators" json:"noVrfValidators,omitempty"`
}
func (m *VoteItem) Reset() { *m = VoteItem{} }
func (m *VoteItem) String() string { return proto.CompactTextString(m) }
func (*VoteItem) ProtoMessage() {}
func (*VoteItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (*VoteItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *VoteItem) GetVotedNodeIndex() int32 {
if m != nil {
......@@ -110,6 +173,41 @@ func (m *VoteItem) GetVoteID() []byte {
return nil
}
func (m *VoteItem) GetLastCBInfo() *CycleBoundaryInfo {
if m != nil {
return m.LastCBInfo
}
return nil
}
func (m *VoteItem) GetShuffleType() int64 {
if m != nil {
return m.ShuffleType
}
return 0
}
func (m *VoteItem) GetValidators() []*SuperNode {
if m != nil {
return m.Validators
}
return nil
}
func (m *VoteItem) GetVrfValidators() []*SuperNode {
if m != nil {
return m.VrfValidators
}
return nil
}
func (m *VoteItem) GetNoVrfValidators() []*SuperNode {
if m != nil {
return m.NoVrfValidators
}
return nil
}
// DPosVote Dpos共识的节点投票,为达成共识用。
type DPosVote struct {
VoteItem *VoteItem `protobuf:"bytes,1,opt,name=voteItem" json:"voteItem,omitempty"`
......@@ -122,7 +220,7 @@ type DPosVote struct {
func (m *DPosVote) Reset() { *m = DPosVote{} }
func (m *DPosVote) String() string { return proto.CompactTextString(m) }
func (*DPosVote) ProtoMessage() {}
func (*DPosVote) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (*DPosVote) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *DPosVote) GetVoteItem() *VoteItem {
if m != nil {
......@@ -166,7 +264,7 @@ type DPosVoteReply struct {
func (m *DPosVoteReply) Reset() { *m = DPosVoteReply{} }
func (m *DPosVoteReply) String() string { return proto.CompactTextString(m) }
func (*DPosVoteReply) ProtoMessage() {}
func (*DPosVoteReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (*DPosVoteReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *DPosVoteReply) GetVote() *DPosVote {
if m != nil {
......@@ -189,7 +287,7 @@ type DPosNotify struct {
func (m *DPosNotify) Reset() { *m = DPosNotify{} }
func (m *DPosNotify) String() string { return proto.CompactTextString(m) }
func (*DPosNotify) ProtoMessage() {}
func (*DPosNotify) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (*DPosNotify) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *DPosNotify) GetVote() *VoteItem {
if m != nil {
......@@ -241,6 +339,8 @@ func (m *DPosNotify) GetSignature() []byte {
}
func init() {
proto.RegisterType((*CycleBoundaryInfo)(nil), "types.CycleBoundaryInfo")
proto.RegisterType((*SuperNode)(nil), "types.SuperNode")
proto.RegisterType((*VoteItem)(nil), "types.VoteItem")
proto.RegisterType((*DPosVote)(nil), "types.DPosVote")
proto.RegisterType((*DPosVoteReply)(nil), "types.DPosVoteReply")
......@@ -250,30 +350,40 @@ func init() {
func init() { proto.RegisterFile("dpos_msg.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 396 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0xdd, 0x6a, 0xdb, 0x30,
0x14, 0xc7, 0x71, 0x1c, 0x3b, 0xce, 0xc9, 0xd7, 0x26, 0xc6, 0x10, 0x63, 0x0c, 0xe3, 0x8d, 0x61,
0xb6, 0x91, 0x8b, 0x6d, 0x2f, 0x30, 0xc8, 0x4d, 0x6e, 0xc2, 0x70, 0x4b, 0x6f, 0x8b, 0x1b, 0xab,
0xb1, 0x21, 0x8e, 0x84, 0xa4, 0x86, 0xe6, 0x21, 0xfa, 0x16, 0x7d, 0x9f, 0xbe, 0x52, 0xd1, 0xf1,
0x87, 0x1c, 0x87, 0xde, 0xe9, 0xfc, 0xfe, 0xd2, 0x51, 0xce, 0x4f, 0x31, 0xcc, 0x33, 0xc1, 0xd5,
0x6d, 0xa9, 0x76, 0x4b, 0x21, 0xb9, 0xe6, 0xc4, 0xd3, 0x27, 0xc1, 0x54, 0xf4, 0x3c, 0x80, 0xe0,
0x86, 0x6b, 0xb6, 0xd6, 0xac, 0x24, 0xdf, 0x61, 0x7e, 0xe4, 0x9a, 0x65, 0x1b, 0x9e, 0xb1, 0xf5,
0x21, 0x63, 0x8f, 0xd4, 0x09, 0x9d, 0xd8, 0x4b, 0x7a, 0x94, 0xfc, 0x80, 0x77, 0x2d, 0xf9, 0x97,
0x65, 0x92, 0x29, 0x45, 0x07, 0xa1, 0x13, 0x4f, 0x93, 0x0b, 0x4e, 0x3e, 0x80, 0xb7, 0x3d, 0x6d,
0xf7, 0x8c, 0xba, 0xa1, 0x13, 0xbb, 0x49, 0x55, 0x90, 0x2f, 0x00, 0xb8, 0xb8, 0xd2, 0xa9, 0xd4,
0x74, 0x88, 0x51, 0x87, 0x90, 0xcf, 0x30, 0xae, 0x2b, 0x2e, 0xa8, 0x87, 0xb1, 0x05, 0x24, 0x84,
0x89, 0x60, 0xb2, 0xe0, 0x59, 0x75, 0xdc, 0xc7, 0xbc, 0x8b, 0x4c, 0xff, 0xa6, 0xe4, 0x82, 0x8e,
0xaa, 0xfe, 0x96, 0x90, 0x8f, 0xe0, 0xe7, 0xac, 0xd8, 0xe5, 0x9a, 0x06, 0x98, 0xd5, 0x95, 0xe1,
0x66, 0x82, 0xf5, 0x8a, 0x8e, 0x71, 0x9e, 0xba, 0x8a, 0x5e, 0x1c, 0x08, 0x56, 0xff, 0xb9, 0x32,
0xaa, 0xc8, 0x4f, 0x08, 0x8e, 0xb5, 0x32, 0x14, 0x34, 0xf9, 0xbd, 0x58, 0xa2, 0xcd, 0x65, 0x63,
0x32, 0x69, 0x37, 0x90, 0x6f, 0x30, 0x33, 0xeb, 0xeb, 0xa2, 0x64, 0x4a, 0xa7, 0xa5, 0x40, 0x51,
0x6e, 0x72, 0x0e, 0x1b, 0xf3, 0xd2, 0x9a, 0x77, 0xad, 0x79, 0x79, 0x61, 0x5e, 0x76, 0xcd, 0x0f,
0xad, 0xf9, 0x2e, 0x37, 0x0e, 0x55, 0xb1, 0x3b, 0xa4, 0xfa, 0x41, 0x32, 0x74, 0x38, 0x4d, 0x2c,
0x88, 0xfe, 0xc2, 0xac, 0x19, 0x28, 0x61, 0x62, 0x7f, 0x22, 0x5f, 0x61, 0x68, 0x5a, 0xf4, 0x26,
0x6a, 0xf7, 0x60, 0x18, 0x3d, 0x0d, 0x00, 0x0c, 0xda, 0x70, 0x5d, 0xdc, 0xbf, 0x75, 0xa6, 0xb5,
0x80, 0xa1, 0x79, 0x8b, 0xca, 0x2e, 0xbe, 0x45, 0x35, 0x7e, 0x87, 0x90, 0x4f, 0x10, 0xe4, 0xa9,
0xca, 0x31, 0x75, 0xf1, 0x67, 0xb6, 0x35, 0x89, 0x61, 0x71, 0xc0, 0xab, 0xac, 0xbf, 0xea, 0xcf,
0xd2, 0xc7, 0x76, 0xa7, 0x55, 0xe8, 0xa1, 0xc2, 0x3e, 0x26, 0xbf, 0xe0, 0xbd, 0x45, 0x8d, 0x44,
0x1f, 0x2f, 0xbe, 0x0c, 0xce, 0x2d, 0x8e, 0x7a, 0x16, 0xef, 0x7c, 0xfc, 0x98, 0xfe, 0xbc, 0x06,
0x00, 0x00, 0xff, 0xff, 0x98, 0x0c, 0x28, 0xf0, 0x5e, 0x03, 0x00, 0x00,
// 558 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0xdd, 0x8a, 0x13, 0x31,
0x14, 0xa6, 0x3b, 0xfd, 0x3d, 0xfd, 0xd9, 0xdd, 0x20, 0x12, 0x44, 0xa4, 0x8c, 0x22, 0x45, 0xa5,
0x48, 0x15, 0x11, 0xc1, 0x0b, 0x77, 0xf7, 0xc2, 0x22, 0x2c, 0x32, 0xbb, 0xf4, 0x56, 0xb2, 0x3b,
0x69, 0x67, 0xa0, 0x6d, 0x42, 0x92, 0x16, 0xe7, 0x21, 0x7c, 0x0d, 0x5f, 0xc7, 0x57, 0x92, 0x9c,
0xcc, 0x4c, 0xa6, 0x53, 0x7a, 0x37, 0xdf, 0x77, 0x7e, 0x92, 0xf3, 0x9d, 0x2f, 0x03, 0xa3, 0x58,
0x0a, 0xfd, 0x6b, 0xa3, 0x57, 0x53, 0xa9, 0x84, 0x11, 0xa4, 0x65, 0x32, 0xc9, 0x75, 0xc8, 0xe1,
0xf2, 0x3a, 0x7b, 0x5c, 0xf3, 0x2b, 0xb1, 0xdb, 0xc6, 0x4c, 0x65, 0xf3, 0xed, 0x52, 0x90, 0x27,
0xd0, 0x7a, 0xb4, 0x24, 0x6d, 0x8c, 0x1b, 0x93, 0x20, 0x72, 0x80, 0xbc, 0x00, 0xd0, 0x46, 0xc8,
0xef, 0x3c, 0x5d, 0x25, 0x86, 0x9e, 0x61, 0xa8, 0xc2, 0x90, 0x67, 0xd0, 0x45, 0xc4, 0x74, 0x42,
0x83, 0x71, 0x63, 0xd2, 0x8b, 0x4a, 0x1c, 0x7e, 0x85, 0xde, 0xdd, 0x4e, 0x72, 0x75, 0x2b, 0x62,
0x4e, 0x28, 0x74, 0x58, 0x1c, 0x2b, 0xae, 0x35, 0x1e, 0x30, 0x88, 0x0a, 0x48, 0x9e, 0x42, 0x5b,
0xee, 0x1e, 0x7e, 0xf0, 0x0c, 0xdb, 0x0f, 0xa2, 0x1c, 0x85, 0x7f, 0x9b, 0xd0, 0x5d, 0x08, 0xc3,
0xe7, 0x86, 0x6f, 0xc8, 0x6b, 0x18, 0xed, 0x85, 0xe1, 0xb1, 0xed, 0x35, 0xdf, 0xc6, 0xfc, 0x37,
0x76, 0x69, 0x45, 0x35, 0x96, 0xbc, 0x81, 0x8b, 0x92, 0xf9, 0x96, 0x9f, 0xe7, 0xda, 0x1e, 0xf1,
0x7e, 0xe2, 0xa0, 0x36, 0x31, 0x7e, 0xdc, 0x19, 0xa6, 0x0c, 0x6d, 0xba, 0x89, 0x3d, 0x43, 0x9e,
0x43, 0x2f, 0x47, 0x42, 0xd2, 0x16, 0x86, 0x3d, 0x41, 0xc6, 0xd0, 0x97, 0x5c, 0xa5, 0x22, 0x76,
0xe5, 0x6d, 0x8c, 0x57, 0x29, 0xdb, 0xbf, 0x80, 0x42, 0xd2, 0x8e, 0xeb, 0xef, 0x19, 0x2b, 0x47,
0xe2, 0xd4, 0xee, 0x62, 0x2c, 0x47, 0x96, 0xb7, 0x13, 0xcc, 0x6f, 0x68, 0xcf, 0xc9, 0xe4, 0x10,
0xf9, 0x0c, 0xb0, 0x66, 0xda, 0x5c, 0x5f, 0xd9, 0x2d, 0x52, 0x18, 0x37, 0x26, 0xfd, 0x19, 0x9d,
0xe2, 0xa2, 0xa7, 0x47, 0x5b, 0x8e, 0x2a, 0xb9, 0xf6, 0xae, 0x3a, 0xd9, 0x2d, 0x97, 0x6b, 0x7e,
0x9f, 0x49, 0x4e, 0xfb, 0xee, 0xae, 0x15, 0x8a, 0xbc, 0x07, 0xd8, 0xb3, 0x75, 0x1a, 0x33, 0x23,
0x94, 0xa6, 0x83, 0x71, 0x30, 0xe9, 0xcf, 0x2e, 0xf2, 0xde, 0xe5, 0x6a, 0xa3, 0x4a, 0x0e, 0xf9,
0x04, 0xc3, 0xbd, 0x5a, 0x2e, 0x7c, 0xd1, 0xf0, 0x44, 0xd1, 0x61, 0x1a, 0xf9, 0x02, 0xe7, 0x5b,
0xb1, 0x38, 0xa8, 0x1c, 0x9d, 0xa8, 0xac, 0x27, 0x86, 0xff, 0x1a, 0xd0, 0xbd, 0xf9, 0x29, 0xb4,
0x35, 0x0b, 0x79, 0x0b, 0xdd, 0x7d, 0x6e, 0x1a, 0xb4, 0x48, 0x7f, 0x76, 0x9e, 0x77, 0x28, 0xbc,
0x14, 0x95, 0x09, 0xe4, 0x15, 0x0c, 0xed, 0xf7, 0x7d, 0xba, 0xe1, 0xda, 0xb0, 0x8d, 0xcc, 0x0d,
0x7e, 0x48, 0x16, 0xde, 0x53, 0xde, 0x7b, 0x81, 0xf7, 0x9e, 0x3a, 0xf2, 0x9e, 0xaa, 0x7a, 0xaf,
0xe9, 0xbd, 0x57, 0xe5, 0xad, 0x8b, 0x74, 0xba, 0xda, 0x32, 0xb3, 0x53, 0x1c, 0x5d, 0x34, 0x88,
0x3c, 0x11, 0x7e, 0x84, 0x61, 0x31, 0x50, 0xc4, 0xe5, 0x3a, 0x23, 0x2f, 0xa1, 0x69, 0x5b, 0xd4,
0x26, 0x2a, 0x73, 0x30, 0x18, 0xfe, 0x39, 0x03, 0xb0, 0xd4, 0xad, 0x30, 0xe9, 0xf2, 0x54, 0x4d,
0xa9, 0x02, 0x06, 0xad, 0x1b, 0x9d, 0xbf, 0xd0, 0x8d, 0xf9, 0xfb, 0xf6, 0x8c, 0x7d, 0xdf, 0x09,
0xd3, 0x09, 0x46, 0x03, 0xbc, 0x66, 0x89, 0xc9, 0xc4, 0xee, 0xcc, 0x1e, 0xe5, 0xf5, 0x73, 0xcf,
0xa5, 0x4e, 0xfb, 0x4c, 0x2f, 0x61, 0x0b, 0x25, 0xac, 0xd3, 0xe4, 0x1d, 0x5c, 0x7a, 0xaa, 0x10,
0xb1, 0x8d, 0x07, 0x1f, 0x07, 0x0e, 0x55, 0xec, 0xd4, 0x54, 0x7c, 0x68, 0xe3, 0x4f, 0xef, 0xc3,
0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x49, 0x1a, 0xb6, 0x06, 0x05, 0x00, 0x00,
}
......@@ -6,6 +6,7 @@ package types
import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"encoding/json"
"errors"
......@@ -14,8 +15,9 @@ import (
"sync"
"github.com/33cn/chain33/common/crypto"
dty "github.com/33cn/plugin/plugin/dapp/dposvote/types"
vrf "github.com/33cn/chain33/common/vrf/secp256k1"
"github.com/33cn/chain33/types"
secp256k1 "github.com/btcsuite/btcd/btcec"
)
// KeyText ...
......@@ -32,8 +34,10 @@ type PrivValidator interface {
SignVote(chainID string, vote *Vote) error
SignNotify(chainID string, notify *Notify) error
SignCBInfo(info *dty.DposCBInfo) error
SignMsg(msg []byte) (sig string, err error)
SignTx(tx *types.Transaction)
VrfEvaluate(input []byte) (hash [32]byte, proof []byte)
VrfProof(pubkey []byte, input []byte, hash [32]byte, proof []byte) bool
}
// PrivValidatorFS implements PrivValidator using data persisted to disk
......@@ -319,40 +323,58 @@ func (pv *PrivValidatorImp) SignNotify(chainID string, notify *Notify) error {
}
// SignCBInfo signs a canonical representation of the DposCBInfo, Implements PrivValidator.
func (pv *PrivValidatorImp) SignCBInfo(info *dty.DposCBInfo) error {
func (pv *PrivValidatorImp) SignMsg(msg []byte) (sig string, err error) {
pv.mtx.Lock()
defer pv.mtx.Unlock()
buf := new(bytes.Buffer)
info.Pubkey = hex.EncodeToString(pv.PubKey.Bytes())
canonical := dty.CanonicalOnceCBInfo{
Cycle: info.Cycle,
StopHeight: info.StopHeight,
StopHash: info.StopHash,
Pubkey: info.Pubkey,
}
byteCB, err := json.Marshal(&canonical)
if err != nil {
return errors.New(Fmt("Error marshal CanonicalOnceCBInfo: %v", err))
}
_, err = buf.Write(byteCB)
_, err = buf.Write(msg)
if err != nil {
return errors.New(Fmt("Error write buffer: %v", err))
return "", errors.New(Fmt("Error write buffer: %v", err))
}
signature := pv.PrivKey.Sign(buf.Bytes())
info.Signature = hex.EncodeToString(signature.Bytes())
return nil
sig = hex.EncodeToString(signature.Bytes())
return sig, nil
}
// SignTx signs a tx, Implements PrivValidator.
func (pv *PrivValidatorImp)SignTx(tx *types.Transaction){
tx.Sign(types.SECP256K1, pv.PrivKey)
}
// VrfEvaluate use input to generate hash & proof.
func (pv *PrivValidatorImp) VrfEvaluate(input []byte) (hash [32]byte, proof []byte) {
pv.mtx.Lock()
defer pv.mtx.Unlock()
privKey, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), pv.PrivKey.Bytes())
vrfPriv := &vrf.PrivateKey{PrivateKey: (*ecdsa.PrivateKey)(privKey)}
hash, proof = vrfPriv.Evaluate(input)
return hash, proof
}
func (pv *PrivValidatorImp) VrfProof(pubkey []byte, input []byte, hash [32]byte, proof []byte) bool {
pv.mtx.Lock()
defer pv.mtx.Unlock()
pubKey, err := secp256k1.ParsePubKey(pubkey, secp256k1.S256())
if err != nil {
return false
}
vrfPub := &vrf.PublicKey{PublicKey: (*ecdsa.PublicKey)(pubKey)}
vrfHash, err := vrfPub.ProofToHash(input, proof)
if err != nil {
return false
}
if bytes.Equal(hash[:], vrfHash[:]){
return true
}
return false
}
// Persist height/round/step and signature
func (pv *PrivValidatorImp) saveSigned(signBytes []byte, sig crypto.Signature) {
......
......@@ -12,12 +12,19 @@ import (
"math/rand"
ttypes "github.com/33cn/plugin/plugin/consensus/dpos/types"
dty "github.com/33cn/plugin/plugin/dapp/dposvote/types"
)
var (
r *rand.Rand
)
const (
ShuffleTypeNoVrf = iota
ShuffleTypeVrf
ShuffleTypePartVrf
)
// ValidatorMgr ...
type ValidatorMgr struct {
// Immutable
......@@ -28,7 +35,11 @@ type ValidatorMgr struct {
// Note that if s.LastBlockHeight causes a valset change,
// we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1
Validators *ttypes.ValidatorSet
VrfValidators *ttypes.ValidatorSet
NoVrfValidators *ttypes.ValidatorSet
LastCycleBoundaryInfo *dty.DposCBInfo
ShuffleCycle int64
ShuffleType int64 //0-no vrf 1-vrf 2-part vrf
// The latest AppHash we've received from calling abci.Commit()
AppHash []byte
}
......@@ -37,10 +48,19 @@ type ValidatorMgr struct {
func (s ValidatorMgr) Copy() ValidatorMgr {
return ValidatorMgr{
ChainID: s.ChainID,
Validators: s.Validators.Copy(),
AppHash: s.AppHash,
ShuffleCycle: s.ShuffleCycle,
ShuffleType: s.ShuffleType,
VrfValidators: s.VrfValidators.Copy(),
NoVrfValidators: s.NoVrfValidators.Copy(),
LastCycleBoundaryInfo: &dty.DposCBInfo{
Cycle: s.LastCycleBoundaryInfo.Cycle,
StopHeight: s.LastCycleBoundaryInfo.StopHeight,
StopHash: s.LastCycleBoundaryInfo.StopHash,
Pubkey: s.LastCycleBoundaryInfo.Pubkey,
Signature: s.LastCycleBoundaryInfo.Signature,
},
}
}
......@@ -97,3 +117,146 @@ func MakeGenesisValidatorMgr(genDoc *ttypes.GenesisDoc) (ValidatorMgr, error) {
AppHash: genDoc.AppHash,
}, nil
}
func (s *ValidatorMgr) GetValidatorByIndex(index int) (addres []byte, val *ttypes.Validator) {
if index < 0 || index >= len(s.Validators.Validators) {
return nil, nil
}
if s.ShuffleType == ShuffleTypeNoVrf {
val = s.Validators.Validators[index]
return val.Address, val.Copy()
} else if s.ShuffleType == ShuffleTypeVrf {
val = s.VrfValidators.Validators[index]
return address.PubKeyToAddress(val.PubKey).Hash160[:], val.Copy()
} else if s.ShuffleType == ShuffleTypePartVrf {
if index < len(s.VrfValidators.Validators) {
val = s.VrfValidators.Validators[index]
return address.PubKeyToAddress(val.PubKey).Hash160[:], val.Copy()
} else {
val = s.NoVrfValidators.Validators[index - len(s.VrfValidators.Validators)]
return address.PubKeyToAddress(val.PubKey).Hash160[:], val.Copy()
}
}
return nil, nil
}
func (s *ValidatorMgr) GetIndexByPubKey(pubkey []byte) (index int) {
if nil == pubkey {
return -1
}
index = -1
if s.ShuffleType == ShuffleTypeNoVrf {
for i := 0; i < s.Validators.Size(); i++ {
if bytes.Equal(s.Validators.Validators[i].PubKey, pubkey) {
index = i
return index
}
}
} else if s.ShuffleType == ShuffleTypeVrf {
for i := 0; i < s.VrfValidators.Size(); i++ {
if bytes.Equal(s.VrfValidators.Validators[i].PubKey, pubkey) {
index = i
return index
}
}
} else if s.ShuffleType == ShuffleTypePartVrf {
for i := 0; i < s.VrfValidators.Size(); i++ {
if bytes.Equal(s.VrfValidators.Validators[i].PubKey, pubkey) {
index = i
return index
}
}
for j := 0; j < s.NoVrfValidators.Size(); j++ {
if bytes.Equal(s.NoVrfValidators.Validators[j].PubKey, pubkey) {
index = j + s.VrfValidators.Size()
return index
}
}
}
return index
}
func (s *ValidatorMgr) FillVoteItem(voteItem *ttypes.VoteItem) {
voteItem.LastCBInfo = &ttypes.CycleBoundaryInfo{
Cycle: s.LastCycleBoundaryInfo.Cycle,
StopHeight: s.LastCycleBoundaryInfo.StopHeight,
StopHash: s.LastCycleBoundaryInfo.StopHash,
}
voteItem.ShuffleType = s.ShuffleType
for i := 0; i < s.Validators.Size(); i++ {
node := &ttypes.SuperNode{
PubKey: s.Validators.Validators[i].PubKey,
Address: s.Validators.Validators[i].Address,
}
voteItem.Validators = append(voteItem.Validators, node)
}
for i := 0; i < s.VrfValidators.Size(); i++ {
node := &ttypes.SuperNode{
PubKey: s.VrfValidators.Validators[i].PubKey,
Address: s.VrfValidators.Validators[i].Address,
}
voteItem.VrfValidators = append(voteItem.VrfValidators, node)
}
for i := 0; i < s.NoVrfValidators.Size(); i++ {
node := &ttypes.SuperNode{
PubKey: s.NoVrfValidators.Validators[i].PubKey,
Address: s.NoVrfValidators.Validators[i].Address,
}
voteItem.NoVrfValidators = append(voteItem.NoVrfValidators, node)
}
}
func (s *ValidatorMgr) UpdateFromVoteItem(voteItem *ttypes.VoteItem) bool {
validators := voteItem.Validators
for i := 0; i < s.Validators.Size(); i++ {
if !bytes.Equal(validators[i].PubKey, s.Validators.Validators[i].PubKey) {
return false
}
}
if s.LastCycleBoundaryInfo == nil ||
voteItem.LastCBInfo.Cycle != s.LastCycleBoundaryInfo.Cycle ||
voteItem.LastCBInfo.StopHeight != s.LastCycleBoundaryInfo.StopHeight ||
voteItem.LastCBInfo.StopHash != s.LastCycleBoundaryInfo.StopHash {
s.LastCycleBoundaryInfo = &dty.DposCBInfo{
Cycle: voteItem.LastCBInfo.Cycle,
StopHeight: voteItem.LastCBInfo.StopHeight,
StopHash: voteItem.LastCBInfo.StopHash,
}
}
var vrfVals []*ttypes.Validator
for i := 0; i < len(voteItem.VrfValidators); i++ {
val := &ttypes.Validator{
Address: voteItem.VrfValidators[i].Address,
PubKey: voteItem.VrfValidators[i].PubKey,
}
vrfVals = append(vrfVals, val)
}
s.VrfValidators = ttypes.NewValidatorSet(vrfVals)
var noVrfVals []*ttypes.Validator
for i := 0; i < len(voteItem.NoVrfValidators); i++ {
val := &ttypes.Validator{
Address: voteItem.NoVrfValidators[i].Address,
PubKey: voteItem.NoVrfValidators[i].PubKey,
}
noVrfVals = append(noVrfVals, val)
}
s.NoVrfValidators = ttypes.NewValidatorSet(noVrfVals)
return true
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment