mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
Various fixes towards state reconstruction
This commit is contained in:
parent
f9034e95b5
commit
3a1ec035b3
@ -21,8 +21,12 @@ proc newChainDB*(basePath: string): ChainDB =
|
|||||||
|
|
||||||
proc get*(db: ChainDB, key: openarray[byte]): seq[byte] =
|
proc get*(db: ChainDB, key: openarray[byte]): seq[byte] =
|
||||||
let s = db.store.getBytes(key)
|
let s = db.store.getBytes(key)
|
||||||
if not s.ok: raiseKeyReadError(key)
|
if s.ok:
|
||||||
return s.value
|
return s.value
|
||||||
|
elif s.error.len == 0:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
raiseKeyReadError(key)
|
||||||
|
|
||||||
proc put*(db: ChainDB, key, value: openarray[byte]) =
|
proc put*(db: ChainDB, key, value: openarray[byte]) =
|
||||||
let s = db.store.put(key, value)
|
let s = db.store.put(key, value)
|
||||||
|
@ -69,10 +69,12 @@ proc get*(db: ChainDB, key: openarray[byte]): seq[byte] =
|
|||||||
var
|
var
|
||||||
resStart = columnBlob(db.selectStmt, 0)
|
resStart = columnBlob(db.selectStmt, 0)
|
||||||
resLen = columnBytes(db.selectStmt, 0)
|
resLen = columnBytes(db.selectStmt, 0)
|
||||||
resSeq = newSeq[byte](resLen)
|
result = newSeq[byte](resLen)
|
||||||
copyMem(resSeq.baseAddr, resStart, resLen)
|
copyMem(result.baseAddr, resStart, resLen)
|
||||||
return resSeq
|
of SQLITE_DONE:
|
||||||
else: raiseKeySearchError(key)
|
discard
|
||||||
|
else:
|
||||||
|
raiseKeyReadError(key)
|
||||||
|
|
||||||
proc put*(db: ChainDB, key, value: openarray[byte]) =
|
proc put*(db: ChainDB, key, value: openarray[byte]) =
|
||||||
template check(op) =
|
template check(op) =
|
||||||
|
@ -31,13 +31,10 @@ proc `$`*(db: BaseChainDB): string =
|
|||||||
result = "BaseChainDB"
|
result = "BaseChainDB"
|
||||||
|
|
||||||
proc getBlockHeader*(self: BaseChainDB; blockHash: Hash256, output: var BlockHeader): bool =
|
proc getBlockHeader*(self: BaseChainDB; blockHash: Hash256, output: var BlockHeader): bool =
|
||||||
try:
|
let data = self.db.get(genericHashKey(blockHash).toOpenArray).toRange
|
||||||
let blk = self.db.get(genericHashKey(blockHash).toOpenArray).toRange
|
if data.len != 0:
|
||||||
if blk.len != 0:
|
output = rlp.decode(data, BlockHeader)
|
||||||
output = rlp.decode(blk, BlockHeader)
|
result = true
|
||||||
result = true
|
|
||||||
except KeyError:
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc getBlockHeader*(self: BaseChainDB, blockHash: Hash256): BlockHeader =
|
proc getBlockHeader*(self: BaseChainDB, blockHash: Hash256): BlockHeader =
|
||||||
## Returns the requested block header as specified by block hash.
|
## Returns the requested block header as specified by block hash.
|
||||||
@ -47,11 +44,10 @@ proc getBlockHeader*(self: BaseChainDB, blockHash: Hash256): BlockHeader =
|
|||||||
raise newException(BlockNotFound, "No block with hash " & blockHash.data.toHex)
|
raise newException(BlockNotFound, "No block with hash " & blockHash.data.toHex)
|
||||||
|
|
||||||
proc getHash(self: BaseChainDB, key: DbKey, output: var Hash256): bool {.inline.} =
|
proc getHash(self: BaseChainDB, key: DbKey, output: var Hash256): bool {.inline.} =
|
||||||
try:
|
let data = self.db.get(key.toOpenArray).toRange
|
||||||
output = rlp.decode(self.db.get(key.toOpenArray).toRange, Hash256)
|
if data.len != 0:
|
||||||
|
output = rlp.decode(data, Hash256)
|
||||||
result = true
|
result = true
|
||||||
except KeyError:
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
||||||
var headHash: Hash256
|
var headHash: Hash256
|
||||||
@ -145,13 +141,13 @@ proc setAsCanonicalChainHead(self: BaseChainDB; headerHash: Hash256): seq[BlockH
|
|||||||
for h in newCanonicalHeaders:
|
for h in newCanonicalHeaders:
|
||||||
self.addBlockNumberToHashLookup(h)
|
self.addBlockNumberToHashLookup(h)
|
||||||
|
|
||||||
self.db.put(canonicalHeadHashKey().toOpenArray, rlp.encode(header.hash).toOpenArray)
|
self.db.put(canonicalHeadHashKey().toOpenArray, rlp.encode(headerHash).toOpenArray)
|
||||||
|
|
||||||
return newCanonicalHeaders
|
return newCanonicalHeaders
|
||||||
|
|
||||||
proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool =
|
proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool =
|
||||||
## Returns True if the header with the given block hash is in our DB.
|
## Returns True if the header with the given block hash is in our DB.
|
||||||
self.db.contains(blockHash.data)
|
self.db.contains(genericHashKey(blockHash).toOpenArray)
|
||||||
|
|
||||||
iterator getBlockTransactionData(self: BaseChainDB, transactionRoot: Hash256): BytesRange =
|
iterator getBlockTransactionData(self: BaseChainDB, transactionRoot: Hash256): BytesRange =
|
||||||
var transactionDb = initHexaryTrie(self.db, transactionRoot)
|
var transactionDb = initHexaryTrie(self.db, transactionRoot)
|
||||||
@ -183,14 +179,15 @@ iterator getBlockTransactions(self: BaseChainDB; transactionRoot: Hash256;
|
|||||||
|
|
||||||
proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): seq[BlockHeader] =
|
proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): seq[BlockHeader] =
|
||||||
let isGenesis = header.parentHash == GENESIS_PARENT_HASH
|
let isGenesis = header.parentHash == GENESIS_PARENT_HASH
|
||||||
|
let headerHash = header.blockHash
|
||||||
if not isGenesis and not self.headerExists(header.parentHash):
|
if not isGenesis and not self.headerExists(header.parentHash):
|
||||||
raise newException(ParentNotFound, "Cannot persist block header " &
|
raise newException(ParentNotFound, "Cannot persist block header " &
|
||||||
$header.hash & " with unknown parent " & $header.parentHash)
|
$headerHash & " with unknown parent " & $header.parentHash)
|
||||||
self.db.put(genericHashKey(header.hash).toOpenArray, rlp.encode(header).toOpenArray)
|
self.db.put(genericHashKey(headerHash).toOpenArray, rlp.encode(header).toOpenArray)
|
||||||
|
|
||||||
let score = if isGenesis: header.difficulty
|
let score = if isGenesis: header.difficulty
|
||||||
else: self.getScore(header.parentHash).u256 + header.difficulty
|
else: self.getScore(header.parentHash).u256 + header.difficulty
|
||||||
self.db.put(blockHashToScoreKey(header.hash).toOpenArray, rlp.encode(score).toOpenArray)
|
self.db.put(blockHashToScoreKey(headerHash).toOpenArray, rlp.encode(score).toOpenArray)
|
||||||
|
|
||||||
self.addBlockNumberToHashLookup(header)
|
self.addBlockNumberToHashLookup(header)
|
||||||
|
|
||||||
@ -198,10 +195,10 @@ proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): seq[BlockHeader
|
|||||||
try:
|
try:
|
||||||
headScore = self.getScore(self.getCanonicalHead().hash)
|
headScore = self.getScore(self.getCanonicalHead().hash)
|
||||||
except CanonicalHeadNotFound:
|
except CanonicalHeadNotFound:
|
||||||
return self.setAsCanonicalChainHead(header.hash)
|
return self.setAsCanonicalChainHead(headerHash)
|
||||||
|
|
||||||
if score > headScore.u256:
|
if score > headScore.u256:
|
||||||
result = self.setAsCanonicalChainHead(header.hash)
|
result = self.setAsCanonicalChainHead(headerHash)
|
||||||
|
|
||||||
proc addTransactionToCanonicalChain(self: BaseChainDB, txHash: Hash256,
|
proc addTransactionToCanonicalChain(self: BaseChainDB, txHash: Hash256,
|
||||||
blockHeader: BlockHeader, index: int) =
|
blockHeader: BlockHeader, index: int) =
|
||||||
|
@ -73,7 +73,7 @@ template raiseKeyWriteError*(key: auto) =
|
|||||||
raise newException(StorageError, "failed to write key " & $key)
|
raise newException(StorageError, "failed to write key " & $key)
|
||||||
|
|
||||||
template raiseKeySearchError*(key: auto) =
|
template raiseKeySearchError*(key: auto) =
|
||||||
raise newException(KeyError, "failure during search for key " & $key)
|
raise newException(StorageError, "failure during search for key " & $key)
|
||||||
|
|
||||||
template raiseKeyDeletionError*(key: auto) =
|
template raiseKeyDeletionError*(key: auto) =
|
||||||
raise newException(StorageError, "failure to delete key " & $key)
|
raise newException(StorageError, "failure to delete key " & $key)
|
||||||
|
@ -14,7 +14,7 @@ import
|
|||||||
config, genesis, rpc/[common, p2p], p2p/chain,
|
config, genesis, rpc/[common, p2p], p2p/chain,
|
||||||
eth_trie
|
eth_trie
|
||||||
|
|
||||||
const UseSqlite = true
|
const UseSqlite = false
|
||||||
|
|
||||||
when UseSqlite:
|
when UseSqlite:
|
||||||
import db/backends/sqlite_backend
|
import db/backends/sqlite_backend
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import ../db/db_chain, eth_common, chronicles, ../vm_state, ../vm_types, ../transaction,
|
import ../db/[db_chain, state_db], eth_common, chronicles, ../vm_state, ../vm_types, ../transaction, ranges,
|
||||||
../vm/[computation, interpreter_dispatch, message]
|
../vm/[computation, interpreter_dispatch, message], ../constants
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -35,17 +35,28 @@ method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarr
|
|||||||
assert(headers.len == bodies.len)
|
assert(headers.len == bodies.len)
|
||||||
|
|
||||||
for i in 0 ..< headers.len:
|
for i in 0 ..< headers.len:
|
||||||
let head = c.db.getCanonicalHead()
|
echo "Persisting block: ", headers[i].blockNumber
|
||||||
# assert(head.blockNumber == headers[i].blockNumber - 1)
|
if headers[i].txRoot != BLANK_ROOT_HASH:
|
||||||
let vmState = newBaseVMState(head, c.db)
|
let head = c.db.getCanonicalHead()
|
||||||
if bodies[i].transactions.len != 0:
|
# assert(head.blockNumber == headers[i].blockNumber - 1)
|
||||||
# echo "block: ", headers[i].blockNumber
|
let vmState = newBaseVMState(head, c.db)
|
||||||
for t in bodies[i].transactions:
|
let stateDb = newAccountStateDB(c.db.db, head.stateRoot)
|
||||||
var msg: Message
|
if bodies[i].transactions.len != 0:
|
||||||
# echo "trns: ", t
|
# echo "block: ", headers[i].blockNumber
|
||||||
|
for t in bodies[i].transactions:
|
||||||
|
var sender: EthAddress
|
||||||
|
if t.getSender(sender):
|
||||||
|
echo "Sender: ", sender
|
||||||
|
let code = stateDb.getCode(sender)
|
||||||
|
debug "Transaction", sender, to = t.to, value = t.value, hasCode = code.len != 0
|
||||||
|
let msg = newMessage(t.gasLimit, t.gasPrice, t.to, sender, t.value, t.payload, code.toSeq)
|
||||||
|
assert(false, "Dont know how to persist transactions")
|
||||||
|
|
||||||
# let msg = newMessage(t.gasLimit, t.gasPrice, t.to, t.getSender,
|
if headers[i].ommersHash != EMPTY_UNCLE_HASH:
|
||||||
|
debug "Ignoring ommers", blockNumber = headers[i].blockNumber
|
||||||
|
|
||||||
|
discard c.db.persistHeaderToDb(headers[i])
|
||||||
|
assert(c.db.getCanonicalHead().blockHash == headers[i].blockHash)
|
||||||
|
|
||||||
# let c = newBaseComputation(vmState,
|
|
||||||
|
|
||||||
discard
|
discard
|
||||||
|
@ -49,7 +49,7 @@ proc toSignature*(transaction: Transaction): Signature =
|
|||||||
bytes[0..31] = transaction.R.toByteArrayBE()
|
bytes[0..31] = transaction.R.toByteArrayBE()
|
||||||
bytes[32..63] = transaction.S.toByteArrayBE()
|
bytes[32..63] = transaction.S.toByteArrayBE()
|
||||||
# TODO: V will become a byte or range soon.
|
# TODO: V will become a byte or range soon.
|
||||||
bytes[64] = transaction.V
|
bytes[64] = transaction.V - 27 # TODO: 27 should come from somewhere
|
||||||
initSignature(bytes)
|
initSignature(bytes)
|
||||||
|
|
||||||
proc getSender*(transaction: Transaction, output: var EthAddress): bool =
|
proc getSender*(transaction: Transaction, output: var EthAddress): bool =
|
||||||
|
@ -25,7 +25,7 @@ proc newBaseComputation*(vmState: BaseVMState, blockNumber: UInt256, message: Me
|
|||||||
result.children = @[]
|
result.children = @[]
|
||||||
result.accountsToDelete = initTable[EthAddress, EthAddress]()
|
result.accountsToDelete = initTable[EthAddress, EthAddress]()
|
||||||
result.logEntries = @[]
|
result.logEntries = @[]
|
||||||
result.code = newCodeStreamFromUnescaped(message.code) # TODO: what is the best repr
|
result.code = newCodeStream(message.code)
|
||||||
# result.rawOutput = "0x"
|
# result.rawOutput = "0x"
|
||||||
result.gasCosts = blockNumber.toFork.forkToSchedule
|
result.gasCosts = blockNumber.toFork.forkToSchedule
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ proc prepareChildMessage*(
|
|||||||
to,
|
to,
|
||||||
value,
|
value,
|
||||||
data,
|
data,
|
||||||
code.bytesToHex, # TODO: use seq[byte] for Message as well
|
code,
|
||||||
childOptions)
|
childOptions)
|
||||||
|
|
||||||
func output*(c: BaseComputation): seq[byte] =
|
func output*(c: BaseComputation): seq[byte] =
|
||||||
|
@ -39,7 +39,7 @@ proc newMessage*(
|
|||||||
sender: EthAddress,
|
sender: EthAddress,
|
||||||
value: UInt256,
|
value: UInt256,
|
||||||
data: seq[byte],
|
data: seq[byte],
|
||||||
code: string,
|
code: seq[byte],
|
||||||
options: MessageOptions = newMessageOptions()): Message =
|
options: MessageOptions = newMessageOptions()): Message =
|
||||||
|
|
||||||
validateGte(options.depth, minimum=0, title="Message.depth")
|
validateGte(options.depth, minimum=0, title="Message.depth")
|
||||||
|
@ -90,7 +90,7 @@ type
|
|||||||
# Not in EVMC API
|
# Not in EVMC API
|
||||||
|
|
||||||
# TODO: Done via callback function (v)table in EVMC
|
# TODO: Done via callback function (v)table in EVMC
|
||||||
code*: string # TODO: seq[byte] is probably a better representation
|
code*: seq[byte]
|
||||||
|
|
||||||
internalOrigin*: EthAddress
|
internalOrigin*: EthAddress
|
||||||
internalCodeAddress*: EthAddress
|
internalCodeAddress*: EthAddress
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
unittest, tables, parseutils,
|
unittest, tables, parseutils, byteutils,
|
||||||
eth_trie/[types, memdb], eth_common/eth_types,
|
eth_trie/[types, memdb], eth_common/eth_types,
|
||||||
../nimbus/[constants, vm_types, vm_state],
|
../nimbus/[constants, vm_types, vm_state],
|
||||||
../nimbus/vm/interpreter,
|
../nimbus/vm/interpreter,
|
||||||
@ -32,7 +32,7 @@ proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputat
|
|||||||
sender=ZERO_ADDRESS, #fixture{"exec"}{"caller"}.getStr,
|
sender=ZERO_ADDRESS, #fixture{"exec"}{"caller"}.getStr,
|
||||||
value=0.u256,
|
value=0.u256,
|
||||||
data = @[],
|
data = @[],
|
||||||
code=code,
|
code=code.hexToSeqByte,
|
||||||
gas=initial_gas,
|
gas=initial_gas,
|
||||||
gasPrice=1) # What is this used for?
|
gasPrice=1) # What is this used for?
|
||||||
# gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.u256,
|
# gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.u256,
|
||||||
|
@ -49,6 +49,8 @@ template backendTests(DB) =
|
|||||||
keyA notin db
|
keyA notin db
|
||||||
keyB in db
|
keyB in db
|
||||||
|
|
||||||
|
check db.get(keyA) == @[]
|
||||||
|
|
||||||
check db.get(keyB) == value1
|
check db.get(keyB) == value1
|
||||||
db.del(keyA)
|
db.del(keyA)
|
||||||
|
|
||||||
|
@ -22,11 +22,6 @@ suite "vm json tests":
|
|||||||
jsonTest("VMTests", testFixture)
|
jsonTest("VMTests", testFixture)
|
||||||
|
|
||||||
|
|
||||||
proc stringFromBytes(x: ByteRange): string =
|
|
||||||
result = newString(x.len)
|
|
||||||
for i in 0 ..< x.len:
|
|
||||||
result[i] = char(x[i])
|
|
||||||
|
|
||||||
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||||
var fixture: JsonNode
|
var fixture: JsonNode
|
||||||
for label, child in fixtures:
|
for label, child in fixtures:
|
||||||
@ -47,13 +42,13 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
|||||||
var memDb = newMemDB()
|
var memDb = newMemDB()
|
||||||
var vmState = newBaseVMState(header, newBaseChainDB(trieDB memDb))
|
var vmState = newBaseVMState(header, newBaseChainDB(trieDB memDb))
|
||||||
let fexec = fixture["exec"]
|
let fexec = fixture["exec"]
|
||||||
var code = ""
|
var code: seq[byte]
|
||||||
vmState.mutateStateDB:
|
vmState.mutateStateDB:
|
||||||
setupStateDB(fixture{"pre"}, db)
|
setupStateDB(fixture{"pre"}, db)
|
||||||
let address = fexec{"address"}.getStr.parseAddress
|
let address = fexec{"address"}.getStr.parseAddress
|
||||||
code = stringFromBytes db.getCode(address)
|
code = db.getCode(address).toSeq
|
||||||
|
|
||||||
code = fexec{"code"}.getStr
|
code = fexec{"code"}.getStr.hexToSeqByte
|
||||||
let toAddress = fexec{"address"}.getStr.parseAddress
|
let toAddress = fexec{"address"}.getStr.parseAddress
|
||||||
let message = newMessage(
|
let message = newMessage(
|
||||||
to = toAddress,
|
to = toAddress,
|
||||||
@ -67,7 +62,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
|||||||
createAddress = toAddress))
|
createAddress = toAddress))
|
||||||
|
|
||||||
#echo fixture{"exec"}
|
#echo fixture{"exec"}
|
||||||
var c = newCodeStreamFromUnescaped(code)
|
var c = newCodeStream(code)
|
||||||
when defined(nimbusdebug):
|
when defined(nimbusdebug):
|
||||||
c.displayDecompiled()
|
c.displayDecompiled()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user