github.com/dominant-strategies/go-quai@v0.28.2/core/bodydb.go (about)

     1  package core
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/dominant-strategies/go-quai/common"
     8  	"github.com/dominant-strategies/go-quai/consensus"
     9  	"github.com/dominant-strategies/go-quai/core/rawdb"
    10  	"github.com/dominant-strategies/go-quai/core/types"
    11  	"github.com/dominant-strategies/go-quai/core/vm"
    12  	"github.com/dominant-strategies/go-quai/ethdb"
    13  	"github.com/dominant-strategies/go-quai/event"
    14  	"github.com/dominant-strategies/go-quai/log"
    15  	"github.com/dominant-strategies/go-quai/params"
    16  	lru "github.com/hashicorp/golang-lru"
    17  )
    18  
    19  const (
    20  	bodyCacheLimit     = 256
    21  	blockCacheLimit    = 256
    22  	maxHeadsQueueLimit = 1024
    23  )
    24  
    25  type BodyDb struct {
    26  	chainConfig *params.ChainConfig // Chain & network configuration
    27  
    28  	db ethdb.Database // Low level persistent database to store final content in
    29  
    30  	chainFeed     event.Feed
    31  	chainSideFeed event.Feed
    32  	rmLogsFeed    event.Feed
    33  	logsFeed      event.Feed
    34  	blockProcFeed event.Feed
    35  	scope         event.SubscriptionScope
    36  
    37  	engine       consensus.Engine
    38  	chainmu      sync.RWMutex
    39  	blockCache   *lru.Cache
    40  	bodyCache    *lru.Cache
    41  	bodyRLPCache *lru.Cache
    42  	processor    *StateProcessor
    43  
    44  	slicesRunning []common.Location
    45  }
    46  
    47  func NewBodyDb(db ethdb.Database, engine consensus.Engine, hc *HeaderChain, chainConfig *params.ChainConfig, cacheConfig *CacheConfig, txLookupLimit *uint64, vmConfig vm.Config, slicesRunning []common.Location) (*BodyDb, error) {
    48  	nodeCtx := common.NodeLocation.Context()
    49  
    50  	bc := &BodyDb{
    51  		chainConfig:   chainConfig,
    52  		engine:        engine,
    53  		db:            db,
    54  		slicesRunning: slicesRunning,
    55  	}
    56  
    57  	// Limiting the number of blocks to be stored in the cache in the case of
    58  	// slices that are not being processed by the node. This helps lower the RAM
    59  	// requirement on the slice nodes
    60  	if bc.ProcessingState() {
    61  		blockCache, _ := lru.New(blockCacheLimit)
    62  		bodyCache, _ := lru.New(bodyCacheLimit)
    63  		bodyRLPCache, _ := lru.New(bodyCacheLimit)
    64  		bc.blockCache = blockCache
    65  		bc.bodyCache = bodyCache
    66  		bc.bodyRLPCache = bodyRLPCache
    67  	} else {
    68  		blockCache, _ := lru.New(10)
    69  		bodyCache, _ := lru.New(10)
    70  		bodyRLPCache, _ := lru.New(10)
    71  		bc.blockCache = blockCache
    72  		bc.bodyCache = bodyCache
    73  		bc.bodyRLPCache = bodyRLPCache
    74  	}
    75  
    76  	// only start the state processor in zone
    77  	if nodeCtx == common.ZONE_CTX && bc.ProcessingState() {
    78  		bc.processor = NewStateProcessor(chainConfig, hc, engine, vmConfig, cacheConfig, txLookupLimit)
    79  		vm.InitializePrecompiles()
    80  	}
    81  
    82  	return bc, nil
    83  }
    84  
    85  // Append
    86  func (bc *BodyDb) Append(block *types.Block, newInboundEtxs types.Transactions) ([]*types.Log, error) {
    87  	bc.chainmu.Lock()
    88  	defer bc.chainmu.Unlock()
    89  
    90  	batch := bc.db.NewBatch()
    91  	stateApply := time.Now()
    92  	nodeCtx := common.NodeLocation.Context()
    93  	var logs []*types.Log
    94  	var err error
    95  	if nodeCtx == common.ZONE_CTX && bc.ProcessingState() {
    96  		// Process our block
    97  		logs, err = bc.processor.Apply(batch, block, newInboundEtxs)
    98  		if err != nil {
    99  			return nil, err
   100  		}
   101  		rawdb.WriteTxLookupEntriesByBlock(batch, block)
   102  	}
   103  	log.Debug("Time taken to", "apply state:", common.PrettyDuration(time.Since(stateApply)))
   104  	if err = batch.Write(); err != nil {
   105  		return nil, err
   106  	}
   107  	return logs, nil
   108  }
   109  
   110  func (bc *BodyDb) ProcessingState() bool {
   111  	nodeCtx := common.NodeLocation.Context()
   112  	for _, slice := range bc.slicesRunning {
   113  		switch nodeCtx {
   114  		case common.PRIME_CTX:
   115  			return true
   116  		case common.REGION_CTX:
   117  			if slice.Region() == common.NodeLocation.Region() {
   118  				return true
   119  			}
   120  		case common.ZONE_CTX:
   121  			if slice.Equal(common.NodeLocation) {
   122  				return true
   123  			}
   124  		}
   125  	}
   126  	return false
   127  }
   128  
   129  // WriteBlock write the block to the bodydb database
   130  func (bc *BodyDb) WriteBlock(block *types.Block) {
   131  	// add the block to the cache as well
   132  	bc.blockCache.Add(block.Hash(), block)
   133  	rawdb.WriteBlock(bc.db, block)
   134  }
   135  
   136  // HasBlock checks if a block is fully present in the database or not.
   137  func (bc *BodyDb) HasBlock(hash common.Hash, number uint64) bool {
   138  	if bc.blockCache.Contains(hash) {
   139  		return true
   140  	}
   141  	return rawdb.HasBody(bc.db, hash, number)
   142  }
   143  
   144  // Engine retreives the BodyDb consensus engine.
   145  func (bc *BodyDb) Engine() consensus.Engine {
   146  	return bc.engine
   147  }
   148  
   149  // GetBlock retrieves a block from the database by hash and number,
   150  // caching it if found.
   151  func (bc *BodyDb) GetBlock(hash common.Hash, number uint64) *types.Block {
   152  	termini := rawdb.ReadTermini(bc.db, hash)
   153  	if termini == nil {
   154  		return nil
   155  	}
   156  	// Short circuit if the block's already in the cache, retrieve otherwise
   157  	if block, ok := bc.blockCache.Get(hash); ok {
   158  		return block.(*types.Block)
   159  	}
   160  	block := rawdb.ReadBlock(bc.db, hash, number)
   161  	if block == nil {
   162  		return nil
   163  	}
   164  	// Cache the found block for next time and return
   165  	bc.blockCache.Add(block.Hash(), block)
   166  	return block
   167  }
   168  
   169  // GetBlockOrCandidate retrieves any known block from the database by hash and number,
   170  // caching it if found.
   171  func (bc *BodyDb) GetBlockOrCandidate(hash common.Hash, number uint64) *types.Block {
   172  	block := rawdb.ReadBlock(bc.db, hash, number)
   173  	if block == nil {
   174  		return nil
   175  	}
   176  	return block
   177  }
   178  
   179  func (bc *BodyDb) Processor() *StateProcessor {
   180  	return bc.processor
   181  }
   182  
   183  // Config retrieves the chain's fork configuration.
   184  func (bc *BodyDb) Config() *params.ChainConfig { return bc.chainConfig }
   185  
   186  // SubscribeChainEvent registers a subscription of ChainEvent.
   187  func (bc *BodyDb) SubscribeChainEvent(ch chan<- ChainEvent) event.Subscription {
   188  	return bc.scope.Track(bc.chainFeed.Subscribe(ch))
   189  }
   190  
   191  // SubscribeRemovedLogsEvent registers a subscription of RemovedLogsEvent.
   192  func (bc *BodyDb) SubscribeRemovedLogsEvent(ch chan<- RemovedLogsEvent) event.Subscription {
   193  	return bc.scope.Track(bc.rmLogsFeed.Subscribe(ch))
   194  }
   195  
   196  // SubscribeLogsEvent registers a subscription of []*types.Log.
   197  func (bc *BodyDb) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   198  	return bc.scope.Track(bc.logsFeed.Subscribe(ch))
   199  }
   200  
   201  // SubscribeBlockProcessingEvent registers a subscription of bool where true means
   202  // block processing has started while false means it has stopped.
   203  func (bc *BodyDb) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription {
   204  	return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
   205  }
   206  
   207  func (bc *BodyDb) HasBlockAndState(hash common.Hash, number uint64) bool {
   208  	return bc.processor.HasBlockAndState(hash, number)
   209  }