X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=blobdiff_plain;f=protocol%2Fprotocol.go;h=a1cbb7099dcdd33f6f4da4f4263cec40f372b72e;hp=d7ea94484e8986833e1f2143f3b95e2fcd524dac;hb=78ef45d4238457b2ad498d738db5a7a7a30df167;hpb=23a183040a74bb684d3a036ef26b1d90c4af76b6 diff --git a/protocol/protocol.go b/protocol/protocol.go index d7ea9448..a1cbb709 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -5,12 +5,13 @@ import ( log "github.com/sirupsen/logrus" - "github.com/vapor/common" - "github.com/vapor/config" - "github.com/vapor/event" - "github.com/vapor/protocol/bc" - "github.com/vapor/protocol/bc/types" - "github.com/vapor/protocol/state" + "github.com/bytom/vapor/common" + "github.com/bytom/vapor/config" + "github.com/bytom/vapor/errors" + "github.com/bytom/vapor/event" + "github.com/bytom/vapor/protocol/bc" + "github.com/bytom/vapor/protocol/bc/types" + "github.com/bytom/vapor/protocol/state" ) const ( @@ -18,12 +19,25 @@ 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 { + Name() string + StartHeight() uint64 + BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error) + ChainStatus() (uint64, *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 + DetachBlock(block *types.Block) error +} + // Chain provides functions for working with the Bytom block chain. type Chain struct { orphanManage *OrphanManage txPool *TxPool store Store processBlockCh chan *processBlockMsg + subProtocols []Protocoler signatureCache *common.Cache eventDispatcher *event.Dispatcher @@ -36,12 +50,13 @@ type Chain struct { } // NewChain returns a new Chain using store as the underlying storage. -func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) { +func NewChain(store Store, txPool *TxPool, subProtocols []Protocoler, eventDispatcher *event.Dispatcher) (*Chain, error) { knownTxs, _ := common.NewOrderedSet(maxKnownTxs) c := &Chain{ orphanManage: NewOrphanManage(), txPool: txPool, store: store, + subProtocols: subProtocols, signatureCache: common.NewCache(maxSignatureCacheSize), eventDispatcher: eventDispatcher, processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize), @@ -67,6 +82,13 @@ func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (* if err != nil { return nil, err } + + for _, p := range c.subProtocols { + if err := c.syncProtocolStatus(p); err != nil { + return nil, errors.Wrap(err, p.Name(), "sync sub protocol status") + } + } + go c.blockProcesser() return c, nil } @@ -90,7 +112,13 @@ func (c *Chain) initChainStatus() error { return err } - consensusResults := []*state.ConsensusResult{&state.ConsensusResult{ + for _, subProtocol := range c.subProtocols { + if err := subProtocol.ApplyBlock(genesisBlock); err != nil { + return err + } + } + + consensusResults := []*state.ConsensusResult{{ Seq: 0, NumOfVote: make(map[string]uint64), CoinbaseReward: make(map[string]uint64), @@ -146,6 +174,11 @@ func (c *Chain) InMainChain(hash bc.Hash) bool { return *blockHash == hash } +// SubProtocols return list of layer 2 consensus protocol +func (c *Chain) SubProtocols() []Protocoler { + return c.subProtocols +} + // trace back to the tail of the chain from the given block header func (c *Chain) traceLongestChainTail(blockHeader *types.BlockHeader) (*types.BlockHeader, error) { longestTail, workQueue := blockHeader, []*types.BlockHeader{blockHeader} @@ -182,6 +215,50 @@ func (c *Chain) markTransactions(txs ...*types.Tx) { } } +func (c *Chain) syncProtocolStatus(subProtocol Protocoler) 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 *protocolHash == c.bestBlockHeader.Hash() { + return nil + } + + for !c.InMainChain(*protocolHash) { + block, err := c.GetBlockByHash(protocolHash) + if err != nil { + return errors.Wrap(err, subProtocol.Name(), "can't get block by hash in chain") + } + + if err := subProtocol.DetachBlock(block); err != nil { + return errors.Wrap(err, subProtocol.Name(), "sub protocol detach block err") + } + + protocolHeight, protocolHash = block.Height-1, &block.PreviousBlockHash + } + + for height := protocolHeight + 1; height <= c.bestBlockHeader.Height; height++ { + block, err := c.GetBlockByHeight(height) + if err != nil { + return errors.Wrap(err, subProtocol.Name(), "can't get block by height in chain") + } + + if err := subProtocol.ApplyBlock(block); err != nil { + return errors.Wrap(err, subProtocol.Name(), "sub protocol apply block err") + } + + blockHash := block.Hash() + protocolHeight, protocolHash = block.Height, &blockHash + } + + return nil +} + // This function must be called with mu lock in above level func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error { if err := c.store.SaveChainStatus(blockHeader, irrBlockHeader, mainBlockHeaders, view, consensusResults); err != nil {