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 )
2019-02-28 04:31:25 +00:00
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 )
2019-02-28 04:31:25 +00:00
gasRefundAmount = ( gasRemaining + gasRefund ) . u256 * tx . gasPrice . u256
2018-12-31 03:27:02 +00:00
db . addBalance ( sender , gasRefundAmount )
2019-02-28 04:31:25 +00:00
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
2018-12-06 23:16:34 +00:00
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 :
2019-02-28 04:31:25 +00:00
result = tx . contractCreate ( vmState , sender )
2018-12-04 11:42:55 +00:00
else :
2019-02-28 04:31:25 +00:00
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