6 log "github.com/sirupsen/logrus"
8 "github.com/bytom/vapor/common"
9 "github.com/bytom/vapor/config"
10 "github.com/bytom/vapor/errors"
11 "github.com/bytom/vapor/event"
12 "github.com/bytom/vapor/protocol/bc"
13 "github.com/bytom/vapor/protocol/bc/types"
14 "github.com/bytom/vapor/protocol/state"
18 maxProcessBlockChSize = 1024
19 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
22 // ErrNotInitSubProtocolChainStatus represent the node state of sub protocol has not been initialized
23 var ErrNotInitSubProtocolChainStatus = errors.New("node state of sub protocol has not been initialized")
25 // SubProtocol is interface for layer 2 consensus protocol
26 type SubProtocol interface {
29 BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error)
31 // ChainStatus return the the current block height and block hash of sub protocol.
32 // it will return ErrNotInitSubProtocolChainStatus if not initialized.
33 ChainStatus() (uint64, *bc.Hash, error)
34 InitChainStatus(*bc.Hash) error
35 ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error
36 ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error
37 ApplyBlock(block *types.Block) error
38 DetachBlock(block *types.Block) error
41 // Chain provides functions for working with the Bytom block chain.
43 orphanManage *OrphanManage
46 processBlockCh chan *processBlockMsg
47 subProtocols []SubProtocol
49 signatureCache *common.Cache
50 eventDispatcher *event.Dispatcher
53 bestBlockHeader *types.BlockHeader // the last block on current main chain
54 lastIrrBlockHeader *types.BlockHeader // the last irreversible block
56 knownTxs *common.OrderedSet
59 // NewChain returns a new Chain using store as the underlying storage.
60 func NewChain(store Store, txPool *TxPool, subProtocols []SubProtocol, eventDispatcher *event.Dispatcher) (*Chain, error) {
61 knownTxs, _ := common.NewOrderedSet(maxKnownTxs)
63 orphanManage: NewOrphanManage(),
66 subProtocols: subProtocols,
67 signatureCache: common.NewCache(maxSignatureCacheSize),
68 eventDispatcher: eventDispatcher,
69 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
72 c.cond.L = new(sync.Mutex)
74 storeStatus := store.GetStoreStatus()
75 if storeStatus == nil {
76 if err := c.initChainStatus(); err != nil {
79 storeStatus = store.GetStoreStatus()
83 c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
88 c.lastIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
93 for _, p := range c.subProtocols {
94 if err := c.syncProtocolStatus(p); err != nil {
95 return nil, errors.Wrap(err, p.Name(), "sync sub protocol status")
103 func (c *Chain) initChainStatus() error {
104 genesisBlock := config.GenesisBlock()
105 txStatus := bc.NewTransactionStatus()
106 for i := range genesisBlock.Transactions {
107 if err := txStatus.SetStatus(i, false); err != nil {
112 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
116 utxoView := state.NewUtxoViewpoint()
117 bcBlock := types.MapBlock(genesisBlock)
118 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
122 for _, subProtocol := range c.subProtocols {
123 if err := subProtocol.ApplyBlock(genesisBlock); err != nil {
128 consensusResults := []*state.ConsensusResult{{
130 NumOfVote: make(map[string]uint64),
131 CoinbaseReward: make(map[string]uint64),
132 BlockHash: genesisBlock.Hash(),
136 genesisBlockHeader := &genesisBlock.BlockHeader
137 return c.store.SaveChainStatus(genesisBlockHeader, genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, consensusResults)
140 // BestBlockHeight returns the current height of the blockchain.
141 func (c *Chain) BestBlockHeight() uint64 {
143 defer c.cond.L.Unlock()
144 return c.bestBlockHeader.Height
147 // BestBlockHash return the hash of the main chain tail block
148 func (c *Chain) BestBlockHash() *bc.Hash {
150 defer c.cond.L.Unlock()
151 bestHash := c.bestBlockHeader.Hash()
155 // LastIrreversibleHeader returns the chain last irreversible block header
156 func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
158 defer c.cond.L.Unlock()
159 return c.lastIrrBlockHeader
162 // BestBlockHeader returns the chain best block header
163 func (c *Chain) BestBlockHeader() *types.BlockHeader {
165 defer c.cond.L.Unlock()
166 return c.bestBlockHeader
169 // InMainChain checks wheather a block is in the main chain
170 func (c *Chain) InMainChain(hash bc.Hash) bool {
171 blockHeader, err := c.store.GetBlockHeader(&hash)
176 blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
178 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
181 return *blockHash == hash
184 // SubProtocols return list of layer 2 consensus protocol
185 func (c *Chain) SubProtocols() []SubProtocol {
186 return c.subProtocols
189 // trace back to the tail of the chain from the given block header
190 func (c *Chain) traceLongestChainTail(blockHeader *types.BlockHeader) (*types.BlockHeader, error) {
191 longestTail, workQueue := blockHeader, []*types.BlockHeader{blockHeader}
193 for ; len(workQueue) > 0; workQueue = workQueue[1:] {
194 currentHeader := workQueue[0]
195 currentHash := currentHeader.Hash()
196 hashes, err := c.store.GetBlockHashesByHeight(currentHeader.Height + 1)
201 for _, h := range hashes {
202 if header, err := c.store.GetBlockHeader(h); err != nil {
204 } else if header.PreviousBlockHash == currentHash {
205 if longestTail.Height < header.Height {
208 workQueue = append(workQueue, header)
212 return longestTail, nil
215 func (c *Chain) hasSeenTx(tx *types.Tx) bool {
216 return c.knownTxs.Has(tx.ID.String())
219 func (c *Chain) markTransactions(txs ...*types.Tx) {
220 for _, tx := range txs {
221 c.knownTxs.Add(tx.ID.String())
225 func (c *Chain) syncProtocolStatus(subProtocol SubProtocol) error {
226 if c.bestBlockHeader.Height < subProtocol.StartHeight() {
230 protocolHeight, protocolHash, err := subProtocol.ChainStatus()
231 if err == ErrNotInitSubProtocolChainStatus {
232 startHash, err := c.store.GetMainChainHash(subProtocol.StartHeight())
234 return errors.Wrap(err, subProtocol.Name(), "can't get block hash by height")
237 if err := subProtocol.InitChainStatus(startHash); err != nil {
238 return errors.Wrap(err, subProtocol.Name(), "fail init chain status")
241 protocolHeight, protocolHash = subProtocol.StartHeight(), startHash
242 } else if err != nil {
243 return errors.Wrap(err, subProtocol.Name(), "can't get chain status")
246 if *protocolHash == c.bestBlockHeader.Hash() {
250 for !c.InMainChain(*protocolHash) {
251 block, err := c.GetBlockByHash(protocolHash)
253 return errors.Wrap(err, subProtocol.Name(), "can't get block by hash in chain")
256 if err := subProtocol.DetachBlock(block); err != nil {
257 return errors.Wrap(err, subProtocol.Name(), "sub protocol detach block err")
260 protocolHeight, protocolHash = block.Height-1, &block.PreviousBlockHash
263 for height := protocolHeight + 1; height <= c.bestBlockHeader.Height; height++ {
264 block, err := c.GetBlockByHeight(height)
266 return errors.Wrap(err, subProtocol.Name(), "can't get block by height in chain")
269 if err := subProtocol.ApplyBlock(block); err != nil {
270 return errors.Wrap(err, subProtocol.Name(), "sub protocol apply block err")
273 blockHash := block.Hash()
274 protocolHeight, protocolHash = block.Height, &blockHash
280 // This function must be called with mu lock in above level
281 func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error {
282 if err := c.store.SaveChainStatus(blockHeader, irrBlockHeader, mainBlockHeaders, view, consensusResults); err != nil {
286 c.bestBlockHeader = blockHeader
287 c.lastIrrBlockHeader = irrBlockHeader
289 blockHash := blockHeader.Hash()
290 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("chain best status has been update")
295 // BlockWaiter returns a channel that waits for the block at the given height.
296 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
297 ch := make(chan struct{}, 1)
300 defer c.cond.L.Unlock()
301 for c.bestBlockHeader.Height < height {
310 // GetTxPool return chain txpool.
311 func (c *Chain) GetTxPool() *TxPool {