mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 05:14:14 +00:00
fix t8n tool tx and env parser
This commit is contained in:
parent
ed518c760f
commit
490b2f8023
@ -10,13 +10,14 @@
|
||||
|
||||
import
|
||||
std/[json, strutils, tables],
|
||||
stew/byteutils,
|
||||
stew/[byteutils, results],
|
||||
stint,
|
||||
eth/[common, rlp, keys],
|
||||
../../nimbus/transaction,
|
||||
../../nimbus/common/chain_config,
|
||||
../common/helpers,
|
||||
./types
|
||||
./types,
|
||||
./txpriv
|
||||
|
||||
export
|
||||
helpers
|
||||
@ -150,6 +151,9 @@ proc parseEnv*(ctx: var TransContext, n: JsonNode) =
|
||||
omitZero(ctx.env, EthTime, parentTimestamp)
|
||||
optional(ctx.env, UInt256, currentBaseFee)
|
||||
omitZero(ctx.env, Hash256, parentUncleHash)
|
||||
optional(ctx.env, UInt256, parentBaseFee)
|
||||
optional(ctx.env, GasInt, parentGasUsed)
|
||||
optional(ctx.env, GasInt, parentGasLimit)
|
||||
|
||||
if n.hasKey("blockHashes"):
|
||||
let w = n["blockHashes"]
|
||||
@ -203,24 +207,79 @@ proc parseTx(n: JsonNode, chainId: ChainID): Transaction =
|
||||
else:
|
||||
tx
|
||||
|
||||
proc parseTxs*(ctx: var TransContext, txs: JsonNode, chainId: ChainID) =
|
||||
proc parseTxLegacy(item: var Rlp): Result[Transaction, string] =
|
||||
try:
|
||||
var tx: Transaction
|
||||
item.readTxLegacy(tx)
|
||||
return ok(tx)
|
||||
except RlpError as x:
|
||||
return err(x.msg)
|
||||
|
||||
proc parseTxTyped(item: var Rlp): Result[Transaction, string] =
|
||||
try:
|
||||
var tx: Transaction
|
||||
var rr = rlpFromBytes(item.read(Blob))
|
||||
rr.readTxTyped(tx)
|
||||
return ok(tx)
|
||||
except RlpError as x:
|
||||
return err(x.msg)
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
if ctx.txs.txsType == TxsRlp:
|
||||
result = newSeqOfCap[Result[Transaction, string]](ctx.txs.r.listLen)
|
||||
var rlp = ctx.txs.r
|
||||
for item in rlp:
|
||||
if item.isList:
|
||||
result.add parseTxLegacy(item)
|
||||
else:
|
||||
result.add parseTxTyped(item)
|
||||
return
|
||||
|
||||
proc txList*(ctx: TransContext, chainId: ChainId): seq[Transaction] =
|
||||
let list = ctx.parseTxs(chainId)
|
||||
for txRes in list:
|
||||
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)
|
||||
for n in txs:
|
||||
ctx.txs.add parseTx(n, chainId)
|
||||
raise newError(ErrorJson,
|
||||
"Transaction list should be a JSON array, got=" & $txs.kind)
|
||||
ctx.txs = TxsList(
|
||||
txsType: TxsJson,
|
||||
n: txs)
|
||||
|
||||
proc parseTxsRlp*(ctx: var TransContext, hexData: string) =
|
||||
let data = hexToSeqByte(hexData)
|
||||
ctx.txs = rlp.decode(data, seq[Transaction])
|
||||
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 parseInputFromStdin*(ctx: var TransContext, chainId: ChainId) =
|
||||
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"], chainId)
|
||||
if n.hasKey("txs"): ctx.parseTxs(n["txs"])
|
||||
if n.hasKey("txsRlp"): ctx.parseTxsRlp(n["txsRlp"].getStr())
|
||||
|
||||
template stripLeadingZeros(value: string): string =
|
||||
@ -336,3 +395,5 @@ proc `@@`*(x: ExecutionResult): JsonNode =
|
||||
}
|
||||
if x.rejected.len > 0:
|
||||
result["rejected"] = @@(x.rejected)
|
||||
if x.currentBaseFee.isSome:
|
||||
result["currentBaseFee"] = @@(x.currentBaseFee)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import
|
||||
std/[json, strutils, times, tables, os, sets],
|
||||
eth/[rlp, trie],
|
||||
eth/[rlp, trie, eip1559],
|
||||
stint, chronicles, stew/results,
|
||||
"."/[config, types, helpers],
|
||||
../../nimbus/[vm_types, vm_state, transaction],
|
||||
@ -11,6 +11,7 @@ import
|
||||
../../nimbus/core/dao,
|
||||
../../nimbus/core/executor/[process_transaction, executor_helpers]
|
||||
|
||||
import stew/byteutils
|
||||
const
|
||||
wrapExceptionEnabled* {.booldefine.} = true
|
||||
stdinSelector = "stdin"
|
||||
@ -56,7 +57,10 @@ proc dispatchOutput(ctx: var TransContext, conf: T8NConf, res: ExecOutput) =
|
||||
dis.dispatch(conf.outputBaseDir, conf.outputAlloc, "alloc", @@(res.alloc))
|
||||
dis.dispatch(conf.outputBaseDir, conf.outputResult, "result", @@(res.result))
|
||||
|
||||
let body = @@(rlp.encode(ctx.txs))
|
||||
let chainId = conf.stateChainId.ChainId
|
||||
let txList = ctx.txList(chainId)
|
||||
|
||||
let body = @@(rlp.encode(txList))
|
||||
dis.dispatch(conf.outputBaseDir, conf.outputBody, "body", body)
|
||||
|
||||
if dis.stdout.len > 0:
|
||||
@ -133,8 +137,10 @@ proc exec(ctx: var TransContext,
|
||||
stateReward: Option[UInt256],
|
||||
header: BlockHeader): ExecOutput =
|
||||
|
||||
let txList = ctx.parseTxs(vmState.com.chainId)
|
||||
|
||||
var
|
||||
receipts = newSeqOfCap[TxReceipt](ctx.txs.len)
|
||||
receipts = newSeqOfCap[TxReceipt](txList.len)
|
||||
rejected = newSeq[RejectedTx]()
|
||||
includedTx = newSeq[Transaction]()
|
||||
|
||||
@ -143,10 +149,18 @@ proc exec(ctx: var TransContext,
|
||||
vmState.mutateStateDB:
|
||||
db.applyDAOHardFork()
|
||||
|
||||
vmState.receipts = newSeqOfCap[Receipt](ctx.txs.len)
|
||||
vmState.receipts = newSeqOfCap[Receipt](txList.len)
|
||||
vmState.cumulativeGasUsed = 0
|
||||
|
||||
for txIndex, tx in ctx.txs:
|
||||
for txIndex, txRes in txList:
|
||||
if txRes.isErr:
|
||||
rejected.add RejectedTx(
|
||||
index: txIndex,
|
||||
error: txRes.error
|
||||
)
|
||||
continue
|
||||
|
||||
let tx = txRes.get
|
||||
var sender: EthAddress
|
||||
if not tx.getSender(sender):
|
||||
rejected.add RejectedTx(
|
||||
@ -176,7 +190,13 @@ proc exec(ctx: var TransContext,
|
||||
)
|
||||
includedTx.add tx
|
||||
|
||||
# Add mining reward? (-1 means rewards are disabled)
|
||||
if stateReward.isSome and stateReward.get >= 0:
|
||||
# Add mining reward. The mining reward may be `0`, which only makes a difference in the cases
|
||||
# where
|
||||
# - the coinbase suicided, or
|
||||
# - there are only 'bad' transactions, which aren't executed. In those cases,
|
||||
# the coinbase gets no txfee, so isn't created, and thus needs to be touched
|
||||
let blockReward = stateReward.get()
|
||||
var mainReward = blockReward
|
||||
for uncle in ctx.env.ommers:
|
||||
@ -216,7 +236,8 @@ proc exec(ctx: var TransContext,
|
||||
# geth using both vmContext.Difficulty and vmContext.Random
|
||||
# therefore we cannot use vmState.difficulty
|
||||
currentDifficulty: ctx.env.currentDifficulty,
|
||||
gasUsed : vmState.cumulativeGasUsed
|
||||
gasUsed : vmState.cumulativeGasUsed,
|
||||
currentBaseFee: ctx.env.currentBaseFee
|
||||
)
|
||||
|
||||
template wrapException(body: untyped) =
|
||||
@ -261,6 +282,20 @@ proc parseChainConfig(network: string): ChainConfig =
|
||||
except ValueError as e:
|
||||
raise newError(ErrorConfig, e.msg)
|
||||
|
||||
proc calcBaseFee(env: EnvStruct): UInt256 =
|
||||
if env.parentGasUsed.isNone:
|
||||
raise newError(ErrorConfig,
|
||||
"'parentBaseFee' exists but missing 'parentGasUsed' in env section")
|
||||
|
||||
if env.parentGasLimit.isNone:
|
||||
raise newError(ErrorConfig,
|
||||
"'parentBaseFee' exists but missing 'parentGasLimit' in env section")
|
||||
|
||||
calcEip1599BaseFee(
|
||||
env.parentGasLimit.get,
|
||||
env.parentGasUsed.get,
|
||||
env.parentBaseFee.get)
|
||||
|
||||
proc transitionAction*(ctx: var TransContext, conf: T8NConf) =
|
||||
wrapException:
|
||||
var tracerFlags = {
|
||||
@ -291,7 +326,7 @@ proc transitionAction*(ctx: var TransContext, conf: T8NConf) =
|
||||
if conf.inputAlloc == stdinSelector or
|
||||
conf.inputEnv == stdinSelector or
|
||||
conf.inputTxs == stdinSelector:
|
||||
ctx.parseInputFromStdin(com.chainId)
|
||||
ctx.parseInputFromStdin()
|
||||
|
||||
if conf.inputAlloc != stdinSelector and conf.inputAlloc.len > 0:
|
||||
let n = json.parseFile(conf.inputAlloc)
|
||||
@ -307,7 +342,7 @@ proc transitionAction*(ctx: var TransContext, conf: T8NConf) =
|
||||
ctx.parseTxsRlp(data.strip(chars={'"'}))
|
||||
else:
|
||||
let n = json.parseFile(conf.inputTxs)
|
||||
ctx.parseTxs(n, com.chainId)
|
||||
ctx.parseTxs(n)
|
||||
|
||||
let uncleHash = if ctx.env.parentUncleHash == Hash256():
|
||||
EMPTY_UNCLE_HASH
|
||||
@ -324,7 +359,12 @@ proc transitionAction*(ctx: var TransContext, conf: T8NConf) =
|
||||
|
||||
# Sanity check, to not `panic` in state_transition
|
||||
if com.isLondon(ctx.env.currentNumber):
|
||||
if ctx.env.currentBaseFee.isNone:
|
||||
if ctx.env.currentBaseFee.isSome:
|
||||
# Already set, currentBaseFee has precedent over parentBaseFee.
|
||||
discard
|
||||
elif ctx.env.parentBaseFee.isSome:
|
||||
ctx.env.currentBaseFee = some(calcBaseFee(ctx.env))
|
||||
else:
|
||||
raise newError(ErrorConfig, "EIP-1559 config but missing 'currentBaseFee' in env section")
|
||||
|
||||
if com.forkGTE(MergeFork):
|
||||
|
96
tools/t8n/txpriv.nim
Normal file
96
tools/t8n/txpriv.nim
Normal file
@ -0,0 +1,96 @@
|
||||
import
|
||||
eth/common
|
||||
|
||||
from stew/objects
|
||||
import checkedEnumAssign
|
||||
|
||||
# these procs are duplicates of nim-eth/eth_types_rlp.nim
|
||||
# both `readTxLegacy` and `readTxTyped` are exported here
|
||||
|
||||
template read[T](rlp: var Rlp, val: var T)=
|
||||
val = rlp.read(type val)
|
||||
|
||||
proc read[T](rlp: var Rlp, val: var Option[T])=
|
||||
if rlp.blobLen != 0:
|
||||
val = some(rlp.read(T))
|
||||
else:
|
||||
rlp.skipElem
|
||||
|
||||
proc readTxLegacy*(rlp: var Rlp, tx: var Transaction)=
|
||||
tx.txType = TxLegacy
|
||||
rlp.tryEnterList()
|
||||
rlp.read(tx.nonce)
|
||||
rlp.read(tx.gasPrice)
|
||||
rlp.read(tx.gasLimit)
|
||||
rlp.read(tx.to)
|
||||
rlp.read(tx.value)
|
||||
rlp.read(tx.payload)
|
||||
rlp.read(tx.V)
|
||||
rlp.read(tx.R)
|
||||
rlp.read(tx.S)
|
||||
|
||||
proc readTxEip2930(rlp: var Rlp, tx: var Transaction)=
|
||||
tx.txType = TxEip2930
|
||||
rlp.tryEnterList()
|
||||
tx.chainId = rlp.read(uint64).ChainId
|
||||
rlp.read(tx.nonce)
|
||||
rlp.read(tx.gasPrice)
|
||||
rlp.read(tx.gasLimit)
|
||||
rlp.read(tx.to)
|
||||
rlp.read(tx.value)
|
||||
rlp.read(tx.payload)
|
||||
rlp.read(tx.accessList)
|
||||
rlp.read(tx.V)
|
||||
rlp.read(tx.R)
|
||||
rlp.read(tx.S)
|
||||
|
||||
proc readTxEip1559(rlp: var Rlp, tx: var Transaction)=
|
||||
tx.txType = TxEip1559
|
||||
rlp.tryEnterList()
|
||||
tx.chainId = rlp.read(uint64).ChainId
|
||||
rlp.read(tx.nonce)
|
||||
rlp.read(tx.maxPriorityFee)
|
||||
rlp.read(tx.maxFee)
|
||||
rlp.read(tx.gasLimit)
|
||||
rlp.read(tx.to)
|
||||
rlp.read(tx.value)
|
||||
rlp.read(tx.payload)
|
||||
rlp.read(tx.accessList)
|
||||
rlp.read(tx.V)
|
||||
rlp.read(tx.R)
|
||||
rlp.read(tx.S)
|
||||
|
||||
proc readTxTyped*(rlp: var Rlp, tx: var Transaction) {.inline.} =
|
||||
# EIP-2718: We MUST decode the first byte as a byte, not `rlp.read(int)`.
|
||||
# If decoded with `rlp.read(int)`, bad transaction data (from the network)
|
||||
# or even just incorrectly framed data for other reasons fails with
|
||||
# any of these misleading error messages:
|
||||
# - "Message too large to fit in memory"
|
||||
# - "Number encoded with a leading zero"
|
||||
# - "Read past the end of the RLP stream"
|
||||
# - "Small number encoded in a non-canonical way"
|
||||
# - "Attempt to read an Int value past the RLP end"
|
||||
# - "The RLP contains a larger than expected Int value"
|
||||
if not rlp.isSingleByte:
|
||||
if not rlp.hasData:
|
||||
raise newException(MalformedRlpError,
|
||||
"Transaction expected but source RLP is empty")
|
||||
raise newException(MalformedRlpError,
|
||||
"TypedTransaction type byte is out of range, must be 0x00 to 0x7f")
|
||||
let txType = rlp.getByteValue
|
||||
rlp.position += 1
|
||||
|
||||
var txVal: TxType
|
||||
if checkedEnumAssign(txVal, txType):
|
||||
case txVal:
|
||||
of TxEip2930:
|
||||
rlp.readTxEip2930(tx)
|
||||
return
|
||||
of TxEip1559:
|
||||
rlp.readTxEip1559(tx)
|
||||
return
|
||||
else:
|
||||
discard
|
||||
|
||||
raise newException(UnsupportedRlpError,
|
||||
"TypedTransaction type must be 1 or 2 in this version, got " & $txType)
|
@ -9,7 +9,7 @@
|
||||
# according to those terms.
|
||||
|
||||
import
|
||||
std/[tables],
|
||||
std/[tables, json],
|
||||
eth/common,
|
||||
../../nimbus/common/chain_config,
|
||||
../common/types
|
||||
@ -40,10 +40,24 @@ type
|
||||
ommers*: seq[Ommer]
|
||||
currentBaseFee*: Option[UInt256]
|
||||
parentUncleHash*: Hash256
|
||||
parentBaseFee*: Option[UInt256]
|
||||
parentGasUsed*: Option[GasInt]
|
||||
parentGasLimit*: Option[GasInt]
|
||||
|
||||
TxsType* = enum
|
||||
TxsNone
|
||||
TxsRlp
|
||||
TxsJson
|
||||
|
||||
TxsList* = object
|
||||
case txsType*: TxsType
|
||||
of TxsRlp: r*: Rlp
|
||||
of TxsJson: n*: JsonNode
|
||||
else: discard
|
||||
|
||||
TransContext* = object
|
||||
alloc*: GenesisAlloc
|
||||
txs*: seq[Transaction]
|
||||
txs*: TxsList
|
||||
env*: EnvStruct
|
||||
|
||||
RejectedTx* = object
|
||||
@ -75,6 +89,7 @@ type
|
||||
rejected*: seq[RejectedTx]
|
||||
currentDifficulty*: Option[DifficultyInt]
|
||||
gasUsed*: GasInt
|
||||
currentBaseFee*: Option[UInt256]
|
||||
|
||||
const
|
||||
ErrorEVM* = 2.T8NExitCode
|
||||
|
Loading…
x
Reference in New Issue
Block a user