nimbus-eth1/nimbus/db/state_db.nim

136 lines
4.5 KiB
Nim
Raw Normal View History

# 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
strformat, tables,
2018-04-11 15:12:28 +00:00
../constants, ../errors, ../validation, ../account, ../logging, ../utils_numeric, .. / utils / [padding, bytes, keccak],
stint, rlp
type
AccountStateDB* = ref object
db*: Table[string, BytesRange]
2018-02-13 17:18:08 +00:00
rootHash*: string # TODO trie
2018-02-13 17:18:08 +00:00
proc newAccountStateDB*(db: Table[string, string], readOnly: bool = false): AccountStateDB =
result = AccountStateDB(db: initTable[string, BytesRange]())
proc logger*(db: AccountStateDB): Logger =
logging.getLogger("db.State")
proc getAccount(db: AccountStateDB, address: string): Account =
# let rlpAccount = db.trie[address]
# if not rlpAccount.isNil:
# account = rlp.decode[Account](rlpAccount)
# account.mutable = true
# else:
# account = newAccount()
result = newAccount() # TODO
proc setAccount(db: AccountStateDB, address: string, account: Account) =
# db.trie[address] = rlp.encode[Account](account)
discard # TODO
2018-02-13 17:18:08 +00:00
proc getCodeHash*(db: AccountStateDB, address: string): string =
validateCanonicalAddress(address, title="Storage Address")
let account = db.getAccount(address)
result = account.codeHash
proc getBalance*(db: AccountStateDB, address: string): UInt256 =
validateCanonicalAddress(address, title="Storage Address")
let account = db.getAccount(address)
account.balance
proc setBalance*(db: var AccountStateDB, address: string, balance: UInt256) =
validateCanonicalAddress(address, title="Storage Address")
let account = db.getAccount(address)
account.balance = balance
db.setAccount(address, account)
proc deltaBalance*(db: var AccountStateDB, address: string, delta: UInt256) =
db.setBalance(address, db.getBalance(address) + delta)
2018-02-13 17:18:08 +00:00
proc setStorage*(db: var AccountStateDB, address: string, slot: UInt256, value: UInt256) =
#validateGte(value, 0, title="Storage Value")
#validateGte(slot, 0, title="Storage Slot")
2018-02-13 17:18:08 +00:00
validateCanonicalAddress(address, title="Storage Address")
2018-02-13 17:18:08 +00:00
# TODO
# let account = db.getAccount(address)
2018-02-13 17:18:08 +00:00
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
let slotAsKey = slot.intToBigEndian.pad32.toString
var storage = db.db
# TODO fix
2018-02-26 11:59:56 +00:00
if value > 0:
let encodedValue = rlp.encode value.intToBigEndian
storage[slotAsKey] = encodedValue
2018-02-26 11:59:56 +00:00
else:
storage.del(slotAsKey)
#storage[slotAsKey] = value
2018-02-13 17:18:08 +00:00
# account.storageRoot = storage.rootHash
# db.setAccount(address, account)
2018-02-26 11:59:56 +00:00
proc getStorage*(db: var AccountStateDB, address: string, slot: UInt256): (UInt256, bool) =
2018-02-13 17:18:08 +00:00
validateCanonicalAddress(address, title="Storage Address")
#validateGte(slot, 0, title="Storage Slot")
2018-02-13 17:18:08 +00:00
# TODO
# make it more correct
# for now, we just use a table
2018-02-13 17:18:08 +00:00
# let account = db.GetAccount(address)
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
let slotAsKey = slot.intToBigEndian.pad32.toString
var storage = db.db
if storage.hasKey(slotAsKey):
2018-02-26 11:59:56 +00:00
#result = storage[slotAsKey]
# XXX: `bigEndianToInt` can be refactored to work with a BytesRange/openarray
# Then we won't need to call `toSeq` here.
result = (storage[slotAsKey].toSeq.bigEndianToInt, true)
else:
2018-02-26 11:59:56 +00:00
result = (0.u256, false)
2018-02-13 17:18:08 +00:00
proc setNonce*(db: var AccountStateDB, address: string, nonce: UInt256) =
2018-02-13 17:18:08 +00:00
validateCanonicalAddress(address, title="Storage Address")
#validateGte(nonce, 0, title="Nonce")
2018-02-13 17:18:08 +00:00
var account = db.getAccount(address)
account.nonce = nonce
db.setAccount(address, account)
proc getNonce*(db: AccountStateDB, address: string): UInt256 =
2018-02-13 17:18:08 +00:00
validateCanonicalAddress(address, title="Storage Address")
let account = db.getAccount(address)
return account.nonce
proc setCode*(db: var AccountStateDB, address: string, code: string) =
validateCanonicalAddress(address, title="Storage Address")
var account = db.getAccount(address)
account.codeHash = keccak(code)
#db.db[account.codeHash] = code
2018-02-13 17:18:08 +00:00
db.setAccount(address, account)
proc getCode*(db: var AccountStateDB, address: string): string =
let codeHash = db.getCodeHash(address)
#if db.db.hasKey(codeHash):
# result = db.db[codeHash]
#else:
result = ""
2018-02-13 17:18:08 +00:00
# proc rootHash*(db: AccountStateDB): string =
# TODO return self.Trie.rootHash
# proc `rootHash=`*(db: var AccountStateDB, value: string) =
# TODO: self.Trie.rootHash = value