OSDN Git Service

mov some logic to tree folder (#2019)
authorPaladz <yzhu101@uottawa.ca>
Wed, 7 Jul 2021 02:21:21 +0000 (10:21 +0800)
committerGitHub <noreply@github.com>
Wed, 7 Jul 2021 02:21:21 +0000 (10:21 +0800)
* mov some logic to tree folder

* less code

* fix bug

* edit parameter name

* elegant

* edit for code review

Co-authored-by: paladz <colt@ColtdeMacBook-Pro.local>
protocol/casper/apply_block.go
protocol/casper/auth_verification.go
protocol/casper/casper.go
protocol/casper/casper_test.go
protocol/casper/tree_node.go

index f180699..419419b 100644 (file)
@@ -61,11 +61,11 @@ func (c *Casper) applyBlockToCheckpoint(block *types.Block) (*state.Checkpoint,
                return nil, err
        }
 
-       checkpoint := node.checkpoint
+       checkpoint := node.Checkpoint
        if mod := block.Height % consensus.ActiveNetParams.BlocksOfEpoch; mod == 1 {
                parent := checkpoint
                checkpoint = state.NewCheckpoint(parent)
-               node.addChild(&treeNode{checkpoint: checkpoint})
+               node.addChild(&treeNode{Checkpoint: checkpoint})
        }
 
        return checkpoint, checkpoint.Increase(block)
@@ -103,10 +103,10 @@ func (c *Casper) replayCheckpoint(hash bc.Hash) (*treeNode, error) {
                return nil, err
        }
 
-       node := &treeNode{checkpoint: state.NewCheckpoint(parent.checkpoint)}
+       node := &treeNode{Checkpoint: state.NewCheckpoint(parent.Checkpoint)}
        parent.addChild(node)
        for _, attachBlock := range attachBlocks {
-               if err := node.checkpoint.Increase(attachBlock); err != nil {
+               if err := node.Increase(attachBlock); err != nil {
                        return nil, err
                }
        }
index 8368113..e69abda 100644 (file)
@@ -23,7 +23,7 @@ func (c *Casper) AuthVerification(v *Verification) error {
        defer c.mu.Unlock()
 
        // root of tree is the last finalized checkpoint
-       if v.TargetHeight < c.tree.checkpoint.Height {
+       if v.TargetHeight < c.tree.Height {
                // discard the verification message which height of target less than height of last finalized checkpoint
                // is for simplify check the vote within the span of its other votes
                return nil
@@ -44,12 +44,12 @@ func (c *Casper) AuthVerification(v *Verification) error {
                return errPubKeyIsNotValidator
        }
 
-       if targetNode.checkpoint.ContainsVerification(validators[v.PubKey].Order, &v.SourceHash) {
+       if targetNode.ContainsVerification(validators[v.PubKey].Order, &v.SourceHash) {
                return nil
        }
 
        oldBestHash := c.bestChain()
-       if err := c.authVerification(v, targetNode.checkpoint, validators); err != nil {
+       if err := c.authVerification(v, targetNode.Checkpoint, validators); err != nil {
                return err
        }
 
@@ -121,8 +121,8 @@ func (c *Casper) setFinalized(checkpoint *state.Checkpoint) {
        }
 
        // update the checkpoint state in memory
-       newRoot.checkpoint.Status = state.Finalized
-       newRoot.checkpoint.Parent = nil
+       newRoot.Status = state.Finalized
+       newRoot.Parent = nil
        c.tree = newRoot
 }
 
index d0b098f..79ad78d 100644 (file)
@@ -31,15 +31,17 @@ type RollbackMsg struct {
 // Casper is BFT based proof of stack consensus algorithm, it provides safety and liveness in theory,
 // it's design mainly refers to https://github.com/ethereum/research/blob/master/papers/casper-basics/casper_basics.pdf
 type Casper struct {
-       mu         sync.RWMutex
-       tree       *treeNode
-       rollbackCh chan *RollbackMsg
-       newEpochCh chan bc.Hash
-       store      state.Store
+       mu    sync.RWMutex
+       store state.Store
+       tree  *treeNode
+
        // block hash -> previous checkpoint hash
        prevCheckpointCache *common.Cache
        // block hash + pubKey -> verification
        verificationCache *common.Cache
+
+       rollbackCh chan *RollbackMsg
+       newEpochCh chan bc.Hash
 }
 
 // NewCasper create a new instance of Casper
@@ -52,12 +54,12 @@ func NewCasper(store state.Store, checkpoints []*state.Checkpoint, rollbackCh ch
        }
 
        casper := &Casper{
-               tree:                makeTree(checkpoints[0], checkpoints[1:]),
-               rollbackCh:          rollbackCh,
-               newEpochCh:          make(chan bc.Hash),
                store:               store,
+               tree:                makeTree(checkpoints[0], checkpoints[1:]),
                prevCheckpointCache: common.NewCache(1024),
                verificationCache:   common.NewCache(1024),
+               rollbackCh:          rollbackCh,
+               newEpochCh:          make(chan bc.Hash),
        }
        go casper.authVerificationLoop()
        return casper
@@ -68,7 +70,7 @@ func (c *Casper) LastFinalized() (uint64, bc.Hash) {
        c.mu.RLock()
        defer c.mu.RUnlock()
 
-       root := c.tree.checkpoint
+       root := c.tree.Checkpoint
        return root.Height, root.Hash
 }
 
@@ -76,8 +78,8 @@ func (c *Casper) LastFinalized() (uint64, bc.Hash) {
 func (c *Casper) LastJustified() (uint64, bc.Hash) {
        c.mu.RLock()
        defer c.mu.RUnlock()
-
-       return lastJustified(c.tree)
+       node := c.tree.lastJustified()
+       return node.Height, node.Hash
 }
 
 // Validators return the validators by specified block hash
@@ -111,41 +113,8 @@ func (c *Casper) ParentCheckpointByPrevHash(prevBlockHash *bc.Hash) (*state.Chec
 
 func (c *Casper) bestChain() bc.Hash {
        // root is init justified
-       root := c.tree.checkpoint
-       _, bestHash, _ := chainOfMaxJustifiedHeight(c.tree, root.Height)
-       return bestHash
-}
-
-func lastJustified(node *treeNode) (uint64, bc.Hash) {
-       lastJustifiedHeight, lastJustifiedHash := uint64(0), bc.Hash{}
-       if node.checkpoint.Status == state.Justified {
-               lastJustifiedHeight, lastJustifiedHash = node.checkpoint.Height, node.checkpoint.Hash
-       }
-
-       for _, child := range node.children {
-               if justifiedHeight, justifiedHash := lastJustified(child); justifiedHeight > lastJustifiedHeight {
-                       lastJustifiedHeight, lastJustifiedHash = justifiedHeight, justifiedHash
-               }
-       }
-       return lastJustifiedHeight, lastJustifiedHash
-}
-
-// justifiedHeight is the max justified height of checkpoint from node to root
-func chainOfMaxJustifiedHeight(node *treeNode, justifiedHeight uint64) (uint64, bc.Hash, uint64) {
-       checkpoint := node.checkpoint
-       if checkpoint.Status == state.Justified {
-               justifiedHeight = checkpoint.Height
-       }
-
-       bestHeight, bestHash, maxJustifiedHeight := checkpoint.Height, checkpoint.Hash, justifiedHeight
-       for _, child := range node.children {
-               height, hash, justified := chainOfMaxJustifiedHeight(child, justifiedHeight)
-               if justified > maxJustifiedHeight || (justified == maxJustifiedHeight && height > bestHeight) ||
-                       (justified == maxJustifiedHeight && height == bestHeight && hash.String() > bestHash.String()) {
-                       bestHeight, bestHash, maxJustifiedHeight = height, hash, justified
-               }
-       }
-       return bestHeight, bestHash, maxJustifiedHeight
+       bestNode, _ := c.tree.bestNode(c.tree.Height)
+       return bestNode.Hash
 }
 
 func (c *Casper) parentCheckpointHash(blockHash *bc.Hash) (*bc.Hash, error) {
index 9a22fc5..4e123f4 100644 (file)
@@ -17,7 +17,7 @@ func TestBestChain(t *testing.T) {
                {
                        desc: "only root node",
                        tree: &treeNode{
-                               checkpoint: &state.Checkpoint{
+                               Checkpoint: &state.Checkpoint{
                                        Height: 0,
                                        Hash:   testutil.MustDecodeHash("f5d687e6a5b60fb533c4296e55260803c54e70ad4898682541da15e894971769"),
                                        Status: state.Justified,
@@ -28,28 +28,28 @@ func TestBestChain(t *testing.T) {
                {
                        desc: "best chain is not the longest chain",
                        tree: &treeNode{
-                               checkpoint: &state.Checkpoint{
+                               Checkpoint: &state.Checkpoint{
                                        Height: 0,
                                        Hash:   testutil.MustDecodeHash("f5d687e6a5b60fb533c4296e55260803c54e70ad4898682541da15e894971769"),
                                        Status: state.Finalized,
                                },
                                children: []*treeNode{
                                        {
-                                               checkpoint: &state.Checkpoint{
+                                               Checkpoint: &state.Checkpoint{
                                                        Height: 5,
                                                        Hash:   testutil.MustDecodeHash("750408823bea9666f263870daded75d8f3d878606ec103bc9401b73714d77729"),
                                                        Status: state.Justified,
                                                },
                                        },
                                        {
-                                               checkpoint: &state.Checkpoint{
+                                               Checkpoint: &state.Checkpoint{
                                                        Height: 5,
                                                        Hash:   testutil.MustDecodeHash("049f012c12b94d34b13163eddbd31866f97b38c5b742e4c170a44d80ff503166"),
                                                        Status: state.Unjustified,
                                                },
                                                children: []*treeNode{
                                                        {
-                                                               checkpoint: &state.Checkpoint{
+                                                               Checkpoint: &state.Checkpoint{
                                                                        Height: 8,
                                                                        Hash:   testutil.MustDecodeHash("8315f5337978076b3097230570484e36586ee27564ebcbf74c2093cd763e32e7"),
                                                                        Status: state.Growing,
@@ -64,21 +64,21 @@ func TestBestChain(t *testing.T) {
                {
                        desc: "two distinct chain has same justified height, the longest chain is the best chain",
                        tree: &treeNode{
-                               checkpoint: &state.Checkpoint{
+                               Checkpoint: &state.Checkpoint{
                                        Height: 0,
                                        Hash:   testutil.MustDecodeHash("f5d687e6a5b60fb533c4296e55260803c54e70ad4898682541da15e894971769"),
                                        Status: state.Justified,
                                },
                                children: []*treeNode{
                                        {
-                                               checkpoint: &state.Checkpoint{
+                                               Checkpoint: &state.Checkpoint{
                                                        Height: 5,
                                                        Hash:   testutil.MustDecodeHash("750408823bea9666f263870daded75d8f3d878606ec103bc9401b73714d77729"),
                                                        Status: state.Unjustified,
                                                },
                                                children: []*treeNode{
                                                        {
-                                                               checkpoint: &state.Checkpoint{
+                                                               Checkpoint: &state.Checkpoint{
                                                                        Height: 7,
                                                                        Hash:   testutil.MustDecodeHash("0bf26d17ff2a578c1a733a1e969184d695e8f3ac6834150acc5c1e9edeb84de9"),
                                                                        Status: state.Growing,
@@ -87,14 +87,14 @@ func TestBestChain(t *testing.T) {
                                                },
                                        },
                                        {
-                                               checkpoint: &state.Checkpoint{
+                                               Checkpoint: &state.Checkpoint{
                                                        Height: 5,
                                                        Hash:   testutil.MustDecodeHash("049f012c12b94d34b13163eddbd31866f97b38c5b742e4c170a44d80ff503166"),
                                                        Status: state.Unjustified,
                                                },
                                                children: []*treeNode{
                                                        {
-                                                               checkpoint: &state.Checkpoint{
+                                                               Checkpoint: &state.Checkpoint{
                                                                        Height: 8,
                                                                        Hash:   testutil.MustDecodeHash("8315f5337978076b3097230570484e36586ee27564ebcbf74c2093cd763e32e7"),
                                                                        Status: state.Growing,
@@ -109,8 +109,8 @@ func TestBestChain(t *testing.T) {
        }
 
        for i, c := range cases {
-               if _, bestHash, _ := chainOfMaxJustifiedHeight(c.tree, c.tree.checkpoint.Height); bestHash != c.wantBestHash {
-                       t.Errorf("case #%d(%s) want best hash:%s, got best hash:%s\n", i, c.desc, c.wantBestHash.String(), bestHash.String())
+               if bestNode, _ := c.tree.bestNode(0); bestNode.Hash != c.wantBestHash {
+                       t.Errorf("case #%d(%s) want best hash:%s, got best hash:%s\n", i, c.desc, c.wantBestHash.String(), bestNode.Hash.String())
                }
        }
 }
index 351ed5b..e00cbd4 100644 (file)
@@ -9,8 +9,8 @@ import (
 )
 
 type treeNode struct {
-       checkpoint *state.Checkpoint
-       children   []*treeNode
+       *state.Checkpoint
+       children []*treeNode
 }
 
 func makeTree(root *state.Checkpoint, successors []*state.Checkpoint) *treeNode {
@@ -19,13 +19,13 @@ func makeTree(root *state.Checkpoint, successors []*state.Checkpoint) *treeNode
                parentToSuccessors[successor.ParentHash] = append(parentToSuccessors[successor.ParentHash], successor)
        }
 
-       rootNode := &treeNode{checkpoint: root}
+       rootNode := &treeNode{Checkpoint: root}
        nodes := []*treeNode{rootNode}
        for len(nodes) != 0 {
                node := nodes[0]
-               for _, successor := range parentToSuccessors[node.checkpoint.Hash] {
-                       child := &treeNode{checkpoint: successor}
-                       successor.Parent = node.checkpoint
+               for _, successor := range parentToSuccessors[node.Hash] {
+                       child := &treeNode{Checkpoint: successor}
+                       successor.Parent = node.Checkpoint
                        node.addChild(child)
                        nodes = append(nodes, child)
                }
@@ -38,6 +38,39 @@ func (t *treeNode) addChild(child *treeNode) {
        t.children = append(t.children, child)
 }
 
+func (t *treeNode) bestNode(justifiedHeight uint64) (*treeNode, uint64) {
+       if t.Status == state.Justified {
+               justifiedHeight = t.Height
+       }
+
+       bestNode, bestJustified := t, justifiedHeight
+       for _, child := range t.children {
+               bestChild, childJustified := child.bestNode(justifiedHeight)
+               if childJustified > bestJustified || (childJustified == bestJustified && bestChild.Height > bestNode.Height) ||
+                       (childJustified == bestJustified && bestChild.Height == bestNode.Height && bestChild.Hash.String() > bestNode.Hash.String()) {
+                       bestNode, bestJustified = bestChild, childJustified
+               }
+       }
+
+       return bestNode, bestJustified
+}
+
+func (t *treeNode) lastJustified() *treeNode {
+       var selected *treeNode
+       if t.Status == state.Justified {
+               selected = t
+       }
+
+       for _, child := range t.children {
+               if childSelected := child.lastJustified(); childSelected == nil {
+                       continue
+               } else if selected == nil || childSelected.Height > selected.Height {
+                       selected = childSelected
+               }
+       }
+       return selected
+}
+
 func (t *treeNode) nodeByHash(blockHash bc.Hash) (*treeNode, error) {
        if c := t.findOnlyOne(func(c *state.Checkpoint) bool {
                return c.Hash == blockHash
@@ -49,7 +82,7 @@ func (t *treeNode) nodeByHash(blockHash bc.Hash) (*treeNode, error) {
 }
 
 func (t *treeNode) findOnlyOne(predicate func(*state.Checkpoint) bool) *treeNode {
-       if predicate(t.checkpoint) {
+       if predicate(t.Checkpoint) {
                return t
        }