OSDN Git Service

Sync for late node (#527)
authorPoseidon <shenao.78@163.com>
Wed, 1 Apr 2020 12:22:04 +0000 (20:22 +0800)
committerGitHub <noreply@github.com>
Wed, 1 Apr 2020 12:22:04 +0000 (20:22 +0800)
* sync for late node

* sync for late node

* remove rubbish

* bug fix

* prevent duplicate init chain status

application/mov/database/mov_store.go
application/mov/mov_core.go
node/node.go
proposal/proposal.go
protocol/protocol.go
test/rollback_test.go

index 20d3101..bbceaec 100644 (file)
@@ -12,6 +12,9 @@ import (
        "github.com/bytom/vapor/protocol/bc/types"
 )
 
+// ErrNotInitDBState represent the database state of mov store is not initialized
+var ErrNotInitDBState = errors.New("database state of mov store is not initialized")
+
 // MovStore is the interface for mov's persistent storage
 type MovStore interface {
        GetMovDatabaseState() (*common.MovDatabaseState, error)
@@ -96,7 +99,7 @@ func (m *LevelDBMovStore) GetMovDatabaseState() (*common.MovDatabaseState, error
                return state, json.Unmarshal(value, state)
        }
 
-       return nil, errors.New("don't find state of mov-database")
+       return nil, ErrNotInitDBState
 }
 
 // InitDBState set the DB's image status
index c4f7760..f91f742 100644 (file)
@@ -11,11 +11,13 @@ import (
        "github.com/bytom/vapor/consensus/segwit"
        dbm "github.com/bytom/vapor/database/leveldb"
        "github.com/bytom/vapor/errors"
+       "github.com/bytom/vapor/protocol"
        "github.com/bytom/vapor/protocol/bc"
        "github.com/bytom/vapor/protocol/bc/types"
 )
 
 var (
+       errChainStatusHasAlreadyInit    = errors.New("mov chain status has already initialized")
        errInvalidTradePairs            = errors.New("The trade pairs in the tx input is invalid")
        errStatusFailMustFalse          = errors.New("status fail of transaction does not allow to be true")
        errInputProgramMustP2WMCScript  = errors.New("input program of trade tx must p2wmc script")
@@ -57,7 +59,7 @@ func (m *Core) ApplyBlock(block *types.Block) error {
 
        if block.Height == m.startBlockHeight {
                blockHash := block.Hash()
-               return m.movStore.InitDBState(block.Height, &blockHash)
+               return m.InitChainStatus(&blockHash)
        }
 
        if err := m.validateMatchedTxSequence(block.Transactions); err != nil {
@@ -98,6 +100,10 @@ func (m *Core) BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft
 // ChainStatus return the current block height and block hash in dex core
 func (m *Core) ChainStatus() (uint64, *bc.Hash, error) {
        state, err := m.movStore.GetMovDatabaseState()
+       if err == database.ErrNotInitDBState {
+               return 0, nil, protocol.ErrNotInitSubProtocolChainStatus
+       }
+
        if err != nil {
                return 0, nil, err
        }
@@ -120,6 +126,15 @@ func (m *Core) DetachBlock(block *types.Block) error {
        return m.movStore.ProcessOrders(addOrders, deleteOrders, &block.BlockHeader)
 }
 
+// InitChainStatus used to init the start block height and start block hash to store
+func (m *Core) InitChainStatus(startHash *bc.Hash) error {
+       if _, err := m.movStore.GetMovDatabaseState(); err == nil {
+               return errChainStatusHasAlreadyInit
+       }
+
+       return m.movStore.InitDBState(m.startBlockHeight, startHash)
+}
+
 // IsDust block the transaction that are not generated by the match engine
 func (m *Core) IsDust(tx *types.Tx) bool {
        for _, input := range tx.Inputs {
index 313f55b..61e2b8c 100644 (file)
@@ -88,7 +88,7 @@ func NewNode(config *cfg.Config) *Node {
        movCore := mov.NewCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
        assetFilter := protocol.NewAssetFilter(config.CrossChain.AssetWhitelist)
        txPool := protocol.NewTxPool(store, []protocol.DustFilterer{movCore, assetFilter}, dispatcher)
-       chain, err := protocol.NewChain(store, txPool, []protocol.Protocoler{movCore}, dispatcher)
+       chain, err := protocol.NewChain(store, txPool, []protocol.SubProtocol{movCore}, dispatcher)
        if err != nil {
                cmn.Exit(cmn.Fmt("Failed to create chain structure: %v", err))
        }
@@ -180,7 +180,7 @@ func Rollback(config *cfg.Config, targetHeight uint64) error {
        dispatcher := event.NewDispatcher()
        movCore := mov.NewCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
        txPool := protocol.NewTxPool(store, []protocol.DustFilterer{movCore}, dispatcher)
-       chain, err := protocol.NewChain(store, txPool, []protocol.Protocoler{movCore}, dispatcher)
+       chain, err := protocol.NewChain(store, txPool, []protocol.SubProtocol{movCore}, dispatcher)
        if err != nil {
                return err
        }
index 1a4d1c8..2186249 100644 (file)
@@ -334,7 +334,7 @@ func (b *blockBuilder) preValidateTxs(txs []*types.Tx, chain *protocol.Chain, vi
        return results, gasLeft
 }
 
-func (b *blockBuilder) validateBySubProtocols(tx *types.Tx, statusFail bool, subProtocols []protocol.Protocoler) error {
+func (b *blockBuilder) validateBySubProtocols(tx *types.Tx, statusFail bool, subProtocols []protocol.SubProtocol) error {
        for _, subProtocol := range subProtocols {
                verifyResult := &bc.TxVerifyResult{StatusFail: statusFail}
                if err := subProtocol.ValidateTx(tx, verifyResult, b.block.Height); err != nil {
index a1cbb70..ea1b2b0 100644 (file)
@@ -19,12 +19,19 @@ const (
        maxKnownTxs           = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
 )
 
-// Protocoler is interface for layer 2 consensus protocol
-type Protocoler interface {
+// ErrNotInitSubProtocolChainStatus represent the node state of sub protocol has not been initialized
+var ErrNotInitSubProtocolChainStatus = errors.New("node state of sub protocol has not been initialized")
+
+// SubProtocol is interface for layer 2 consensus protocol
+type SubProtocol interface {
        Name() string
        StartHeight() uint64
        BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error)
+
+       // ChainStatus return the the current block height and block hash of sub protocol.
+       // it will return ErrNotInitSubProtocolChainStatus if not initialized.
        ChainStatus() (uint64, *bc.Hash, error)
+       InitChainStatus(*bc.Hash) error
        ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error
        ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error
        ApplyBlock(block *types.Block) error
@@ -37,7 +44,7 @@ type Chain struct {
        txPool         *TxPool
        store          Store
        processBlockCh chan *processBlockMsg
-       subProtocols   []Protocoler
+       subProtocols   []SubProtocol
 
        signatureCache  *common.Cache
        eventDispatcher *event.Dispatcher
@@ -50,7 +57,7 @@ type Chain struct {
 }
 
 // NewChain returns a new Chain using store as the underlying storage.
-func NewChain(store Store, txPool *TxPool, subProtocols []Protocoler, eventDispatcher *event.Dispatcher) (*Chain, error) {
+func NewChain(store Store, txPool *TxPool, subProtocols []SubProtocol, eventDispatcher *event.Dispatcher) (*Chain, error) {
        knownTxs, _ := common.NewOrderedSet(maxKnownTxs)
        c := &Chain{
                orphanManage:    NewOrphanManage(),
@@ -175,7 +182,7 @@ func (c *Chain) InMainChain(hash bc.Hash) bool {
 }
 
 // SubProtocols return list of layer 2 consensus protocol
-func (c *Chain) SubProtocols() []Protocoler {
+func (c *Chain) SubProtocols() []SubProtocol {
        return c.subProtocols
 }
 
@@ -215,14 +222,25 @@ func (c *Chain) markTransactions(txs ...*types.Tx) {
        }
 }
 
-func (c *Chain) syncProtocolStatus(subProtocol Protocoler) error {
+func (c *Chain) syncProtocolStatus(subProtocol SubProtocol) error {
        if c.bestBlockHeader.Height < subProtocol.StartHeight() {
                return nil
        }
 
        protocolHeight, protocolHash, err := subProtocol.ChainStatus()
-       if err != nil {
-               return errors.Wrap(err, "failed on get sub protocol status")
+       if err == ErrNotInitSubProtocolChainStatus {
+               startHash, err := c.store.GetMainChainHash(subProtocol.StartHeight())
+               if err != nil {
+                       return errors.Wrap(err, subProtocol.Name(), "can't get block hash by height")
+               }
+
+               if err := subProtocol.InitChainStatus(startHash); err != nil {
+                       return errors.Wrap(err, subProtocol.Name(), "fail init chain status")
+               }
+
+               protocolHeight, protocolHash = subProtocol.StartHeight(), startHash
+       } else if err != nil {
+               return errors.Wrap(err, subProtocol.Name(), "can't get chain status")
        }
 
        if *protocolHash == c.bestBlockHeader.Hash() {
index d40f9ba..00bc599 100644 (file)
@@ -1460,7 +1460,7 @@ func TestRollback(t *testing.T) {
                        t.Fatal(err)
                }
 
-               chain, err := protocol.NewChain(store, nil, []protocol.Protocoler{movCore}, nil)
+               chain, err := protocol.NewChain(store, nil, []protocol.SubProtocol{movCore}, nil)
                if err != nil {
                        t.Fatal(err)
                }