diff --git a/nimbus/db/state_db.nim b/nimbus/db/state_db.nim index a1c446327..cb4a03aea 100644 --- a/nimbus/db/state_db.nim +++ b/nimbus/db/state_db.nim @@ -171,13 +171,26 @@ proc getCode*(db: AccountStateDB, address: EthAddress): ByteRange = let data = triedb.get(contractHashKey(db.getCodeHash(address)).toOpenArray) data.toRange -proc hasCodeOrNonce*(account: AccountStateDB, address: EthAddress): bool {.inline.} = - account.getNonce(address) != 0 or account.getCodeHash(address) != EMPTY_SHA3 +proc hasCodeOrNonce*(db: AccountStateDB, address: EthAddress): bool {.inline.} = + db.getNonce(address) != 0 or db.getCodeHash(address) != EMPTY_SHA3 proc dumpAccount*(db: AccountStateDB, addressS: string): string = let address = addressS.parseAddress return fmt"{addressS}: Storage: {db.getStorage(address, 0.u256)}; getAccount: {db.getAccount address}" +proc accountExist*(db: AccountStateDB, address: EthAddress): bool = + db.trie.get(createRangeFromAddress address).len > 0 + +proc isDeadAccount*(db: AccountStateDB, address: EthAddress): bool = + let recordFound = db.trie.get(createRangeFromAddress address) + if recordFound.len > 0: + let account = rlp.decode(recordFound, Account) + result = account.codeHash == EMPTY_SHA3 and + account.balance.isZero and + account.nonce == 0 + else: + result = true + proc rootHash*(db: ReadOnlyStateDB): KeccakHash {.borrow.} proc getAccount*(db: ReadOnlyStateDB, address: EthAddress): Account {.borrow.} proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.} @@ -186,4 +199,6 @@ proc getStorageRoot*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow proc getStorage*(db: ReadOnlyStateDB, address: EthAddress, slot: UInt256): (UInt256, bool) {.borrow.} proc getNonce*(db: ReadOnlyStateDB, address: EthAddress): AccountNonce {.borrow.} proc getCode*(db: ReadOnlyStateDB, address: EthAddress): ByteRange {.borrow.} -proc hasCodeOrNonce*(account: ReadOnlyStateDB, address: EthAddress): bool {.borrow.} +proc hasCodeOrNonce*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.} +proc accountExist*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.} +proc isDeadAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.} diff --git a/tests/all_tests.nim b/tests/all_tests.nim index c3fa9b9fa..2856545f7 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -21,4 +21,5 @@ import ./test_code_stream, ./test_op_bit, ./test_op_env, ./test_op_memory, - ./test_op_misc \ No newline at end of file + ./test_op_misc, + ./test_state_db \ No newline at end of file diff --git a/tests/test_state_db.nim b/tests/test_state_db.nim new file mode 100644 index 000000000..ff0e81681 --- /dev/null +++ b/tests/test_state_db.nim @@ -0,0 +1,45 @@ +# Nimbus +# Copyright (c) 2018 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import unittest, strutils, eth_trie/[hexary, db], + ../nimbus/db/state_db, byteutils, eth_common, + ranges + +suite "Account State DB": + var + memDB = newMemoryDB() + trie = initHexaryTrie(memDB) + stateDB = newAccountStateDB(memDB, trie.rootHash, true) + address: EthAddress + + hexToByteArray("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", address) + + test "accountExist and isDeadAccount": + check stateDB.accountExist(address) == false + check stateDB.isDeadAccount(address) == true + + var acc = stateDB.getAccount(address) + acc.balance = 1000.u256 + stateDB.setAccount(address, acc) + + check stateDB.accountExist(address) == true + check stateDB.isDeadAccount(address) == false + + acc.balance = 0.u256 + acc.nonce = 1 + stateDB.setAccount(address, acc) + check stateDB.isDeadAccount(address) == false + + var code = hexToSeqByte("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6") + stateDB.setCode(address, code.toRange) + stateDB.setNonce(address, 0) + check stateDB.isDeadAccount(address) == false + + code = @[] + stateDB.setCode(address, code.toRange) + check stateDB.isDeadAccount(address) == true + check stateDB.accountExist(address) == true