nimbus-eth1/tools/evmstate/helpers.nim

184 lines
5.8 KiB
Nim

# Nimbus
# Copyright (c) 2022-2024 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
std/[json, strutils],
eth/common/keys,
eth/common/headers,
eth/common/transactions,
eth/trie/trie_defs,
stint,
stew/byteutils,
../../nimbus/transaction,
../../nimbus/db/ledger,
../../nimbus/common/chain_config
template fromJson(T: type Address, n: JsonNode): Address =
Address.fromHex(n.getStr)
proc fromJson(T: type UInt256, n: JsonNode): UInt256 =
# stTransactionTest/ValueOverflow.json
# prevent parsing exception and subtitute it with max uint256
let hex = n.getStr
if ':' in hex:
high(UInt256)
else:
UInt256.fromHex(hex)
template fromJson*(T: type Bytes32, n: JsonNode): Bytes32 =
Bytes32(hexToByteArray(n.getStr, 32))
template fromJson*(T: type Hash32, n: JsonNode): Hash32 =
Hash32(hexToByteArray(n.getStr, 32))
proc fromJson(T: type seq[byte], n: JsonNode): T =
let hex = n.getStr
if hex.len == 0:
@[]
else:
hexToSeqByte(hex)
template fromJson(T: type uint64, n: JsonNode): uint64 =
fromHex[AccountNonce](n.getStr)
template fromJson(T: type EthTime, n: JsonNode): EthTime =
EthTime(fromHex[uint64](n.getStr))
proc fromJson(T: type PrivateKey, n: JsonNode): PrivateKey =
var secretKey = n.getStr
removePrefix(secretKey, "0x")
PrivateKey.fromHex(secretKey).tryGet()
proc fromJson(T: type AccessList, n: JsonNode): AccessList =
if n.kind == JNull:
return
for x in n:
var ap = AccessPair(
address: Address.fromJson(x["address"])
)
let sks = x["storageKeys"]
for sk in sks:
ap.storageKeys.add Bytes32.fromHex(sk.getStr)
result.add ap
proc fromJson(T: type seq[Hash32], list: JsonNode): T =
for x in list:
result.add Hash32.fromHex(x.getStr)
template required(T: type, nField: string): auto =
fromJson(T, n[nField])
template required(T: type, nField: string, index: int): auto =
fromJson(T, n[nField][index])
template omitZero(T: type, nField: string): auto =
if n.hasKey(nField):
fromJson(T, n[nField])
else:
default(T)
template omitZero(T: type, nField: string, index: int): auto =
if n.hasKey(nField):
fromJson(T, n[nField][index])
else:
default(T)
template optional(T: type, nField: string): auto =
if n.hasKey(nField):
Opt.some(T.fromJson(n[nField]))
else:
Opt.none(T)
proc txType(n: JsonNode): TxType =
if "blobVersionedHashes" in n:
return TxEip4844
if "gasPrice" notin n:
return TxEip1559
if "accessLists" in n:
return TxEip2930
TxLegacy
proc parseHeader*(n: JsonNode): Header =
Header(
coinbase : required(Address, "currentCoinbase"),
difficulty : required(DifficultyInt, "currentDifficulty"),
number : required(BlockNumber, "currentNumber"),
gasLimit : required(GasInt, "currentGasLimit"),
timestamp : required(EthTime, "currentTimestamp"),
stateRoot : emptyRlpHash,
mixHash : omitZero(Bytes32, "currentRandom"),
baseFeePerGas : optional(UInt256, "currentBaseFee"),
withdrawalsRoot: optional(Hash32, "currentWithdrawalsRoot"),
excessBlobGas : optional(uint64, "currentExcessBlobGas"),
parentBeaconBlockRoot: optional(Hash32, "currentBeaconRoot"),
)
proc parseParentHeader*(n: JsonNode): Header =
Header(
stateRoot: emptyRlpHash,
excessBlobGas: optional(uint64, "parentExcessBlobGas"),
blobGasUsed: optional(uint64, "parentBlobGasUsed"),
)
proc parseTx*(n: JsonNode, dataIndex, gasIndex, valueIndex: int): Transaction =
var tx = Transaction(
txType : txType(n),
nonce : required(AccountNonce, "nonce"),
gasLimit: required(GasInt, "gasLimit", gasIndex),
value : required(UInt256, "value", valueIndex),
payload : required(seq[byte], "data", dataIndex),
chainId : ChainId(1),
gasPrice: omitZero(GasInt, "gasPrice"),
maxFeePerGas : omitZero(GasInt, "maxFeePerGas"),
accessList : omitZero(AccessList, "accessLists", dataIndex),
maxPriorityFeePerGas: omitZero(GasInt, "maxPriorityFeePerGas"),
maxFeePerBlobGas : omitZero(UInt256, "maxFeePerBlobGas"),
versionedHashes : omitZero(seq[Hash32], "blobVersionedHashes")
)
let rawTo = n["to"].getStr
if rawTo != "":
tx.to = Opt.some(Address.fromHex(rawTo))
let secretKey = required(PrivateKey, "secretKey")
signTransaction(tx, secretKey, false)
proc parseTx*(txData, index: JsonNode): Transaction =
let
dataIndex = index["data"].getInt
gasIndex = index["gas"].getInt
valIndex = index["value"].getInt
parseTx(txData, dataIndex, gasIndex, valIndex)
proc setupStateDB*(wantedState: JsonNode, stateDB: LedgerRef) =
for ac, accountData in wantedState:
let account = Address.fromHex(ac)
for slot, value in accountData{"storage"}:
stateDB.setStorage(account, fromHex(UInt256, slot), fromHex(UInt256, value.getStr))
stateDB.setNonce(account, fromJson(AccountNonce, accountData["nonce"]))
stateDB.setCode(account, fromJson(seq[byte], accountData["code"]))
stateDB.setBalance(account, fromJson(UInt256, accountData["balance"]))
iterator postState*(node: JsonNode): (Address, GenesisAccount) =
for ac, accountData in node:
let account = Address.fromHex(ac)
var ga = GenesisAccount(
nonce : fromJson(AccountNonce, accountData["nonce"]),
code : fromJson(seq[byte], accountData["code"]),
balance: fromJson(UInt256, accountData["balance"]),
)
for slot, value in accountData{"storage"}:
ga.storage[fromHex(UInt256, slot)] = fromHex(UInt256, value.getStr)
yield (account, ga)