aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/dexon-foundation
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-11-30 19:07:36 +0800
committerWei-Ning Huang <w@byzantine-lab.io>2019-06-12 17:27:19 +0800
commit8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da (patch)
treef4d86e8e631c78cbf498764a427b2fbdf88c9f86 /vendor/github.com/dexon-foundation
parent2777a457ba570455ef9641faf33f59852ea93d9e (diff)
downloadgo-tangerine-8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da.tar
go-tangerine-8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da.tar.gz
go-tangerine-8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da.tar.bz2
go-tangerine-8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da.tar.lz
go-tangerine-8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da.tar.xz
go-tangerine-8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da.tar.zst
go-tangerine-8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da.zip
vendor: update to latest core (#71)
Diffstat (limited to 'vendor/github.com/dexon-foundation')
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/common/types.go17
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go7
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go133
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go77
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go3
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go34
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go13
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go17
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go45
9 files changed, 118 insertions, 228 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go b/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go
index a5dfab10e..883492bf3 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go
@@ -15,23 +15,6 @@
// along with the dexon-consensus library. If not, see
// <http://www.gnu.org/licenses/>.
-// Copyright 2018 The dexon-consensus Authors
-// This file is part of the dexon-consensus library.
-//
-// The dexon-consensus library is free software: you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation, either version 3 of the License,
-// or (at your option) any later version.
-//
-// The dexon-consensus library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the dexon-consensus library. If not, see
-// <http://www.gnu.org/licenses/>.
-
package common
import (
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go
index f695e36cc..6f50bfc16 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go
@@ -387,7 +387,12 @@ Loop:
for {
nextHeight, err = mgr.lattice.NextHeight(recv.round, setting.chainID)
if err != nil {
- panic(err)
+ mgr.logger.Debug("Error getting next height",
+ "error", err,
+ "round", recv.round,
+ "chainID", setting.chainID)
+ err = nil
+ nextHeight = oldPos.Height
}
if isStop(oldPos) || nextHeight == 0 {
break
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go
index 20a7bdd4a..89ba978d0 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go
@@ -18,7 +18,6 @@
package core
import (
- "container/heap"
"fmt"
"sync"
"time"
@@ -50,40 +49,40 @@ type pendingRandomnessResult struct {
type finalizedBlockHeap = types.ByFinalizationHeight
type compactionChain struct {
- gov Governance
- chainUnsynced uint32
- tsigVerifier *TSigVerifierCache
- blocks map[common.Hash]*types.Block
- blockRandomness map[common.Hash][]byte
- pendingRandomness map[common.Hash]pendingRandomnessResult
- pendingBlocks []*types.Block
- pendingFinalizedBlocks *finalizedBlockHeap
- lock sync.RWMutex
- prevBlock *types.Block
+ gov Governance
+ chainUnsynced uint32
+ tsigVerifier *TSigVerifierCache
+ blocks map[common.Hash]*types.Block
+ blockRandomness map[common.Hash][]byte
+ pendingRandomness map[common.Hash]pendingRandomnessResult
+ pendingBlocks []*types.Block
+ lock sync.RWMutex
+ prevBlock *types.Block
}
func newCompactionChain(gov Governance) *compactionChain {
- pendingFinalizedBlocks := &finalizedBlockHeap{}
- heap.Init(pendingFinalizedBlocks)
return &compactionChain{
- gov: gov,
- tsigVerifier: NewTSigVerifierCache(gov, 7),
- blocks: make(map[common.Hash]*types.Block),
- blockRandomness: make(map[common.Hash][]byte),
- pendingRandomness: make(map[common.Hash]pendingRandomnessResult),
- pendingFinalizedBlocks: pendingFinalizedBlocks,
+ gov: gov,
+ tsigVerifier: NewTSigVerifierCache(gov, 7),
+ blocks: make(map[common.Hash]*types.Block),
+ blockRandomness: make(map[common.Hash][]byte),
+ pendingRandomness: make(map[common.Hash]pendingRandomnessResult),
}
}
+// init the compaction chain module with a finalized block, or just an empty
+// block for bootstrap case.
func (cc *compactionChain) init(initBlock *types.Block) {
cc.lock.Lock()
defer cc.lock.Unlock()
cc.prevBlock = initBlock
cc.pendingBlocks = []*types.Block{}
+ // It's the bootstrap case, compactionChain would only deliver blocks until
+ // tips of all chains are received.
if initBlock.Finalization.Height == 0 {
cc.chainUnsynced = cc.gov.Configuration(uint64(0)).NumChains
- cc.pendingBlocks = append(cc.pendingBlocks, initBlock)
}
+ cc.pendingBlocks = append(cc.pendingBlocks, initBlock)
}
func (cc *compactionChain) registerBlock(block *types.Block) {
@@ -190,16 +189,14 @@ func (cc *compactionChain) verifyRandomness(
Signature: randomness}), nil
}
-func (cc *compactionChain) processFinalizedBlock(block *types.Block) {
+func (cc *compactionChain) processFinalizedBlock(block *types.Block) error {
if block.Finalization.Height <= cc.lastBlock().Finalization.Height {
- return
+ return nil
}
-
// Block of round 0 should not have randomness.
if block.Position.Round == 0 && len(block.Finalization.Randomness) != 0 {
- return
+ return nil
}
-
cc.lock.Lock()
defer cc.lock.Unlock()
// The randomness result is missed previously.
@@ -207,95 +204,13 @@ func (cc *compactionChain) processFinalizedBlock(block *types.Block) {
ok, err := cc.verifyRandomness(
block.Hash, block.Position.Round, block.Finalization.Randomness)
if err != nil {
- panic(err)
+ return err
}
if ok {
cc.blockRandomness[block.Hash] = block.Finalization.Randomness
}
- return
- }
-
- heap.Push(cc.pendingFinalizedBlocks, block)
-
- return
-}
-
-func (cc *compactionChain) extractFinalizedBlocks() []*types.Block {
- prevBlock := cc.lastBlock()
-
- blocks := func() []*types.Block {
- cc.lock.Lock()
- defer cc.lock.Unlock()
- blocks := []*types.Block{}
- prevHeight := prevBlock.Finalization.Height
- for cc.pendingFinalizedBlocks.Len() != 0 {
- tip := (*cc.pendingFinalizedBlocks)[0]
- // Pop blocks that are already confirmed.
- if tip.Finalization.Height <= prevBlock.Finalization.Height {
- heap.Pop(cc.pendingFinalizedBlocks)
- continue
- }
- // Since we haven't verified the finalized block,
- // it is possible to be forked.
- if tip.Finalization.Height == prevHeight ||
- tip.Finalization.Height == prevHeight+1 {
- prevHeight = tip.Finalization.Height
- blocks = append(blocks, tip)
- heap.Pop(cc.pendingFinalizedBlocks)
- } else {
- break
- }
- }
- return blocks
- }()
- toPending := []*types.Block{}
- confirmed := []*types.Block{}
- for _, b := range blocks {
- if b.Hash == prevBlock.Hash &&
- b.Finalization.Height == prevBlock.Finalization.Height {
- continue
- }
- ok, err := cc.verifyRandomness(
- b.Hash, b.Position.Round, b.Finalization.Randomness)
- if err != nil {
- toPending = append(toPending, b)
- continue
- }
- if !ok {
- continue
- }
- // Fork resolution: choose block with smaller hash.
- if prevBlock.Finalization.Height == b.Finalization.Height {
- //TODO(jimmy-dexon): remove this panic after test.
- if true {
- // workaround to `go vet` error
- panic(fmt.Errorf(
- "forked finalized block %s,%s", prevBlock.Hash, b.Hash))
- }
- if b.Hash.Less(prevBlock.Hash) {
- confirmed = confirmed[:len(confirmed)-1]
- } else {
- continue
- }
- }
- if b.Finalization.Height-prevBlock.Finalization.Height > 1 {
- toPending = append(toPending, b)
- continue
- }
- confirmed = append(confirmed, b)
- prevBlock = b
}
- cc.lock.Lock()
- defer cc.lock.Unlock()
- if len(confirmed) != 0 && cc.prevBlock.Finalization.Height == 0 {
- // Pop the initBlock inserted when bootstrapping.
- cc.pendingBlocks = cc.pendingBlocks[1:]
- }
- cc.prevBlock = prevBlock
- for _, b := range toPending {
- heap.Push(cc.pendingFinalizedBlocks, b)
- }
- return confirmed
+ return nil
}
func (cc *compactionChain) processBlockRandomnessResult(
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go
index af4041766..253c9a59f 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go
@@ -401,7 +401,7 @@ func NewConsensus(
ID: ID,
ccModule: newCompactionChain(gov),
lattice: lattice,
- app: app,
+ app: newNonBlocking(app, debugApp),
gov: gov,
db: db,
network: network,
@@ -639,9 +639,9 @@ func (con *Consensus) initialRound(
// Stop the Consensus core.
func (con *Consensus) Stop() {
+ con.ctxCancel()
con.baMgr.stop()
con.event.Reset()
- con.ctxCancel()
}
func (con *Consensus) processMsg(msgChan <-chan interface{}) {
@@ -761,44 +761,9 @@ func (con *Consensus) ProcessVote(vote *types.Vote) (err error) {
func (con *Consensus) ProcessAgreementResult(
rand *types.AgreementResult) error {
// Sanity Check.
- notarySet, err := con.nodeSetCache.GetNotarySet(
- rand.Position.Round, rand.Position.ChainID)
- if err != nil {
+ if err := VerifyAgreementResult(rand, con.nodeSetCache); err != nil {
return err
}
- if len(rand.Votes) < len(notarySet)/3*2+1 {
- return ErrNotEnoughVotes
- }
- if len(rand.Votes) > len(notarySet) {
- return ErrIncorrectVoteProposer
- }
- for _, vote := range rand.Votes {
- if rand.IsEmptyBlock {
- if (vote.BlockHash != common.Hash{}) {
- return ErrIncorrectVoteBlockHash
- }
- } else {
- if vote.BlockHash != rand.BlockHash {
- return ErrIncorrectVoteBlockHash
- }
- }
- if vote.Type != types.VoteCom {
- return ErrIncorrectVoteType
- }
- if vote.Position != rand.Position {
- return ErrIncorrectVotePosition
- }
- if _, exist := notarySet[vote.ProposerID]; !exist {
- return ErrIncorrectVoteProposer
- }
- ok, err := verifyVoteSignature(&vote)
- if err != nil {
- return err
- }
- if !ok {
- return ErrIncorrectVoteSignature
- }
- }
// Syncing BA Module.
if err := con.baMgr.processAgreementResult(rand); err != nil {
return err
@@ -956,39 +921,9 @@ func (con *Consensus) processBlock(block *types.Block) (err error) {
return
}
-// processFinalizedBlock is the entry point for syncing blocks.
-func (con *Consensus) processFinalizedBlock(block *types.Block) (err error) {
- if err = con.lattice.SanityCheck(block); err != nil {
- if err != ErrRetrySanityCheckLater {
- return
- }
- err = nil
- }
- con.ccModule.processFinalizedBlock(block)
- for {
- confirmed := con.ccModule.extractFinalizedBlocks()
- if len(confirmed) == 0 {
- break
- }
- if err = con.lattice.ctModule.processBlocks(confirmed); err != nil {
- return
- }
- for _, b := range confirmed {
- if err = con.db.Put(*b); err != nil {
- if err != blockdb.ErrBlockExists {
- return
- }
- err = nil
- }
- con.lattice.ProcessFinalizedBlock(b)
- // TODO(jimmy): BlockConfirmed and DeliverBlock may not be removed if
- // application implements state snapshot.
- con.logger.Debug("Calling Application.BlockConfirmed", "block", b)
- con.app.BlockConfirmed(*b.Clone())
- con.deliverBlock(b)
- }
- }
- return
+// processFinalizedBlock is the entry point for handling finalized blocks.
+func (con *Consensus) processFinalizedBlock(block *types.Block) error {
+ return con.ccModule.processFinalizedBlock(block)
}
// PrepareBlock would setup header fields of block based on its ProposerID.
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go
index e07476d44..69798540f 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go
@@ -49,9 +49,6 @@ type Application interface {
// Debug describes the application interface that requires
// more detailed consensus execution.
type Debug interface {
- // StronglyAcked is called when a block is strongly acked.
- StronglyAcked(blockHash common.Hash)
-
// TotalOrderingDelivered is called when the total ordering algorithm deliver
// a set of block.
TotalOrderingDelivered(common.Hashes, uint32)
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go
index f76813d82..e578e3f4f 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go
@@ -39,7 +39,6 @@ type Lattice struct {
app Application
debug Debug
pool blockPool
- retryAdd bool
data *latticeData
toModule *totalOrdering
ctModule *consensusTimestamp
@@ -64,7 +63,7 @@ func NewLattice(
debug: debug,
pool: newBlockPool(cfg.NumChains),
data: newLatticeData(db, dMoment, round, cfg),
- toModule: newTotalOrdering(dMoment, cfg),
+ toModule: newTotalOrdering(dMoment, round, cfg),
ctModule: newConsensusTimestamp(dMoment, round, cfg.NumChains),
logger: logger,
}
@@ -211,10 +210,6 @@ func (l *Lattice) addBlockToLattice(
}
for _, b := range outputBlocks {
- // TODO(jimmy-dexon): change this name of classic DEXON algorithm.
- if l.debug != nil {
- l.debug.StronglyAcked(b.Hash)
- }
l.logger.Debug("Calling Application.BlockConfirmed", "block", b)
l.app.BlockConfirmed(*b.Clone())
// Purge blocks in pool with the same chainID and lower height.
@@ -310,4 +305,31 @@ func (l *Lattice) AppendConfig(round uint64, config *types.Config) (err error) {
// ProcessFinalizedBlock is used for syncing lattice data.
func (l *Lattice) ProcessFinalizedBlock(b *types.Block) {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+ // Syncing state for core.latticeData module.
+ if err := l.data.addFinalizedBlock(b); err != nil {
+ panic(err)
+ }
+ l.pool.purgeBlocks(b.Position.ChainID, b.Position.Height)
+ // Syncing state for core.totalOrdering module.
+ toDelivered, deliveredMode, err := l.toModule.processBlock(b)
+ if err != nil {
+ panic(err)
+ }
+ if len(toDelivered) == 0 {
+ return
+ }
+ hashes := make(common.Hashes, len(toDelivered))
+ for idx := range toDelivered {
+ hashes[idx] = toDelivered[idx].Hash
+ }
+ if l.debug != nil {
+ l.debug.TotalOrderingDelivered(hashes, deliveredMode)
+ }
+ // Sync core.consensusTimestamp module.
+ if err = l.ctModule.processBlocks(toDelivered); err != nil {
+ panic(err)
+ }
+ return
}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go
index a73331fae..f94d3c631 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go
@@ -29,10 +29,6 @@ type blockConfirmedEvent struct {
block *types.Block
}
-type stronglyAckedEvent struct {
- blockHash common.Hash
-}
-
type totalOrderingDeliveredEvent struct {
blockHashes common.Hashes
mode uint32
@@ -93,8 +89,6 @@ func (nb *nonBlocking) run() {
nb.running.Add(1)
}()
switch e := event.(type) {
- case stronglyAckedEvent:
- nb.debug.StronglyAcked(e.blockHash)
case blockConfirmedEvent:
nb.app.BlockConfirmed(*e.block)
case totalOrderingDeliveredEvent:
@@ -139,13 +133,6 @@ func (nb *nonBlocking) BlockConfirmed(block types.Block) {
nb.addEvent(blockConfirmedEvent{&block})
}
-// StronglyAcked is called when a block is strongly acked.
-func (nb *nonBlocking) StronglyAcked(blockHash common.Hash) {
- if nb.debug != nil {
- nb.addEvent(stronglyAckedEvent{blockHash})
- }
-}
-
// TotalOrderingDelivered is called when the total ordering algorithm deliver
// a set of block.
func (nb *nonBlocking) TotalOrderingDelivered(
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go
index 90848ce7a..52f927005 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go
@@ -44,9 +44,9 @@ const (
)
var (
- // ErrNotValidDAG would be reported when block subbmitted to totalOrdering
+ // ErrInvalidDAG is reported when block subbmitted to totalOrdering
// didn't form a DAG.
- ErrNotValidDAG = errors.New("not a valid dag")
+ ErrInvalidDAG = errors.New("invalid dag")
// ErrFutureRoundDelivered means some blocks from later rounds are
// delivered, this means program error.
ErrFutureRoundDelivered = errors.New("future round delivered")
@@ -347,7 +347,7 @@ func (v *totalOrderingCandidateInfo) addBlock(b *types.Block) error {
rec.count = 1
} else {
if b.Position.Height <= rec.minHeight {
- return ErrNotValidDAG
+ return ErrInvalidDAG
}
rec.count++
}
@@ -640,12 +640,12 @@ func (global *totalOrderingGlobalVector) addBlock(
if tip != nil {
// Perform light weight sanity check based on tip.
if tip.Position.Round > b.Position.Round {
- err = ErrNotValidDAG
+ err = ErrInvalidDAG
return
}
if DiffUint64(tip.Position.Round, b.Position.Round) > 1 {
if b.Position.Height != 0 {
- err = ErrNotValidDAG
+ err = ErrInvalidDAG
return
}
// Add breakpoint.
@@ -657,7 +657,7 @@ func (global *totalOrderingGlobalVector) addBlock(
})
} else {
if b.Position.Height != tip.Position.Height+1 {
- err = ErrNotValidDAG
+ err = ErrInvalidDAG
return
}
}
@@ -792,9 +792,9 @@ type totalOrdering struct {
}
// newTotalOrdering constructs an totalOrdering instance.
-func newTotalOrdering(dMoment time.Time, cfg *types.Config) *totalOrdering {
+func newTotalOrdering(dMoment time.Time, round uint64, cfg *types.Config) *totalOrdering {
config := &totalOrderingConfig{}
- config.fromConfig(0, cfg)
+ config.fromConfig(round, cfg)
config.setRoundBeginTime(dMoment)
candidates := make([]*totalOrderingCandidateInfo, config.numChains)
to := &totalOrdering{
@@ -816,6 +816,7 @@ func newTotalOrdering(dMoment time.Time, cfg *types.Config) *totalOrdering {
// round R, next time you can only add the config for round R+1.
func (to *totalOrdering) appendConfig(
round uint64, config *types.Config) error {
+
if round != uint64(len(to.configs))+to.configs[0].roundID {
return ErrRoundNotIncreasing
}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go
index 441aac174..bc5e33636 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go
@@ -167,6 +167,51 @@ func VerifyBlock(b *types.Block) (err error) {
return
}
+// VerifyAgreementResult perform sanity check against a types.AgreementResult
+// instance.
+func VerifyAgreementResult(
+ res *types.AgreementResult, cache *utils.NodeSetCache) error {
+ notarySet, err := cache.GetNotarySet(
+ res.Position.Round, res.Position.ChainID)
+ if err != nil {
+ return err
+ }
+ if len(res.Votes) < len(notarySet)/3*2+1 {
+ return ErrNotEnoughVotes
+ }
+ if len(res.Votes) > len(notarySet) {
+ return ErrIncorrectVoteProposer
+ }
+ for _, vote := range res.Votes {
+ if res.IsEmptyBlock {
+ if (vote.BlockHash != common.Hash{}) {
+ return ErrIncorrectVoteBlockHash
+ }
+ } else {
+ if vote.BlockHash != res.BlockHash {
+ return ErrIncorrectVoteBlockHash
+ }
+ }
+ if vote.Type != types.VoteCom {
+ return ErrIncorrectVoteType
+ }
+ if vote.Position != res.Position {
+ return ErrIncorrectVotePosition
+ }
+ if _, exist := notarySet[vote.ProposerID]; !exist {
+ return ErrIncorrectVoteProposer
+ }
+ ok, err := verifyVoteSignature(&vote)
+ if err != nil {
+ return err
+ }
+ if !ok {
+ return ErrIncorrectVoteSignature
+ }
+ }
+ return nil
+}
+
// DiffUint64 calculates difference between two uint64.
func DiffUint64(a, b uint64) uint64 {
if a > b {