github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/cache.go (about) 1 package types 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 8 ethcmn "github.com/ethereum/go-ethereum/common" 9 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 10 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto" 11 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 12 "github.com/spf13/viper" 13 ) 14 15 var ( 16 maxAccInMap = 100000 17 deleteAccCount = 10000 18 maxStorageInMap = 10000000 19 deleteStorageCount = 1000000 20 21 FlagMultiCache = "multi-cache" 22 MaxAccInMultiCache = "multi-cache-acc" 23 MaxStorageInMultiCache = "multi-cache-storage" 24 UseCache bool 25 ) 26 27 type Account interface { 28 Copy() Account 29 GetAddress() AccAddress 30 SetAddress(AccAddress) error 31 GetPubKey() crypto.PubKey 32 SetPubKey(crypto.PubKey) error 33 GetAccountNumber() uint64 34 SetAccountNumber(uint64) error 35 GetSequence() uint64 36 SetSequence(uint64) error 37 GetCoins() Coins 38 SetCoins(Coins) error 39 SpendableCoins(blockTime time.Time) Coins 40 String() string 41 } 42 43 type ModuleAccount interface { 44 Account 45 46 GetName() string 47 GetPermissions() []string 48 HasPermission(string) bool 49 } 50 51 type storageWithCache struct { 52 value []byte 53 dirty bool 54 } 55 56 type accountWithCache struct { 57 acc Account 58 gas uint64 59 isDirty bool 60 } 61 62 type codeWithCache struct { 63 code []byte 64 isDirty bool 65 } 66 67 type Cache struct { 68 useCache bool 69 parent *Cache 70 gasConfig types.GasConfig 71 72 storageMap map[ethcmn.Address]map[ethcmn.Hash]*storageWithCache 73 accMap map[ethcmn.Address]*accountWithCache 74 codeMap map[ethcmn.Hash]*codeWithCache 75 76 accMutex sync.RWMutex 77 } 78 79 func initCacheParam() { 80 UseCache = viper.GetBool(FlagMultiCache) 81 82 if data := viper.GetInt(MaxAccInMultiCache); data != 0 { 83 maxAccInMap = data 84 deleteAccCount = maxAccInMap / 10 85 } 86 87 if data := viper.GetInt(MaxStorageInMultiCache); data != 0 { 88 maxStorageInMap = data 89 deleteStorageCount = maxStorageInMap / 10 90 } 91 } 92 93 func NewChainCache() *Cache { 94 initCacheParam() 95 return NewCache(nil, UseCache) 96 } 97 98 func (c *Cache) Clear() { 99 if c == nil { 100 return 101 } 102 103 c.storageMap = make(map[ethcmn.Address]map[ethcmn.Hash]*storageWithCache) 104 c.codeMap = make(map[ethcmn.Hash]*codeWithCache) 105 c.accMap = make(map[ethcmn.Address]*accountWithCache) 106 c.useCache = false 107 } 108 109 func NewCache(parent *Cache, useCache bool) *Cache { 110 return &Cache{ 111 useCache: useCache, 112 parent: parent, 113 114 storageMap: make(map[ethcmn.Address]map[ethcmn.Hash]*storageWithCache), 115 accMap: make(map[ethcmn.Address]*accountWithCache), 116 codeMap: make(map[ethcmn.Hash]*codeWithCache), 117 gasConfig: types.KVGasConfig(), 118 } 119 120 } 121 122 func (c *Cache) skip() bool { 123 if c == nil || !c.useCache { 124 return true 125 } 126 return false 127 } 128 129 func (c *Cache) IsEnabled() bool { 130 return !c.skip() 131 } 132 133 func (c *Cache) DisableCache() { 134 c.useCache = false 135 } 136 137 func (c *Cache) UpdateAccount(addr AccAddress, acc Account, lenBytes int, isDirty bool) { 138 if c.skip() { 139 return 140 } 141 ethAddr := ethcmn.BytesToAddress(addr.Bytes()) 142 accWithCache := &accountWithCache{ 143 acc: acc, 144 isDirty: isDirty, 145 gas: types.Gas(lenBytes)*c.gasConfig.ReadCostPerByte + c.gasConfig.ReadCostFlat, 146 } 147 c.accMutex.Lock() 148 c.accMap[ethAddr] = accWithCache 149 c.accMutex.Unlock() 150 } 151 152 func (c *Cache) UpdateStorage(addr ethcmn.Address, key ethcmn.Hash, value []byte, isDirty bool) { 153 if c.skip() { 154 return 155 } 156 157 if _, ok := c.storageMap[addr]; !ok { 158 c.storageMap[addr] = make(map[ethcmn.Hash]*storageWithCache, 0) 159 } 160 c.storageMap[addr][key] = &storageWithCache{ 161 value: value, 162 dirty: isDirty, 163 } 164 } 165 166 func (c *Cache) UpdateCode(key []byte, value []byte, isdirty bool) { 167 if c.skip() { 168 return 169 } 170 hash := ethcmn.BytesToHash(key) 171 c.codeMap[hash] = &codeWithCache{ 172 code: value, 173 isDirty: isdirty, 174 } 175 } 176 177 func (c *Cache) GetAccount(addr ethcmn.Address) (Account, uint64, bool) { 178 if c.skip() { 179 return nil, 0, false 180 } 181 182 c.accMutex.RLock() 183 data, ok := c.accMap[addr] 184 c.accMutex.RUnlock() 185 if ok { 186 return data.acc, data.gas, ok 187 } 188 189 if c.parent != nil { 190 acc, gas, ok := c.parent.GetAccount(addr) 191 return acc, gas, ok 192 } 193 return nil, 0, false 194 } 195 196 func (c *Cache) GetStorage(addr ethcmn.Address, key ethcmn.Hash) ([]byte, bool) { 197 if c.skip() { 198 return nil, false 199 } 200 if _, hasAddr := c.storageMap[addr]; hasAddr { 201 data, hasKey := c.storageMap[addr][key] 202 if hasKey { 203 return data.value, hasKey 204 } 205 } 206 207 if c.parent != nil { 208 return c.parent.GetStorage(addr, key) 209 } 210 return nil, false 211 } 212 213 func (c *Cache) GetCode(key []byte) ([]byte, bool) { 214 if c.skip() { 215 return nil, false 216 } 217 218 hash := ethcmn.BytesToHash(key) 219 if data, ok := c.codeMap[hash]; ok { 220 return data.code, ok 221 } 222 223 if c.parent != nil { 224 return c.parent.GetCode(hash.Bytes()) 225 } 226 return nil, false 227 } 228 229 func (c *Cache) Write(updateDirty bool) { 230 if c.skip() { 231 return 232 } 233 234 if c.parent == nil { 235 return 236 } 237 238 c.writeStorage(updateDirty) 239 c.writeAcc(updateDirty) 240 c.writeCode(updateDirty) 241 } 242 243 func (c *Cache) writeStorage(updateDirty bool) { 244 for addr, storages := range c.storageMap { 245 if _, ok := c.parent.storageMap[addr]; !ok { 246 c.parent.storageMap[addr] = make(map[ethcmn.Hash]*storageWithCache, 0) 247 } 248 249 for key, v := range storages { 250 if needWriteToParent(updateDirty, v.dirty) { 251 c.parent.storageMap[addr][key] = v 252 } 253 } 254 } 255 c.storageMap = make(map[ethcmn.Address]map[ethcmn.Hash]*storageWithCache) 256 } 257 258 func (c *Cache) setAcc(addr ethcmn.Address, v *accountWithCache) { 259 c.accMutex.Lock() 260 c.accMap[addr] = v 261 c.accMutex.Unlock() 262 } 263 264 func (c *Cache) writeAcc(updateDirty bool) { 265 c.accMutex.RLock() 266 for addr, v := range c.accMap { 267 if needWriteToParent(updateDirty, v.isDirty) { 268 c.parent.setAcc(addr, v) 269 } 270 } 271 c.accMutex.RUnlock() 272 273 c.accMutex.Lock() 274 for k := range c.accMap { 275 delete(c.accMap, k) 276 } 277 c.accMutex.Unlock() 278 } 279 280 func (c *Cache) writeCode(updateDirty bool) { 281 for hash, v := range c.codeMap { 282 if needWriteToParent(updateDirty, v.isDirty) { 283 c.parent.codeMap[hash] = v 284 } 285 } 286 c.codeMap = make(map[ethcmn.Hash]*codeWithCache) 287 } 288 289 func needWriteToParent(updateDirty bool, dirty bool) bool { 290 // not dirty 291 if !dirty { 292 return true 293 } 294 295 // dirty 296 if updateDirty { 297 return true 298 } 299 return false 300 } 301 302 func (c *Cache) storageSize() int { 303 lenStorage := 0 304 for _, v := range c.storageMap { 305 lenStorage += len(v) 306 } 307 return lenStorage 308 } 309 310 func (c *Cache) TryDelete(logger log.Logger, height int64) { 311 if c.skip() { 312 return 313 } 314 if height%1000 == 0 { 315 c.logInfo(logger, "null") 316 } 317 318 lenStorage := c.storageSize() 319 if c.lenOfAccMap() < maxAccInMap && lenStorage < maxStorageInMap { 320 return 321 } 322 323 deleteMsg := "" 324 lenOfAcc := c.lenOfAccMap() 325 if lenOfAcc >= maxAccInMap { 326 deleteMsg += fmt.Sprintf("Acc:Deleted Before:%d", lenOfAcc) 327 cnt := 0 328 c.accMutex.Lock() 329 for key := range c.accMap { 330 delete(c.accMap, key) 331 cnt++ 332 if cnt > deleteAccCount { 333 break 334 } 335 } 336 c.accMutex.Unlock() 337 } 338 339 if lenStorage >= maxStorageInMap { 340 deleteMsg += fmt.Sprintf("Storage:Deleted Before:len(contract):%d, len(storage):%d", len(c.storageMap), lenStorage) 341 cnt := 0 342 for key, value := range c.storageMap { 343 cnt += len(value) 344 delete(c.storageMap, key) 345 if cnt > deleteStorageCount { 346 break 347 } 348 } 349 } 350 if deleteMsg != "" { 351 c.logInfo(logger, deleteMsg) 352 } 353 } 354 355 func (c *Cache) logInfo(logger log.Logger, deleteMsg string) { 356 nowStats := fmt.Sprintf("len(acc):%d len(contracts):%d len(storage):%d", c.lenOfAccMap(), len(c.storageMap), c.storageSize()) 357 logger.Info("MultiCache", "deleteMsg", deleteMsg, "nowStats", nowStats) 358 } 359 360 func (c *Cache) lenOfAccMap() (l int) { 361 c.accMutex.RLock() 362 l = len(c.accMap) 363 c.accMutex.RUnlock() 364 return 365 }