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 }