github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/types/statedb.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "fmt" 7 ethermint "github.com/fibonacci-chain/fbc/app/types" 8 "github.com/tendermint/go-amino" 9 "math/big" 10 "sort" 11 "sync" 12 13 "github.com/fibonacci-chain/fbc/libs/system/trace" 14 15 "github.com/ethereum/go-ethereum/common" 16 ethcmn "github.com/ethereum/go-ethereum/common" 17 "github.com/ethereum/go-ethereum/core/rawdb" 18 ethstate "github.com/ethereum/go-ethereum/core/state" 19 ethtypes "github.com/ethereum/go-ethereum/core/types" 20 ethvm "github.com/ethereum/go-ethereum/core/vm" 21 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 22 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mpt" 23 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/prefix" 24 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 25 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 26 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth" 27 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 28 ) 29 30 var ( 31 _ ethvm.StateDB = (*CommitStateDB)(nil) 32 33 zeroBalance = sdk.ZeroInt().BigInt() 34 ) 35 36 type revision struct { 37 id int 38 journalIndex int 39 } 40 41 type CommitStateDBParams struct { 42 StoreKey sdk.StoreKey 43 ParamSpace Subspace 44 AccountKeeper AccountKeeper 45 SupplyKeeper SupplyKeeper 46 BankKeeper BankKeeper 47 Ada DbAdapter 48 // Amino codec 49 Cdc *codec.Codec 50 51 DB ethstate.Database 52 Trie ethstate.Trie 53 RootHash ethcmn.Hash 54 } 55 56 type Watcher interface { 57 SaveAccount(account auth.Account, isDirectly bool) 58 AddDelAccMsg(account auth.Account, isDirectly bool) 59 SaveState(addr ethcmn.Address, key, value []byte) 60 Enabled() bool 61 SaveContractBlockedListItem(addr sdk.AccAddress) 62 SaveContractDeploymentWhitelistItem(addr sdk.AccAddress) 63 DeleteContractBlockedList(addr sdk.AccAddress) 64 DeleteContractDeploymentWhitelist(addr sdk.AccAddress) 65 SaveContractMethodBlockedListItem(addr sdk.AccAddress, methods []byte) 66 } 67 68 type CacheCode struct { 69 CodeHash []byte 70 Code []byte 71 } 72 73 // CommitStateDB implements the Geth state.StateDB interface. Instead of using 74 // a trie and database for querying and persistence, the Keeper uses KVStores 75 // and an account mapper is used to facilitate state transitions. 76 // 77 // TODO: This implementation is subject to change in regards to its statefull 78 // manner. In otherwords, how this relates to the keeper in this module. 79 // Warning!!! If you change CommitStateDB.member you must be careful ResetCommitStateDB contract BananaLF. 80 type CommitStateDB struct { 81 db ethstate.Database 82 trie ethstate.Trie // only storage addr -> storageMptRoot in this mpt tree 83 prefetcher *mpt.TriePrefetcher 84 originalRoot ethcmn.Hash 85 86 // TODO: We need to store the context as part of the structure itself opposed 87 // to being passed as a parameter (as it should be) in order to implement the 88 // StateDB interface. Perhaps there is a better way. 89 ctx sdk.Context 90 91 storeKey sdk.StoreKey 92 paramSpace Subspace 93 accountKeeper AccountKeeper 94 supplyKeeper SupplyKeeper 95 bankKeeper BankKeeper 96 97 // array that hold 'live' objects, which will get modified while processing a 98 // state transition 99 stateObjects map[ethcmn.Address]*stateObject 100 stateObjectsPending map[ethcmn.Address]struct{} // State objects finalized but not yet written to the mpt tree 101 stateObjectsDirty map[ethcmn.Address]struct{} // State objects modified in the current execution 102 103 // The refund counter, also used by state transitioning. 104 refund uint64 105 106 thash, bhash ethcmn.Hash 107 txIndex int 108 logSize uint 109 logs map[ethcmn.Hash][]*ethtypes.Log 110 111 preimages map[ethcmn.Hash][]byte 112 113 // DB error. 114 // State objects are used by the consensus core and VM which are 115 // unable to deal with database-level errors. Any error that occurs 116 // during a database read is memo-ized here and will eventually be returned 117 // by StateDB.Commit. 118 dbErr error 119 120 // Journal of state modifications. This is the backbone of 121 // Snapshot and RevertToSnapshot. 122 journal *journal 123 validRevisions []revision 124 nextRevisionID int 125 126 // Per-transaction access list 127 accessList *accessList 128 129 // mutex for state deep copying 130 lock sync.Mutex 131 132 params *Params 133 codeCache map[ethcmn.Address]CacheCode 134 dbAdapter DbAdapter 135 136 // Amino codec 137 cdc *codec.Codec 138 139 updatedAccount map[ethcmn.Address]struct{} // will destroy every block 140 141 GuFactor sdk.Dec 142 } 143 144 // Warning!!! If you change CommitStateDB.member you must be careful ResetCommitStateDB contract BananaLF. 145 146 type StoreProxy interface { 147 Set(key, value []byte) 148 Get(key []byte) []byte 149 Delete(key []byte) 150 Has(key []byte) bool 151 } 152 153 type DbAdapter interface { 154 NewStore(parent types.KVStore, prefix []byte) StoreProxy 155 } 156 157 type DefaultPrefixDb struct { 158 } 159 160 func (d DefaultPrefixDb) NewStore(parent types.KVStore, Prefix []byte) StoreProxy { 161 return prefix.NewStore(parent, Prefix) 162 } 163 164 // NewCommitStateDB returns a reference to a newly initialized CommitStateDB 165 // which implements Geth's state.StateDB interface. 166 // 167 // CONTRACT: Stores used for state must be cache-wrapped as the ordering of the 168 // key/value space matters in determining the merkle root. 169 func NewCommitStateDB(csdbParams CommitStateDBParams) *CommitStateDB { 170 csdb := &CommitStateDB{ 171 db: csdbParams.DB, 172 trie: csdbParams.Trie, 173 originalRoot: csdbParams.RootHash, 174 175 storeKey: csdbParams.StoreKey, 176 paramSpace: csdbParams.ParamSpace, 177 accountKeeper: csdbParams.AccountKeeper, 178 supplyKeeper: csdbParams.SupplyKeeper, 179 bankKeeper: csdbParams.BankKeeper, 180 cdc: csdbParams.Cdc, 181 182 stateObjects: make(map[ethcmn.Address]*stateObject), 183 stateObjectsPending: make(map[ethcmn.Address]struct{}), 184 stateObjectsDirty: make(map[ethcmn.Address]struct{}), 185 preimages: make(map[ethcmn.Hash][]byte), 186 journal: newJournal(), 187 validRevisions: []revision{}, 188 accessList: newAccessList(), 189 logSize: 0, 190 logs: make(map[ethcmn.Hash][]*ethtypes.Log), 191 codeCache: make(map[ethcmn.Address]CacheCode, 0), 192 dbAdapter: csdbParams.Ada, 193 updatedAccount: make(map[ethcmn.Address]struct{}), 194 GuFactor: DefaultGuFactor, 195 } 196 197 return csdb 198 } 199 200 func ResetCommitStateDB(csdb *CommitStateDB, csdbParams CommitStateDBParams, ctx *sdk.Context) { 201 csdb.db = csdbParams.DB 202 csdb.trie = csdbParams.Trie 203 csdb.originalRoot = csdbParams.RootHash 204 205 csdb.storeKey = csdbParams.StoreKey 206 csdb.paramSpace = csdbParams.ParamSpace 207 csdb.accountKeeper = csdbParams.AccountKeeper 208 csdb.supplyKeeper = csdbParams.SupplyKeeper 209 csdb.bankKeeper = csdbParams.BankKeeper 210 csdb.cdc = csdbParams.Cdc 211 212 if csdb.stateObjects != nil { 213 for k := range csdb.stateObjects { 214 delete(csdb.stateObjects, k) 215 } 216 } else { 217 csdb.stateObjects = make(map[ethcmn.Address]*stateObject) 218 } 219 220 if csdb.stateObjectsPending != nil { 221 for k := range csdb.stateObjectsPending { 222 delete(csdb.stateObjectsPending, k) 223 } 224 } else { 225 csdb.stateObjectsPending = make(map[ethcmn.Address]struct{}) 226 } 227 228 if csdb.stateObjectsDirty != nil { 229 for k := range csdb.stateObjectsDirty { 230 delete(csdb.stateObjectsDirty, k) 231 } 232 } else { 233 csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{}) 234 } 235 236 if csdb.preimages != nil { 237 for k := range csdb.preimages { 238 delete(csdb.preimages, k) 239 } 240 } else { 241 csdb.preimages = make(map[ethcmn.Hash][]byte) 242 } 243 244 if csdb.journal != nil { 245 csdb.journal.entries = nil 246 if csdb.journal.dirties != nil { 247 for k := range csdb.journal.dirties { 248 delete(csdb.journal.dirties, k) 249 } 250 } else { 251 csdb.journal.dirties = make(map[ethcmn.Address]int) 252 } 253 } else { 254 csdb.journal = newJournal() 255 } 256 257 if csdb.validRevisions != nil { 258 csdb.validRevisions = csdb.validRevisions[:0] 259 } else { 260 csdb.validRevisions = []revision{} 261 } 262 263 if csdb.accessList != nil { 264 if csdb.accessList.addresses != nil { 265 for k := range csdb.accessList.addresses { 266 delete(csdb.accessList.addresses, k) 267 } 268 } else { 269 csdb.accessList.addresses = make(map[ethcmn.Address]int) 270 } 271 csdb.accessList.slots = nil 272 } else { 273 csdb.accessList = newAccessList() 274 } 275 276 csdb.logSize = 0 277 278 if csdb.logs != nil { 279 for k := range csdb.logs { 280 delete(csdb.logs, k) 281 } 282 } else { 283 csdb.logs = make(map[ethcmn.Hash][]*ethtypes.Log) 284 } 285 286 if csdb.codeCache != nil { 287 for k := range csdb.codeCache { 288 delete(csdb.codeCache, k) 289 } 290 } else { 291 csdb.codeCache = make(map[ethcmn.Address]CacheCode, 0) 292 } 293 294 csdb.dbAdapter = csdbParams.Ada 295 296 if csdb.updatedAccount != nil { 297 for k := range csdb.updatedAccount { 298 delete(csdb.updatedAccount, k) 299 } 300 } else { 301 csdb.updatedAccount = make(map[ethcmn.Address]struct{}) 302 } 303 304 csdb.prefetcher = nil 305 csdb.ctx = *ctx 306 csdb.refund = 0 307 csdb.thash = ethcmn.Hash{} 308 csdb.bhash = ethcmn.Hash{} 309 csdb.txIndex = 0 310 csdb.dbErr = nil 311 csdb.nextRevisionID = 0 312 csdb.params = nil 313 csdb.GuFactor = DefaultGuFactor 314 } 315 316 func CreateEmptyCommitStateDB(csdbParams CommitStateDBParams, ctx sdk.Context) *CommitStateDB { 317 csdb := NewCommitStateDB(csdbParams).WithContext(ctx) 318 return csdb 319 } 320 321 func (csdb *CommitStateDB) WithHistoricalTrie() *CommitStateDB { 322 heightBytes := sdk.Uint64ToBigEndian(uint64(csdb.ctx.BlockHeight())) 323 rst, err := csdb.db.TrieDB().DiskDB().Get(append(mpt.KeyPrefixEvmRootMptHash, heightBytes...)) 324 if err != nil || len(rst) == 0 { 325 return csdb 326 } 327 rootHash := ethcmn.BytesToHash(rst) 328 tire, err := csdb.db.OpenTrie(rootHash) 329 if err != nil { 330 return csdb 331 } 332 csdb.originalRoot = rootHash 333 csdb.trie = tire 334 return csdb 335 } 336 337 func (csdb *CommitStateDB) SetInternalDb(dba DbAdapter) { 338 csdb.dbAdapter = dba 339 } 340 341 // WithContext returns a Database with an updated SDK context 342 func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB { 343 csdb.ctx = ctx 344 return csdb 345 } 346 347 func (csdb *CommitStateDB) GetCacheCode(addr ethcmn.Address) *CacheCode { 348 if !csdb.ctx.IsCheckTx() { 349 funcName := "GetCacheCode" 350 trace.StartTxLog(funcName) 351 defer trace.StopTxLog(funcName) 352 } 353 354 code, ok := csdb.codeCache[addr] 355 if ok { 356 return &code 357 } 358 359 return nil 360 } 361 362 func (csdb *CommitStateDB) IteratorCode(cb func(addr ethcmn.Address, c CacheCode) bool) { 363 for addr, v := range csdb.codeCache { 364 cb(addr, v) 365 } 366 } 367 368 // ---------------------------------------------------------------------------- 369 // Setters 370 // ---------------------------------------------------------------------------- 371 372 // SetHeightHash sets the block header hash associated with a given height. 373 func (csdb *CommitStateDB) SetHeightHash(height uint64, hash ethcmn.Hash) { 374 if !csdb.ctx.IsCheckTx() { 375 funcName := "SetHeightHash" 376 trace.StartTxLog(funcName) 377 defer trace.StopTxLog(funcName) 378 } 379 380 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 381 csdb.setHeightHashInRawDB(height, hash) 382 return 383 } 384 385 store := csdb.dbAdapter.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightHash) 386 key := HeightHashKey(height) 387 store.Set(key, hash.Bytes()) 388 if mpt.TrieWriteAhead { 389 csdb.setHeightHashInRawDB(height, hash) 390 } 391 } 392 393 // SetParams sets the evm parameters to the param space. 394 func (csdb *CommitStateDB) SetParams(params Params) { 395 csdb.params = ¶ms 396 csdb.paramSpace.SetParamSet(csdb.ctx, ¶ms) 397 GetEvmParamsCache().SetNeedParamsUpdate() 398 } 399 400 // SetStorage replaces the entire storage for the specified account with given 401 // storage. This function should only be used for debugging. 402 func (csdb *CommitStateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) { 403 stateObject := csdb.GetOrNewStateObject(addr) 404 if stateObject != nil { 405 stateObject.SetStorage(storage) 406 } 407 } 408 409 // SetBalance sets the balance of an account. 410 func (csdb *CommitStateDB) SetBalance(addr ethcmn.Address, amount *big.Int) { 411 so := csdb.GetOrNewStateObject(addr) 412 if so != nil { 413 so.SetBalance(amount) 414 } 415 } 416 417 // AddBalance adds amount to the account associated with addr. 418 func (csdb *CommitStateDB) AddBalance(addr ethcmn.Address, amount *big.Int) { 419 if !csdb.ctx.IsCheckTx() { 420 funcName := "AddBalance" 421 trace.StartTxLog(funcName) 422 defer trace.StopTxLog(funcName) 423 } 424 425 so := csdb.GetOrNewStateObject(addr) 426 if so != nil { 427 so.AddBalance(amount) 428 } 429 } 430 431 // SubBalance subtracts amount from the account associated with addr. 432 func (csdb *CommitStateDB) SubBalance(addr ethcmn.Address, amount *big.Int) { 433 if !csdb.ctx.IsCheckTx() { 434 funcName := "SubBalance" 435 trace.StartTxLog(funcName) 436 defer trace.StopTxLog(funcName) 437 } 438 439 so := csdb.GetOrNewStateObject(addr) 440 if so != nil { 441 so.SubBalance(amount) 442 } 443 } 444 445 // SetNonce sets the nonce (sequence number) of an account. 446 func (csdb *CommitStateDB) SetNonce(addr ethcmn.Address, nonce uint64) { 447 if !csdb.ctx.IsCheckTx() { 448 funcName := "SetNonce" 449 trace.StartTxLog(funcName) 450 defer trace.StopTxLog(funcName) 451 } 452 453 so := csdb.GetOrNewStateObject(addr) 454 if so != nil { 455 so.SetNonce(nonce) 456 } 457 } 458 459 // SetState sets the storage state with a key, value pair for an account. 460 func (csdb *CommitStateDB) SetState(addr ethcmn.Address, key, value ethcmn.Hash) { 461 if !csdb.ctx.IsCheckTx() { 462 funcName := "SetState" 463 trace.StartTxLog(funcName) 464 defer trace.StopTxLog(funcName) 465 } 466 467 so := csdb.GetOrNewStateObject(addr) 468 if so != nil { 469 so.SetState(csdb.db, key, value) 470 } 471 } 472 473 // SetCode sets the code for a given account. 474 func (csdb *CommitStateDB) SetCode(addr ethcmn.Address, code []byte) { 475 if !csdb.ctx.IsCheckTx() { 476 funcName := "SetCode" 477 trace.StartTxLog(funcName) 478 defer trace.StopTxLog(funcName) 479 } 480 481 so := csdb.GetOrNewStateObject(addr) 482 if so != nil { 483 hash := Keccak256HashWithCache(code) 484 so.SetCode(hash, code) 485 csdb.codeCache[addr] = CacheCode{ 486 CodeHash: hash.Bytes(), 487 Code: code, 488 } 489 } 490 } 491 492 // ---------------------------------------------------------------------------- 493 // Transaction logs 494 // Required for upgrade logic or ease of querying. 495 // NOTE: we use BinaryLengthPrefixed since the tx logs are also included on Result data, 496 // which can't use BinaryBare. 497 // ---------------------------------------------------------------------------- 498 499 // SetLogs sets the logs for a transaction in the KVStore. 500 func (csdb *CommitStateDB) SetLogs(hash ethcmn.Hash, logs []*ethtypes.Log) error { 501 csdb.logs[hash] = logs 502 return nil 503 } 504 505 // DeleteLogs removes the logs from the KVStore. It is used during journal.Revert. 506 func (csdb *CommitStateDB) DeleteLogs(hash ethcmn.Hash) { 507 delete(csdb.logs, hash) 508 } 509 510 // AddLog adds a new log to the state and sets the log metadata from the state. 511 func (csdb *CommitStateDB) AddLog(log *ethtypes.Log) { 512 if !csdb.ctx.IsCheckTx() { 513 funcName := "AddLog" 514 trace.StartTxLog(funcName) 515 defer trace.StopTxLog(funcName) 516 } 517 518 csdb.journal.append(addLogChange{txhash: csdb.thash}) 519 520 log.TxHash = csdb.thash 521 log.BlockHash = csdb.bhash 522 log.TxIndex = uint(csdb.txIndex) 523 log.Index = csdb.logSize 524 525 csdb.logSize = csdb.logSize + 1 526 csdb.logs[csdb.thash] = append(csdb.logs[csdb.thash], log) 527 } 528 529 // AddPreimage records a SHA3 preimage seen by the VM. 530 func (csdb *CommitStateDB) AddPreimage(hash ethcmn.Hash, preimage []byte) { 531 if !csdb.ctx.IsCheckTx() { 532 funcName := "AddPreimage" 533 trace.StartTxLog(funcName) 534 defer trace.StopTxLog(funcName) 535 } 536 537 if _, ok := csdb.preimages[hash]; !ok { 538 csdb.journal.append(addPreimageChange{hash: hash}) 539 pi := make([]byte, len(preimage)) 540 copy(pi, preimage) 541 csdb.preimages[hash] = pi 542 } 543 } 544 545 // AddRefund adds gas to the refund counter. 546 func (csdb *CommitStateDB) AddRefund(gas uint64) { 547 if !csdb.ctx.IsCheckTx() { 548 funcName := "AddRefund" 549 trace.StartTxLog(funcName) 550 defer trace.StopTxLog(funcName) 551 } 552 553 csdb.journal.append(refundChange{prev: csdb.refund}) 554 csdb.refund += gas 555 } 556 557 // SubRefund removes gas from the refund counter. It will panic if the refund 558 // counter goes below zero. 559 func (csdb *CommitStateDB) SubRefund(gas uint64) { 560 if !csdb.ctx.IsCheckTx() { 561 funcName := "SubRefund" 562 trace.StartTxLog(funcName) 563 defer trace.StopTxLog(funcName) 564 } 565 566 csdb.journal.append(refundChange{prev: csdb.refund}) 567 if gas > csdb.refund { 568 panic("refund counter below zero") 569 } 570 571 csdb.refund -= gas 572 } 573 574 // AddAddressToAccessList adds the given address to the access list 575 func (csdb *CommitStateDB) AddAddressToAccessList(addr ethcmn.Address) { 576 if !csdb.ctx.IsCheckTx() { 577 funcName := "AddAddressToAccessList" 578 trace.StartTxLog(funcName) 579 defer trace.StopTxLog(funcName) 580 } 581 582 if csdb.accessList.AddAddress(addr) { 583 csdb.journal.append(accessListAddAccountChange{&addr}) 584 } 585 } 586 587 // AddSlotToAccessList adds the given (address, slot)-tuple to the access list 588 func (csdb *CommitStateDB) AddSlotToAccessList(addr ethcmn.Address, slot ethcmn.Hash) { 589 if !csdb.ctx.IsCheckTx() { 590 funcName := "AddSlotToAccessList" 591 trace.StartTxLog(funcName) 592 defer trace.StopTxLog(funcName) 593 } 594 595 addrMod, slotMod := csdb.accessList.AddSlot(addr, slot) 596 if addrMod { 597 // In practice, this should not happen, since there is no way to enter the 598 // scope of 'address' without having the 'address' become already added 599 // to the access list (via call-variant, create, etc). 600 // Better safe than sorry, though 601 csdb.journal.append(accessListAddAccountChange{&addr}) 602 } 603 if slotMod { 604 csdb.journal.append(accessListAddSlotChange{ 605 address: &addr, 606 slot: &slot, 607 }) 608 } 609 } 610 func (csdb *CommitStateDB) PrepareAccessList(sender ethcmn.Address, dest *ethcmn.Address, precompiles []ethcmn.Address, txAccesses ethtypes.AccessList) { 611 if !csdb.ctx.IsCheckTx() { 612 funcName := "PrepareAccessList" 613 trace.StartTxLog(funcName) 614 defer trace.StopTxLog(funcName) 615 } 616 617 csdb.AddAddressToAccessList(sender) 618 if csdb != nil { 619 csdb.AddAddressToAccessList(*dest) 620 // If it's a create-tx, the destination will be added inside evm.create 621 } 622 for _, addr := range precompiles { 623 csdb.AddAddressToAccessList(addr) 624 } 625 for _, el := range txAccesses { 626 csdb.AddAddressToAccessList(el.Address) 627 for _, key := range el.StorageKeys { 628 csdb.AddSlotToAccessList(el.Address, key) 629 } 630 } 631 } 632 633 // AddressInAccessList returns true if the given address is in the access list. 634 func (csdb *CommitStateDB) AddressInAccessList(addr ethcmn.Address) bool { 635 if !csdb.ctx.IsCheckTx() { 636 funcName := "AddressInAccessList" 637 trace.StartTxLog(funcName) 638 defer trace.StopTxLog(funcName) 639 } 640 641 return csdb.accessList.ContainsAddress(addr) 642 } 643 644 // SlotInAccessList returns true if the given (address, slot)-tuple is in the access list. 645 func (csdb *CommitStateDB) SlotInAccessList(addr ethcmn.Address, slot ethcmn.Hash) (bool, bool) { 646 if !csdb.ctx.IsCheckTx() { 647 funcName := "SlotInAccessList" 648 trace.StartTxLog(funcName) 649 defer trace.StopTxLog(funcName) 650 } 651 652 return csdb.accessList.Contains(addr, slot) 653 } 654 655 // ---------------------------------------------------------------------------- 656 // Getters 657 // ---------------------------------------------------------------------------- 658 659 // GetHeightHash returns the block header hash associated with a given block height and chain epoch number. 660 func (csdb *CommitStateDB) GetHeightHash(height uint64) ethcmn.Hash { 661 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 662 return csdb.getHeightHashInRawDB(height) 663 } 664 665 store := csdb.dbAdapter.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightHash) 666 key := HeightHashKey(height) 667 bz := store.Get(key) 668 if len(bz) == 0 { 669 return ethcmn.Hash{} 670 } 671 672 return ethcmn.BytesToHash(bz) 673 } 674 675 // GetParams returns the total set of evm parameters. 676 func (csdb *CommitStateDB) GetParams() Params { 677 if csdb.params == nil { 678 var params Params 679 if csdb.ctx.UseParamCache() { 680 if GetEvmParamsCache().IsNeedParamsUpdate() { 681 csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms) 682 GetEvmParamsCache().UpdateParams(params, csdb.ctx.IsCheckTx()) 683 } else { 684 params = GetEvmParamsCache().GetParams() 685 } 686 } else { 687 csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms) 688 } 689 csdb.params = ¶ms 690 } 691 return *csdb.params 692 } 693 694 // GetBalance retrieves the balance from the given address or 0 if object not 695 // found. 696 func (csdb *CommitStateDB) GetBalance(addr ethcmn.Address) *big.Int { 697 if !csdb.ctx.IsCheckTx() { 698 funcName := "GetBalance" 699 trace.StartTxLog(funcName) 700 defer trace.StopTxLog(funcName) 701 } 702 703 so := csdb.getStateObject(addr) 704 if so != nil { 705 return so.Balance() 706 } 707 708 return zeroBalance 709 } 710 711 // GetNonce returns the nonce (sequence number) for a given account. 712 func (csdb *CommitStateDB) GetNonce(addr ethcmn.Address) uint64 { 713 if !csdb.ctx.IsCheckTx() { 714 funcName := "GetNonce" 715 trace.StartTxLog(funcName) 716 defer trace.StopTxLog(funcName) 717 } 718 719 so := csdb.getStateObject(addr) 720 if so != nil { 721 return so.Nonce() 722 } 723 724 return 0 725 } 726 727 // TxIndex returns the current transaction index set by Prepare. 728 func (csdb *CommitStateDB) TxIndex() int { 729 return csdb.txIndex 730 } 731 732 // BlockHash returns the current block hash set by Prepare. 733 func (csdb *CommitStateDB) BlockHash() ethcmn.Hash { 734 return csdb.bhash 735 } 736 737 func (csdb *CommitStateDB) SetBlockHash(hash ethcmn.Hash) { 738 csdb.bhash = hash 739 } 740 741 // GetCode returns the code for a given account. 742 func (csdb *CommitStateDB) GetCode(addr ethcmn.Address) []byte { 743 if !csdb.ctx.IsCheckTx() { 744 funcName := "GetCode" 745 trace.StartTxLog(funcName) 746 defer trace.StopTxLog(funcName) 747 } 748 749 // check for the contract calling from blocked list if contract blocked list is enabled 750 if csdb.GetParams().EnableContractBlockedList && csdb.IsContractInBlockedList(addr.Bytes()) { 751 err := ErrContractBlockedVerify{fmt.Sprintf("failed. the contract %s is not allowed to invoke", addr.Hex())} 752 panic(err) 753 } 754 755 so := csdb.getStateObject(addr) 756 if so != nil { 757 return so.Code(csdb.db) 758 } 759 return nil 760 } 761 762 // GetCode returns the code for a given code hash. 763 func (csdb *CommitStateDB) GetCodeByHash(hash ethcmn.Hash) []byte { 764 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 765 return csdb.GetCodeByHashInRawDB(hash) 766 } 767 768 ctx := csdb.ctx 769 store := csdb.dbAdapter.NewStore(ctx.KVStore(csdb.storeKey), KeyPrefixCode) 770 code := store.Get(hash.Bytes()) 771 return code 772 } 773 774 // GetCodeSize returns the code size for a given account. 775 func (csdb *CommitStateDB) GetCodeSize(addr ethcmn.Address) int { 776 if !csdb.ctx.IsCheckTx() { 777 funcName := "GetCodeSize" 778 trace.StartTxLog(funcName) 779 defer trace.StopTxLog(funcName) 780 } 781 782 so := csdb.getStateObject(addr) 783 if so != nil { 784 return so.CodeSize(csdb.db) 785 } 786 return 0 787 } 788 789 // GetCodeHash returns the code hash for a given account. 790 func (csdb *CommitStateDB) GetCodeHash(addr ethcmn.Address) ethcmn.Hash { 791 if !csdb.ctx.IsCheckTx() { 792 funcName := "GetCodeHash" 793 trace.StartTxLog(funcName) 794 defer trace.StopTxLog(funcName) 795 } 796 797 so := csdb.getStateObject(addr) 798 if so == nil { 799 return ethcmn.Hash{} 800 } 801 802 return ethcmn.BytesToHash(so.CodeHash()) 803 } 804 805 // GetState retrieves a value from the given account's storage store. 806 func (csdb *CommitStateDB) GetState(addr ethcmn.Address, hash ethcmn.Hash) ethcmn.Hash { 807 if !csdb.ctx.IsCheckTx() { 808 funcName := "GetState" 809 trace.StartTxLog(funcName) 810 defer trace.StopTxLog(funcName) 811 } 812 813 so := csdb.getStateObject(addr) 814 if so != nil { 815 return so.GetState(csdb.db, hash) 816 } 817 818 return ethcmn.Hash{} 819 } 820 821 // GetStateByKey retrieves a value from the given account's storage store. 822 func (csdb *CommitStateDB) GetStateByKey(addr ethcmn.Address, key ethcmn.Hash) ethcmn.Hash { 823 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 824 return csdb.GetStateByKeyMpt(addr, key) 825 } 826 827 ctx := csdb.ctx 828 store := csdb.dbAdapter.NewStore(ctx.KVStore(csdb.storeKey), AddressStoragePrefix(addr)) 829 data := store.Get(key.Bytes()) 830 831 return ethcmn.BytesToHash(data) 832 } 833 834 // GetCommittedState retrieves a value from the given account's committed 835 // storage. 836 func (csdb *CommitStateDB) GetCommittedState(addr ethcmn.Address, hash ethcmn.Hash) ethcmn.Hash { 837 if !csdb.ctx.IsCheckTx() { 838 funcName := "GetCommittedState" 839 trace.StartTxLog(funcName) 840 defer trace.StopTxLog(funcName) 841 } 842 843 so := csdb.getStateObject(addr) 844 if so != nil { 845 return so.GetCommittedState(csdb.db, hash) 846 } 847 848 return ethcmn.Hash{} 849 } 850 851 // GetLogs returns the current logs for a given transaction hash from the KVStore. 852 func (csdb *CommitStateDB) GetLogs(hash ethcmn.Hash) ([]*ethtypes.Log, error) { 853 return csdb.logs[hash], nil 854 } 855 856 // GetRefund returns the current value of the refund counter. 857 func (csdb *CommitStateDB) GetRefund() uint64 { 858 if !csdb.ctx.IsCheckTx() { 859 funcName := "GetRefund" 860 trace.StartTxLog(funcName) 861 defer trace.StopTxLog(funcName) 862 } 863 864 return csdb.refund 865 } 866 867 // Preimages returns a list of SHA3 preimages that have been submitted. 868 func (csdb *CommitStateDB) Preimages() map[ethcmn.Hash][]byte { 869 return csdb.preimages 870 } 871 872 // HasSuicided returns if the given account for the specified address has been 873 // killed. 874 func (csdb *CommitStateDB) HasSuicided(addr ethcmn.Address) bool { 875 if !csdb.ctx.IsCheckTx() { 876 funcName := "HasSuicided" 877 trace.StartTxLog(funcName) 878 defer trace.StopTxLog(funcName) 879 } 880 881 so := csdb.getStateObject(addr) 882 if so != nil { 883 return so.suicided 884 } 885 886 return false 887 } 888 889 // StorageTrie returns nil as the state in Ethermint does not use a direct 890 // storage trie. 891 func (csdb *CommitStateDB) StorageTrie(addr ethcmn.Address) ethstate.Trie { 892 stateObject := csdb.getStateObject(addr) 893 if stateObject == nil { 894 return nil 895 } 896 cpy := stateObject.deepCopy(csdb) 897 cpy.updateTrie(csdb.db) 898 return cpy.getTrie(csdb.db) 899 } 900 901 // ---------------------------------------------------------------------------- 902 // Persistence 903 // ---------------------------------------------------------------------------- 904 905 // Commit writes the state to the appropriate KVStores. For each state object 906 // in the cache, it will either be removed, or have it's code set and/or it's 907 // state (storage) updated. In addition, the state object (account) itself will 908 // be written. Finally, the root hash (version) will be returned. 909 func (csdb *CommitStateDB) Commit(deleteEmptyObjects bool) (ethcmn.Hash, error) { 910 // Finalize any pending changes and merge everything into the tries 911 csdb.IntermediateRoot(deleteEmptyObjects) 912 913 // If there was a trie prefetcher operating, it gets aborted and irrevocably 914 // modified after we start retrieving tries. Remove it from the statedb after 915 // this round of use. 916 // 917 // This is weird pre-byzantium since the first tx runs with a prefetcher and 918 // the remainder without, but pre-byzantium even the initial prefetcher is 919 // useless, so no sleep lost. 920 prefetcher := csdb.prefetcher 921 if csdb.prefetcher != nil { 922 defer func() { 923 csdb.prefetcher.Close() 924 csdb.prefetcher = nil 925 }() 926 } 927 928 // Now we're about to start to write changes to the trie. The trie is so far 929 // _untouched_. We can check with the prefetcher, if it can give us a trie 930 // which has the same root, but also has some content loaded into it. 931 if prefetcher != nil { 932 if trie := prefetcher.Trie(csdb.originalRoot); trie != nil { 933 csdb.trie = trie 934 } 935 } 936 937 if !tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 938 if mpt.TrieWriteAhead { 939 // Commit objects to the trie, measuring the elapsed time 940 codeWriter := csdb.db.TrieDB().DiskDB().NewBatch() 941 usedAddrs := make([][]byte, 0, len(csdb.stateObjectsPending)) 942 943 for addr := range csdb.stateObjectsDirty { 944 if obj := csdb.stateObjects[addr]; !obj.deleted { 945 // Write any contract code associated with the state object 946 if obj.code != nil && obj.dirtyCode { 947 obj.commitCode() 948 949 rawdb.WriteCode(codeWriter, ethcmn.BytesToHash(obj.CodeHash()), obj.code) 950 obj.dirtyCode = false 951 } 952 953 // Write any storage changes in the state object to its storage trie 954 if err := obj.CommitTrie(csdb.db); err != nil { 955 return ethcmn.Hash{}, err 956 } 957 958 csdb.UpdateAccountStorageInfo(obj) 959 } else { 960 csdb.DeleteAccountStorageInfo(obj) 961 } 962 963 usedAddrs = append(usedAddrs, ethcmn.CopyBytes(addr[:])) // Copy needed for closure 964 } 965 if prefetcher != nil { 966 prefetcher.Used(csdb.originalRoot, usedAddrs) 967 } 968 969 if codeWriter.ValueSize() > 0 { 970 if err := codeWriter.Write(); err != nil { 971 csdb.SetError(fmt.Errorf("failed to commit dirty codes: %s", err.Error())) 972 } 973 } 974 } else { 975 // Commit objects to the trie, measuring the elapsed time 976 for addr := range csdb.stateObjectsDirty { 977 if so := csdb.stateObjects[addr]; !so.deleted { 978 // Write any contract code associated with the state object 979 if so.code != nil && so.dirtyCode { 980 so.commitCode() 981 so.dirtyCode = false 982 } 983 } 984 } 985 } 986 987 if len(csdb.stateObjectsDirty) > 0 { 988 csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{}) 989 } 990 991 return ethcmn.Hash{}, nil 992 } else { 993 return csdb.CommitMpt(prefetcher) 994 } 995 } 996 997 // Finalise finalizes the state objects (accounts) state by setting their state, 998 // removing the csdb destructed objects and clearing the journal as well as the 999 // refunds. 1000 func (csdb *CommitStateDB) Finalise(deleteEmptyObjects bool) { 1001 addressesToPrefetch := make([][]byte, 0, len(csdb.journal.dirties)) 1002 for addr := range csdb.journal.dirties { 1003 obj, exist := csdb.stateObjects[addr] 1004 if !exist { 1005 // ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2 1006 // That tx goes out of gas, and although the notion of 'touched' does not exist there, the 1007 // touch-event will still be recorded in the journal. Since ripeMD is a special snowflake, 1008 // it will persist in the journal even though the journal is reverted. In this special circumstance, 1009 // it may exist in `s.journal.dirties` but not in `s.stateObjects`. 1010 // Thus, we can safely ignore it here 1011 continue 1012 } 1013 if obj.suicided || (deleteEmptyObjects && obj.empty()) { 1014 obj.deleted = true 1015 } else { 1016 obj.finalise(true) // Prefetch slots in the background 1017 } 1018 csdb.stateObjectsPending[addr] = struct{}{} 1019 csdb.stateObjectsDirty[addr] = struct{}{} 1020 1021 // At this point, also ship the address off to the precacher. The precacher 1022 // will start loading tries, and when the change is eventually committed, 1023 // the commit-phase will be a lot faster 1024 addressesToPrefetch = append(addressesToPrefetch, ethcmn.CopyBytes(addr[:])) // Copy needed for closure 1025 } 1026 if csdb.prefetcher != nil && len(addressesToPrefetch) > 0 { 1027 csdb.prefetcher.Prefetch(csdb.originalRoot, addressesToPrefetch) 1028 } 1029 1030 // Invalidate journal because reverting across transactions is not allowed. 1031 csdb.clearJournalAndRefund() 1032 } 1033 1034 // IntermediateRoot returns the current root hash of the state. It is called in 1035 // between transactions to get the root hash that goes into transaction 1036 // receipts. 1037 // 1038 // NOTE: The SDK has not concept or method of getting any intermediate merkle 1039 // root as commitment of the merkle-ized tree doesn't happen until the 1040 // BaseApps' EndBlocker. 1041 func (csdb *CommitStateDB) IntermediateRoot(deleteEmptyObjects bool) ethcmn.Hash { 1042 // Finalise all the dirty storage states and write them into the tries 1043 csdb.Finalise(deleteEmptyObjects) 1044 1045 if !tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1046 for addr := range csdb.stateObjectsPending { 1047 if obj := csdb.stateObjects[addr]; !obj.deleted { 1048 obj.commitState(csdb.db) 1049 } 1050 } 1051 } else { 1052 // Although naively it makes sense to retrieve the account trie and then do 1053 // the contract storage and account updates sequentially, that short circuits 1054 // the account prefetcher. Instead, let's process all the storage updates 1055 // first, giving the account prefeches just a few more milliseconds of time 1056 // to pull useful data from disk. 1057 for addr := range csdb.stateObjectsPending { 1058 if obj := csdb.stateObjects[addr]; !obj.deleted { 1059 obj.updateRoot(csdb.db) 1060 } 1061 } 1062 } 1063 1064 //usedAddrs := make([][]byte, 0, len(csdb.stateObjectsPending)) 1065 for addr := range csdb.stateObjectsPending { 1066 if obj := csdb.stateObjects[addr]; obj.deleted { 1067 csdb.deleteStateObject(obj) 1068 } else { 1069 csdb.updateStateObject(obj) 1070 } 1071 //usedAddrs = append(usedAddrs, ethcmn.CopyBytes(addr[:])) // Copy needed for closure 1072 } 1073 //if csdb.prefetcher != nil { 1074 // csdb.prefetcher.used(csdb.originalRoot, usedAddrs) 1075 //} 1076 1077 if len(csdb.stateObjectsPending) > 0 { 1078 csdb.stateObjectsPending = make(map[ethcmn.Address]struct{}) 1079 } 1080 1081 return ethcmn.Hash{} 1082 } 1083 1084 // updateStateObject writes the given state object to the store. 1085 func (csdb *CommitStateDB) updateStateObject(so *stateObject) error { 1086 // NOTE: we don't use sdk.NewCoin here to avoid panic on test importer's genesis 1087 newBalance := sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromBigIntWithPrec(so.Balance(), sdk.Precision)} // int2dec 1088 if !newBalance.IsValid() { 1089 return fmt.Errorf("invalid balance %s", newBalance) 1090 } 1091 1092 //checking and reject tx if address in blacklist 1093 if csdb.bankKeeper.BlacklistedAddr(so.account.GetAddress()) { 1094 return fmt.Errorf("address <%s> in blacklist is not allowed", so.account.GetAddress().String()) 1095 } 1096 1097 coins := so.account.GetCoins() 1098 balance := coins.AmountOf(newBalance.Denom) 1099 if balance.IsZero() || !balance.Equal(newBalance.Amount) { 1100 coins = coins.Add(newBalance) 1101 } 1102 1103 if err := so.account.SetCoins(coins); err != nil { 1104 return err 1105 } 1106 1107 csdb.accountKeeper.SetAccount(csdb.ctx, so.account) 1108 if !csdb.ctx.IsCheckTx() { 1109 if csdb.ctx.GetWatcher().Enabled() { 1110 csdb.ctx.GetWatcher().SaveAccount(so.account) 1111 } 1112 } 1113 1114 return nil 1115 } 1116 1117 // deleteStateObject removes the given state object from the state store. 1118 func (csdb *CommitStateDB) deleteStateObject(so *stateObject) { 1119 so.deleted = true 1120 csdb.accountKeeper.RemoveAccount(csdb.ctx, so.account) 1121 1122 //if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) || types2.EnableDoubleWrite { 1123 // csdb.DeleteAccountStorageInfo(so) 1124 //} 1125 } 1126 1127 // ---------------------------------------------------------------------------- 1128 // Snapshotting 1129 // ---------------------------------------------------------------------------- 1130 1131 // Snapshot returns an identifier for the current revision of the state. 1132 func (csdb *CommitStateDB) Snapshot() int { 1133 if !csdb.ctx.IsCheckTx() { 1134 funcName := "Snapshot" 1135 trace.StartTxLog(funcName) 1136 defer trace.StopTxLog(funcName) 1137 } 1138 1139 id := csdb.nextRevisionID 1140 csdb.nextRevisionID++ 1141 1142 csdb.validRevisions = append( 1143 csdb.validRevisions, 1144 revision{ 1145 id: id, 1146 journalIndex: csdb.journal.length(), 1147 }, 1148 ) 1149 1150 return id 1151 } 1152 1153 // RevertToSnapshot reverts all state changes made since the given revision. 1154 func (csdb *CommitStateDB) RevertToSnapshot(revID int) { 1155 if !csdb.ctx.IsCheckTx() { 1156 funcName := "RevertToSnapshot" 1157 trace.StartTxLog(funcName) 1158 defer trace.StopTxLog(funcName) 1159 } 1160 1161 // find the snapshot in the stack of valid snapshots 1162 idx := sort.Search(len(csdb.validRevisions), func(i int) bool { 1163 return csdb.validRevisions[i].id >= revID 1164 }) 1165 1166 if idx == len(csdb.validRevisions) || csdb.validRevisions[idx].id != revID { 1167 panic(fmt.Errorf("revision ID %v cannot be reverted", revID)) 1168 } 1169 1170 snapshot := csdb.validRevisions[idx].journalIndex 1171 1172 // replay the journal to undo changes and remove invalidated snapshots 1173 csdb.journal.revert(csdb, snapshot) 1174 csdb.validRevisions = csdb.validRevisions[:idx] 1175 } 1176 1177 // ---------------------------------------------------------------------------- 1178 // Auxiliary 1179 // ---------------------------------------------------------------------------- 1180 1181 // Database retrieves the low level database supporting the lower level trie 1182 // ops. It is not used in Ethermint, so it returns nil. 1183 func (csdb *CommitStateDB) Database() ethstate.Database { 1184 return csdb.db 1185 } 1186 1187 // Empty returns whether the state object is either non-existent or empty 1188 // according to the EIP161 specification (balance = nonce = code = 0). 1189 func (csdb *CommitStateDB) Empty(addr ethcmn.Address) bool { 1190 if !csdb.ctx.IsCheckTx() { 1191 funcName := "Empty" 1192 trace.StartTxLog(funcName) 1193 defer trace.StopTxLog(funcName) 1194 } 1195 1196 so := csdb.getStateObject(addr) 1197 return so == nil || so.empty() 1198 } 1199 1200 // Exist reports whether the given account address exists in the state. Notably, 1201 // this also returns true for suicided accounts. 1202 func (csdb *CommitStateDB) Exist(addr ethcmn.Address) bool { 1203 if !csdb.ctx.IsCheckTx() { 1204 funcName := "Exist" 1205 trace.StartTxLog(funcName) 1206 defer trace.StopTxLog(funcName) 1207 } 1208 1209 return csdb.getStateObject(addr) != nil 1210 } 1211 1212 // Error returns the first non-nil error the StateDB encountered. 1213 func (csdb *CommitStateDB) Error() error { 1214 return csdb.dbErr 1215 } 1216 1217 // Suicide marks the given account as suicided and clears the account balance. 1218 // 1219 // The account's state object is still available until the state is committed, 1220 // getStateObject will return a non-nil account after Suicide. 1221 func (csdb *CommitStateDB) Suicide(addr ethcmn.Address) bool { 1222 if !csdb.ctx.IsCheckTx() { 1223 funcName := "Suicide" 1224 trace.StartTxLog(funcName) 1225 defer trace.StopTxLog(funcName) 1226 } 1227 1228 so := csdb.getStateObject(addr) 1229 if so == nil { 1230 return false 1231 } 1232 1233 csdb.journal.append(suicideChange{ 1234 account: &addr, 1235 prev: so.suicided, 1236 prevBalance: sdk.NewDecFromBigIntWithPrec(so.Balance(), sdk.Precision), // int2dec 1237 }) 1238 1239 so.markSuicided() 1240 so.SetBalance(new(big.Int)) 1241 1242 return true 1243 } 1244 1245 // Reset clears out all ephemeral state objects from the state db, but keeps 1246 // the underlying account mapper and store keys to avoid reloading data for the 1247 // next operations. 1248 func (csdb *CommitStateDB) Reset(_ ethcmn.Hash) error { 1249 csdb.stateObjects = make(map[ethcmn.Address]*stateObject) 1250 csdb.stateObjectsPending = make(map[ethcmn.Address]struct{}) 1251 csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{}) 1252 csdb.thash = ethcmn.Hash{} 1253 csdb.bhash = ethcmn.Hash{} 1254 csdb.txIndex = 0 1255 csdb.logSize = 0 1256 csdb.preimages = make(map[ethcmn.Hash][]byte) 1257 csdb.accessList = newAccessList() 1258 csdb.params = nil 1259 1260 csdb.clearJournalAndRefund() 1261 return nil 1262 } 1263 1264 // ClearStateObjects clears cache of state objects to handle account changes outside of the EVM 1265 func (csdb *CommitStateDB) ClearStateObjects() { 1266 csdb.stateObjects = make(map[ethcmn.Address]*stateObject) 1267 csdb.stateObjectsPending = make(map[ethcmn.Address]struct{}) 1268 csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{}) 1269 } 1270 1271 func (csdb *CommitStateDB) clearJournalAndRefund() { 1272 if len(csdb.journal.entries) > 0 { 1273 csdb.journal = newJournal() 1274 csdb.refund = 0 1275 } 1276 csdb.validRevisions = csdb.validRevisions[:0] // Snapshots can be created without journal entires 1277 } 1278 1279 // Prepare sets the current transaction hash and index and block hash which is 1280 // used when the EVM emits new state logs. 1281 func (csdb *CommitStateDB) Prepare(thash, bhash ethcmn.Hash, txi int) { 1282 csdb.thash = thash 1283 csdb.bhash = bhash 1284 csdb.txIndex = txi 1285 } 1286 1287 // CreateAccount explicitly creates a state object. If a state object with the 1288 // address already exists the balance is carried over to the new account. 1289 // 1290 // CreateAccount is called during the EVM CREATE operation. The situation might 1291 // arise that a contract does the following: 1292 // 1293 // 1. sends funds to sha(account ++ (nonce + 1)) 1294 // 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) 1295 // 1296 // Carrying over the balance ensures that Ether doesn't disappear. 1297 func (csdb *CommitStateDB) CreateAccount(addr ethcmn.Address) { 1298 if !csdb.ctx.IsCheckTx() { 1299 funcName := "CreateAccount" 1300 trace.StartTxLog(funcName) 1301 defer trace.StopTxLog(funcName) 1302 } 1303 1304 newobj, prevobj := csdb.createObject(addr) 1305 if prevobj != nil { 1306 newobj.setBalance(sdk.DefaultBondDenom, sdk.NewDecFromBigIntWithPrec(prevobj.Balance(), sdk.Precision)) // int2dec 1307 } 1308 } 1309 1310 // ForEachStorage iterates over each storage items, all invoke the provided 1311 // callback on each key, value pair. 1312 func (csdb *CommitStateDB) ForEachStorage(addr ethcmn.Address, cb func(key, value ethcmn.Hash) (stop bool)) error { 1313 if !csdb.ctx.IsCheckTx() { 1314 funcName := "ForEachStorage" 1315 trace.StartTxLog(funcName) 1316 defer trace.StopTxLog(funcName) 1317 } 1318 1319 so := csdb.getStateObject(addr) 1320 if so == nil { 1321 return nil 1322 } 1323 1324 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1325 return csdb.ForEachStorageMpt(so, cb) 1326 } 1327 1328 store := csdb.ctx.KVStore(csdb.storeKey) 1329 prefix := AddressStoragePrefix(so.Address()) 1330 iterator := sdk.KVStorePrefixIterator(store, prefix) 1331 defer iterator.Close() 1332 1333 for ; iterator.Valid(); iterator.Next() { 1334 key := ethcmn.BytesToHash(iterator.Key()) 1335 value := ethcmn.BytesToHash(iterator.Value()) 1336 1337 if value, dirty := so.dirtyStorage[key]; dirty { 1338 if cb(key, value) { 1339 break 1340 } 1341 continue 1342 } 1343 1344 // check if iteration stops 1345 if cb(key, value) { 1346 return nil 1347 } 1348 } 1349 1350 return nil 1351 } 1352 1353 // GetOrNewStateObject retrieves a state object or create a new state object if 1354 // nil. 1355 func (csdb *CommitStateDB) GetOrNewStateObject(addr ethcmn.Address) StateObject { 1356 so := csdb.getStateObject(addr) 1357 if so == nil || so.deleted { 1358 so, _ = csdb.createObject(addr) 1359 } 1360 1361 return so 1362 } 1363 1364 // createObject creates a new state object. If there is an existing account with 1365 // the given address, it is overwritten and returned as the second return value. 1366 func (csdb *CommitStateDB) createObject(addr ethcmn.Address) (newObj, prevObj *stateObject) { 1367 prevObj = csdb.getStateObject(addr) 1368 1369 acc := csdb.accountKeeper.NewAccountWithAddress(csdb.ctx, sdk.AccAddress(addr.Bytes())) 1370 1371 newObj = newStateObject(csdb, acc, ethtypes.EmptyRootHash) 1372 newObj.setNonce(0) // sets the object to dirty 1373 1374 if prevObj == nil { 1375 csdb.journal.append(createObjectChange{account: &addr}) 1376 } else { 1377 csdb.journal.append(resetObjectChange{prev: prevObj}) 1378 } 1379 csdb.setStateObject(newObj) 1380 1381 if prevObj != nil && !prevObj.deleted { 1382 return newObj, prevObj 1383 } 1384 return newObj, nil 1385 } 1386 1387 // SetError remembers the first non-nil error it is called with. 1388 func (csdb *CommitStateDB) SetError(err error) { 1389 if err != nil { 1390 csdb.Logger().Debug("CommitStateDB", "error", err) 1391 } 1392 1393 if csdb.dbErr == nil { 1394 csdb.dbErr = err 1395 } 1396 } 1397 1398 // getStateObject attempts to retrieve a state object given by the address. 1399 // Returns nil and sets an error if not found. 1400 func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *stateObject) { 1401 if obj := csdb.getDeletedStateObject(addr); obj != nil && !obj.deleted { 1402 return obj 1403 } 1404 return nil 1405 } 1406 1407 func (csdb *CommitStateDB) setStateObject(so *stateObject) { 1408 csdb.stateObjects[so.Address()] = so 1409 } 1410 1411 // RawDump returns a raw state dump. 1412 // 1413 // TODO: Implement if we need it, especially for the RPC API. 1414 func (csdb *CommitStateDB) RawDump() ethstate.Dump { 1415 return ethstate.Dump{} 1416 } 1417 1418 type preimageEntry struct { 1419 // hash key of the preimage entry 1420 hash ethcmn.Hash 1421 preimage []byte 1422 } 1423 1424 func (csdb *CommitStateDB) SetLogSize(logSize uint) { 1425 csdb.logSize = logSize 1426 } 1427 1428 func (csdb *CommitStateDB) GetLogSize() uint { 1429 return csdb.logSize 1430 } 1431 1432 // SetContractDeploymentWhitelistMember sets the target address list into whitelist store 1433 func (csdb *CommitStateDB) SetContractDeploymentWhitelist(addrList AddressList) { 1434 if csdb.ctx.GetWatcher().Enabled() { 1435 for i := 0; i < len(addrList); i++ { 1436 csdb.ctx.GetWatcher().SaveContractDeploymentWhitelistItem(addrList[i]) 1437 } 1438 } 1439 1440 var store StoreProxy 1441 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1442 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1443 } else { 1444 store = csdb.ctx.KVStore(csdb.storeKey) 1445 } 1446 1447 for i := 0; i < len(addrList); i++ { 1448 store.Set(GetContractDeploymentWhitelistMemberKey(addrList[i]), []byte("")) 1449 } 1450 } 1451 1452 // DeleteContractDeploymentWhitelist deletes the target address list from whitelist store 1453 func (csdb *CommitStateDB) DeleteContractDeploymentWhitelist(addrList AddressList) { 1454 if csdb.ctx.GetWatcher().Enabled() { 1455 for i := 0; i < len(addrList); i++ { 1456 csdb.ctx.GetWatcher().DeleteContractDeploymentWhitelist(addrList[i]) 1457 } 1458 } 1459 1460 var store StoreProxy 1461 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1462 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1463 } else { 1464 store = csdb.ctx.KVStore(csdb.storeKey) 1465 } 1466 1467 for i := 0; i < len(addrList); i++ { 1468 store.Delete(GetContractDeploymentWhitelistMemberKey(addrList[i])) 1469 } 1470 } 1471 1472 // GetContractDeploymentWhitelist gets the whole contract deployment whitelist currently 1473 func (csdb *CommitStateDB) GetContractDeploymentWhitelist() (whitelist AddressList) { 1474 var store sdk.KVStore 1475 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1476 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1477 } else { 1478 store = csdb.ctx.KVStore(csdb.storeKey) 1479 } 1480 1481 iterator := sdk.KVStorePrefixIterator(store, KeyPrefixContractDeploymentWhitelist) 1482 defer iterator.Close() 1483 1484 for ; iterator.Valid(); iterator.Next() { 1485 whitelist = append(whitelist, splitApprovedDeployerAddress(iterator.Key())) 1486 } 1487 1488 return 1489 } 1490 1491 // IsDeployerInWhitelist checks whether the deployer is in the whitelist as a distributor 1492 func (csdb *CommitStateDB) IsDeployerInWhitelist(deployerAddr sdk.AccAddress) bool { 1493 var bs StoreProxy 1494 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1495 bs = csdb.dbAdapter.NewStore(csdb.paramSpace.CustomKVStore(csdb.ctx), KeyPrefixContractDeploymentWhitelist) 1496 } else { 1497 bs = csdb.dbAdapter.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixContractDeploymentWhitelist) 1498 } 1499 1500 return bs.Has(deployerAddr) 1501 } 1502 1503 // SetContractBlockedList sets the target address list into blocked list store 1504 func (csdb *CommitStateDB) SetContractBlockedList(addrList AddressList) { 1505 defer GetEvmParamsCache().SetNeedBlockedUpdate() 1506 if csdb.ctx.GetWatcher().Enabled() { 1507 for i := 0; i < len(addrList); i++ { 1508 csdb.ctx.GetWatcher().SaveContractBlockedListItem(addrList[i]) 1509 } 1510 } 1511 1512 var store sdk.KVStore 1513 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1514 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1515 } else { 1516 store = csdb.ctx.KVStore(csdb.storeKey) 1517 } 1518 1519 for i := 0; i < len(addrList); i++ { 1520 store.Set(GetContractBlockedListMemberKey(addrList[i]), []byte("")) 1521 } 1522 } 1523 1524 // DeleteContractBlockedList deletes the target address list from blocked list store 1525 func (csdb *CommitStateDB) DeleteContractBlockedList(addrList AddressList) { 1526 defer GetEvmParamsCache().SetNeedBlockedUpdate() 1527 if csdb.ctx.GetWatcher().Enabled() { 1528 for i := 0; i < len(addrList); i++ { 1529 csdb.ctx.GetWatcher().DeleteContractBlockedList(addrList[i]) 1530 } 1531 } 1532 1533 var store sdk.KVStore 1534 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1535 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1536 } else { 1537 store = csdb.ctx.KVStore(csdb.storeKey) 1538 } 1539 1540 for i := 0; i < len(addrList); i++ { 1541 store.Delete(GetContractBlockedListMemberKey(addrList[i])) 1542 } 1543 } 1544 1545 // GetContractBlockedList gets the whole contract blocked list currently 1546 func (csdb *CommitStateDB) GetContractBlockedList() (blockedList AddressList) { 1547 var store sdk.KVStore 1548 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1549 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1550 } else { 1551 store = csdb.ctx.KVStore(csdb.storeKey) 1552 } 1553 1554 iterator := sdk.KVStorePrefixIterator(store, KeyPrefixContractBlockedList) 1555 defer iterator.Close() 1556 1557 for ; iterator.Valid(); iterator.Next() { 1558 if len(iterator.Value()) == 0 { 1559 blockedList = append(blockedList, splitBlockedContractAddress(iterator.Key())) 1560 } 1561 } 1562 1563 return 1564 } 1565 1566 // IsContractInBlockedList checks whether the contract address is in the blocked list 1567 func (csdb *CommitStateDB) IsContractInBlockedList(contractAddr sdk.AccAddress) bool { 1568 bc := csdb.GetContractMethodBlockedByAddress(contractAddr) 1569 if bc == nil { 1570 //contractAddr is not blocked 1571 return false 1572 } 1573 // check contractAddr whether block full-method and special-method 1574 return bc.IsAllMethodBlocked() 1575 } 1576 1577 // GetContractMethodBlockedByAddress gets contract methods blocked by address 1578 func (csdb *CommitStateDB) GetContractMethodBlockedByAddress(contractAddr sdk.AccAddress) *BlockedContract { 1579 if csdb.ctx.UseParamCache() { 1580 tempEnableCache := true 1581 if GetEvmParamsCache().IsNeedBlockedUpdate() { 1582 bcl := csdb.GetContractMethodBlockedList() 1583 GetEvmParamsCache().UpdateBlockedContractMethod(bcl, csdb.ctx.IsCheckTx()) 1584 // Note: when checktx GetEvmParamsCache().UpdateBlockedContractMethod will not be really update, so we must find GetBlockedContract from db. 1585 if csdb.ctx.IsCheckTx() { 1586 tempEnableCache = false 1587 } 1588 } 1589 if tempEnableCache { 1590 return GetEvmParamsCache().GetBlockedContractMethod(amino.BytesToStr(contractAddr)) 1591 } 1592 } 1593 1594 //use dbAdapter for watchdb or prefixdb 1595 var bs StoreProxy 1596 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1597 bs = csdb.dbAdapter.NewStore(csdb.paramSpace.CustomKVStore(csdb.ctx), KeyPrefixContractBlockedList) 1598 } else { 1599 bs = csdb.dbAdapter.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixContractBlockedList) 1600 } 1601 1602 if ok := bs.Has(contractAddr); !ok { 1603 // address is not exist 1604 return nil 1605 } else { 1606 value := bs.Get(contractAddr) 1607 methods := ContractMethods{} 1608 var bc *BlockedContract 1609 if len(value) == 0 { 1610 //address is exist,but the blocked is old version. 1611 bc = NewBlockContract(contractAddr, methods) 1612 } else { 1613 // get block contract from cache without anmio 1614 if contractMethodBlockedCache != nil { 1615 if cm, ok := contractMethodBlockedCache.GetContractMethod(value); ok { 1616 return NewBlockContract(contractAddr, cm) 1617 } 1618 } 1619 //address is exist,but the blocked is new version. 1620 csdb.cdc.MustUnmarshalJSON(value, &methods) 1621 bc = NewBlockContract(contractAddr, methods) 1622 1623 // write block contract into cache 1624 if contractMethodBlockedCache != nil { 1625 contractMethodBlockedCache.SetContractMethod(value, methods) 1626 } 1627 } 1628 return bc 1629 } 1630 } 1631 1632 // InsertContractMethodBlockedList sets the list of contract method blocked into blocked list store 1633 func (csdb *CommitStateDB) InsertContractMethodBlockedList(contractList BlockedContractList) sdk.Error { 1634 defer GetEvmParamsCache().SetNeedBlockedUpdate() 1635 if err := contractList.ValidateExtra(); err != nil { 1636 return err 1637 } 1638 for i := 0; i < len(contractList); i++ { 1639 bc := csdb.GetContractMethodBlockedByAddress(contractList[i].Address) 1640 if bc != nil { 1641 result, err := bc.BlockMethods.InsertContractMethods(contractList[i].BlockMethods) 1642 if err != nil { 1643 return err 1644 } 1645 bc.BlockMethods = result 1646 } else { 1647 bc = &contractList[i] 1648 } 1649 1650 csdb.SetContractMethodBlocked(*bc) 1651 } 1652 return nil 1653 } 1654 1655 // DeleteContractMethodBlockedList delete the list of contract method blocked from blocked list store 1656 func (csdb *CommitStateDB) DeleteContractMethodBlockedList(contractList BlockedContractList) sdk.Error { 1657 defer GetEvmParamsCache().SetNeedBlockedUpdate() 1658 for i := 0; i < len(contractList); i++ { 1659 bc := csdb.GetContractMethodBlockedByAddress(contractList[i].Address) 1660 if bc != nil { 1661 result, err := bc.BlockMethods.DeleteContractMethodMap(contractList[i].BlockMethods) 1662 if err != nil { 1663 return ErrBlockedContractMethodIsNotExist(contractList[i].Address, err) 1664 } 1665 bc.BlockMethods = result 1666 //if block contract method delete empty then remove contract from blocklist. 1667 if len(bc.BlockMethods) == 0 { 1668 addressList := AddressList{} 1669 addressList = append(addressList, bc.Address) 1670 //in watchdb contract blocked and contract method blocked use same prefix 1671 //so delete contract method blocked is can use function of delete contract blocked 1672 csdb.DeleteContractBlockedList(addressList) 1673 } else { 1674 csdb.SetContractMethodBlocked(*bc) 1675 } 1676 } else { 1677 return ErrBlockedContractMethodIsNotExist(contractList[i].Address, ErrorContractMethodBlockedIsNotExist) 1678 } 1679 } 1680 return nil 1681 } 1682 1683 // GetContractMethodBlockedList get the list of contract method blocked from blocked list store 1684 func (csdb *CommitStateDB) GetContractMethodBlockedList() (blockedContractList BlockedContractList) { 1685 var store sdk.KVStore 1686 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1687 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1688 } else { 1689 store = csdb.ctx.KVStore(csdb.storeKey) 1690 } 1691 1692 iterator := sdk.KVStorePrefixIterator(store, KeyPrefixContractBlockedList) 1693 defer iterator.Close() 1694 1695 for ; iterator.Valid(); iterator.Next() { 1696 addr := sdk.AccAddress(splitBlockedContractAddress(iterator.Key())) 1697 value := iterator.Value() 1698 methods := ContractMethods{} 1699 if len(value) != 0 { 1700 csdb.cdc.MustUnmarshalJSON(value, &methods) 1701 } 1702 bc := NewBlockContract(addr, methods) 1703 blockedContractList = append(blockedContractList, *bc) 1704 } 1705 return 1706 } 1707 1708 // IsContractMethodBlocked checks whether the contract method is blocked 1709 func (csdb *CommitStateDB) IsContractMethodBlocked(contractAddr sdk.AccAddress, method string) bool { 1710 bc := csdb.GetContractMethodBlockedByAddress(contractAddr) 1711 if bc == nil { 1712 //contractAddr is not blocked 1713 return false 1714 } 1715 // it maybe happens,because ok_verifier verify called before getCode, for executing old logic follow code is return false 1716 if bc.IsAllMethodBlocked() { 1717 return false 1718 } 1719 // check contractAddr whether block full-method and special-method 1720 return bc.IsMethodBlocked(method) 1721 } 1722 1723 // SetContractMethodBlocked sets contract method blocked into blocked list store 1724 func (csdb *CommitStateDB) SetContractMethodBlocked(contract BlockedContract) { 1725 SortContractMethods(contract.BlockMethods) 1726 value := csdb.cdc.MustMarshalJSON(contract.BlockMethods) 1727 value = sdk.MustSortJSON(value) 1728 if csdb.ctx.GetWatcher().Enabled() { 1729 csdb.ctx.GetWatcher().SaveContractMethodBlockedListItem(contract.Address, value) 1730 } 1731 1732 var store sdk.KVStore 1733 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1734 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1735 } else { 1736 store = csdb.ctx.KVStore(csdb.storeKey) 1737 } 1738 1739 key := GetContractBlockedListMemberKey(contract.Address) 1740 store.Set(key, value) 1741 } 1742 1743 func (csdb *CommitStateDB) GetAccount(addr ethcmn.Address) *ethermint.EthAccount { 1744 obj := csdb.getStateObject(addr) 1745 if obj == nil { 1746 return nil 1747 } 1748 return obj.account 1749 } 1750 1751 func (csdb *CommitStateDB) UpdateContractBytecode(ctx sdk.Context, p ManageContractByteCodeProposal) sdk.Error { 1752 contract := ethcmn.BytesToAddress(p.Contract) 1753 substituteContract := ethcmn.BytesToAddress(p.SubstituteContract) 1754 1755 revertContractByteCode := p.Contract.String() == p.SubstituteContract.String() 1756 1757 preCode := csdb.GetCode(contract) 1758 contractAcc := csdb.GetAccount(contract) 1759 if contractAcc == nil { 1760 return ErrNotContracAddress(fmt.Errorf("%s", contract.String())) 1761 } 1762 preCodeHash := contractAcc.CodeHash 1763 1764 var newCodeHash []byte 1765 if revertContractByteCode { 1766 newCodeHash = csdb.getInitContractCodeHash(p.Contract) 1767 if len(newCodeHash) == 0 || bytes.Equal(preCodeHash, newCodeHash) { 1768 return ErrContractCodeNotBeenUpdated(contract.String()) 1769 } 1770 } else { 1771 newCodeHash = csdb.GetCodeHash(substituteContract).Bytes() 1772 } 1773 1774 newCode := csdb.GetCodeByHash(ethcmn.BytesToHash(newCodeHash)) 1775 // update code 1776 csdb.SetCode(contract, newCode) 1777 1778 // store init code 1779 csdb.storeInitContractCodeHash(p.Contract, preCodeHash) 1780 1781 // commit state db 1782 csdb.Commit(false) 1783 return csdb.afterUpdateContractByteCode(ctx, contract, substituteContract, preCodeHash, preCode, newCode) 1784 } 1785 1786 var ( 1787 EventTypeContractUpdateByProposal = "contract-update-by-proposal" 1788 ) 1789 1790 func (csdb *CommitStateDB) afterUpdateContractByteCode(ctx sdk.Context, contract, substituteContract ethcmn.Address, preCodeHash, preCode, newCode []byte) error { 1791 contractAfterUpdateCode := csdb.GetAccount(contract) 1792 if contractAfterUpdateCode == nil { 1793 return ErrNotContracAddress(fmt.Errorf("%s", contractAfterUpdateCode.String())) 1794 } 1795 1796 // log 1797 ctx.Logger().Info("updateContractByteCode", "contract", contract, "preCodeHash", hex.EncodeToString(preCodeHash), "preCodeSize", len(preCode), 1798 "codeHashAfterUpdateCode", hex.EncodeToString(contractAfterUpdateCode.CodeHash), "codeSizeAfterUpdateCode", len(newCode)) 1799 // emit event 1800 ctx.EventManager().EmitEvent(sdk.NewEvent( 1801 EventTypeContractUpdateByProposal, 1802 sdk.NewAttribute("contract", contract.String()), 1803 sdk.NewAttribute("preCodeHash", hex.EncodeToString(preCodeHash)), 1804 sdk.NewAttribute("preCodeSize", fmt.Sprintf("%d", len(preCode))), 1805 sdk.NewAttribute("SubstituteContract", substituteContract.String()), 1806 sdk.NewAttribute("codeHashAfterUpdateCode", hex.EncodeToString(contractAfterUpdateCode.CodeHash)), 1807 sdk.NewAttribute("codeSizeAfterUpdateCode", fmt.Sprintf("%d", len(newCode))), 1808 )) 1809 // update watcher 1810 csdb.WithContext(ctx).IteratorCode(func(addr ethcmn.Address, c CacheCode) bool { 1811 ctx.GetWatcher().SaveContractCode(addr, c.Code, uint64(ctx.BlockHeight())) 1812 ctx.GetWatcher().SaveContractCodeByHash(c.CodeHash, c.Code) 1813 ctx.GetWatcher().SaveAccount(contractAfterUpdateCode) 1814 return true 1815 }) 1816 return nil 1817 } 1818 1819 func (csdb *CommitStateDB) storeInitContractCodeHash(addr sdk.AccAddress, codeHash []byte) { 1820 var store sdk.KVStore 1821 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1822 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1823 } else { 1824 store = csdb.ctx.KVStore(csdb.storeKey) 1825 } 1826 key := GetInitContractCodeHashKey(addr) 1827 if !store.Has(key) { 1828 store.Set(key, codeHash) 1829 } 1830 } 1831 1832 func (csdb *CommitStateDB) getInitContractCodeHash(addr sdk.AccAddress) []byte { 1833 var store sdk.KVStore 1834 if tmtypes.HigherThanMars(csdb.ctx.BlockHeight()) { 1835 store = csdb.paramSpace.CustomKVStore(csdb.ctx) 1836 } else { 1837 store = csdb.ctx.KVStore(csdb.storeKey) 1838 } 1839 key := GetInitContractCodeHashKey(addr) 1840 return store.Get(key) 1841 }