t8n parser: migrate from std/json to json-serialization (#2764)
This commit is contained in:
parent
c9f97e6cd6
commit
993cbe64db
|
@ -8,10 +8,14 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
std/[json, strutils, tables],
|
||||
std/[strutils, tables],
|
||||
stew/byteutils,
|
||||
stint,
|
||||
json_serialization,
|
||||
json_serialization/stew/results,
|
||||
eth/common/eth_types_rlp,
|
||||
eth/common/keys,
|
||||
eth/common/blocks,
|
||||
|
@ -23,7 +27,26 @@ import
|
|||
export
|
||||
helpers
|
||||
|
||||
proc parseHexOrInt[T](x: string): T =
|
||||
createJsonFlavor T8Conv,
|
||||
automaticObjectSerialization = false,
|
||||
requireAllFields = false,
|
||||
omitOptionalFields = true, # Skip optional fields==none in Writer
|
||||
allowUnknownFields = true,
|
||||
skipNullFields = true # Skip optional fields==null in Reader
|
||||
|
||||
AccessPair.useDefaultSerializationIn T8Conv
|
||||
Withdrawal.useDefaultSerializationIn T8Conv
|
||||
Ommer.useDefaultSerializationIn T8Conv
|
||||
Authorization.useDefaultSerializationIn T8Conv
|
||||
TxObject.useDefaultSerializationIn T8Conv
|
||||
|
||||
template wrapValueError(body: untyped) =
|
||||
try:
|
||||
body
|
||||
except ValueError as exc:
|
||||
r.raiseUnexpectedValue(exc.msg)
|
||||
|
||||
proc parseHexOrInt[T](x: string): T {.raises: [ValueError].} =
|
||||
when T is UInt256:
|
||||
if x.startsWith("0x"):
|
||||
UInt256.fromHex(x)
|
||||
|
@ -35,249 +58,221 @@ proc parseHexOrInt[T](x: string): T =
|
|||
else:
|
||||
parseInt(x).T
|
||||
|
||||
proc fromJson(T: type Address, n: JsonNode, field: string): Address =
|
||||
try:
|
||||
Address.fromHex(n[field].getStr())
|
||||
except ValueError:
|
||||
raise newError(ErrorJson, "malformed Eth address " & n[field].getStr)
|
||||
proc parsePaddedHex[T](r: var JsonReader[T8Conv], val: var T)
|
||||
{.raises: [IOError, ValueError, JsonReaderError].} =
|
||||
var data = r.parseString()
|
||||
data.removePrefix("0x")
|
||||
const
|
||||
valLen = sizeof(T)
|
||||
hexLen = valLen*2
|
||||
if data.len < hexLen:
|
||||
data = repeat('0', hexLen - data.len) & data
|
||||
if data.len > hexLen:
|
||||
r.raiseUnexpectedValue("hex string is longer than expected: " & $hexLen & " get: " & $data.len)
|
||||
val = T(hexToByteArray(data, valLen))
|
||||
|
||||
template fromJson(T: type seq[byte], n: JsonNode, field: string): seq[byte] =
|
||||
hexToSeqByte(n[field].getStr())
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var Address)
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
wrapValueError:
|
||||
r.parsePaddedHex(val)
|
||||
|
||||
proc fromJson(T: type uint64, n: JsonNode, field: string): uint64 =
|
||||
if n[field].kind == JInt:
|
||||
n[field].getInt().uint64
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var Bytes32)
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
wrapValueError:
|
||||
r.parsePaddedHex(val)
|
||||
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var Hash32)
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
wrapValueError:
|
||||
r.parsePaddedHex(val)
|
||||
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var UInt256)
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
wrapValueError:
|
||||
val = parseHexOrInt[UInt256](r.parseString())
|
||||
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var uint64)
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
let tok = r.tokKind
|
||||
if tok == JsonValueKind.Number:
|
||||
val = r.parseInt(uint64)
|
||||
else:
|
||||
parseHexOrInt[uint64](n[field].getStr())
|
||||
wrapValueError:
|
||||
val = parseHexOrInt[uint64](r.parseString())
|
||||
|
||||
template fromJson(T: type UInt256, n: JsonNode, field: string): UInt256 =
|
||||
parseHexOrInt[UInt256](n[field].getStr())
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var ChainId)
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
wrapValueError:
|
||||
val = parseHexOrInt[uint64](r.parseString()).ChainId
|
||||
|
||||
template fromJson(T: type ChainId, n: JsonNode, field: string): ChainId =
|
||||
parseHexOrInt[uint64](n[field].getStr()).ChainId
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var EthTime)
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
wrapValueError:
|
||||
val = parseHexOrInt[uint64](r.parseString()).EthTime
|
||||
|
||||
proc fromJson(T: type Bytes32, n: JsonNode): Bytes32 =
|
||||
var num = n.getStr()
|
||||
num.removePrefix("0x")
|
||||
if num.len < 64:
|
||||
num = repeat('0', 64 - num.len) & num
|
||||
Bytes32(hexToByteArray(num, 32))
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var seq[byte])
|
||||
{.raises: [IOError, JsonReaderError].} =
|
||||
wrapValueError:
|
||||
val = hexToSeqByte(r.parseString())
|
||||
|
||||
proc fromJson(T: type Bytes32, n: JsonNode, field: string): Bytes32 =
|
||||
fromJson(T, n[field])
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var GenesisStorage)
|
||||
{.raises: [IOError, SerializationError].} =
|
||||
r.parseObjectCustomKey:
|
||||
let slot = r.readValue(UInt256)
|
||||
do:
|
||||
val[slot] = r.readValue(UInt256)
|
||||
|
||||
proc fromJson(T: type Hash32, n: JsonNode): Hash32 =
|
||||
var num = n.getStr()
|
||||
num.removePrefix("0x")
|
||||
if num.len < 64:
|
||||
num = repeat('0', 64 - num.len) & num
|
||||
Hash32(hexToByteArray(num, 32))
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var GenesisAccount)
|
||||
{.raises: [IOError, SerializationError].} =
|
||||
var balanceParsed = false
|
||||
r.parseObject(key):
|
||||
case key
|
||||
of "code" : r.readValue(val.code)
|
||||
of "nonce" : r.readValue(val.nonce)
|
||||
of "balance":
|
||||
r.readValue(val.balance)
|
||||
balanceParsed = true
|
||||
of "storage": r.readValue(val.storage)
|
||||
else: discard r.readValue(JsonString)
|
||||
if not balanceParsed:
|
||||
r.raiseUnexpectedValue("GenesisAccount: balance required")
|
||||
|
||||
proc fromJson(T: type Hash32, n: JsonNode, field: string): Hash32 =
|
||||
fromJson(T, n[field])
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var GenesisAlloc)
|
||||
{.raises: [IOError, SerializationError].} =
|
||||
r.parseObjectCustomKey:
|
||||
let address = r.readValue(Address)
|
||||
do:
|
||||
val[address] = r.readValue(GenesisAccount)
|
||||
|
||||
template fromJson(T: type EthTime, n: JsonNode, field: string): EthTime =
|
||||
EthTime(parseHexOrInt[uint64](n[field].getStr()))
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var Table[uint64, Hash32])
|
||||
{.raises: [IOError, SerializationError].} =
|
||||
wrapValueError:
|
||||
r.parseObjectCustomKey:
|
||||
let number = parseHexOrInt[uint64](r.parseString())
|
||||
do:
|
||||
val[number] = r.readValue(Hash32)
|
||||
|
||||
proc fromJson(T: type AccessList, n: JsonNode, field: string): AccessList =
|
||||
let z = n[field]
|
||||
if z.kind == JNull:
|
||||
return
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var EnvStruct)
|
||||
{.raises: [IOError, SerializationError].} =
|
||||
var
|
||||
currentCoinbaseParsed = false
|
||||
currentGasLimitParsed = false
|
||||
currentNumberParsed = false
|
||||
currentTimestampParsed = false
|
||||
|
||||
for x in z:
|
||||
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
|
||||
r.parseObject(key):
|
||||
case key
|
||||
of "currentCoinbase":
|
||||
r.readValue(val.currentCoinbase)
|
||||
currentCoinbaseParsed = true
|
||||
of "currentGasLimit":
|
||||
r.readValue(val.currentGasLimit)
|
||||
currentGasLimitParsed = true
|
||||
of "currentNumber":
|
||||
r.readValue(val.currentNumber)
|
||||
currentNumberParsed = true
|
||||
of "currentTimestamp":
|
||||
r.readValue(val.currentTimestamp)
|
||||
currentTimestampParsed = true
|
||||
of "currentDifficulty": r.readValue(val.currentDifficulty)
|
||||
of "currentRandom": r.readValue(val.currentRandom)
|
||||
of "parentDifficulty": r.readValue(val.parentDifficulty)
|
||||
of "parentTimestamp": r.readValue(val.parentTimestamp)
|
||||
of "currentBaseFee": r.readValue(val.currentBaseFee)
|
||||
of "parentUncleHash": r.readValue(val.parentUncleHash)
|
||||
of "parentBaseFee": r.readValue(val.parentBaseFee)
|
||||
of "parentGasUsed": r.readValue(val.parentGasUsed)
|
||||
of "parentGasLimit": r.readValue(val.parentGasLimit)
|
||||
of "currentBlobGasUsed": r.readValue(val.currentBlobGasUsed)
|
||||
of "currentExcessBlobGas": r.readValue(val.currentExcessBlobGas)
|
||||
of "parentBlobGasUsed": r.readValue(val.parentBlobGasUsed)
|
||||
of "parentExcessBlobGas": r.readValue(val.parentExcessBlobGas)
|
||||
of "parentBeaconBlockRoot": r.readValue(val.parentBeaconBlockRoot)
|
||||
of "blockHashes": r.readValue(val.blockHashes)
|
||||
of "ommers": r.readValue(val.ommers)
|
||||
of "withdrawals": r.readValue(val.withdrawals)
|
||||
else: discard r.readValue(JsonString)
|
||||
|
||||
proc fromJson(T: type Ommer, n: JsonNode): Ommer =
|
||||
Ommer(
|
||||
delta: fromJson(uint64, n, "delta"),
|
||||
address: fromJson(Address, n, "address")
|
||||
)
|
||||
if not currentCoinbaseParsed:
|
||||
r.raiseUnexpectedValue("env: currentCoinbase required")
|
||||
if not currentGasLimitParsed:
|
||||
r.raiseUnexpectedValue("env: currentGasLimit required")
|
||||
if not currentNumberParsed:
|
||||
r.raiseUnexpectedValue("env: currentNumber required")
|
||||
if not currentTimestampParsed:
|
||||
r.raiseUnexpectedValue("env: currentTimestamp required")
|
||||
|
||||
proc fromJson(T: type Withdrawal, n: JsonNode): Withdrawal =
|
||||
Withdrawal(
|
||||
index: fromJson(uint64, n, "index"),
|
||||
validatorIndex: fromJson(uint64, n, "validatorIndex"),
|
||||
address: fromJson(Address, n, "address"),
|
||||
amount: fromJson(uint64, n, "amount")
|
||||
)
|
||||
proc readValue*(r: var JsonReader[T8Conv], val: var TransContext)
|
||||
{.raises: [IOError, SerializationError].} =
|
||||
r.parseObject(key):
|
||||
case key
|
||||
of "alloc" : r.readValue(val.alloc)
|
||||
of "env" : r.readValue(val.env)
|
||||
of "txs" : r.readValue(val.txsJson)
|
||||
of "txsRlp" : r.readValue(val.txsRlp)
|
||||
|
||||
proc fromJson(T: type Authorization, n: JsonNode): Authorization =
|
||||
Authorization(
|
||||
chainId: fromJson(ChainId, n, "chainId"),
|
||||
address: fromJson(Address, n, "address"),
|
||||
nonce: fromJson(uint64, n, "nonce"),
|
||||
v: fromJson(uint64, n, "v"),
|
||||
r: fromJson(UInt256, n, "r"),
|
||||
s: fromJson(UInt256, n, "s"),
|
||||
)
|
||||
proc parseTxJson(txo: TxObject, chainId: ChainID): Result[Transaction, string] =
|
||||
template required(field) =
|
||||
const fName = astToStr(oField)
|
||||
if txo.field.isNone:
|
||||
return err("missing required field '" & fName & "' in transaction")
|
||||
tx.field = txo.field.get
|
||||
|
||||
proc fromJson(T: type seq[Authorization], n: JsonNode, field: string): T =
|
||||
let list = n[field]
|
||||
for x in list:
|
||||
result.add Authorization.fromJson(x)
|
||||
template required(field, alias) =
|
||||
const fName = astToStr(oField)
|
||||
if txo.field.isNone:
|
||||
return err("missing required field '" & fName & "' in transaction")
|
||||
tx.alias = txo.field.get
|
||||
|
||||
proc fromJson(T: type seq[VersionedHash], n: JsonNode, field: string): T =
|
||||
let list = n[field]
|
||||
for x in list:
|
||||
result.add VersionedHash.fromHex(x.getStr)
|
||||
template optional(field) =
|
||||
if txo.field.isSome:
|
||||
tx.field = txo.field.get
|
||||
|
||||
template `gas=`(tx: var Transaction, x: GasInt) =
|
||||
tx.gasLimit = x
|
||||
|
||||
template `input=`(tx: var Transaction, x: seq[byte]) =
|
||||
tx.payload = x
|
||||
|
||||
template `v=`(tx: var Transaction, x: uint64) =
|
||||
tx.V = x
|
||||
|
||||
template `r=`(tx: var Transaction, x: UInt256) =
|
||||
tx.R = x
|
||||
|
||||
template `s=`(tx: var Transaction, x: UInt256) =
|
||||
tx.S = x
|
||||
|
||||
template `blobVersionedHashes=`(tx: var Transaction, x: seq[VersionedHash]) =
|
||||
tx.versionedHashes = x
|
||||
|
||||
template required(o: untyped, T: type, oField: untyped) =
|
||||
const fName = astToStr(oField)
|
||||
if not n.hasKey(fName):
|
||||
raise newError(ErrorJson, "missing required field '" & fName & "' in transaction")
|
||||
o.oField = T.fromJson(n, fName)
|
||||
|
||||
template omitZero(o: untyped, T: type, oField: untyped) =
|
||||
const fName = astToStr(oField)
|
||||
if n.hasKey(fName):
|
||||
o.oField = T.fromJson(n, fName)
|
||||
|
||||
template optional(o: untyped, T: type, oField: untyped) =
|
||||
const fName = astToStr(oField)
|
||||
if n.hasKey(fName) and n[fName].kind != JNull:
|
||||
o.oField = Opt.some(T.fromJson(n, fName))
|
||||
|
||||
proc parseAlloc*(ctx: var TransContext, n: JsonNode) =
|
||||
for accAddr, acc in n:
|
||||
let address = Address.fromHex(accAddr)
|
||||
var ga = GenesisAccount()
|
||||
if acc.hasKey("code"):
|
||||
ga.code = seq[byte].fromJson(acc, "code")
|
||||
if acc.hasKey("nonce"):
|
||||
ga.nonce = AccountNonce.fromJson(acc, "nonce")
|
||||
if acc.hasKey("balance"):
|
||||
ga.balance = UInt256.fromJson(acc, "balance")
|
||||
else:
|
||||
raise newError(ErrorJson, "GenesisAlloc: balance required")
|
||||
if acc.hasKey("storage"):
|
||||
let storage = acc["storage"]
|
||||
for k, v in storage:
|
||||
ga.storage[UInt256.fromHex(k)] = UInt256.fromHex(v.getStr())
|
||||
ctx.alloc[address] = ga
|
||||
|
||||
proc parseEnv*(ctx: var TransContext, n: JsonNode) =
|
||||
required(ctx.env, Address, currentCoinbase)
|
||||
required(ctx.env, GasInt, currentGasLimit)
|
||||
required(ctx.env, BlockNumber, currentNumber)
|
||||
required(ctx.env, EthTime, currentTimestamp)
|
||||
optional(ctx.env, DifficultyInt, currentDifficulty)
|
||||
optional(ctx.env, Bytes32, currentRandom)
|
||||
optional(ctx.env, DifficultyInt, parentDifficulty)
|
||||
omitZero(ctx.env, EthTime, parentTimestamp)
|
||||
optional(ctx.env, UInt256, currentBaseFee)
|
||||
omitZero(ctx.env, Hash32, parentUncleHash)
|
||||
optional(ctx.env, UInt256, parentBaseFee)
|
||||
optional(ctx.env, GasInt, parentGasUsed)
|
||||
optional(ctx.env, GasInt, parentGasLimit)
|
||||
optional(ctx.env, uint64, currentBlobGasUsed)
|
||||
optional(ctx.env, uint64, currentExcessBlobGas)
|
||||
optional(ctx.env, uint64, parentBlobGasUsed)
|
||||
optional(ctx.env, uint64, parentExcessBlobGas)
|
||||
optional(ctx.env, Hash32, parentBeaconBlockRoot)
|
||||
|
||||
if n.hasKey("blockHashes"):
|
||||
let w = n["blockHashes"]
|
||||
for k, v in w:
|
||||
ctx.env.blockHashes[parseHexOrInt[uint64](k)] = Hash32.fromHex(v.getStr())
|
||||
|
||||
if n.hasKey("ommers"):
|
||||
let w = n["ommers"]
|
||||
for v in w:
|
||||
ctx.env.ommers.add Ommer.fromJson(v)
|
||||
|
||||
if n.hasKey("withdrawals"):
|
||||
let w = n["withdrawals"]
|
||||
var withdrawals: seq[Withdrawal]
|
||||
for v in w:
|
||||
withdrawals.add Withdrawal.fromJson(v)
|
||||
ctx.env.withdrawals = Opt.some(withdrawals)
|
||||
|
||||
proc parseTx(n: JsonNode, chainId: ChainID): Transaction =
|
||||
var tx: Transaction
|
||||
if not n.hasKey("type"):
|
||||
tx.txType = TxLegacy
|
||||
else:
|
||||
tx.txType = uint64.fromJson(n, "type").TxType
|
||||
|
||||
required(tx, AccountNonce, nonce)
|
||||
required(tx, GasInt, gas)
|
||||
required(tx, UInt256, value)
|
||||
required(tx, seq[byte], input)
|
||||
|
||||
if n.hasKey("to"):
|
||||
tx.to = Opt.some(Address.fromJson(n, "to"))
|
||||
tx.txType = txo.`type`.get(0'u64).TxType
|
||||
required(nonce)
|
||||
required(gas, gasLimit)
|
||||
required(value)
|
||||
required(input, payload)
|
||||
tx.to = txo.to
|
||||
tx.chainId = chainId
|
||||
|
||||
case tx.txType
|
||||
of TxLegacy:
|
||||
required(tx, GasInt, gasPrice)
|
||||
required(gasPrice)
|
||||
of TxEip2930:
|
||||
required(tx, GasInt, gasPrice)
|
||||
required(tx, ChainId, chainId)
|
||||
omitZero(tx, AccessList, accessList)
|
||||
required(gasPrice)
|
||||
required(chainId)
|
||||
optional(accessList)
|
||||
of TxEip1559:
|
||||
required(tx, ChainId, chainId)
|
||||
required(tx, GasInt, maxPriorityFeePerGas)
|
||||
required(tx, GasInt, maxFeePerGas)
|
||||
omitZero(tx, AccessList, accessList)
|
||||
required(chainId)
|
||||
required(maxPriorityFeePerGas)
|
||||
required(maxFeePerGas)
|
||||
optional(accessList)
|
||||
of TxEip4844:
|
||||
required(tx, ChainId, chainId)
|
||||
required(tx, GasInt, maxPriorityFeePerGas)
|
||||
required(tx, GasInt, maxFeePerGas)
|
||||
omitZero(tx, AccessList, accessList)
|
||||
required(tx, UInt256, maxFeePerBlobGas)
|
||||
required(tx, seq[VersionedHash], blobVersionedHashes)
|
||||
required(chainId)
|
||||
required(maxPriorityFeePerGas)
|
||||
required(maxFeePerGas)
|
||||
optional(accessList)
|
||||
required(maxFeePerBlobGas)
|
||||
required(blobVersionedHashes, versionedHashes)
|
||||
of TxEip7702:
|
||||
required(tx, ChainId, chainId)
|
||||
required(tx, GasInt, maxPriorityFeePerGas)
|
||||
required(tx, GasInt, maxFeePerGas)
|
||||
omitZero(tx, AccessList, accessList)
|
||||
required(tx, seq[Authorization], authorizationList)
|
||||
required(chainId)
|
||||
required(maxPriorityFeePerGas)
|
||||
required(maxFeePerGas)
|
||||
optional(accessList)
|
||||
required(authorizationList)
|
||||
|
||||
var eip155 = true
|
||||
if n.hasKey("protected"):
|
||||
eip155 = n["protected"].bval
|
||||
|
||||
if n.hasKey("secretKey"):
|
||||
let data = seq[byte].fromJson(n, "secretKey")
|
||||
let secretKey = PrivateKey.fromRaw(data).tryGet
|
||||
signTransaction(tx, secretKey, eip155)
|
||||
let eip155 = txo.protected.get(true)
|
||||
if txo.secretKey.isSome:
|
||||
let secretKey = PrivateKey.fromRaw(txo.secretKey.get).valueOr:
|
||||
return err($error)
|
||||
ok(signTransaction(tx, secretKey, eip155))
|
||||
else:
|
||||
required(tx, uint64, v)
|
||||
required(tx, UInt256, r)
|
||||
required(tx, UInt256, s)
|
||||
tx
|
||||
|
||||
proc parseTxJson(ctx: TransContext, i: int, chainId: ChainId): Result[Transaction, string] =
|
||||
try:
|
||||
let n = ctx.txs.n[i]
|
||||
return ok(parseTx(n, chainId))
|
||||
except Exception as x:
|
||||
return err(x.msg)
|
||||
required(v, V)
|
||||
required(r, R)
|
||||
required(s, S)
|
||||
ok(tx)
|
||||
|
||||
proc readNestedTx(rlp: var Rlp): Result[Transaction, string] =
|
||||
try:
|
||||
|
@ -289,54 +284,62 @@ proc readNestedTx(rlp: var Rlp): Result[Transaction, string] =
|
|||
except RlpError as exc:
|
||||
err(exc.msg)
|
||||
|
||||
proc parseTxs*(ctx: TransContext, chainId: ChainId): seq[Result[Transaction, string]] =
|
||||
if ctx.txs.txsType == TxsJson:
|
||||
let len = ctx.txs.n.len
|
||||
result = newSeqOfCap[Result[Transaction, string]](len)
|
||||
for i in 0 ..< len:
|
||||
result.add ctx.parseTxJson(i, chainId)
|
||||
return
|
||||
proc parseTxs*(ctx: var TransContext, chainId: ChainId)
|
||||
{.raises: [T8NError, RlpError].} =
|
||||
var numTxs = ctx.txsJson.len
|
||||
var rlp: Rlp
|
||||
|
||||
if ctx.txs.txsType == TxsRlp:
|
||||
result = newSeqOfCap[Result[Transaction, string]](ctx.txs.r.listLen)
|
||||
var rlp = ctx.txs.r
|
||||
if ctx.txsRlp.len > 0:
|
||||
rlp = rlpFromBytes(ctx.txsRlp)
|
||||
if rlp.isList.not:
|
||||
raise newError(ErrorRlp, "RLP Transaction list should be a list")
|
||||
numTxs += rlp.listLen
|
||||
|
||||
ctx.txList = newSeqOfCap[Result[Transaction, string]](numTxs)
|
||||
for tx in ctx.txsJson:
|
||||
ctx.txList.add parseTxJson(tx, chainId)
|
||||
|
||||
if ctx.txsRlp.len > 0:
|
||||
for item in rlp:
|
||||
result.add rlp.readNestedTx()
|
||||
ctx.txList.add rlp.readNestedTx()
|
||||
|
||||
return
|
||||
|
||||
proc txList*(ctx: TransContext, chainId: ChainId): seq[Transaction] =
|
||||
let list = ctx.parseTxs(chainId)
|
||||
for txRes in list:
|
||||
proc filterGoodTransactions*(ctx: TransContext): seq[Transaction] =
|
||||
for txRes in ctx.txList:
|
||||
if txRes.isOk:
|
||||
result.add txRes.get
|
||||
|
||||
proc parseTxs*(ctx: var TransContext, txs: JsonNode) =
|
||||
if txs.kind == JNull:
|
||||
return
|
||||
if txs.kind != JArray:
|
||||
raise newError(ErrorJson,
|
||||
"Transaction list should be a JSON array, got=" & $txs.kind)
|
||||
ctx.txs = TxsList(
|
||||
txsType: TxsJson,
|
||||
n: txs)
|
||||
template wrapException(procName: string, body) =
|
||||
try:
|
||||
body
|
||||
except SerializationError as exc:
|
||||
debugEcho "procName: ", procName
|
||||
raise newError(ErrorJson, exc.msg)
|
||||
except IOError as exc:
|
||||
debugEcho "procName: ", procName
|
||||
raise newError(ErrorJson, exc.msg)
|
||||
|
||||
proc parseTxsRlp*(ctx: var TransContext, hexData: string) =
|
||||
let bytes = hexToSeqByte(hexData)
|
||||
ctx.txs = TxsList(
|
||||
txsType: TxsRlp,
|
||||
r: rlpFromBytes(bytes)
|
||||
)
|
||||
if ctx.txs.r.isList.not:
|
||||
raise newError(ErrorRlp, "RLP Transaction list should be a list")
|
||||
proc parseTxsJson*(ctx: var TransContext, jsonFile: string) {.raises: [T8NError].} =
|
||||
wrapException("parseTxsJson"):
|
||||
ctx.txsJson = T8Conv.loadFile(jsonFile, seq[TxObject])
|
||||
|
||||
proc parseInputFromStdin*(ctx: var TransContext) =
|
||||
let data = stdin.readAll()
|
||||
let n = json.parseJson(data)
|
||||
if n.hasKey("alloc"): ctx.parseAlloc(n["alloc"])
|
||||
if n.hasKey("env"): ctx.parseEnv(n["env"])
|
||||
if n.hasKey("txs"): ctx.parseTxs(n["txs"])
|
||||
if n.hasKey("txsRlp"): ctx.parseTxsRlp(n["txsRlp"].getStr())
|
||||
proc parseAlloc*(ctx: var TransContext, allocFile: string) {.raises: [T8NError].} =
|
||||
wrapException("parseAlloc"):
|
||||
ctx.alloc = T8Conv.loadFile(allocFile, GenesisAlloc)
|
||||
|
||||
proc parseEnv*(ctx: var TransContext, envFile: string) {.raises: [T8NError].} =
|
||||
wrapException("parseEnv"):
|
||||
ctx.env = T8Conv.loadFile(envFile, EnvStruct)
|
||||
|
||||
proc parseTxsRlp*(ctx: var TransContext, hexData: string) {.raises: [ValueError].} =
|
||||
ctx.txsRlp = hexToSeqByte(hexData)
|
||||
|
||||
proc parseInputFromStdin*(ctx: var TransContext) {.raises: [T8NError].} =
|
||||
wrapException("parseInputFromStdin"):
|
||||
let jsonData = stdin.readAll()
|
||||
ctx = T8Conv.decode(jsonData, TransContext)
|
||||
|
||||
import
|
||||
std/json
|
||||
|
||||
template stripLeadingZeros(value: string): string =
|
||||
var cidx = 0
|
||||
|
@ -427,29 +430,6 @@ proc `@@`(x: RejectedTx): JsonNode =
|
|||
"error": %(x.error)
|
||||
}
|
||||
|
||||
proc `@@`(x: DepositRequest): JsonNode =
|
||||
%{
|
||||
"pubkey": @@(x.pubkey),
|
||||
"withdrawalCredentials": @@(x.withdrawalCredentials),
|
||||
"amount": @@(x.amount),
|
||||
"signature": @@(x.signature),
|
||||
"index": @@(x.index),
|
||||
}
|
||||
|
||||
proc `@@`(x: WithdrawalRequest): JsonNode =
|
||||
%{
|
||||
"sourceAddress": @@(x.sourceAddress),
|
||||
"validatorPubkey": @@(x.validatorPubkey),
|
||||
"amount": @@(x.amount),
|
||||
}
|
||||
|
||||
proc `@@`(x: ConsolidationRequest): JsonNode =
|
||||
%{
|
||||
"sourceAddress": @@(x.sourceAddress),
|
||||
"sourcePubkey": @@(x.sourcePubkey),
|
||||
"targetPubkey": @@(x.targetPubkey),
|
||||
}
|
||||
|
||||
proc `@@`[T](x: seq[T]): JsonNode =
|
||||
result = newJArray()
|
||||
for c in x:
|
||||
|
|
|
@ -64,7 +64,7 @@ proc dispatch(dis: var Dispatch, baseDir, fName, name: string, obj: JsonNode) =
|
|||
fName
|
||||
writeFile(path, obj.pretty)
|
||||
|
||||
proc dispatchOutput(ctx: var TransContext, conf: T8NConf, res: ExecOutput) =
|
||||
proc dispatchOutput(ctx: TransContext, conf: T8NConf, res: ExecOutput) =
|
||||
var dis = Dispatch.init()
|
||||
createDir(conf.outputBaseDir)
|
||||
|
||||
|
@ -72,7 +72,7 @@ proc dispatchOutput(ctx: var TransContext, conf: T8NConf, res: ExecOutput) =
|
|||
dis.dispatch(conf.outputBaseDir, conf.outputResult, "result", @@(res.result))
|
||||
|
||||
let chainId = conf.stateChainId.ChainId
|
||||
let txList = ctx.txList(chainId)
|
||||
let txList = ctx.filterGoodTransactions()
|
||||
|
||||
let body = @@(rlp.encode(txList))
|
||||
dis.dispatch(conf.outputBaseDir, conf.outputBody, "body", body)
|
||||
|
@ -216,16 +216,14 @@ proc closeTrace(vmState: BaseVMState, closeStream: bool) =
|
|||
if tracer.isNil.not and closeStream:
|
||||
tracer.close()
|
||||
|
||||
proc exec(ctx: var TransContext,
|
||||
proc exec(ctx: TransContext,
|
||||
vmState: BaseVMState,
|
||||
stateReward: Option[UInt256],
|
||||
header: Header,
|
||||
conf: T8NConf): ExecOutput =
|
||||
|
||||
let txList = ctx.parseTxs(vmState.com.chainId)
|
||||
|
||||
var
|
||||
receipts = newSeqOfCap[TxReceipt](txList.len)
|
||||
receipts = newSeqOfCap[TxReceipt](ctx.txList.len)
|
||||
rejected = newSeq[RejectedTx]()
|
||||
includedTx = newSeq[Transaction]()
|
||||
|
||||
|
@ -234,7 +232,7 @@ proc exec(ctx: var TransContext,
|
|||
vmState.mutateStateDB:
|
||||
db.applyDAOHardFork()
|
||||
|
||||
vmState.receipts = newSeqOfCap[Receipt](txList.len)
|
||||
vmState.receipts = newSeqOfCap[Receipt](ctx.txList.len)
|
||||
vmState.cumulativeGasUsed = 0
|
||||
|
||||
if ctx.env.parentBeaconBlockRoot.isSome:
|
||||
|
@ -253,7 +251,7 @@ proc exec(ctx: var TransContext,
|
|||
vmState.processParentBlockHash(prevHash).isOkOr:
|
||||
raise newError(ErrorConfig, error)
|
||||
|
||||
for txIndex, txRes in txList:
|
||||
for txIndex, txRes in ctx.txList:
|
||||
if txRes.isErr:
|
||||
rejected.add RejectedTx(
|
||||
index: txIndex,
|
||||
|
@ -442,20 +440,17 @@ proc transitionAction*(ctx: var TransContext, conf: T8NConf) =
|
|||
ctx.parseInputFromStdin()
|
||||
|
||||
if conf.inputAlloc != stdinSelector and conf.inputAlloc.len > 0:
|
||||
let n = json.parseFile(conf.inputAlloc)
|
||||
ctx.parseAlloc(n)
|
||||
ctx.parseAlloc(conf.inputAlloc)
|
||||
|
||||
if conf.inputEnv != stdinSelector and conf.inputEnv.len > 0:
|
||||
let n = json.parseFile(conf.inputEnv)
|
||||
ctx.parseEnv(n)
|
||||
ctx.parseEnv(conf.inputEnv)
|
||||
|
||||
if conf.inputTxs != stdinSelector and conf.inputTxs.len > 0:
|
||||
if conf.inputTxs.endsWith(".rlp"):
|
||||
let data = readFile(conf.inputTxs)
|
||||
ctx.parseTxsRlp(data.strip(chars={'"'}))
|
||||
else:
|
||||
let n = json.parseFile(conf.inputTxs)
|
||||
ctx.parseTxs(n)
|
||||
ctx.parseTxsJson(conf.inputTxs)
|
||||
|
||||
let uncleHash = if ctx.env.parentUncleHash == default(Hash32):
|
||||
EMPTY_UNCLE_HASH
|
||||
|
@ -546,6 +541,7 @@ proc transitionAction*(ctx: var TransContext, conf: T8NConf) =
|
|||
db.setupAlloc(ctx.alloc)
|
||||
db.persist(clearEmptyAccount = false)
|
||||
|
||||
ctx.parseTxs(com.chainId)
|
||||
let res = exec(ctx, vmState, conf.stateReward, header, conf)
|
||||
|
||||
if vmState.hashError.len > 0:
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
# according to those terms.
|
||||
|
||||
import
|
||||
std/[tables, json],
|
||||
std/[tables],
|
||||
eth/common/blocks,
|
||||
eth/common/receipts,
|
||||
eth/rlp,
|
||||
results,
|
||||
stint,
|
||||
../../nimbus/common/chain_config,
|
||||
|
@ -54,21 +53,35 @@ type
|
|||
parentExcessBlobGas*: Opt[uint64]
|
||||
parentBeaconBlockRoot*: Opt[Hash32]
|
||||
|
||||
TxsType* = enum
|
||||
TxsNone
|
||||
TxsRlp
|
||||
TxsJson
|
||||
TxObject* = object
|
||||
`type`*: Opt[uint64]
|
||||
nonce* : Opt[AccountNonce]
|
||||
gas* : Opt[GasInt]
|
||||
value* : Opt[UInt256]
|
||||
input* : Opt[seq[byte]]
|
||||
to* : Opt[Address]
|
||||
v* : Opt[uint64]
|
||||
r* : Opt[UInt256]
|
||||
s* : Opt[UInt256]
|
||||
gasPrice* : Opt[GasInt]
|
||||
chainId* : Opt[ChainId]
|
||||
accessList*: Opt[AccessList]
|
||||
protected* : Opt[bool]
|
||||
secretKey* : Opt[seq[byte]]
|
||||
maxPriorityFeePerGas*: Opt[GasInt]
|
||||
maxFeePerGas* : Opt[GasInt]
|
||||
maxFeePerBlobGas* : Opt[UInt256]
|
||||
blobVersionedHashes* : Opt[seq[Hash32]]
|
||||
authorizationList* : Opt[seq[Authorization]]
|
||||
|
||||
TxsList* = object
|
||||
case txsType*: TxsType
|
||||
of TxsRlp: r*: Rlp
|
||||
of TxsJson: n*: JsonNode
|
||||
else: discard
|
||||
TxList* = seq[Result[Transaction, string]]
|
||||
|
||||
TransContext* = object
|
||||
alloc*: GenesisAlloc
|
||||
txs*: TxsList
|
||||
env*: EnvStruct
|
||||
alloc* : GenesisAlloc
|
||||
txsRlp* : seq[byte]
|
||||
txsJson*: seq[TxObject]
|
||||
txList* : TxList
|
||||
env* : EnvStruct
|
||||
|
||||
RejectedTx* = object
|
||||
index*: int
|
||||
|
|
Loading…
Reference in New Issue