2019-04-18 01:27:55 +00:00
import options , sets ,
2020-04-20 18:12:44 +00:00
eth / [ common , bloom , trie / db ] , chronicles , nimcrypto ,
2020-05-30 03:14:59 +00:00
.. / db / [ db_chain , accounts_cache ] ,
2018-12-14 07:32:45 +00:00
.. / utils , .. / constants , .. / transaction ,
.. / vm_state , .. / vm_types , .. / vm_state_transactions ,
2021-03-31 11:10:28 +00:00
.. / vm_computation , .. / vm_message , .. / vm / precompiles ,
2021-03-31 09:46:50 +00:00
. / vm_forks ,
2020-04-12 10:33:17 +00:00
. / dao , .. / config
2018-12-04 11:42:55 +00:00
2019-04-23 12:50:45 +00:00
proc processTransaction * ( tx : Transaction , sender : EthAddress , vmState : BaseVMState , fork : Fork ) : 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
2018-12-06 23:16:34 +00:00
trace " Sender " , sender
2019-02-27 06:11:31 +00:00
trace " txHash " , rlpHash = tx . rlpHash
2020-12-11 10:51:17 +00:00
# EIP2929
if fork > = FkBerlin :
vmState . mutateStateDB :
db . accessList ( sender )
if not tx . isContractCreation :
#If it's a create-tx, the destination will be added inside evm.create
db . accessList ( tx . getRecipient )
for c in activePrecompiles ( ) :
db . accessList ( c )
2020-01-24 12:52:55 +00:00
if validateTransaction ( vmState , tx , sender , fork ) :
2020-01-20 11:59:46 +00:00
var c = setupComputation ( vmState , tx , sender , fork )
2019-04-18 00:56:57 +00:00
vmState . mutateStateDB :
2020-01-30 15:22:38 +00:00
db . subBalance ( sender , tx . gasLimit . u256 * tx . gasPrice . u256 )
2020-01-10 11:18:36 +00:00
execComputation ( c )
2020-01-30 15:54:29 +00:00
result = tx . gasLimit
2020-01-10 11:18:36 +00:00
if not c . shouldBurnGas :
2020-01-30 15:54:29 +00:00
c . refundGas ( tx , sender )
result - = c . gasMeter . gasRemaining
2019-04-18 00:56:57 +00:00
2020-01-30 15:54:29 +00:00
vmState . cumulativeGasUsed + = result
2019-04-18 00:56:57 +00:00
2020-06-22 00:48:23 +00:00
let miner = vmState . coinbase ( )
2020-06-19 13:24:09 +00:00
2019-04-18 00:56:57 +00:00
vmState . mutateStateDB :
2020-01-10 11:18:36 +00:00
# miner fee
2020-01-30 15:54:29 +00:00
let txFee = result . u256 * tx . gasPrice . u256
2020-06-19 13:24:09 +00:00
db . addBalance ( miner , txFee )
2020-01-10 11:18:36 +00:00
for deletedAccount in vmState . suicides :
db . deleteAccount deletedAccount
2018-12-12 00:32:33 +00:00
2020-01-09 06:51:54 +00:00
if fork > = FkSpurious :
2020-06-19 13:24:09 +00:00
vmState . touchedAccounts . incl ( miner )
2020-01-09 06:51:54 +00:00
# EIP158/161 state clearing
for account in vmState . touchedAccounts :
if db . accountExists ( account ) and db . isEmptyAccount ( account ) :
debug " state clearing " , account
db . deleteAccount ( account )
2019-04-18 01:27:55 +00:00
2020-06-06 03:05:11 +00:00
if vmState . generateWitness :
vmState . accountDb . collectWitnessData ( )
2020-06-15 06:28:08 +00:00
vmState . accountDb . persist ( clearCache = false )
2019-03-11 15:32:25 +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
2019-09-07 08:38:44 +00:00
proc makeReceipt * ( vmState : BaseVMState , 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 :
2019-04-22 09:37:41 +00:00
result . stateRootOrStatus = hashOrStatus ( vmState . status )
2018-12-14 07:32:45 +00:00
2019-04-18 00:56:57 +00:00
result . cumulativeGasUsed = vmState . cumulativeGasUsed
2018-12-14 07:32:45 +00:00
result . logs = vmState . getAndClearLogEntries ( )
result . bloom = logsBloom ( result . logs ) . value . toByteArrayBE
2018-12-12 00:32:33 +00:00
2019-05-14 04:31:30 +00:00
func eth ( n : int ) : Uint256 {. compileTime . } =
n . u256 * pow ( 10 . u256 , 18 )
const
eth5 = 5 . eth
eth3 = 3 . eth
eth2 = 2 . eth
2019-09-07 08:38:44 +00:00
blockRewards * : array [ Fork , Uint256 ] = [
2019-05-14 04:31:30 +00:00
eth5 , # FkFrontier
eth5 , # FkHomestead
eth5 , # FkTangerine
eth5 , # FkSpurious
eth3 , # FkByzantium
2019-11-11 05:20:21 +00:00
eth2 , # FkConstantinople
2020-03-04 09:32:30 +00:00
eth2 , # FkPetersburg
2020-11-19 04:59:53 +00:00
eth2 , # FkIstanbul
eth2 # FkBerlin
2019-05-14 04:31:30 +00:00
]
2020-06-19 13:24:09 +00:00
proc calculateReward ( fork : Fork , header : BlockHeader , body : BlockBody , vmState : BaseVMState ) =
# PoA consensus engine have no reward for miner
if vmState . consensusEnginePoA : return
let blockReward = blockRewards [ fork ]
var mainReward = blockReward
for uncle in body . uncles :
var uncleReward = uncle . blockNumber . u256 + 8 . u256
uncleReward - = header . blockNumber . u256
uncleReward = uncleReward * blockReward
uncleReward = uncleReward div 8 . u256
vmState . mutateStateDB :
db . addBalance ( uncle . coinbase , uncleReward )
mainReward + = blockReward div 32 . u256
vmState . mutateStateDB :
db . addBalance ( header . coinbase , mainReward )
2019-03-20 03:22:37 +00:00
proc processBlock * ( chainDB : BaseChainDB , header : BlockHeader , body : BlockBody , vmState : BaseVMState ) : ValidationResult =
2019-11-28 10:02:11 +00:00
var dbTx = chainDB . db . beginTransaction ( )
defer : dbTx . dispose ( )
2019-04-06 14:50:43 +00:00
if chainDB . config . daoForkSupport and header . blockNumber = = chainDB . config . daoForkBlock :
vmState . mutateStateDB :
db . applyDAOHardFork ( )
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
2020-04-12 10:33:17 +00:00
let fork = chainDB . config . toFork ( vmState . blockNumber )
2019-04-22 09:52:18 +00:00
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 )
2019-04-18 00:56:57 +00:00
vmState . cumulativeGasUsed = 0
2018-12-25 05:58:55 +00:00
for txIndex , tx in body . transactions :
2019-04-18 00:56:57 +00:00
var sender : EthAddress
if tx . getSender ( sender ) :
2020-04-15 11:09:49 +00:00
discard processTransaction ( tx , sender , vmState , fork )
2018-12-12 00:32:33 +00:00
else :
2019-04-18 00:56:57 +00:00
debug " Could not get sender " , txIndex , tx
return ValidationResult . Error
2019-04-22 09:52:18 +00:00
vmState . receipts [ txIndex ] = makeReceipt ( vmState , fork )
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
2020-06-19 13:24:09 +00:00
calculateReward ( fork , header , body , vmState )
2018-12-12 00:32:33 +00:00
# Reward beneficiary
2019-03-07 08:04:32 +00:00
vmState . mutateStateDB :
2020-06-06 03:05:11 +00:00
if vmState . generateWitness :
db . collectWitnessData ( )
2020-06-15 06:28:08 +00:00
db . persist ( ClearCache in vmState . flags )
2018-12-12 00:32:33 +00:00
2019-03-07 08:04:32 +00:00
let stateDb = vmState . accountDb
2018-12-25 05:58:55 +00:00
if header . stateRoot ! = stateDb . rootHash :
2020-06-10 05:54:15 +00:00
when defined ( geth ) :
error " Wrong state root in block " , blockNumber = header . blockNumber , expected = header . stateRoot , actual = stateDb . rootHash
else :
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
2019-11-28 10:02:11 +00:00
# `applyDeletes = false`
2019-12-06 05:27:29 +00:00
# If the trie pruning activated, each of the block will have its own state trie keep intact,
# rather than destroyed by trie pruning. But the current block will still get a pruned trie.
# If trie pruning deactivated, `applyDeletes` have no effects.
2019-11-28 10:02:11 +00:00
dbTx . commit ( applyDeletes = false )