From 4cc0ef427c1071219ede1958fb4cfc6eaf571493 Mon Sep 17 00:00:00 2001
From: andri lim <jangko128@gmail.com>
Date: Fri, 1 Feb 2019 16:25:10 +0700
Subject: [PATCH] add ccountExist and isDeadAccount to AccountStateDB

---
 nimbus/db/state_db.nim  | 21 ++++++++++++++++---
 tests/all_tests.nim     |  3 ++-
 tests/test_state_db.nim | 45 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 4 deletions(-)
 create mode 100644 tests/test_state_db.nim

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
