nimbus-eth1/nimbus/p2p/executor.nim

153 lines
5.6 KiB
Nim
Raw Normal View History

2018-12-31 03:27:02 +00:00
import options,
2019-02-05 19:15:50 +00:00
eth/[common, bloom], ranges, chronicles, nimcrypto,
2018-12-14 07:32:45 +00:00
../db/[db_chain, state_db],
../utils, ../constants, ../transaction,
../vm_state, ../vm_types, ../vm_state_transactions,
2018-12-25 05:58:55 +00:00
../vm/[computation, interpreter_dispatch, message],
../vm/interpreter/vm_forks
2018-12-04 11:42:55 +00:00
2019-02-27 06:11:31 +00:00
proc contractCall*(tx: Transaction, vmState: BaseVMState, sender: EthAddress, forkOverride=none(Fork)): GasInt =
2018-12-31 03:27:02 +00:00
var db = vmState.accountDb
2019-02-27 03:30:03 +00:00
var computation = setupComputation(vmState, tx, sender, forkOverride)
result = tx.gasLimit
2018-12-31 03:27:02 +00:00
if execComputation(computation):
let
2019-02-27 03:30:03 +00:00
gasRemaining = computation.gasMeter.gasRemaining
gasRefunded = computation.getGasRefund()
gasUsed = tx.gasLimit - gasRemaining
2018-12-31 03:27:02 +00:00
gasRefund = min(gasRefunded, gasUsed div 2)
gasRefundAmount = (gasRemaining + gasRefund).u256 * tx.gasPrice.u256
2018-12-31 03:27:02 +00:00
db.addBalance(sender, gasRefundAmount)
return (gasUsed - gasRefund)
2018-12-31 03:27:02 +00:00
2019-02-27 06:11:31 +00:00
proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMState): GasInt =
2018-12-04 11:42:55 +00:00
## Process the transaction, write the results to db.
## Returns amount of ETH to be rewarded to miner
trace "Sender", sender
2019-02-27 06:11:31 +00:00
trace "txHash", rlpHash = tx.rlpHash
2018-12-31 03:27:02 +00:00
var db = vmState.accountDb
2018-12-04 11:42:55 +00:00
var transactionFailed = false
# TODO: combine/refactor re validate
2019-02-27 06:11:31 +00:00
let upfrontGasCost = tx.gasLimit.u256 * tx.gasPrice.u256
let upfrontCost = upfrontGasCost + tx.value
2018-12-04 11:42:55 +00:00
var balance = db.getBalance(sender)
if balance < upfrontCost:
if balance <= upfrontGasCost:
2019-02-27 06:11:31 +00:00
result = (balance div tx.gasPrice.u256).truncate(GasInt)
2018-12-04 11:42:55 +00:00
balance = 0.u256
else:
2019-02-27 06:11:31 +00:00
result = tx.gasLimit
2018-12-04 11:42:55 +00:00
balance -= upfrontGasCost
transactionFailed = true
else:
2019-02-27 05:42:26 +00:00
balance -= upfrontGasCost
2018-12-04 11:42:55 +00:00
2019-02-27 06:11:31 +00:00
db.incNonce(sender)
2018-12-04 11:42:55 +00:00
db.setBalance(sender, balance)
2019-02-27 06:11:31 +00:00
if transactionFailed: return
2018-12-04 11:42:55 +00:00
2019-02-27 06:11:31 +00:00
# TODO: Run the vm with proper fork
if tx.isContractCreation:
result = tx.contractCreate(vmState, sender)
2018-12-04 11:42:55 +00:00
else:
result = tx.contractCall(vmState, sender)
2018-12-12 00:32:33 +00:00
2018-12-14 07:32:45 +00:00
type
# TODO: these types need to be removed
2019-02-05 19:15:50 +00:00
# once eth/bloom and eth/common sync'ed
Bloom = common.BloomFilter
LogsBloom = bloom.BloomFilter
2018-12-14 07:32:45 +00:00
# TODO: move these three receipt procs below somewhere else more appropriate
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-31 03:27:02 +00:00
proc makeReceipt(vmState: BaseVMState, cumulativeGasUsed: GasInt, fork = FkFrontier): Receipt =
2018-12-14 07:32:45 +00:00
if fork < FkByzantium:
2018-12-31 03:27:02 +00:00
result.stateRootOrStatus = hashOrStatus(vmState.accountDb.rootHash)
2018-12-14 07:32:45 +00:00
else:
# TODO: post byzantium fork use status instead of rootHash
let vmStatus = true # success or failure
result.stateRootOrStatus = hashOrStatus(vmStatus)
result.cumulativeGasUsed = cumulativeGasUsed
result.logs = vmState.getAndClearLogEntries()
result.bloom = logsBloom(result.logs).value.toByteArrayBE
2018-12-12 00:32:33 +00:00
2018-12-25 05:58:55 +00:00
proc processBlock*(chainDB: BaseChainDB, head, header: BlockHeader, body: BlockBody, vmState: BaseVMState): ValidationResult =
2018-12-12 00:32:33 +00:00
let blockReward = 5.u256 * pow(10.u256, 18) # 5 ETH
2018-12-25 05:58:55 +00:00
if body.transactions.calcTxRoot != header.txRoot:
debug "Mismatched txRoot", blockNumber=header.blockNumber
2018-12-12 00:32:33 +00:00
return ValidationResult.Error
2018-12-31 03:27:02 +00:00
var stateDb = vmState.accountDb
2018-12-25 05:58:55 +00:00
if header.txRoot != BLANK_ROOT_HASH:
if body.transactions.len == 0:
debug "No transactions in body", blockNumber=header.blockNumber
2018-12-12 00:32:33 +00:00
return ValidationResult.Error
else:
2018-12-25 05:58:55 +00:00
trace "Has transactions", blockNumber = header.blockNumber, blockHash = header.blockHash
2018-12-12 00:32:33 +00:00
2018-12-25 12:10:04 +00:00
vmState.receipts = newSeq[Receipt](body.transactions.len)
2018-12-12 00:32:33 +00:00
var cumulativeGasUsed = GasInt(0)
2018-12-25 05:58:55 +00:00
for txIndex, tx in body.transactions:
2018-12-12 00:32:33 +00:00
var sender: EthAddress
if tx.getSender(sender):
2019-02-27 03:30:03 +00:00
let gasUsed = processTransaction(tx, sender, vmState)
2018-12-12 00:32:33 +00:00
cumulativeGasUsed += gasUsed
# miner fee
2019-02-27 03:30:03 +00:00
let txFee = gasUsed.u256 * tx.gasPrice.u256
2018-12-25 05:58:55 +00:00
stateDb.addBalance(header.coinbase, txFee)
2018-12-12 00:32:33 +00:00
else:
2018-12-25 05:58:55 +00:00
debug "Could not get sender", txIndex, tx
2018-12-12 00:32:33 +00:00
return ValidationResult.Error
2018-12-31 03:27:02 +00:00
vmState.receipts[txIndex] = makeReceipt(vmState, cumulativeGasUsed)
2018-12-12 00:32:33 +00:00
var mainReward = blockReward
2018-12-25 05:58:55 +00:00
if header.ommersHash != EMPTY_UNCLE_HASH:
let h = chainDB.persistUncles(body.uncles)
if h != header.ommersHash:
2018-12-12 00:32:33 +00:00
debug "Uncle hash mismatch"
return ValidationResult.Error
2018-12-25 05:58:55 +00:00
for uncle in body.uncles:
var uncleReward = uncle.blockNumber + 8.u256
uncleReward -= header.blockNumber
2018-12-12 00:32:33 +00:00
uncleReward = uncleReward * blockReward
uncleReward = uncleReward div 8.u256
2018-12-25 05:58:55 +00:00
stateDb.addBalance(uncle.coinbase, uncleReward)
2018-12-12 00:32:33 +00:00
mainReward += blockReward div 32.u256
# Reward beneficiary
2018-12-25 05:58:55 +00:00
stateDb.addBalance(header.coinbase, mainReward)
2018-12-12 00:32:33 +00:00
2018-12-25 05:58:55 +00:00
if header.stateRoot != stateDb.rootHash:
error "Wrong state root in block", blockNumber=header.blockNumber, expected=header.stateRoot, actual=stateDb.rootHash, arrivedFrom=chainDB.getCanonicalHead().stateRoot
2018-12-12 00:32:33 +00:00
# this one is a show stopper until we are confident in our VM's
# compatibility with the main chain
2018-12-25 10:31:51 +00:00
return ValidationResult.Error
2018-12-12 00:32:33 +00:00
2018-12-25 05:58:55 +00:00
let bloom = createBloom(vmState.receipts)
if header.bloom != bloom:
debug "wrong bloom in block", blockNumber=header.blockNumber
return ValidationResult.Error
2018-12-12 00:32:33 +00:00
2018-12-25 05:58:55 +00:00
let receiptRoot = calcReceiptRoot(vmState.receipts)
if header.receiptRoot != receiptRoot:
debug "wrong receiptRoot in block", blockNumber=header.blockNumber, actual=receiptRoot, expected=header.receiptRoot
return ValidationResult.Error