nimbus-eth1/tests/test_vm_json.nim
Zahary Karadjov 343cc4fa43 Populate the persistent databases with the empty RLP key.
Also implements transactional block persistence. Two issues
in the transaction processing code have been discovered that
might affect other usages such as the CALL instruction.

The main fix gets us past block 49000.

You may need to clean up your database.
2018-10-05 03:36:48 +03:00

101 lines
3.8 KiB
Nim

# 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
unittest, strformat, strutils, sequtils, tables, json, ospaths, times,
byteutils, ranges/typedranges, nimcrypto/[keccak, hash],
rlp, eth_trie/db, eth_common,
./test_helpers,
../nimbus/[constants, errors],
../nimbus/[vm_state, vm_types],
../nimbus/utils/header,
../nimbus/vm/interpreter,
../nimbus/db/[db_chain, state_db]
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus)
suite "vm json tests":
jsonTest("VMTests", testFixture)
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
var fixture: JsonNode
for label, child in fixtures:
fixture = child
break
let fenv = fixture["env"]
var emptyRlpHash = keccak256.digest(rlp.encode(""))
let header = BlockHeader(
coinbase: fenv{"currentCoinbase"}.getStr.parseAddress,
difficulty: fromHex(UInt256, fenv{"currentDifficulty"}.getStr),
blockNumber: fenv{"currentNumber"}.getHexadecimalInt.u256,
gasLimit: fenv{"currentGasLimit"}.getHexadecimalInt.GasInt,
timestamp: fenv{"currentTimestamp"}.getHexadecimalInt.int64.fromUnix,
stateRoot: emptyRlpHash
)
var vmState = newBaseVMState(header, newBaseChainDB(newMemoryDB()))
let fexec = fixture["exec"]
var code: seq[byte]
vmState.mutateStateDB:
setupStateDB(fixture{"pre"}, db)
let address = fexec{"address"}.getStr.parseAddress
code = db.getCode(address).toSeq
code = fexec{"code"}.getStr.hexToSeqByte
let toAddress = fexec{"address"}.getStr.parseAddress
let message = newMessage(
to = toAddress,
sender = fexec{"caller"}.getStr.parseAddress,
value = cast[uint64](fexec{"value"}.getHexadecimalInt).u256, # Cast workaround for negative value
data = fexec{"data"}.getStr.hexToSeqByte,
code = code,
gas = fexec{"gas"}.getHexadecimalInt,
gasPrice = fexec{"gasPrice"}.getHexadecimalInt,
options = newMessageOptions(origin=fexec{"origin"}.getStr.parseAddress,
createAddress = toAddress))
var computation = newBaseComputation(vmState, header.blockNumber, message)
computation.executeOpcodes()
if not fixture{"post"}.isNil:
# Success checks
check(not computation.isError)
if computation.isError:
echo "Computation error: ", computation.error.info
let logEntries = computation.getLogEntries()
if not fixture{"logs"}.isNil:
discard
# TODO hashLogEntries let actualLogsHash = hashLogEntries(logEntries)
# let expectedLogsHash = fixture{"logs"}.getStr
# check(expectedLogsHash == actualLogsHash)
elif logEntries.len > 0:
checkpoint(&"Got log entries: {logEntries}")
fail()
let expectedOutput = fixture{"out"}.getStr
check(computation.outputHex == expectedOutput)
let gasMeter = computation.gasMeter
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt
let actualGasRemaining = gasMeter.gasRemaining
checkpoint(&"Remaining: {actualGasRemaining} - Expected: {expectedGasRemaining}")
check(actualGasRemaining == expectedGasRemaining or
computation.code.hasSStore() and
(actualGasRemaining > expectedGasRemaining and (actualGasRemaining - expectedGasRemaining) mod 15_000 == 0 or
expectedGasRemaining > actualGasRemaining and (expectedGasRemaining - actualGasRemaining) mod 15_000 == 0))
if not fixture{"post"}.isNil:
verifyStateDb(fixture{"post"}, computation.vmState.readOnlyStateDB)
else:
# Error checks
check(computation.isError)
# TODO postState = fixture{"pre"}