m.Handle("/get-merkle-proof", jsonHandler(a.getMerkleProof))
+ m.Handle("/get-vote-result", jsonHandler(a.getVoteResult))
+
m.HandleFunc("/websocket-subscribe", a.websocketHandler)
handler := walletHandler(m, walletEnable)
--- /dev/null
+package api
+
+import (
+ "sort"
+
+ chainjson "github.com/vapor/encoding/json"
+)
+
+type voteInfo struct {
+ Vote string `json:"vote"`
+ VoteNum uint64 `json:"vote_number"`
+}
+
+type voteInfoSlice []*voteInfo
+func (v voteInfoSlice) Len() int { return len(v) }
+func (v voteInfoSlice) Less(i, j int) bool { return v[i].VoteNum > v[j].VoteNum }
+func (v voteInfoSlice) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
+
+func (a *API) getVoteResult(req struct {
+ BlockHash chainjson.HexBytes `json:"block_hash"`
+ BlockHeight uint64 `json:"block_height"`
+}) Response {
+ blockHash := hexBytesToHash(req.BlockHash)
+ if len(req.BlockHash) != 32 {
+ blockHeader, err := a.chain.GetHeaderByHeight(req.BlockHeight)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ blockHash = blockHeader.Hash()
+ }
+
+ voteResult, err := a.chain.GetVoteResultByHash(&blockHash)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ voteInfos := []*voteInfo{}
+ for pubKey, voteNum := range voteResult.NumOfVote {
+ voteInfos = append(voteInfos, &voteInfo{
+ Vote: pubKey,
+ VoteNum: voteNum,
+ })
+ }
+ sort.Sort(voteInfoSlice(voteInfos))
+ return NewSuccessResponse(voteInfos)
+}
return signCount > len(consensusNodes)*2/3
}
-// NextLeaderTime returns the start time of the specified public key as the next leader node
+// GetVoteResultByHash return vote result by block hash
+func (c *Chain) GetVoteResultByHash(blockHash *bc.Hash) (*state.VoteResult, error) {
+ blockNode := c.index.GetNode(blockHash)
+ return c.consensusNodeManager.getVoteResult(state.CalcVoteSeq(blockNode.Height), blockNode)
+}
+
+// IsBlocker returns whether the consensus node is a blocker at the specified time
func (c *Chain) IsBlocker(prevBlockHash *bc.Hash, pubkey string, timeStamp uint64) (bool, error) {
return c.consensusNodeManager.isBlocker(prevBlockHash, pubkey, timeStamp)
}
package protocol
import (
- "github.com/vapor/config"
"github.com/vapor/consensus"
"github.com/vapor/errors"
"github.com/vapor/protocol/bc"
preSeq = bestSeq
}
- voteResult, err := c.store.GetVoteResult(preSeq)
- if err != nil {
- return nil, err
- }
-
lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash)
if err != nil {
return nil, err
}
- if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil {
- return nil, err
- }
-
- result, err := voteResult.ConsensusNodes()
+ voteResult, err := c.getVoteResult(preSeq, lastBlockNode)
if err != nil {
return nil, err
}
- if len(result) != 0 {
- return result, nil
- }
- return federationNodes(), nil
+ return voteResult.ConsensusNodes()
}
func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) {
blockNode := c.blockIndex.BestNode()
seq := state.CalcVoteSeq(blockNode.Height)
+ return c.getVoteResult(seq, blockNode)
+}
+
+// getVoteResult return the vote result
+// seq represent the sequence of vote
+// blockNode represent the chain in which the result of the vote is located
+// Voting results need to be adjusted according to the chain
+func (c *consensusNodeManager) getVoteResult(seq uint64, blockNode *state.BlockNode) (*state.VoteResult, error) {
voteResult, err := c.store.GetVoteResult(seq)
if err != nil {
return nil, err
mainChainNode := c.blockIndex.GetNode(&voteResult.BlockHash)
var attachNodes []*state.BlockNode
var detachNodes []*state.BlockNode
- for forkChainNode := node; mainChainNode != forkChainNode; forkChainNode = forkChainNode.Parent {
- if forkChainNode.Height == mainChainNode.Height {
+ for forkChainNode := node; mainChainNode != forkChainNode; {
+ var forChainRollback, mainChainRollBack bool
+ if forChainRollback = forkChainNode.Height >= mainChainNode.Height; forChainRollback {
+ attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
+ }
+ if mainChainRollBack = forkChainNode.Height <= mainChainNode.Height; mainChainRollBack {
detachNodes = append(detachNodes, mainChainNode)
+ }
+ if forChainRollback {
+ forkChainNode = forkChainNode.Parent
+ }
+ if mainChainRollBack {
mainChainNode = mainChainNode.Parent
}
- attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
}
for _, node := range detachNodes {
}
return nil
}
-
-func federationNodes() map[string]*state.ConsensusNode {
- voteResult := map[string]*state.ConsensusNode{}
- for i, xpub := range config.CommonConfig.Federation.Xpubs {
- voteResult[xpub.String()] = &state.ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)}
- }
- return voteResult
-}
"sort"
"github.com/vapor/consensus"
+ "github.com/vapor/config"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/errors"
"github.com/vapor/math/checked"
nodes[i].Order = uint64(i)
result[nodes[i].XPub.String()] = nodes[i]
}
- return result, nil
+
+ if len(result) != 0 {
+ return result, nil
+ }
+ return federationNodes(), nil
+}
+
+func federationNodes() map[string]*ConsensusNode {
+ voteResult := map[string]*ConsensusNode{}
+ for i, xpub := range config.CommonConfig.Federation.Xpubs {
+ voteResult[xpub.String()] = &ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)}
+ }
+ return voteResult
}
func (v *VoteResult) DetachBlock(block *types.Block) error {
type voteDetail struct {
Vote string `json:"vote"`
- VoteAmount uint64 `json:"vote_amount"`
+ VoteNumber uint64 `json:"vote_number"`
}
// AccountVotes account vote
type AccountVotes struct {
AccountID string `json:"account_id"`
Alias string `json:"account_alias"`
- TotalVoteAmount uint64 `json:"total_vote_amount"`
+ TotalVoteNumber uint64 `json:"total_vote_number"`
VoteDetails []voteDetail `json:"vote_details"`
}
for _, xpub := range sortedXpub {
voteDetails = append(voteDetails, voteDetail{
Vote: xpub,
- VoteAmount: accVote[id][xpub],
+ VoteNumber: accVote[id][xpub],
})
voteTotal += accVote[id][xpub]
}
Alias: alias,
AccountID: id,
VoteDetails: voteDetails,
- TotalVoteAmount: voteTotal,
+ TotalVoteNumber: voteTotal,
})
}