github.com/igggame/nebulas-go@v2.1.0+incompatible/core/blockchain.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package core
    20  
    21  import (
    22  	"crypto/rand"
    23  	"io"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/nebulasio/go-nebulas/core/state"
    28  
    29  	"github.com/gogo/protobuf/proto"
    30  	lru "github.com/hashicorp/golang-lru"
    31  	"github.com/nebulasio/go-nebulas/core/pb"
    32  	"github.com/nebulasio/go-nebulas/storage"
    33  	"github.com/nebulasio/go-nebulas/util"
    34  	"github.com/nebulasio/go-nebulas/util/byteutils"
    35  	"github.com/nebulasio/go-nebulas/util/logging"
    36  	"github.com/sirupsen/logrus"
    37  )
    38  
    39  // storage: key -> value
    40  // scheme -> scheme version
    41  // genesis hash -> genesis block
    42  // blockchain_tail -> tail block hash
    43  // block hash -> block
    44  // height -> block hash
    45  
    46  // BlockChain the BlockChain core type.
    47  type BlockChain struct {
    48  	chainID uint32
    49  
    50  	genesis *corepb.Genesis
    51  
    52  	genesisBlock *Block
    53  	tailBlock    *Block
    54  
    55  	bkPool *BlockPool
    56  	txPool *TransactionPool
    57  
    58  	consensusHandler Consensus
    59  	syncService      SyncService
    60  
    61  	cachedBlocks       *lru.Cache
    62  	detachedTailBlocks *lru.Cache
    63  
    64  	// latest irreversible block
    65  	lib *Block
    66  
    67  	storage storage.Storage
    68  
    69  	eventEmitter *EventEmitter
    70  
    71  	nvm NVM
    72  
    73  	nr NR
    74  
    75  	dip Dip
    76  
    77  	quitCh chan int
    78  
    79  	superNode bool
    80  
    81  	// deprecated
    82  	unsupportedKeyword string
    83  }
    84  
    85  const (
    86  
    87  	// EagleNebula chain id for 1.x
    88  	EagleNebula = 1 << 4
    89  
    90  	// ChunkSize is the size of blocks in a chunk
    91  	ChunkSize = 32
    92  
    93  	// Tail Key in storage
    94  	Tail = "blockchain_tail"
    95  
    96  	// LIB (latest irreversible block) in storage
    97  	LIB = "blockchain_lib"
    98  
    99  	// transaction's block height
   100  	TxBlockHeight = "height"
   101  )
   102  
   103  // NewBlockChain create new #BlockChain instance.
   104  func NewBlockChain(neb Neblet) (*BlockChain, error) {
   105  	if neb == nil || neb.Config() == nil || neb.Config().Chain == nil {
   106  		return nil, ErrNilArgument
   107  	}
   108  
   109  	var gasPrice, gasLimit *util.Uint128
   110  	var err error
   111  	if 0 == len(neb.Config().Chain.GasPrice) {
   112  		gasPrice = util.NewUint128()
   113  	} else {
   114  		gasPrice, err = util.NewUint128FromString(neb.Config().Chain.GasPrice)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  	}
   119  
   120  	if 0 == len(neb.Config().Chain.GasLimit) {
   121  		gasLimit = util.NewUint128()
   122  	} else {
   123  		gasLimit, err = util.NewUint128FromString(neb.Config().Chain.GasLimit)
   124  		if err != nil {
   125  			return nil, err
   126  		}
   127  	}
   128  
   129  	blockPool, err := NewBlockPool(128)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	blockPool.RegisterInNetwork(neb.NetService())
   134  
   135  	txPool, err := NewTransactionPool(327680)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	txPool.setEventEmitter(neb.EventEmitter())
   140  	if err := txPool.SetGasConfig(gasPrice, gasLimit); err != nil {
   141  		return nil, err
   142  	}
   143  	txPool.RegisterInNetwork(neb.NetService())
   144  	access, err := NewAccess(neb.Config().Chain.Access)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	txPool.setAccess(access)
   149  
   150  	var bc = &BlockChain{
   151  		chainID:            neb.Config().Chain.ChainId,
   152  		genesis:            neb.Genesis(),
   153  		bkPool:             blockPool,
   154  		txPool:             txPool,
   155  		storage:            neb.Storage(),
   156  		eventEmitter:       neb.EventEmitter(),
   157  		nvm:                neb.Nvm(),
   158  		nr:                 neb.Nr(),
   159  		dip:                neb.Dip(),
   160  		quitCh:             make(chan int, 1),
   161  		superNode:          neb.Config().Chain.SuperNode,
   162  		unsupportedKeyword: neb.Config().Chain.UnsupportedKeyword,
   163  	}
   164  
   165  	bc.cachedBlocks, err = lru.New(128)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	bc.detachedTailBlocks, err = lru.New(128)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	bc.bkPool.setBlockChain(bc)
   176  	bc.txPool.setBlockChain(bc)
   177  
   178  	return bc, nil
   179  }
   180  
   181  // Setup the blockchain
   182  func (bc *BlockChain) Setup(neb Neblet) error {
   183  	bc.consensusHandler = neb.Consensus()
   184  
   185  	if err := bc.CheckGenesisConfig(neb); err != nil {
   186  		return err
   187  	}
   188  
   189  	var err error
   190  	bc.genesisBlock, err = bc.LoadGenesisFromStorage()
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	bc.tailBlock, err = bc.LoadTailFromStorage()
   196  	if err != nil {
   197  		return err
   198  	}
   199  	logging.CLog().WithFields(logrus.Fields{
   200  		"tail": bc.tailBlock,
   201  	}).Info("Tail Block.")
   202  
   203  	bc.lib, err = bc.LoadLIBFromStorage()
   204  	if err != nil {
   205  		return err
   206  	}
   207  	logging.CLog().WithFields(logrus.Fields{
   208  		"block": bc.lib,
   209  	}).Info("Latest Irreversible Block.")
   210  
   211  	return nil
   212  }
   213  
   214  // Start start loop.
   215  func (bc *BlockChain) Start() {
   216  	logging.CLog().Info("Starting BlockChain...")
   217  
   218  	go bc.loop()
   219  }
   220  
   221  // Stop stop loop.
   222  func (bc *BlockChain) Stop() {
   223  	logging.CLog().Info("Stopping BlockChain...")
   224  	bc.quitCh <- 0
   225  }
   226  
   227  func (bc *BlockChain) loop() {
   228  	logging.CLog().Info("Started BlockChain.")
   229  	timerChan := time.NewTicker(15 * time.Second).C
   230  	for {
   231  		select {
   232  		case <-bc.quitCh:
   233  			logging.CLog().Info("Stopped BlockChain.")
   234  			return
   235  		case <-timerChan:
   236  			bc.ConsensusHandler().UpdateLIB()
   237  			metricsLruCacheBlock.Update(int64(bc.cachedBlocks.Len()))
   238  			metricsLruTailBlock.Update(int64(bc.detachedTailBlocks.Len()))
   239  		}
   240  	}
   241  }
   242  
   243  // CheckGenesisConfig check if the genesis and config is valid
   244  func (bc *BlockChain) CheckGenesisConfig(neb Neblet) error {
   245  	genesis, err := DumpGenesis(bc)
   246  	//db.genesis has and config lack
   247  	if neb.Genesis() == nil && err == nil {
   248  		neb.SetGenesis(genesis)
   249  		if neb.Config().Chain.ChainId != neb.Genesis().Meta.ChainId {
   250  			return ErrInvalidConfigChainID
   251  		}
   252  	} else if neb.Genesis() == nil && err != nil {
   253  		logging.CLog().Fatal("Failed to find genesis config in config file")
   254  	} else if neb.Genesis() != nil && err != nil {
   255  		//first start
   256  		if neb.Config().Chain.ChainId != neb.Genesis().Meta.ChainId {
   257  			return ErrInvalidConfigChainID
   258  		}
   259  	} else {
   260  		if neb.Config().Chain.ChainId != neb.Genesis().Meta.ChainId {
   261  			return ErrInvalidConfigChainID
   262  		}
   263  
   264  		return CheckGenesisConfByDB(genesis, neb.Genesis())
   265  	}
   266  
   267  	logging.CLog().WithFields(logrus.Fields{
   268  		"meta.chainid":           neb.Genesis().Meta.ChainId,
   269  		"consensus.dpos.dynasty": neb.Genesis().Consensus.Dpos.Dynasty,
   270  		"token.distribution":     neb.Genesis().TokenDistribution,
   271  	}).Info("Genesis Configuration.")
   272  	return nil
   273  }
   274  
   275  // ChainID return the chainID.
   276  func (bc *BlockChain) ChainID() uint32 {
   277  	return bc.chainID
   278  }
   279  
   280  // Storage return the storage.
   281  func (bc *BlockChain) Storage() storage.Storage {
   282  	return bc.storage
   283  }
   284  
   285  // GenesisBlock return the genesis block.
   286  func (bc *BlockChain) GenesisBlock() *Block {
   287  	return bc.genesisBlock
   288  }
   289  
   290  // TailBlock return the tail block.
   291  func (bc *BlockChain) TailBlock() *Block {
   292  	return bc.tailBlock
   293  }
   294  
   295  // LIB return the latest irrversible block
   296  func (bc *BlockChain) LIB() *Block {
   297  	return bc.lib
   298  }
   299  
   300  // SetLIB update the latest irrversible block
   301  func (bc *BlockChain) SetLIB(lib *Block) {
   302  	bc.lib = lib
   303  }
   304  
   305  // EventEmitter return the eventEmitter.
   306  func (bc *BlockChain) EventEmitter() *EventEmitter {
   307  	return bc.eventEmitter
   308  }
   309  
   310  func (bc *BlockChain) triggerRevertBlockEvent(blocks []string) {
   311  	for i := len(blocks) - 1; i >= 0; i-- {
   312  		bc.eventEmitter.Trigger(&state.Event{
   313  			Topic: TopicRevertBlock,
   314  			Data:  blocks[i],
   315  		})
   316  	}
   317  }
   318  
   319  func (bc *BlockChain) revertBlocks(from *Block, to *Block) error {
   320  	reverted := to
   321  	var revertTimes int64
   322  	blocks := []string{}
   323  	for revertTimes = 0; !reverted.Hash().Equals(from.Hash()); {
   324  		if reverted.Hash().Equals(bc.lib.Hash()) {
   325  			return ErrCannotRevertLIB
   326  		}
   327  
   328  		reverted.ReturnTransactions()
   329  		logging.VLog().WithFields(logrus.Fields{
   330  			"block": reverted,
   331  		}).Warn("A block is reverted.")
   332  		revertTimes++
   333  		blocks = append(blocks, reverted.String())
   334  
   335  		reverted = bc.GetBlock(reverted.header.parentHash)
   336  		if reverted == nil {
   337  			return ErrMissingParentBlock
   338  		}
   339  	}
   340  	go bc.triggerRevertBlockEvent(blocks)
   341  	// record count of reverted blocks
   342  	if revertTimes > 0 {
   343  		metricsBlockRevertTimesGauge.Update(revertTimes)
   344  		metricsBlockRevertMeter.Mark(1)
   345  	}
   346  	return nil
   347  }
   348  
   349  func (bc *BlockChain) dropTxsInBlockFromTxPool(block *Block) {
   350  	for _, tx := range block.transactions {
   351  		bc.txPool.Del(tx)
   352  	}
   353  }
   354  
   355  func (bc *BlockChain) triggerNewTailInfo(blocks []*Block) {
   356  	for i := len(blocks) - 1; i >= 0; i-- {
   357  		block := blocks[i]
   358  		bc.eventEmitter.Trigger(&state.Event{
   359  			Topic: TopicNewTailBlock,
   360  			Data:  block.String(),
   361  		})
   362  
   363  		for _, v := range block.transactions {
   364  			bc.storage.Put(append(v.hash, []byte(TxBlockHeight)...), byteutils.FromUint64(block.height))
   365  			events, err := block.FetchEvents(v.hash)
   366  			if err == nil {
   367  				for _, e := range events {
   368  					bc.eventEmitter.Trigger(e)
   369  				}
   370  			}
   371  		}
   372  	}
   373  }
   374  
   375  func (bc *BlockChain) buildIndexByBlockHeight(from *Block, to *Block) error {
   376  	blocks := []*Block{}
   377  	for !to.Hash().Equals(from.Hash()) {
   378  		err := bc.storage.Put(byteutils.FromUint64(to.height), to.Hash())
   379  		if err != nil {
   380  			return err
   381  		}
   382  		blocks = append(blocks, to)
   383  		go bc.dropTxsInBlockFromTxPool(to)
   384  		to = bc.GetBlock(to.header.parentHash)
   385  		if to == nil {
   386  			return ErrMissingParentBlock
   387  		}
   388  	}
   389  	go bc.triggerNewTailInfo(blocks)
   390  	return nil
   391  }
   392  
   393  // SetTailBlock set tail block.
   394  func (bc *BlockChain) SetTailBlock(newTail *Block) error {
   395  	if newTail == nil {
   396  		return ErrNilArgument
   397  	}
   398  	oldTail := bc.tailBlock
   399  	ancestor, err := bc.FindCommonAncestorWithTail(newTail)
   400  	if err != nil {
   401  		logging.VLog().WithFields(logrus.Fields{
   402  			"target": newTail,
   403  			"tail":   oldTail,
   404  		}).Debug("Failed to find common ancestor with tail")
   405  		return err
   406  	}
   407  
   408  	if err := bc.revertBlocks(ancestor, oldTail); err != nil {
   409  		logging.VLog().WithFields(logrus.Fields{
   410  			"from":  ancestor,
   411  			"to":    oldTail,
   412  			"range": "(from, to]",
   413  		}).Debug("Failed to revert blocks.")
   414  		return err
   415  	}
   416  
   417  	// build index by block height
   418  	if err := bc.buildIndexByBlockHeight(ancestor, newTail); err != nil {
   419  		logging.VLog().WithFields(logrus.Fields{
   420  			"from":  ancestor,
   421  			"to":    newTail,
   422  			"range": "(from, to]",
   423  		}).Debug("Failed to build index by block height.")
   424  		return err
   425  	}
   426  
   427  	// record new tail
   428  	if err := bc.StoreTailHashToStorage(newTail); err != nil { // Refine: rename, delete ToStorage
   429  		return err
   430  	}
   431  	bc.tailBlock = newTail
   432  
   433  	metricsBlockHeightGauge.Update(int64(newTail.Height()))
   434  	metricsBlocktailHashGauge.Update(int64(byteutils.HashBytes(newTail.Hash())))
   435  
   436  	return nil
   437  }
   438  
   439  // GetBlockOnCanonicalChainByHeight return block in given height
   440  func (bc *BlockChain) GetBlockOnCanonicalChainByHeight(height uint64) *Block {
   441  
   442  	if height > bc.tailBlock.height {
   443  		return nil
   444  	}
   445  
   446  	blockHash, err := bc.storage.Get(byteutils.FromUint64(height))
   447  	if err != nil {
   448  		return nil
   449  	}
   450  	return bc.GetBlock(blockHash)
   451  }
   452  
   453  // GetBlockOnCanonicalChainByHash check if a block is on canonical chain
   454  func (bc *BlockChain) GetBlockOnCanonicalChainByHash(blockHash byteutils.Hash) *Block {
   455  	blockByHash := bc.GetBlock(blockHash)
   456  	if blockByHash == nil {
   457  		logging.VLog().WithFields(logrus.Fields{
   458  			"hash": blockHash.Hex(),
   459  			"tail": bc.tailBlock,
   460  			"err":  "cannot find block with the given hash in local storage",
   461  		}).Debug("Failed to check a block on canonical chain.")
   462  		return nil
   463  	}
   464  	blockByHeight := bc.GetBlockOnCanonicalChainByHeight(blockByHash.height)
   465  	if blockByHeight == nil {
   466  		logging.VLog().WithFields(logrus.Fields{
   467  			"height": blockByHash.height,
   468  			"tail":   bc.tailBlock,
   469  			"err":    "cannot find block with the given height in local storage",
   470  		}).Debug("Failed to check a block on canonical chain.")
   471  		return nil
   472  	}
   473  	if !blockByHeight.Hash().Equals(blockByHash.Hash()) {
   474  		logging.VLog().WithFields(logrus.Fields{
   475  			"blockByHash":   blockByHash,
   476  			"blockByHeight": blockByHeight,
   477  			"tail":          bc.tailBlock,
   478  			"err":           "block with the given hash isn't on canonical chain",
   479  		}).Debug("Failed to check a block on canonical chain.")
   480  		return nil
   481  	}
   482  	return blockByHeight
   483  }
   484  
   485  // GetInputForVRFSigner returns [ getBlock(block.height - 2 * dynasty.size).hash, block.parent.seed ]
   486  func (bc *BlockChain) GetInputForVRFSigner(parentHash byteutils.Hash, height uint64) (ancestorHash, parentSeed []byte, err error) {
   487  	if parentHash == nil || !RandomAvailableAtHeight(height) {
   488  		return nil, nil, ErrInvalidArgument
   489  	}
   490  
   491  	nob := bc.consensusHandler.NumberOfBlocksInDynasty()
   492  	if height > nob*2 {
   493  		b := bc.GetBlockOnCanonicalChainByHeight(height - nob*2)
   494  		if b == nil {
   495  			logging.VLog().WithFields(logrus.Fields{
   496  				"blockHeight":          height,
   497  				"targetHeight":         height - nob,
   498  				"numOfBlocksInDynasty": nob,
   499  			}).Error("Block not found.")
   500  			return nil, nil, ErrNotBlockInCanonicalChain
   501  		}
   502  		ancestorHash = b.Hash()
   503  	} else {
   504  		ancestorHash = bc.GenesisBlock().Hash()
   505  	}
   506  
   507  	parent := bc.GetBlockOnCanonicalChainByHash(parentHash)
   508  	if parent == nil || parent.height+1 != height {
   509  		return nil, nil, ErrInvalidBlockHash
   510  	}
   511  
   512  	if RandomAvailableAtHeight(parent.height) {
   513  		if !parent.HasRandomSeed() {
   514  			logging.VLog().WithFields(logrus.Fields{
   515  				"parent": parent,
   516  			}).Error("Parent block has no random seed, unexpected error.")
   517  			metricsUnexpectedBehavior.Update(1)
   518  			return nil, nil, ErrInvalidBlockRandom
   519  		}
   520  		parentSeed = parent.header.random.VrfSeed
   521  	} else {
   522  		parentSeed = bc.GenesisBlock().Hash()
   523  	}
   524  	return
   525  }
   526  
   527  // FindCommonAncestorWithTail return the block's common ancestor with current tail
   528  func (bc *BlockChain) FindCommonAncestorWithTail(block *Block) (*Block, error) {
   529  	if block == nil {
   530  		return nil, ErrNilArgument
   531  	}
   532  	target := bc.GetBlock(block.Hash())
   533  	if target == nil {
   534  		target = bc.GetBlock(block.ParentHash())
   535  	}
   536  	if target == nil {
   537  		return nil, ErrMissingParentBlock
   538  	}
   539  
   540  	tail := bc.TailBlock()
   541  	if tail.Height() > target.Height() {
   542  		tail = bc.GetBlockOnCanonicalChainByHeight(target.Height())
   543  		if tail == nil {
   544  			return nil, ErrMissingParentBlock
   545  		}
   546  	}
   547  
   548  	for tail.Height() < target.Height() {
   549  		target = bc.GetBlock(target.header.parentHash)
   550  		if target == nil {
   551  			return nil, ErrMissingParentBlock
   552  		}
   553  	}
   554  
   555  	for !tail.Hash().Equals(target.Hash()) {
   556  		tail = bc.GetBlock(tail.header.parentHash)
   557  		target = bc.GetBlock(target.header.parentHash)
   558  		if tail == nil || target == nil {
   559  			return nil, ErrMissingParentBlock
   560  		}
   561  	}
   562  
   563  	return target, nil
   564  }
   565  
   566  // BlockPool return block pool.
   567  func (bc *BlockChain) BlockPool() *BlockPool {
   568  	return bc.bkPool
   569  }
   570  
   571  // TransactionPool return block pool.
   572  func (bc *BlockChain) TransactionPool() *TransactionPool {
   573  	return bc.txPool
   574  }
   575  
   576  // SetConsensusHandler set consensus handler.
   577  func (bc *BlockChain) SetConsensusHandler(handler Consensus) {
   578  	bc.consensusHandler = handler
   579  }
   580  
   581  // SetSyncService set sync service.
   582  func (bc *BlockChain) SetSyncService(syncService SyncService) {
   583  	bc.syncService = syncService
   584  }
   585  
   586  // StartActiveSync start active sync task
   587  func (bc *BlockChain) StartActiveSync() bool {
   588  	if bc.syncService.StartActiveSync() {
   589  		bc.consensusHandler.SuspendMining()
   590  		go func() {
   591  			bc.syncService.WaitingForFinish()
   592  			bc.consensusHandler.ResumeMining()
   593  		}()
   594  		return true
   595  	}
   596  	return false
   597  }
   598  
   599  // IsActiveSyncing returns true if being syncing
   600  func (bc *BlockChain) IsActiveSyncing() bool {
   601  	return bc.syncService.IsActiveSyncing()
   602  }
   603  
   604  // ConsensusHandler return consensus handler.
   605  func (bc *BlockChain) ConsensusHandler() Consensus {
   606  	return bc.consensusHandler
   607  }
   608  
   609  // NewBlock create new #Block instance.
   610  func (bc *BlockChain) NewBlock(coinbase *Address) (*Block, error) {
   611  	if coinbase == nil {
   612  		return nil, ErrInvalidArgument
   613  	}
   614  	return bc.NewBlockFromParent(coinbase, bc.tailBlock)
   615  }
   616  
   617  // NewBlockFromParent create new block from parent block and return it.
   618  func (bc *BlockChain) NewBlockFromParent(coinbase *Address, parentBlock *Block) (*Block, error) {
   619  	if parentBlock == nil || coinbase == nil {
   620  		return nil, ErrNilArgument
   621  	}
   622  	return NewBlock(bc.chainID, coinbase, parentBlock)
   623  }
   624  
   625  // PutVerifiedNewBlocks put verified new blocks and tails.
   626  func (bc *BlockChain) putVerifiedNewBlocks(parent *Block, allBlocks, tailBlocks []*Block) error {
   627  	for _, v := range allBlocks {
   628  		bc.cachedBlocks.Add(v.Hash().Hex(), v)
   629  		if err := bc.StoreBlockToStorage(v); err != nil {
   630  			logging.VLog().WithFields(logrus.Fields{
   631  				"block": v,
   632  				"err":   err,
   633  			}).Debug("Failed to store the verified block.")
   634  			return err
   635  		}
   636  
   637  		logging.VLog().WithFields(logrus.Fields{
   638  			"block": v,
   639  		}).Info("Accepted the new block on chain")
   640  
   641  		metricsBlockOnchainTimer.Update(time.Duration(time.Now().Unix() - v.Timestamp()))
   642  		for _, tx := range v.transactions {
   643  			metricsTxOnchainTimer.Update(time.Duration(time.Now().Unix() - tx.Timestamp()))
   644  		}
   645  	}
   646  	for _, v := range tailBlocks {
   647  		bc.detachedTailBlocks.Add(v.Hash().Hex(), v)
   648  	}
   649  
   650  	bc.detachedTailBlocks.Remove(parent.Hash().Hex())
   651  
   652  	return nil
   653  }
   654  
   655  // DetachedTailBlocks return detached tail blocks, used by Fork Choice algorithm.
   656  func (bc *BlockChain) DetachedTailBlocks() []*Block {
   657  	ret := make([]*Block, 0)
   658  	for _, k := range bc.detachedTailBlocks.Keys() {
   659  		v, _ := bc.detachedTailBlocks.Get(k)
   660  		if v != nil {
   661  			block := v.(*Block)
   662  			ret = append(ret, block)
   663  		}
   664  	}
   665  	return ret
   666  }
   667  
   668  // GetBlock return block of given hash from local storage and detachedBlocks.
   669  func (bc *BlockChain) GetBlock(hash byteutils.Hash) *Block {
   670  	v, _ := bc.cachedBlocks.Get(hash.Hex())
   671  	if v == nil {
   672  		block, err := LoadBlockFromStorage(hash, bc)
   673  		if err != nil {
   674  			return nil
   675  		}
   676  		return block
   677  	}
   678  
   679  	block := v.(*Block)
   680  	return block
   681  }
   682  
   683  // GetContract return contract of given address
   684  func (bc *BlockChain) GetContract(addr *Address) (state.Account, error) {
   685  	worldState, err := bc.TailBlock().WorldState().Clone()
   686  	if err != nil {
   687  		return nil, err
   688  	}
   689  	contract, err := CheckContract(addr, worldState)
   690  	if err != nil {
   691  		return nil, err
   692  	}
   693  	return contract, nil
   694  }
   695  
   696  // GetTransaction return transaction of given hash from local storage.
   697  func (bc *BlockChain) GetTransaction(hash byteutils.Hash) (*Transaction, error) {
   698  	worldState, err := bc.TailBlock().WorldState().Clone()
   699  	if err != nil {
   700  		return nil, err
   701  	}
   702  	tx, err := GetTransaction(hash, worldState)
   703  	if err != nil {
   704  		return nil, err
   705  	}
   706  	return tx, nil
   707  }
   708  
   709  // GetTransactionHeight return transaction's block height
   710  func (bc *BlockChain) GetTransactionHeight(hash byteutils.Hash) (uint64, error) {
   711  	bytes, err := bc.storage.Get(append(hash, []byte(TxBlockHeight)...))
   712  	if err != nil && err != storage.ErrKeyNotFound {
   713  		return 0, err
   714  	}
   715  
   716  	if len(bytes) == 0 {
   717  		// for empty value (history txs), height = 0
   718  		return 0, nil
   719  	}
   720  
   721  	return byteutils.Uint64(bytes), nil
   722  }
   723  
   724  // GasPrice returns the lowest transaction gas price.
   725  func (bc *BlockChain) GasPrice() *util.Uint128 {
   726  	gasPrice := TransactionMaxGasPrice
   727  	tailBlock := bc.TailBlock()
   728  	// search latest block who has transactions, try 128 times at most
   729  	for i := 0; i < 128; i++ {
   730  		// if the block is genesis, stop find the parent block
   731  		if CheckGenesisBlock(tailBlock) {
   732  			break
   733  		}
   734  
   735  		if len(tailBlock.transactions) > 0 {
   736  			break
   737  		}
   738  		tailBlock = bc.GetBlock(tailBlock.ParentHash())
   739  	}
   740  
   741  	if len(tailBlock.transactions) > 0 {
   742  		for _, tx := range tailBlock.transactions {
   743  			if tx.gasPrice.Cmp(gasPrice) < 0 {
   744  				gasPrice = tx.gasPrice
   745  			}
   746  		}
   747  	} else {
   748  		// if no transactions have been submitted, use the default gasPrice
   749  		gasPrice = bc.txPool.GetMinGasPrice()
   750  	}
   751  
   752  	return gasPrice
   753  }
   754  
   755  // SimulateResult the result of simulating transaction execution
   756  type SimulateResult struct {
   757  	GasUsed *util.Uint128
   758  	Msg     string
   759  	Err     error
   760  }
   761  
   762  // SimulateTransactionExecution execute transaction in sandbox and rollback all changes, used to EstimateGas and Call api.
   763  func (bc *BlockChain) SimulateTransactionExecution(tx *Transaction) (*SimulateResult, error) {
   764  	if tx == nil {
   765  		return nil, ErrInvalidArgument
   766  	}
   767  
   768  	// create block.
   769  	block, err := bc.NewBlock(GenesisCoinbase)
   770  	if err != nil {
   771  		return nil, err
   772  	}
   773  
   774  	sVrfSeed, sVrfProof := make([]byte, 32), make([]byte, 129)
   775  	_, _ = io.ReadFull(rand.Reader, sVrfSeed)
   776  	_, _ = io.ReadFull(rand.Reader, sVrfProof)
   777  	block.header.random.VrfSeed = sVrfSeed
   778  	block.header.random.VrfProof = sVrfProof
   779  
   780  	defer block.RollBack()
   781  
   782  	// simulate execution.
   783  	return tx.simulateExecution(block)
   784  }
   785  
   786  // Dump dump full chain.
   787  func (bc *BlockChain) Dump(count int) string {
   788  	rl := []string{}
   789  	block := bc.tailBlock
   790  	rl = append(rl, block.String())
   791  	for i := 1; i < count; i++ {
   792  		if !CheckGenesisBlock(block) {
   793  			block = bc.GetBlock(block.ParentHash())
   794  			rl = append(rl, block.String())
   795  		}
   796  	}
   797  
   798  	rls := "[" + strings.Join(rl, ",") + "]"
   799  	return rls
   800  }
   801  
   802  // StoreBlockToStorage store block
   803  func (bc *BlockChain) StoreBlockToStorage(block *Block) error {
   804  	pbBlock, err := block.ToProto()
   805  	if err != nil {
   806  		return err
   807  	}
   808  	value, err := proto.Marshal(pbBlock)
   809  	if err != nil {
   810  		return err
   811  	}
   812  	err = bc.storage.Put(block.Hash(), value)
   813  	if err != nil {
   814  		return err
   815  	}
   816  	return nil
   817  }
   818  
   819  // StoreTailHashToStorage store tail block hash
   820  func (bc *BlockChain) StoreTailHashToStorage(block *Block) error { // ToRefine, update func to StoreTailHashToStorage
   821  	return bc.storage.Put([]byte(Tail), block.Hash())
   822  }
   823  
   824  // StoreLIBHashToStorage store LIB block hash
   825  func (bc *BlockChain) StoreLIBHashToStorage(block *Block) error {
   826  	return bc.storage.Put([]byte(LIB), block.Hash())
   827  }
   828  
   829  // LoadTailFromStorage load tail block
   830  func (bc *BlockChain) LoadTailFromStorage() (*Block, error) {
   831  	hash, err := bc.storage.Get([]byte(Tail))
   832  	if err != nil && err != storage.ErrKeyNotFound {
   833  		return nil, err
   834  	}
   835  	if err == storage.ErrKeyNotFound {
   836  		genesis, err := bc.LoadGenesisFromStorage()
   837  		if err != nil {
   838  			return nil, err
   839  		}
   840  
   841  		if err := bc.StoreTailHashToStorage(genesis); err != nil {
   842  			return nil, err
   843  		}
   844  
   845  		return genesis, nil
   846  	}
   847  
   848  	return LoadBlockFromStorage(hash, bc)
   849  }
   850  
   851  // LoadGenesisFromStorage load genesis
   852  func (bc *BlockChain) LoadGenesisFromStorage() (*Block, error) { // ToRefine, remove or ?
   853  	genesis, err := LoadBlockFromStorage(GenesisHash, bc)
   854  	if err != nil && err != storage.ErrKeyNotFound {
   855  		return nil, err
   856  	}
   857  	if err == storage.ErrKeyNotFound {
   858  		genesis, err = NewGenesisBlock(bc.genesis, bc)
   859  		if err != nil {
   860  			return nil, err
   861  		}
   862  		if err := bc.StoreBlockToStorage(genesis); err != nil {
   863  			return nil, err
   864  		}
   865  		heightKey := byteutils.FromUint64(genesis.height)
   866  		if err := bc.storage.Put(heightKey, genesis.Hash()); err != nil {
   867  			return nil, err
   868  		}
   869  	}
   870  	return genesis, nil
   871  }
   872  
   873  // LoadLIBFromStorage load LIB
   874  func (bc *BlockChain) LoadLIBFromStorage() (*Block, error) {
   875  	hash, err := bc.storage.Get([]byte(LIB))
   876  	if err != nil && err != storage.ErrKeyNotFound {
   877  		return nil, err
   878  	}
   879  
   880  	if err == storage.ErrKeyNotFound {
   881  		if err := bc.StoreLIBHashToStorage(bc.genesisBlock); err != nil {
   882  			return nil, err
   883  		}
   884  		return bc.genesisBlock, nil
   885  	}
   886  
   887  	return LoadBlockFromStorage(hash, bc)
   888  }