OSDN Git Service

refactor casper (#1940)
authorPoseidon <shenao.78@163.com>
Wed, 26 May 2021 06:52:26 +0000 (14:52 +0800)
committerGitHub <noreply@github.com>
Wed, 26 May 2021 06:52:26 +0000 (14:52 +0800)
* refactor casper

* add comment

database/store.go
protocol/apply_block.go
protocol/auth_verification.go
protocol/block.go
protocol/casper.go
protocol/protocol.go
protocol/state/checkpoint.go
protocol/store.go
protocol/txpool_test.go
protocol/verfication.go

index 548c27f..b46f4cb 100644 (file)
@@ -333,7 +333,7 @@ func (s *Store) loadCheckpointsFromIter(iter dbm.Iterator) ([]*state.Checkpoint,
 }
 
 // SaveCheckpoints bulk save multiple checkpoint
-func (s *Store) SaveCheckpoints(checkpoints ...*state.Checkpoint) error {
+func (s *Store) SaveCheckpoints(checkpoints []*state.Checkpoint) error {
        batch := s.db.NewBatch()
 
        if err := s.saveCheckpoints(batch, checkpoints); err != nil {
index b470256..c1526d8 100644 (file)
@@ -48,11 +48,12 @@ func (c *Casper) ApplyBlock(block *types.Block) (*Verification, *state.Checkpoin
                return nil, nil, err
        }
 
-       if err := c.applySupLinks(target, block.SupLinks, validators); err != nil {
+       affectedCheckpoints, err := c.applySupLinks(target, block.SupLinks, validators)
+       if err != nil {
                return nil, nil, err
        }
 
-       return verification, target, nil
+       return verification, target, c.saveCheckpoints(affectedCheckpoints, target)
 }
 
 func (c *Casper) applyBlockToCheckpoint(block *types.Block) (*state.Checkpoint, error) {
@@ -116,9 +117,9 @@ func (c *Casper) applyTransactions(target *state.Checkpoint, transactions []*typ
 }
 
 // applySupLinks copy the block's supLink to the checkpoint
-func (c *Casper) applySupLinks(target *state.Checkpoint, supLinks []*types.SupLink, validators map[string]*state.Validator) error {
+func (c *Casper) applySupLinks(target *state.Checkpoint, supLinks []*types.SupLink, validators map[string]*state.Validator) (map[bc.Hash]*state.Checkpoint, error) {
        if target.Height%state.BlocksOfEpoch != 0 {
-               return nil
+               return nil, nil
        }
 
        affectedCheckpoints := make(map[bc.Hash]*state.Checkpoint)
@@ -132,7 +133,7 @@ func (c *Casper) applySupLinks(target *state.Checkpoint, supLinks []*types.SupLi
 
                checkpoints, err := c.addVerificationToCheckpoint(target, validators, validVerifications...)
                if err != nil {
-                       return err
+                       return nil, err
                }
 
                for _, c := range checkpoints {
@@ -140,12 +141,7 @@ func (c *Casper) applySupLinks(target *state.Checkpoint, supLinks []*types.SupLi
                }
        }
 
-       delete(affectedCheckpoints, target.Hash)
-       var checkpoints []*state.Checkpoint
-       for _, c := range affectedCheckpoints {
-               checkpoints = append(checkpoints, c)
-       }
-       return c.store.SaveCheckpoints(checkpoints...)
+       return affectedCheckpoints, nil
 }
 
 func (c *Casper) applyMyVerification(target *state.Checkpoint, block *types.Block, validators map[string]*state.Validator) (*Verification, error) {
@@ -178,12 +174,11 @@ func (c *Casper) myVerification(target *state.Checkpoint, validators map[string]
        }
 
        validatorOrder := validators[pubKey].Order
-       source := c.lastJustifiedCheckpointOfBranch(target)
-       if target.ContainsVerification(source.Hash, validatorOrder) {
+       if target.ContainsVerification(validatorOrder, nil) {
                return nil, nil
        }
 
-       if source != nil {
+       if source := c.lastJustifiedCheckpointOfBranch(target); source != nil {
                v := &Verification{
                        SourceHash:   source.Hash,
                        TargetHash:   target.Hash,
@@ -206,6 +201,18 @@ func (c *Casper) myVerification(target *state.Checkpoint, validators map[string]
        return nil, nil
 }
 
+func (c *Casper) saveCheckpoints(affectedCheckpoints map[bc.Hash]*state.Checkpoint, target *state.Checkpoint) error {
+       // the target checkpoint must eventually be saved in the chain state
+       delete(affectedCheckpoints, target.Hash)
+
+       var checkpoints []*state.Checkpoint
+       for _, c := range affectedCheckpoints {
+               checkpoints = append(checkpoints, c)
+       }
+       return c.store.SaveCheckpoints(checkpoints)
+}
+
+
 type guarantyArgs struct {
        Amount uint64
        PubKey []byte
index fb9e3aa..44ba114 100644 (file)
@@ -34,7 +34,7 @@ func (c *Casper) AuthVerification(v *Verification) error {
                return errPubKeyIsNotValidator
        }
 
-       if target.ContainsVerification(v.SourceHash, validators[v.PubKey].Order) {
+       if target.ContainsVerification(validators[v.PubKey].Order, &v.SourceHash) {
                return nil
        }
 
@@ -62,7 +62,7 @@ func (c *Casper) authVerification(v *Verification, target *state.Checkpoint, val
                return err
        }
 
-       if err := c.store.SaveCheckpoints(checkpoints...); err != nil {
+       if err := c.store.SaveCheckpoints(checkpoints); err != nil {
                return err
        }
 
@@ -93,7 +93,7 @@ func (c *Casper) addVerificationToCheckpoint(target *state.Checkpoint, validator
 
        _, newBestHash := c.bestChain()
        if oldBestHash != newBestHash {
-               c.rollbackNotifyCh <- nil
+               c.rollbackNotifyCh <- newBestHash
        }
 
        return affectedCheckpoints, nil
index eb5abf3..f2dc01d 100644 (file)
@@ -305,8 +305,8 @@ func (c *Chain) blockProcessor() {
                case msg := <-c.processBlockCh:
                        isOrphan, err := c.processBlock(msg.block)
                        msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
-               case <-c.rollbackNotifyCh:
-                       if err := c.rollback(); err != nil {
+               case newBestHash := <-c.rollbackNotifyCh:
+                       if err := c.rollback(newBestHash); err != nil {
                                log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on rollback block")
                        }
                }
@@ -341,13 +341,12 @@ func (c *Chain) processBlock(block *types.Block) (bool, error) {
        return false, nil
 }
 
-func (c *Chain) rollback() error {
-       latestBestBlockHash := c.latestBestBlockHash()
-       if c.bestNode.Hash == *latestBestBlockHash {
+func (c *Chain) rollback(newBestHash bc.Hash) error {
+       if c.bestNode.Hash == newBestHash {
                return nil
        }
 
-       node := c.index.GetNode(latestBestBlockHash)
+       node := c.index.GetNode(&newBestHash)
        log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
        return c.reorganizeChain(node)
 }
index d73ead3..8787fec 100644 (file)
@@ -29,7 +29,7 @@ const minGuaranty = 1E14
 type Casper struct {
        mu               sync.RWMutex
        tree             *treeNode
-       rollbackNotifyCh chan interface{}
+       rollbackNotifyCh chan bc.Hash
        newEpochCh       chan bc.Hash
        store            Store
        // pubKey -> conflicting verifications
@@ -46,7 +46,7 @@ type Casper struct {
 // argument checkpoints load the checkpoints from leveldb
 // the first element of checkpoints must genesis checkpoint or the last finalized checkpoint in order to reduce memory space
 // the others must be successors of first one
-func NewCasper(store Store, checkpoints []*state.Checkpoint, rollbackNotifyCh chan interface{}) *Casper {
+func NewCasper(store Store, checkpoints []*state.Checkpoint, rollbackNotifyCh chan bc.Hash) *Casper {
        if checkpoints[0].Height != 0 && checkpoints[0].Status != state.Finalized {
                log.Panic("first element of checkpoints must genesis or in finalized status")
        }
index 7d96ed1..ea3d7f9 100644 (file)
@@ -24,7 +24,7 @@ type Chain struct {
        store            Store
        casper           *Casper
        processBlockCh   chan *processBlockMsg
-       rollbackNotifyCh chan interface{}
+       rollbackNotifyCh chan bc.Hash
        eventDispatcher  *event.Dispatcher
 
        cond     sync.Cond
@@ -42,7 +42,7 @@ func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage,
                eventDispatcher:  eventDispatcher,
                txPool:           txPool,
                store:            store,
-               rollbackNotifyCh: make(chan interface{}),
+               rollbackNotifyCh: make(chan bc.Hash),
                processBlockCh:   make(chan *processBlockMsg, maxProcessBlockChSize),
        }
        c.cond.L = new(sync.Mutex)
@@ -101,7 +101,7 @@ func (c *Chain) initChainStatus() error {
        return c.store.SaveChainStatus(node, utxoView, contractView, []*state.Checkpoint{checkpoint}, 0, &checkpoint.Hash)
 }
 
-func newCasper(store Store, storeStatus *BlockStoreState, rollbackNotifyCh chan interface{}) (*Casper, error) {
+func newCasper(store Store, storeStatus *BlockStoreState, rollbackNotifyCh chan bc.Hash) (*Casper, error) {
        checkpoints, err := store.CheckpointsFromNode(storeStatus.FinalizedHeight, storeStatus.FinalizedHash)
        if err != nil {
                return nil, err
@@ -136,11 +136,6 @@ func (c *Chain) BestBlockHash() *bc.Hash {
        return &c.bestNode.Hash
 }
 
-func (c *Chain) latestBestBlockHash() *bc.Hash {
-       _, hash := c.casper.BestChain()
-       return &hash
-}
-
 // GetValidator return validator by specified blockHash and timestamp
 func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
        prevCheckpoint, err := c.casper.prevCheckpointByPrevHash(prevHash)
index 6986c7a..aa5b730 100644 (file)
@@ -86,9 +86,10 @@ func (c *Checkpoint) AddVerification(sourceHash bc.Hash, sourceHeight uint64, va
 }
 
 // ContainsVerification return whether the specified validator has add verification to current checkpoint
-func (c *Checkpoint) ContainsVerification(sourceHash bc.Hash, validatorOrder int) bool {
+// sourceHash not as filter if is nil,
+func (c *Checkpoint) ContainsVerification(validatorOrder int, sourceHash *bc.Hash) bool {
        for _, supLink := range c.SupLinks {
-               if supLink.SourceHash == sourceHash && supLink.Signatures[validatorOrder] != "" {
+               if (sourceHash == nil || supLink.SourceHash == *sourceHash) && supLink.Signatures[validatorOrder] != "" {
                        return true
                }
        }
index db4dfc5..bfb9bbd 100644 (file)
@@ -21,7 +21,7 @@ type Store interface {
        GetCheckpoint(*bc.Hash) (*state.Checkpoint, error)
        CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error)
        GetCheckpointsByHeight(uint64) ([]*state.Checkpoint, error)
-       SaveCheckpoints(...*state.Checkpoint) error
+       SaveCheckpoints([]*state.Checkpoint) error
 
        LoadBlockIndex(uint64) (*state.BlockIndex, error)
        SaveBlock(*types.Block) error
index e6ece43..3924202 100644 (file)
@@ -100,7 +100,7 @@ type mockStore struct{}
 func (s *mockStore) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error)     { return nil, nil }
 func (s *mockStore) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error)       { return nil, nil }
 func (s *mockStore) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
-func (s *mockStore) SaveCheckpoints(...*state.Checkpoint) error                   { return nil }
+func (s *mockStore) SaveCheckpoints([]*state.Checkpoint) error                   { return nil }
 func (s *mockStore) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error)      { return nil, nil }
 func (s *mockStore) BlockExist(hash *bc.Hash) bool                                { return false }
 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error)                      { return nil, nil }
@@ -597,7 +597,7 @@ type mockStore1 struct{}
 func (s *mockStore1) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error)     { return nil, nil }
 func (s *mockStore1) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error)       { return nil, nil }
 func (s *mockStore1) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
-func (s *mockStore1) SaveCheckpoints(...*state.Checkpoint) error                   { return nil }
+func (s *mockStore1) SaveCheckpoints([]*state.Checkpoint) error                   { return nil }
 func (s *mockStore1) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error)      { return nil, nil }
 func (s *mockStore1) BlockExist(hash *bc.Hash) bool                                { return false }
 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error)                      { return nil, nil }
index b48de26..54bae5c 100644 (file)
@@ -25,35 +25,9 @@ type Verification struct {
        PubKey       string
 }
 
-// EncodeMessage encode the verification for the validators to sign or verify
-func (v *Verification) EncodeMessage() ([]byte, error) {
-       buff := new(bytes.Buffer)
-       if _, err := v.SourceHash.WriteTo(buff); err != nil {
-               return nil, err
-       }
-
-       if _, err := v.TargetHash.WriteTo(buff); err != nil {
-               return nil, err
-       }
-
-       uint64Buff := make([]byte, 8)
-
-       binary.LittleEndian.PutUint64(uint64Buff, v.SourceHeight)
-       if _, err := buff.Write(uint64Buff); err != nil {
-               return nil, err
-       }
-
-       binary.LittleEndian.PutUint64(uint64Buff, v.TargetHeight)
-       if _, err := buff.Write(uint64Buff); err != nil {
-               return nil, err
-       }
-
-       return sha3Hash(buff.Bytes())
-}
-
 // Sign used to sign the verification by specified xPrv
 func (v *Verification) Sign(xPrv chainkd.XPrv) error {
-       message, err := v.EncodeMessage()
+       message, err := v.encodeMessage()
        if err != nil {
                return err
        }
@@ -74,7 +48,7 @@ func (v *Verification) VerifySignature() error {
                return err
        }
 
-       message, err := v.EncodeMessage()
+       message, err := v.encodeMessage()
        if err != nil {
                return err
        }
@@ -88,6 +62,32 @@ func (v *Verification) VerifySignature() error {
        return nil
 }
 
+// encodeMessage encode the verification for the validators to sign or verify
+func (v *Verification) encodeMessage() ([]byte, error) {
+       buff := new(bytes.Buffer)
+       if _, err := v.SourceHash.WriteTo(buff); err != nil {
+               return nil, err
+       }
+
+       if _, err := v.TargetHash.WriteTo(buff); err != nil {
+               return nil, err
+       }
+
+       uint64Buff := make([]byte, 8)
+
+       binary.LittleEndian.PutUint64(uint64Buff, v.SourceHeight)
+       if _, err := buff.Write(uint64Buff); err != nil {
+               return nil, err
+       }
+
+       binary.LittleEndian.PutUint64(uint64Buff, v.TargetHeight)
+       if _, err := buff.Write(uint64Buff); err != nil {
+               return nil, err
+       }
+
+       return sha3Hash(buff.Bytes())
+}
+
 func sha3Hash(message []byte) ([]byte, error) {
        sha3 := sha3pool.Get256()
        defer sha3pool.Put256(sha3)