2019-02-05 20:15:50 +01:00
|
|
|
import ../db/[db_chain, state_db], eth/common, chronicles, ../vm_state, ../vm_types, ../transaction, ranges,
|
2019-03-19 23:30:35 +07:00
|
|
|
../vm/[computation, message], ../constants, stint, nimcrypto,
|
2019-02-05 20:15:50 +01:00
|
|
|
../vm_state_transactions, sugar, ../utils, eth/trie/db, ../tracer, ./executor
|
2018-08-29 11:49:01 +03:00
|
|
|
|
|
|
|
type
|
|
|
|
Chain* = ref object of AbstractChainDB
|
|
|
|
db: BaseChainDB
|
|
|
|
|
|
|
|
proc newChain*(db: BaseChainDB): Chain =
|
|
|
|
result.new
|
|
|
|
result.db = db
|
|
|
|
|
2019-01-15 15:02:25 +01:00
|
|
|
method genesisHash*(c: Chain): KeccakHash {.gcsafe.} =
|
2018-08-29 11:49:01 +03:00
|
|
|
c.db.getBlockHash(0.toBlockNumber)
|
|
|
|
|
2019-01-15 15:02:25 +01:00
|
|
|
method getBlockHeader*(c: Chain, b: HashOrNum, output: var BlockHeader): bool {.gcsafe.} =
|
2018-08-29 11:49:01 +03:00
|
|
|
case b.isHash
|
|
|
|
of true:
|
|
|
|
c.db.getBlockHeader(b.hash, output)
|
|
|
|
else:
|
|
|
|
c.db.getBlockHeader(b.number, output)
|
|
|
|
|
2019-01-15 15:02:25 +01:00
|
|
|
method getBestBlockHeader*(c: Chain): BlockHeader {.gcsafe.} =
|
2018-08-29 11:49:01 +03:00
|
|
|
c.db.getCanonicalHead()
|
|
|
|
|
2019-01-15 15:02:25 +01:00
|
|
|
method getSuccessorHeader*(c: Chain, h: BlockHeader, output: var BlockHeader): bool {.gcsafe.} =
|
2018-08-29 11:49:01 +03:00
|
|
|
let n = h.blockNumber + 1
|
|
|
|
c.db.getBlockHeader(n, output)
|
|
|
|
|
|
|
|
method getBlockBody*(c: Chain, blockHash: KeccakHash): BlockBodyRef =
|
|
|
|
result = nil
|
|
|
|
|
2018-12-14 13:46:56 +01:00
|
|
|
method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarray[BlockBody]): ValidationResult =
|
2018-08-29 11:49:01 +03:00
|
|
|
# Run the VM here
|
2018-12-14 13:46:56 +01:00
|
|
|
if headers.len != bodies.len:
|
|
|
|
debug "Number of headers not matching number of bodies"
|
|
|
|
return ValidationResult.Error
|
2018-08-29 11:49:01 +03:00
|
|
|
|
2018-10-05 03:20:12 +03:00
|
|
|
let transaction = c.db.db.beginTransaction()
|
|
|
|
defer: transaction.dispose()
|
|
|
|
|
2018-12-14 13:46:56 +01:00
|
|
|
trace "Persisting blocks", fromBlock = headers[0].blockNumber, toBlock = headers[^1].blockNumber
|
2018-08-29 11:49:01 +03:00
|
|
|
for i in 0 ..< headers.len:
|
2018-09-10 11:44:07 +03:00
|
|
|
let head = c.db.getCanonicalHead()
|
2019-02-14 22:20:41 +07:00
|
|
|
let vmState = newBaseVMState(head.stateRoot, headers[i], c.db)
|
2019-03-20 10:22:37 +07:00
|
|
|
let validationResult = processBlock(c.db, headers[i], bodies[i], vmState)
|
2018-09-10 11:44:07 +03:00
|
|
|
|
2019-01-12 19:49:08 +07:00
|
|
|
when not defined(release):
|
2018-12-25 12:58:55 +07:00
|
|
|
if validationResult == ValidationResult.Error:
|
2019-02-03 16:08:13 +07:00
|
|
|
dumpDebuggingMetaData(c.db, headers[i], bodies[i], vmState)
|
2019-01-23 13:59:26 +01:00
|
|
|
raise newException(Exception, "Validation error. Debugging metadata dumped.")
|
2018-09-10 11:44:07 +03:00
|
|
|
|
2019-01-09 15:35:02 +07:00
|
|
|
if validationResult != ValidationResult.OK:
|
2019-03-31 22:34:11 +02:00
|
|
|
return validationResult
|
2018-12-10 19:04:34 +07:00
|
|
|
|
2018-09-06 20:05:22 +03:00
|
|
|
discard c.db.persistHeaderToDb(headers[i])
|
2018-12-14 13:46:56 +01:00
|
|
|
if c.db.getCanonicalHead().blockHash != headers[i].blockHash:
|
|
|
|
debug "Stored block header hash doesn't match declared hash"
|
|
|
|
return ValidationResult.Error
|
2018-10-05 03:20:12 +03:00
|
|
|
|
2018-11-28 09:25:36 +07:00
|
|
|
c.db.persistTransactions(headers[i].blockNumber, bodies[i].transactions)
|
2018-12-25 12:58:55 +07:00
|
|
|
c.db.persistReceipts(vmState.receipts)
|
2018-11-24 08:00:58 +07:00
|
|
|
|
2018-10-05 03:20:12 +03:00
|
|
|
transaction.commit()
|
2019-03-13 01:13:59 +01:00
|
|
|
|
2019-03-13 21:41:52 +01:00
|
|
|
method getTrieDB*(c: Chain): TrieDatabaseRef {.gcsafe.} =
|
2019-03-13 01:13:59 +01:00
|
|
|
c.db.db
|
|
|
|
|