2018-09-06 17:05:22 +00:00
import .. / db / [ db_chain , state_db ] , eth_common , chronicles , .. / vm_state , .. / vm_types , .. / transaction , ranges ,
2018-09-29 15:36:42 +00:00
.. / vm / [ computation , interpreter_dispatch , message ] , .. / 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
# these types need to eradicated
# once eth_bloom and eth_common sync'ed
Bloom = eth_common . BloomFilter
LogsBloom = eth_bloom . BloomFilter
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
proc makeReceipt ( vmState : BaseVMState , stateRoot : Hash256 , cumulativeGasUsed : GasInt ) : Receipt =
# TODO: post byzantium fork use status instead of rootHash
# currently, vmState.rootHash vs stateDb.rootHash can be different
# need to wait #188 solved
#result.stateRootOrStatus = hashOrStatus(vmState.blockHeader.stateRoot)
result . stateRootOrStatus = hashOrStatus ( stateRoot )
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
2018-10-05 00:20:12 +00:00
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 )
2018-09-06 17:05:22 +00:00
if headers [ i ] . txRoot ! = BLANK_ROOT_HASH :
2018-12-10 15:54:19 +00:00
assert ( head . blockNumber = = headers [ i ] . blockNumber - 1 )
2018-09-06 17:05:22 +00:00
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
2018-09-06 17:05:22 +00:00
if bodies [ i ] . transactions . len ! = 0 :
2018-12-06 23:16:34 +00:00
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 :
2018-09-06 17:05:22 +00:00
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
# perhaps this can be moved somewhere else
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
2018-09-06 17:05:22 +00:00
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 :
2018-12-06 23:16:34 +00:00
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 :
debug " wrong receipt in block " , blockNumber = headers [ i ] . blockNumber , receiptRoot , valid = headers [ i ] . receiptRoot
assert ( headers [ i ] . receiptRoot = = receiptRoot )
2018-09-06 17:05:22 +00:00
discard c . db . persistHeaderToDb ( headers [ i ] )
assert ( c . db . getCanonicalHead ( ) . blockHash = = headers [ i ] . blockHash )
2018-10-05 00:20:12 +00:00
2018-11-28 02:25:36 +00:00
c . db . persistTransactions ( headers [ i ] . blockNumber , bodies [ i ] . transactions )
2018-12-10 12:04:34 +00:00
c . db . persistReceipts ( receipts )
2018-11-24 01:00:58 +00:00
2018-10-05 00:20:12 +00:00
transaction . commit ( )