nimbus-eth1/nimbus/p2p/chain.nim

151 lines
5.8 KiB
Nim
Raw Normal View History

import ../db/[db_chain, state_db], eth_common, chronicles, ../vm_state, ../vm_types, ../transaction, ranges,
2018-12-11 09:01:26 +00:00
../vm/[computation, interpreter_dispatch, message, interpreter/vm_forks], ../constants, stint, nimcrypto,
2018-12-10 12:04:34 +00:00
../vm_state_transactions, sugar, ../utils, eth_trie/db, ../tracer, ./executor, json,
2018-12-10 15:54:19 +00:00
eth_bloom, strutils
2018-12-10 12:04:34 +00:00
type
2018-12-11 09:01:26 +00:00
# TODO: these types need to be removed
2018-12-10 12:04:34 +00:00
# once eth_bloom and eth_common sync'ed
Bloom = eth_common.BloomFilter
LogsBloom = eth_bloom.BloomFilter
2018-12-11 09:01:26 +00:00
# TODO: move these three receipt procs below somewhere else more appropriate
2018-12-10 12:04:34 +00:00
func logsBloom(logs: openArray[Log]): LogsBloom =
for log in logs:
result.incl log.address
for topic in log.topics:
result.incl topic
func createBloom*(receipts: openArray[Receipt]): Bloom =
var bloom: LogsBloom
for receipt in receipts:
bloom.value = bloom.value or logsBloom(receipt.logs).value
result = bloom.value.toByteArrayBE
2018-12-11 09:01:26 +00:00
proc makeReceipt(vmState: BaseVMState, stateRoot: Hash256, cumulativeGasUsed: GasInt, fork = FkFrontier): Receipt =
if fork < FkByzantium:
# TODO: which one: vmState.blockHeader.stateRoot or stateDb.rootHash?
# currently, vmState.blockHeader.stateRoot vs stateDb.rootHash can be different
# need to wait #188 solved
result.stateRootOrStatus = hashOrStatus(stateRoot)
else:
# TODO: post byzantium fork use status instead of rootHash
let vmStatus = true # success or failure
result.stateRootOrStatus = hashOrStatus(vmStatus)
2018-12-10 12:04:34 +00:00
result.cumulativeGasUsed = cumulativeGasUsed
result.logs = vmState.getAndClearLogEntries()
result.bloom = logsBloom(result.logs).value.toByteArrayBE
2018-08-29 08:49:01 +00:00
type
Chain* = ref object of AbstractChainDB
db: BaseChainDB
proc newChain*(db: BaseChainDB): Chain =
result.new
result.db = db
method genesisHash*(c: Chain): KeccakHash =
c.db.getBlockHash(0.toBlockNumber)
method getBlockHeader*(c: Chain, b: HashOrNum, output: var BlockHeader): bool =
case b.isHash
of true:
c.db.getBlockHeader(b.hash, output)
else:
c.db.getBlockHeader(b.number, output)
method getBestBlockHeader*(c: Chain): BlockHeader =
c.db.getCanonicalHead()
method getSuccessorHeader*(c: Chain, h: BlockHeader, output: var BlockHeader): bool =
let n = h.blockNumber + 1
c.db.getBlockHeader(n, output)
method getBlockBody*(c: Chain, blockHash: KeccakHash): BlockBodyRef =
result = nil
2018-12-10 15:54:19 +00:00
method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarray[BlockBody]) =
2018-08-29 08:49:01 +00:00
# Run the VM here
assert(headers.len == bodies.len)
2018-09-10 08:44:07 +00:00
let blockReward = 5.u256 * pow(10.u256, 18) # 5 ETH
let transaction = c.db.db.beginTransaction()
defer: transaction.dispose()
2018-12-10 15:54:19 +00:00
debug "Persisting blocks", range = $headers[0].blockNumber & " - " & $headers[^1].blockNumber
2018-08-29 08:49:01 +00:00
for i in 0 ..< headers.len:
2018-09-10 08:44:07 +00:00
let head = c.db.getCanonicalHead()
assert(head.blockNumber == headers[i].blockNumber - 1)
2018-11-30 10:07:20 +00:00
var stateDb = newAccountStateDB(c.db.db, head.stateRoot, c.db.pruneTrie)
2018-12-10 12:04:34 +00:00
var receipts = newSeq[Receipt](bodies[i].transactions.len)
2018-09-10 08:44:07 +00:00
assert(bodies[i].transactions.calcTxRoot == headers[i].txRoot)
if headers[i].txRoot != BLANK_ROOT_HASH:
2018-12-10 15:54:19 +00:00
assert(head.blockNumber == headers[i].blockNumber - 1)
let vmState = newBaseVMState(head, c.db)
2018-09-10 08:44:07 +00:00
assert(bodies[i].transactions.len != 0)
2018-12-10 12:04:34 +00:00
var cumulativeGasUsed = GasInt(0)
2018-09-10 08:44:07 +00:00
if bodies[i].transactions.len != 0:
trace "Has transactions", blockNumber = headers[i].blockNumber, blockHash = headers[i].blockHash
2018-09-10 08:44:07 +00:00
2018-12-10 12:04:34 +00:00
for txIndex, tx in bodies[i].transactions:
var sender: EthAddress
2018-12-10 12:04:34 +00:00
if tx.getSender(sender):
let txFee = processTransaction(stateDb, tx, sender, vmState)
2018-12-10 15:54:19 +00:00
2018-12-11 09:01:26 +00:00
# perhaps this can be altered somehow
# or processTransaction return only gasUsed
# a `div` here is ugly and possibly div by zero
2018-12-10 12:04:34 +00:00
let gasUsed = (txFee div tx.gasPrice.u256).truncate(GasInt)
cumulativeGasUsed += gasUsed
2018-12-10 15:54:19 +00:00
# miner fee
stateDb.addBalance(headers[i].coinbase, txFee)
2018-09-10 08:44:07 +00:00
else:
assert(false, "Could not get sender")
2018-12-10 12:04:34 +00:00
receipts[txIndex] = makeReceipt(vmState, stateDb.rootHash, cumulativeGasUsed)
2018-09-10 08:44:07 +00:00
2018-12-10 15:54:19 +00:00
var mainReward = blockReward
if headers[i].ommersHash != EMPTY_UNCLE_HASH:
2018-09-10 08:44:07 +00:00
let h = c.db.persistUncles(bodies[i].uncles)
assert(h == headers[i].ommersHash)
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:
debug "Wrong state root in block", blockNumber = headers[i].blockNumber, expected = headers[i].stateRoot, actual = stateDb.rootHash, arrivedFrom = c.db.getCanonicalHead().stateRoot
let ttrace = traceTransaction(c.db, headers[i], bodies[i], bodies[i].transactions.len - 1, {})
trace "NIMBUS TRACE", transactionTrace=ttrace.pretty()
2018-12-04 11:42:55 +00:00
2018-09-10 08:44:07 +00:00
assert(headers[i].stateRoot == stateDb.rootHash)
2018-12-10 12:04:34 +00:00
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:
2018-12-11 01:16:21 +00:00
debug "wrong receiptRoot in block", blockNumber = headers[i].blockNumber, actual=receiptRoot, expected=headers[i].receiptRoot
2018-12-10 12:04:34 +00:00
assert(headers[i].receiptRoot == receiptRoot)
discard c.db.persistHeaderToDb(headers[i])
assert(c.db.getCanonicalHead().blockHash == headers[i].blockHash)
c.db.persistTransactions(headers[i].blockNumber, bodies[i].transactions)
2018-12-10 12:04:34 +00:00
c.db.persistReceipts(receipts)
transaction.commit()