X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=blobdiff_plain;f=protocol%2Fstate%2Fconsensus_result.go;h=d392e1c796aa7632fd72f254d0197d829b43952e;hp=ff08429cdc3edb900c955e76e4c63dafdc1a9de9;hb=e2c1a2332391eb4111e3158127f87d6f5f249d3c;hpb=73164af54a2587ba479b8b133274e3ecd0559a68 diff --git a/protocol/state/consensus_result.go b/protocol/state/consensus_result.go index ff08429c..d392e1c7 100644 --- a/protocol/state/consensus_result.go +++ b/protocol/state/consensus_result.go @@ -4,6 +4,8 @@ import ( "encoding/hex" "sort" + log "github.com/sirupsen/logrus" + "github.com/vapor/common/arithmetic" "github.com/vapor/config" "github.com/vapor/consensus" @@ -14,6 +16,17 @@ import ( "github.com/vapor/protocol/bc/types" ) +const logModule = "state/consensus" + +// fedConsensusPath is used to derive federation root xpubs for signing blocks +var fedConsensusPath = [][]byte{ + []byte{0xff, 0xff, 0xff, 0xff}, + []byte{0xff, 0x00, 0x00, 0x00}, + []byte{0xff, 0xff, 0xff, 0xff}, + []byte{0xff, 0x00, 0x00, 0x00}, + []byte{0xff, 0x00, 0x00, 0x00}, +} + // ConsensusNode represents a consensus node type ConsensusNode struct { XPub chainkd.XPub @@ -38,9 +51,11 @@ type CoinbaseReward struct { // SortByAmount implements sort.Interface for CoinbaseReward slices type SortByAmount []CoinbaseReward -func (a SortByAmount) Len() int { return len(a) } -func (a SortByAmount) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a SortByAmount) Less(i, j int) bool { return a[i].Amount < a[j].Amount } +func (a SortByAmount) Len() int { return len(a) } +func (a SortByAmount) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a SortByAmount) Less(i, j int) bool { + return a[i].Amount > a[j].Amount || (a[i].Amount == a[j].Amount && hex.EncodeToString(a[i].ControlProgram) > hex.EncodeToString(a[j].ControlProgram)) +} // CalCoinbaseReward calculate the coinbase reward for block func CalCoinbaseReward(block *types.Block) (*CoinbaseReward, error) { @@ -58,7 +73,11 @@ func CalCoinbaseReward(block *types.Block) (*CoinbaseReward, error) { return nil, errors.Wrap(checked.ErrOverflow, "calculate transaction fee") } - result.Amount += txFee + ok := false + result.Amount, ok = checked.AddUint64(result.Amount, txFee) + if !ok { + return nil, checked.ErrOverflow + } } return result, nil } @@ -98,39 +117,47 @@ func (c *ConsensusResult) ApplyBlock(block *types.Block) error { } for _, tx := range block.Transactions { - for _, input := range tx.Inputs { - vetoInput, ok := input.TypedInput.(*types.VetoInput) - if !ok { - continue - } + if err := c.ApplyTransaction(tx); err != nil { + return err + } + } - pubkey := hex.EncodeToString(vetoInput.Vote) - c.NumOfVote[pubkey], ok = checked.SubUint64(c.NumOfVote[pubkey], vetoInput.Amount) - if !ok { - return checked.ErrOverflow - } + c.BlockHash = block.Hash() + c.BlockHeight = block.Height + c.Seq = CalcVoteSeq(block.Height) + return nil +} - if c.NumOfVote[pubkey] == 0 { - delete(c.NumOfVote, pubkey) - } +// ApplyTransaction calculate the consensus result for transaction +func (c *ConsensusResult) ApplyTransaction(tx *types.Tx) error { + for _, input := range tx.Inputs { + vetoInput, ok := input.TypedInput.(*types.VetoInput) + if !ok { + continue } - for _, output := range tx.Outputs { - voteOutput, ok := output.TypedOutput.(*types.VoteOutput) - if !ok { - continue - } + pubkey := hex.EncodeToString(vetoInput.Vote) + c.NumOfVote[pubkey], ok = checked.SubUint64(c.NumOfVote[pubkey], vetoInput.Amount) + if !ok { + return checked.ErrOverflow + } - pubkey := hex.EncodeToString(voteOutput.Vote) - if c.NumOfVote[pubkey], ok = checked.AddUint64(c.NumOfVote[pubkey], voteOutput.Amount); !ok { - return checked.ErrOverflow - } + if c.NumOfVote[pubkey] == 0 { + delete(c.NumOfVote, pubkey) } } - c.BlockHash = block.Hash() - c.BlockHeight = block.Height - c.Seq = CalcVoteSeq(block.Height) + for _, output := range tx.Outputs { + voteOutput, ok := output.TypedOutput.(*types.VoteOutput) + if !ok { + continue + } + + pubkey := hex.EncodeToString(voteOutput.Vote) + if c.NumOfVote[pubkey], ok = checked.AddUint64(c.NumOfVote[pubkey], voteOutput.Amount); !ok { + return checked.ErrOverflow + } + } return nil } @@ -161,7 +188,9 @@ func (c *ConsensusResult) ConsensusNodes() (map[string]*ConsensusNode, error) { if voteNum >= consensus.ActiveNetParams.MinConsensusNodeVoteNum { var xpub chainkd.XPub if err := xpub.UnmarshalText([]byte(pubkey)); err != nil { - return nil, err + log.WithFields(log.Fields{"module": logModule, "err": err, "XPub": xpub.String()}).Debug("failed on unmarshal XPub") + delete(c.NumOfVote, pubkey) + continue } nodes = append(nodes, &ConsensusNode{XPub: xpub, VoteNum: voteNum}) @@ -232,16 +261,6 @@ func (c *ConsensusResult) DetachBlock(block *types.Block) error { // DetachCoinbaseReward detach coinbase reward func (c *ConsensusResult) DetachCoinbaseReward(block *types.Block) error { - if block.Height%consensus.ActiveNetParams.RoundVoteBlockNums == 0 { - for i, output := range block.Transactions[0].Outputs { - if i == 0 { - continue - } - program := output.ControlProgram() - c.CoinbaseReward[hex.EncodeToString(program)] = output.AssetAmount().Amount - } - } - reward, err := CalCoinbaseReward(block) if err != nil { return err @@ -256,6 +275,17 @@ func (c *ConsensusResult) DetachCoinbaseReward(block *types.Block) error { if c.CoinbaseReward[program] == 0 { delete(c.CoinbaseReward, program) } + + if block.Height%consensus.ActiveNetParams.RoundVoteBlockNums == 1 { + c.CoinbaseReward = map[string]uint64{} + for i, output := range block.Transactions[0].Outputs { + if i == 0 { + continue + } + program := output.ControlProgram() + c.CoinbaseReward[hex.EncodeToString(program)] = output.AssetAmount().Amount + } + } return nil } @@ -309,7 +339,8 @@ func (c *ConsensusResult) GetCoinbaseRewards(blockHeight uint64) ([]CoinbaseRewa func federationNodes() map[string]*ConsensusNode { consensusResult := map[string]*ConsensusNode{} for i, xpub := range config.CommonConfig.Federation.Xpubs { - consensusResult[xpub.String()] = &ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)} + derivedXPub := xpub.Derive(fedConsensusPath) + consensusResult[derivedXPub.String()] = &ConsensusNode{XPub: derivedXPub, VoteNum: 0, Order: uint64(i)} } return consensusResult }