move block processing to executor
This commit is contained in:
parent
f613f8b3c6
commit
35c1c7e075
|
@ -71,80 +71,23 @@ method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarr
|
||||||
debug "Number of headers not matching number of bodies"
|
debug "Number of headers not matching number of bodies"
|
||||||
return ValidationResult.Error
|
return ValidationResult.Error
|
||||||
|
|
||||||
let blockReward = 5.u256 * pow(10.u256, 18) # 5 ETH
|
|
||||||
|
|
||||||
let transaction = c.db.db.beginTransaction()
|
let transaction = c.db.db.beginTransaction()
|
||||||
defer: transaction.dispose()
|
defer: transaction.dispose()
|
||||||
|
|
||||||
trace "Persisting blocks", fromBlock = headers[0].blockNumber, toBlock = headers[^1].blockNumber
|
trace "Persisting blocks", fromBlock = headers[0].blockNumber, toBlock = headers[^1].blockNumber
|
||||||
for i in 0 ..< headers.len:
|
for i in 0 ..< headers.len:
|
||||||
let head = c.db.getCanonicalHead()
|
let head = c.db.getCanonicalHead()
|
||||||
var stateDb = newAccountStateDB(c.db.db, head.stateRoot, c.db.pruneTrie)
|
let vmState = if headers[i].txRoot != BLANK_ROOT_HASH: newBaseVMState(head, c.db)
|
||||||
var receipts = newSeq[Receipt](bodies[i].transactions.len)
|
else: nil
|
||||||
|
let success = processBlock(c.db, head, headers[i], bodies[i], vmState)
|
||||||
|
|
||||||
if bodies[i].transactions.calcTxRoot != headers[i].txRoot:
|
if not success:
|
||||||
debug "Mismatched txRoot", i
|
let ttrace = traceTransaction(c.db, headers[i], bodies[i], bodies[i].transactions.len - 1, {})
|
||||||
return ValidationResult.Error
|
trace "NIMBUS TRACE", transactionTrace=ttrace.pretty()
|
||||||
|
let dump = dumpBlockState(headers[i], bodies[i])
|
||||||
|
trace "NIMBUS STATE DUMP", dump=dump.pretty()
|
||||||
|
|
||||||
if headers[i].txRoot != BLANK_ROOT_HASH:
|
assert(success)
|
||||||
let vmState = newBaseVMState(head, c.db)
|
|
||||||
if bodies[i].transactions.len == 0:
|
|
||||||
debug "No transactions in body", i
|
|
||||||
return ValidationResult.Error
|
|
||||||
else:
|
|
||||||
trace "Has transactions", blockNumber = headers[i].blockNumber, blockHash = headers[i].blockHash
|
|
||||||
|
|
||||||
var cumulativeGasUsed = GasInt(0)
|
|
||||||
for txIndex, tx in bodies[i].transactions:
|
|
||||||
var sender: EthAddress
|
|
||||||
if tx.getSender(sender):
|
|
||||||
let txFee = processTransaction(stateDb, tx, sender, vmState)
|
|
||||||
|
|
||||||
# perhaps this can be altered somehow
|
|
||||||
# or processTransaction return only gasUsed
|
|
||||||
# a `div` here is ugly and possibly div by zero
|
|
||||||
let gasUsed = (txFee div tx.gasPrice.u256).truncate(GasInt)
|
|
||||||
cumulativeGasUsed += gasUsed
|
|
||||||
|
|
||||||
# miner fee
|
|
||||||
stateDb.addBalance(headers[i].coinbase, txFee)
|
|
||||||
else:
|
|
||||||
debug "Could not get sender", i, tx
|
|
||||||
return ValidationResult.Error
|
|
||||||
receipts[txIndex] = makeReceipt(vmState, stateDb.rootHash, cumulativeGasUsed)
|
|
||||||
|
|
||||||
var mainReward = blockReward
|
|
||||||
if headers[i].ommersHash != EMPTY_UNCLE_HASH:
|
|
||||||
let h = c.db.persistUncles(bodies[i].uncles)
|
|
||||||
if h != headers[i].ommersHash:
|
|
||||||
debug "Uncle hash mismatch"
|
|
||||||
return ValidationResult.Error
|
|
||||||
for u in 0 ..< bodies[i].uncles.len:
|
|
||||||
var uncleReward = bodies[i].uncles[u].blockNumber + 8.u256
|
|
||||||
uncleReward -= headers[i].blockNumber
|
|
||||||
uncleReward = uncleReward * blockReward
|
|
||||||
uncleReward = uncleReward div 8.u256
|
|
||||||
stateDb.addBalance(bodies[i].uncles[u].coinbase, uncleReward)
|
|
||||||
mainReward += blockReward div 32.u256
|
|
||||||
|
|
||||||
# Reward beneficiary
|
|
||||||
stateDb.addBalance(headers[i].coinbase, mainReward)
|
|
||||||
|
|
||||||
if headers[i].stateRoot != stateDb.rootHash:
|
|
||||||
error "Wrong state root in block", blockNumber = headers[i].blockNumber, expected = headers[i].stateRoot, actual = stateDb.rootHash, arrivedFrom = c.db.getCanonicalHead().stateRoot
|
|
||||||
# this one is a show stopper until we are confident in our VM's
|
|
||||||
# compatibility with the main chain
|
|
||||||
raise(newException(Exception, "Wrong state root in block"))
|
|
||||||
|
|
||||||
let bloom = createBloom(receipts)
|
|
||||||
if headers[i].bloom != bloom:
|
|
||||||
debug "wrong bloom in block", blockNumber = headers[i].blockNumber
|
|
||||||
assert(headers[i].bloom == bloom)
|
|
||||||
|
|
||||||
let receiptRoot = calcReceiptRoot(receipts)
|
|
||||||
if headers[i].receiptRoot != receiptRoot:
|
|
||||||
debug "wrong receiptRoot in block", blockNumber = headers[i].blockNumber, actual=receiptRoot, expected=headers[i].receiptRoot
|
|
||||||
assert(headers[i].receiptRoot == receiptRoot)
|
|
||||||
|
|
||||||
discard c.db.persistHeaderToDb(headers[i])
|
discard c.db.persistHeaderToDb(headers[i])
|
||||||
if c.db.getCanonicalHead().blockHash != headers[i].blockHash:
|
if c.db.getCanonicalHead().blockHash != headers[i].blockHash:
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import ../db/[db_chain, state_db], ../transaction, eth_common,
|
import ../db/[db_chain, state_db], ../transaction, eth_common,
|
||||||
../vm_state, ../vm_types, ../vm_state_transactions, ranges,
|
../vm_state, ../vm_types, ../vm_state_transactions, ranges,
|
||||||
chronicles, ../vm/[computation, interpreter_dispatch, message],
|
chronicles, ../vm/[computation, interpreter_dispatch, message],
|
||||||
../rpc/hexstrings, byteutils, nimcrypto
|
../rpc/hexstrings, byteutils, nimcrypto,
|
||||||
|
../utils, ../constants
|
||||||
|
|
||||||
proc processTransaction*(db: var AccountStateDB, t: Transaction, sender: EthAddress, vmState: BaseVMState): UInt256 =
|
proc processTransaction*(db: var AccountStateDB, t: Transaction, sender: EthAddress, vmState: BaseVMState): UInt256 =
|
||||||
## Process the transaction, write the results to db.
|
## Process the transaction, write the results to db.
|
||||||
|
@ -66,3 +67,74 @@ proc processTransaction*(db: var AccountStateDB, t: Transaction, sender: EthAddr
|
||||||
|
|
||||||
db.addBalance(sender, refund)
|
db.addBalance(sender, refund)
|
||||||
return gasUsed.u256 * t.gasPrice.u256
|
return gasUsed.u256 * t.gasPrice.u256
|
||||||
|
|
||||||
|
|
||||||
|
proc processBlock*(chainDB: BaseChainDB, head, header: BlockHeader, body: BlockBody, vmState: BaseVMState): bool =
|
||||||
|
let blockReward = 5.u256 * pow(10.u256, 18) # 5 ETH
|
||||||
|
|
||||||
|
var stateDb = newAccountStateDB(c.db.db, head.stateRoot, c.db.pruneTrie)
|
||||||
|
var receipts = newSeq[Receipt](bodies[i].transactions.len)
|
||||||
|
|
||||||
|
if bodies[i].transactions.calcTxRoot != headers[i].txRoot:
|
||||||
|
debug "Mismatched txRoot", i
|
||||||
|
return ValidationResult.Error
|
||||||
|
|
||||||
|
if headers[i].txRoot != BLANK_ROOT_HASH:
|
||||||
|
let vmState = newBaseVMState(head, c.db)
|
||||||
|
if bodies[i].transactions.len == 0:
|
||||||
|
debug "No transactions in body", i
|
||||||
|
return ValidationResult.Error
|
||||||
|
else:
|
||||||
|
trace "Has transactions", blockNumber = headers[i].blockNumber, blockHash = headers[i].blockHash
|
||||||
|
|
||||||
|
var cumulativeGasUsed = GasInt(0)
|
||||||
|
for txIndex, tx in bodies[i].transactions:
|
||||||
|
var sender: EthAddress
|
||||||
|
if tx.getSender(sender):
|
||||||
|
let txFee = processTransaction(stateDb, tx, sender, vmState)
|
||||||
|
|
||||||
|
# perhaps this can be altered somehow
|
||||||
|
# or processTransaction return only gasUsed
|
||||||
|
# a `div` here is ugly and possibly div by zero
|
||||||
|
let gasUsed = (txFee div tx.gasPrice.u256).truncate(GasInt)
|
||||||
|
cumulativeGasUsed += gasUsed
|
||||||
|
|
||||||
|
# miner fee
|
||||||
|
stateDb.addBalance(headers[i].coinbase, txFee)
|
||||||
|
else:
|
||||||
|
debug "Could not get sender", i, tx
|
||||||
|
return ValidationResult.Error
|
||||||
|
receipts[txIndex] = makeReceipt(vmState, stateDb.rootHash, cumulativeGasUsed)
|
||||||
|
|
||||||
|
var mainReward = blockReward
|
||||||
|
if headers[i].ommersHash != EMPTY_UNCLE_HASH:
|
||||||
|
let h = c.db.persistUncles(bodies[i].uncles)
|
||||||
|
if h != headers[i].ommersHash:
|
||||||
|
debug "Uncle hash mismatch"
|
||||||
|
return ValidationResult.Error
|
||||||
|
for u in 0 ..< bodies[i].uncles.len:
|
||||||
|
var uncleReward = bodies[i].uncles[u].blockNumber + 8.u256
|
||||||
|
uncleReward -= headers[i].blockNumber
|
||||||
|
uncleReward = uncleReward * blockReward
|
||||||
|
uncleReward = uncleReward div 8.u256
|
||||||
|
stateDb.addBalance(bodies[i].uncles[u].coinbase, uncleReward)
|
||||||
|
mainReward += blockReward div 32.u256
|
||||||
|
|
||||||
|
# Reward beneficiary
|
||||||
|
stateDb.addBalance(headers[i].coinbase, mainReward)
|
||||||
|
|
||||||
|
if headers[i].stateRoot != stateDb.rootHash:
|
||||||
|
error "Wrong state root in block", blockNumber = headers[i].blockNumber, expected = headers[i].stateRoot, actual = stateDb.rootHash, arrivedFrom = c.db.getCanonicalHead().stateRoot
|
||||||
|
# this one is a show stopper until we are confident in our VM's
|
||||||
|
# compatibility with the main chain
|
||||||
|
raise(newException(Exception, "Wrong state root in block"))
|
||||||
|
|
||||||
|
let bloom = createBloom(receipts)
|
||||||
|
if headers[i].bloom != bloom:
|
||||||
|
debug "wrong bloom in block", blockNumber = headers[i].blockNumber
|
||||||
|
assert(headers[i].bloom == bloom)
|
||||||
|
|
||||||
|
let receiptRoot = calcReceiptRoot(receipts)
|
||||||
|
if headers[i].receiptRoot != receiptRoot:
|
||||||
|
debug "wrong receiptRoot in block", blockNumber = headers[i].blockNumber, actual=receiptRoot, expected=headers[i].receiptRoot
|
||||||
|
assert(headers[i].receiptRoot == receiptRoot)
|
|
@ -69,8 +69,10 @@ proc setupDebugRpc*(chainDB: BaseChainDB, rpcsrv: RpcServer) =
|
||||||
## "latest" or "pending", as in the default block parameter.
|
## "latest" or "pending", as in the default block parameter.
|
||||||
let
|
let
|
||||||
header = chainDB.headerFromTag(quantityTag)
|
header = chainDB.headerFromTag(quantityTag)
|
||||||
|
blockHash = chainDB.getBlockHash(header.blockNumber)
|
||||||
|
body = getBlockBody(blockHash)
|
||||||
|
|
||||||
dumpBlockState(header)
|
dumpBlockState(header, body)
|
||||||
|
|
||||||
rpcsrv.rpc("debug_dumpBlockStateByHash") do(data: EthHashStr) -> JsonNode:
|
rpcsrv.rpc("debug_dumpBlockStateByHash") do(data: EthHashStr) -> JsonNode:
|
||||||
## Retrieves the state that corresponds to the block number and returns
|
## Retrieves the state that corresponds to the block number and returns
|
||||||
|
@ -80,5 +82,7 @@ proc setupDebugRpc*(chainDB: BaseChainDB, rpcsrv: RpcServer) =
|
||||||
let
|
let
|
||||||
h = data.toHash
|
h = data.toHash
|
||||||
header = chainDB.getBlockHeader(h)
|
header = chainDB.getBlockHeader(h)
|
||||||
|
blockHash = chainDB.getBlockHash(header.blockNumber)
|
||||||
|
body = getBlockBody(blockHash)
|
||||||
|
|
||||||
dumpBlockState(header)
|
dumpBlockState(header, body)
|
||||||
|
|
|
@ -9,7 +9,7 @@ proc getParentHeader(self: BaseChainDB, header: BlockHeader): BlockHeader =
|
||||||
proc prefixHex(x: openArray[byte]): string =
|
proc prefixHex(x: openArray[byte]): string =
|
||||||
"0x" & toHex(x, true)
|
"0x" & toHex(x, true)
|
||||||
|
|
||||||
proc toJson(db: AccountStateDB, address: EthAddress, name: string): JsonNode =
|
proc accountToJson(db: AccountStateDB, address: EthAddress, name: string): JsonNode =
|
||||||
result = newJObject()
|
result = newJObject()
|
||||||
result["name"] = %name
|
result["name"] = %name
|
||||||
result["address"] = %($address)
|
result["address"] = %($address)
|
||||||
|
@ -28,14 +28,14 @@ proc toJson(db: AccountStateDB, address: EthAddress, name: string): JsonNode =
|
||||||
result["storage"] = storage
|
result["storage"] = storage
|
||||||
|
|
||||||
proc captureStateAccount(n: JsonNode, db: AccountStateDB, sender: EthAddress, header: BlockHeader, tx: Transaction) =
|
proc captureStateAccount(n: JsonNode, db: AccountStateDB, sender: EthAddress, header: BlockHeader, tx: Transaction) =
|
||||||
n.add toJson(db, sender, "sender")
|
n.add accountToJson(db, sender, "sender")
|
||||||
n.add toJson(db, header.coinbase, "miner")
|
n.add accountToJson(db, header.coinbase, "miner")
|
||||||
|
|
||||||
if tx.isContractCreation:
|
if tx.isContractCreation:
|
||||||
let contractAddress = generateAddress(sender, tx.accountNonce)
|
let contractAddress = generateAddress(sender, tx.accountNonce)
|
||||||
n.add toJson(db, contractAddress, "contract")
|
n.add accountToJson(db, contractAddress, "contract")
|
||||||
else:
|
else:
|
||||||
n.add toJson(db, tx.to, "recipient")
|
n.add accountToJson(db, tx.to, "recipient")
|
||||||
|
|
||||||
proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||||
body: BlockBody, txIndex: int, tracerFlags: set[TracerFlags] = {}): JsonNode =
|
body: BlockBody, txIndex: int, tracerFlags: set[TracerFlags] = {}): JsonNode =
|
||||||
|
@ -88,5 +88,5 @@ proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||||
n[k.prefixHex] = %v.prefixHex
|
n[k.prefixHex] = %v.prefixHex
|
||||||
result["state"] = n
|
result["state"] = n
|
||||||
|
|
||||||
proc dumpBlockState*(header: BlockHeader): JsonNode =
|
proc dumpBlockState*(header: BlockHeader, body: BlockBody): JsonNode =
|
||||||
discard
|
discard
|
Loading…
Reference in New Issue