184 lines
5.8 KiB
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)
|