2018-09-07 19:44:17 +00:00
|
|
|
# Nimbus
|
|
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
import
|
2018-09-27 19:09:26 +00:00
|
|
|
unittest, strformat, strutils, tables, json, ospaths, times,
|
2018-11-28 19:02:21 +00:00
|
|
|
byteutils, ranges/typedranges, nimcrypto/[keccak, hash], options,
|
2019-02-05 19:15:50 +00:00
|
|
|
eth/[rlp, common, keys], eth/trie/db, chronicles,
|
2019-02-27 06:18:44 +00:00
|
|
|
./test_helpers, ../nimbus/p2p/executor,
|
2018-09-07 19:44:17 +00:00
|
|
|
../nimbus/[constants, errors],
|
2019-02-26 07:04:12 +00:00
|
|
|
../nimbus/[vm_state, vm_types, vm_state_transactions, utils],
|
2018-09-07 19:44:17 +00:00
|
|
|
../nimbus/vm/interpreter,
|
|
|
|
../nimbus/db/[db_chain, state_db]
|
|
|
|
|
2019-02-28 08:22:07 +00:00
|
|
|
proc hashLogEntries(logs: seq[Log]): string =
|
|
|
|
toLowerAscii("0x" & $keccak(rlp.encode(logs)))
|
|
|
|
|
2018-09-07 19:44:17 +00:00
|
|
|
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus)
|
|
|
|
|
|
|
|
suite "generalstate json tests":
|
|
|
|
jsonTest("GeneralStateTests", testFixture)
|
|
|
|
|
2019-02-28 08:22:07 +00:00
|
|
|
proc testFixtureIndexes(prevStateRoot: Hash256, header: BlockHeader, pre: JsonNode, tx: Transaction,
|
|
|
|
sender: EthAddress, expectedHash, expectedLogs: string, testStatusIMPL: var TestStatus, fork: Fork) =
|
2018-12-11 23:26:08 +00:00
|
|
|
when enabledLogLevel <= TRACE:
|
|
|
|
let tracerFlags = {TracerFlags.EnableTracing}
|
|
|
|
else:
|
|
|
|
let tracerFlags: set[TracerFlags] = {}
|
2019-02-14 15:20:41 +00:00
|
|
|
var vmState = newBaseVMState(prevStateRoot, header, newBaseChainDB(newMemoryDb()), tracerFlags)
|
2018-09-19 16:46:14 +00:00
|
|
|
vmState.mutateStateDB:
|
|
|
|
setupStateDB(pre, db)
|
|
|
|
|
|
|
|
defer:
|
|
|
|
#echo vmState.readOnlyStateDB.dumpAccount("c94f5374fce5edbc8e2a8697c15331677e6ebf0b")
|
2018-11-28 19:02:21 +00:00
|
|
|
let obtainedHash = "0x" & `$`(vmState.readOnlyStateDB.rootHash).toLowerAscii
|
|
|
|
check obtainedHash == expectedHash
|
2019-02-28 08:22:07 +00:00
|
|
|
let logEntries = vmState.getAndClearLogEntries()
|
|
|
|
let actualLogsHash = hashLogEntries(logEntries)
|
|
|
|
let expectedLogsHash = toLowerAscii(expectedLogs)
|
|
|
|
check(expectedLogsHash == actualLogsHash)
|
2018-09-19 16:46:14 +00:00
|
|
|
|
2019-02-27 06:18:44 +00:00
|
|
|
if not validateTransaction(vmState, tx, sender):
|
2018-09-19 16:46:14 +00:00
|
|
|
vmState.mutateStateDB:
|
|
|
|
# pre-EIP158 (e.g., Byzantium) should ensure currentCoinbase exists
|
|
|
|
# in later forks, don't create at all
|
|
|
|
db.addBalance(header.coinbase, 0.u256)
|
|
|
|
return
|
|
|
|
|
2019-02-27 06:18:44 +00:00
|
|
|
let gasCost = tx.gasLimit.u256 * tx.gasPrice.u256
|
2018-09-19 16:46:14 +00:00
|
|
|
vmState.mutateStateDB:
|
2019-02-26 07:41:37 +00:00
|
|
|
db.incNonce(sender)
|
2019-02-27 05:42:26 +00:00
|
|
|
db.subBalance(sender, gasCost)
|
2019-02-28 04:31:25 +00:00
|
|
|
let gasUsed = if tx.isContractCreation and tx.payload.len > 0:
|
|
|
|
tx.contractCreate(vmState, sender, some(fork))
|
|
|
|
else:
|
|
|
|
tx.contractCall(vmState, sender, some(fork))
|
2019-02-27 06:18:44 +00:00
|
|
|
db.addBalance(header.coinbase, gasUsed.u256 * tx.gasPrice.u256)
|
2018-09-18 00:35:41 +00:00
|
|
|
|
2018-09-19 16:46:14 +00:00
|
|
|
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
|
|
|
var fixture: JsonNode
|
|
|
|
for label, child in fixtures:
|
|
|
|
fixture = child
|
|
|
|
break
|
2018-09-07 19:44:17 +00:00
|
|
|
|
2018-09-19 16:46:14 +00:00
|
|
|
let fenv = fixture["env"]
|
2018-09-25 12:52:28 +00:00
|
|
|
var emptyRlpHash = keccak256.digest(rlp.encode(""))
|
2018-09-19 16:46:14 +00:00
|
|
|
let header = BlockHeader(
|
|
|
|
coinbase: fenv["currentCoinbase"].getStr.ethAddressFromHex,
|
|
|
|
difficulty: fromHex(UInt256, fenv{"currentDifficulty"}.getStr),
|
|
|
|
blockNumber: fenv{"currentNumber"}.getHexadecimalInt.u256,
|
|
|
|
gasLimit: fenv{"currentGasLimit"}.getHexadecimalInt.GasInt,
|
|
|
|
timestamp: fenv{"currentTimestamp"}.getHexadecimalInt.int64.fromUnix,
|
|
|
|
stateRoot: emptyRlpHash
|
|
|
|
)
|
|
|
|
|
|
|
|
let ftrans = fixture["transaction"]
|
2018-11-28 19:02:21 +00:00
|
|
|
for fork in supportedForks:
|
2019-02-28 08:22:07 +00:00
|
|
|
if fixture["post"].hasKey(forkNames[fork]):
|
2018-11-28 19:02:21 +00:00
|
|
|
# echo "[fork: ", forkNames[fork], "]"
|
|
|
|
for expectation in fixture["post"][forkNames[fork]]:
|
|
|
|
let
|
|
|
|
expectedHash = expectation["hash"].getStr
|
2019-02-28 08:22:07 +00:00
|
|
|
expectedLogs = expectation["logs"].getStr
|
2018-11-28 19:02:21 +00:00
|
|
|
indexes = expectation["indexes"]
|
|
|
|
dataIndex = indexes["data"].getInt
|
|
|
|
gasIndex = indexes["gas"].getInt
|
|
|
|
valueIndex = indexes["value"].getInt
|
|
|
|
let transaction = ftrans.getFixtureTransaction(dataIndex, gasIndex, valueIndex)
|
|
|
|
let sender = ftrans.getFixtureTransactionSender
|
2019-02-28 08:22:07 +00:00
|
|
|
testFixtureIndexes(emptyRlpHash, header, fixture["pre"], transaction,
|
|
|
|
sender, expectedHash, expectedLogs, testStatusIMPL, fork)
|
|
|
|
|