Introduce wrapper type for EIP-4844 transactions
EIP-4844 blob sidecars are a concept that only exists in the mempool. After inclusion of a transaction into an execution block, only the versioned hash within the transaction remains. To improve type safety, replace the `Transaction.networkPayload` member with a wrapper type `PooledTransaction` that is used in contexts where blob sidecars exist.
This commit is contained in:
parent
143f2e99f5
commit
aedf76f9c8
|
@ -22,7 +22,7 @@
|
|||
path = vendor/nim-eth
|
||||
url = https://github.com/status-im/nim-eth.git
|
||||
ignore = dirty
|
||||
branch = master
|
||||
branch = feat/eip-6493
|
||||
[submodule "vendor/nim-http-utils"]
|
||||
path = vendor/nim-http-utils
|
||||
url = https://github.com/status-im/nim-http-utils.git
|
||||
|
|
|
@ -336,7 +336,7 @@ func getTimestamp*(cust: CustomPayloadData, basePayload: ExecutionPayload): uint
|
|||
# Construct a customized payload by taking an existing payload as base and mixing it CustomPayloadData
|
||||
# blockHash is calculated automatically.
|
||||
proc customizePayload*(cust: CustomPayloadData, data: ExecutableData): ExecutableData {.gcsafe.} =
|
||||
var customHeader = blockHeader(data.basePayload, removeBlobs = false, beaconRoot = data.beaconRoot)
|
||||
var customHeader = blockHeader(data.basePayload, beaconRoot = data.beaconRoot)
|
||||
if cust.transactions.isSome:
|
||||
customHeader.txRoot = calcTxRoot(cust.transactions.get)
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ type
|
|||
TestBlobTxPool* = ref object
|
||||
currentBlobID* : BlobID
|
||||
currentTxIndex*: int
|
||||
transactions* : Table[common.Hash256, Transaction]
|
||||
transactions* : Table[common.Hash256, PooledTransaction]
|
||||
hashesByIndex* : Table[int, common.Hash256]
|
||||
|
||||
const
|
||||
|
@ -53,7 +53,7 @@ func getMinExcessBlobGasForBlobGasPrice(data_gas_price: uint64): uint64 =
|
|||
func getMinExcessBlobsForBlobGasPrice*(data_gas_price: uint64): uint64 =
|
||||
return getMinExcessBlobGasForBlobGasPrice(data_gas_price) div GAS_PER_BLOB.uint64
|
||||
|
||||
proc addBlobTransaction*(pool: TestBlobTxPool, tx: Transaction) =
|
||||
proc addBlobTransaction*(pool: TestBlobTxPool, tx: PooledTransaction) =
|
||||
let txHash = rlpHash(tx)
|
||||
pool.transactions[txHash] = tx
|
||||
|
||||
|
@ -178,19 +178,19 @@ proc getBlobDataInPayload*(pool: TestBlobTxPool, payload: ExecutionPayload): Res
|
|||
return err("blob data is nil")
|
||||
|
||||
let np = blobTx.networkPayload
|
||||
if blobTx.versionedHashes.len != np.commitments.len or
|
||||
if blobTx.tx.versionedHashes.len != np.commitments.len or
|
||||
np.commitments.len != np.blobs.len or
|
||||
np.blobs.len != np.proofs.len:
|
||||
return err("invalid blob wrap data")
|
||||
|
||||
for i in 0..<blobTx.versionedHashes.len:
|
||||
for i in 0..<blobTx.tx.versionedHashes.len:
|
||||
blobData.data.add BlobWrapData(
|
||||
versionedHash: blobTx.versionedHashes[i],
|
||||
versionedHash: blobTx.tx.versionedHashes[i],
|
||||
commitment : np.commitments[i],
|
||||
blob : np.blobs[i],
|
||||
proof : np.proofs[i],
|
||||
)
|
||||
blobData.txs.add blobTx
|
||||
blobData.txs.add blobTx.tx
|
||||
|
||||
return ok(blobData)
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ method execute*(step: DevP2PRequestPooledTransactionHash, ctx: CancunTestContext
|
|||
|
||||
var
|
||||
txHashes = newSeq[common.Hash256](step.transactionIndexes.len)
|
||||
txs = newSeq[Transaction](step.transactionIndexes.len)
|
||||
txs = newSeq[PooledTransaction](step.transactionIndexes.len)
|
||||
|
||||
for i, txIndex in step.transactionIndexes:
|
||||
if not ctx.txPool.hashesByIndex.hasKey(txIndex):
|
||||
|
|
|
@ -80,7 +80,7 @@ method execute*(step: SendBlobTransactions, ctx: CancunTestContext): bool =
|
|||
|
||||
let blobTx = res.get
|
||||
if not step.skipVerificationFromNode:
|
||||
let r = verifyTransactionFromNode(engine.client, blobTx)
|
||||
let r = verifyTransactionFromNode(engine.client, blobTx.tx)
|
||||
if r.isErr:
|
||||
error "verify tx from node", msg=r.error
|
||||
return false
|
||||
|
|
|
@ -333,7 +333,7 @@ proc getNextPayload(cl: CLMocker): bool =
|
|||
cl.latestShouldOverrideBuilder = x.shouldOverrideBuilder
|
||||
|
||||
let beaconRoot = ethHash cl.latestPayloadAttributes.parentBeaconblockRoot
|
||||
let header = blockHeader(cl.latestPayloadBuilt, removeBlobs = true, beaconRoot = beaconRoot)
|
||||
let header = blockHeader(cl.latestPayloadBuilt, beaconRoot = beaconRoot)
|
||||
let blockHash = w3Hash header.blockHash
|
||||
if blockHash != cl.latestPayloadBuilt.blockHash:
|
||||
error "CLMocker: getNextPayload blockHash mismatch",
|
||||
|
|
|
@ -192,7 +192,7 @@ method getName(cs: InvalidMissingAncestorReOrgSyncTest): string =
|
|||
$cs.invalidField, $cs.emptyTransactions, $cs.reOrgFromCanonical, $cs.invalidIndex]
|
||||
|
||||
proc executableDataToBlock(ex: ExecutableData): EthBlock =
|
||||
ethBlock(ex.basePayload, removeBlobs = true, beaconRoot = ex.beaconRoot)
|
||||
ethBlock(ex.basePayload, beaconRoot = ex.beaconRoot)
|
||||
|
||||
method execute(cs: InvalidMissingAncestorReOrgSyncTest, env: TestEnv): bool =
|
||||
var sec = env.addEngine(true, cs.reOrgFromCanonical)
|
||||
|
|
|
@ -380,7 +380,7 @@ method execute(cs: PayloadBuildAfterInvalidPayloadTest, env: TestEnv): bool =
|
|||
type
|
||||
InvalidTxChainIDTest* = ref object of EngineSpec
|
||||
InvalidTxChainIDShadow = ref object
|
||||
invalidTx: Transaction
|
||||
invalidTx: PooledTransaction
|
||||
|
||||
method withMainFork(cs: InvalidTxChainIDTest, fork: EngineFork): BaseSpec =
|
||||
var res = cs.clone()
|
||||
|
@ -430,7 +430,9 @@ method execute(cs: InvalidTxChainIDTest, env: TestEnv): bool =
|
|||
chainID: some((chainId.uint64 + 1'u64).ChainId)
|
||||
)
|
||||
|
||||
shadow.invalidTx = env.customizeTransaction(sender, tx, txCustomizerData)
|
||||
shadow.invalidTx = tx
|
||||
shadow.invalidTx.tx = env.customizeTransaction(
|
||||
sender, shadow.invalidTx.tx, txCustomizerData)
|
||||
testCond env.sendTx(shadow.invalidTx):
|
||||
info "Error on sending transaction with incorrect chain ID"
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ type
|
|||
startBlockNumber: uint64
|
||||
blockCount: int
|
||||
currentTxIndex: int
|
||||
txs: seq[Transaction]
|
||||
txs: seq[PooledTransaction]
|
||||
|
||||
method withMainFork(cs: PrevRandaoTransactionTest, fork: EngineFork): BaseSpec =
|
||||
var res = cs.clone()
|
||||
|
|
|
@ -119,9 +119,9 @@ type
|
|||
|
||||
ShadowTx = ref object
|
||||
payload: ExecutionPayload
|
||||
nextTx: Transaction
|
||||
tx: Option[Transaction]
|
||||
sendTransaction: proc(i: int): Transaction {.gcsafe.}
|
||||
nextTx: PooledTransaction
|
||||
tx: Option[PooledTransaction]
|
||||
sendTransaction: proc(i: int): PooledTransaction {.gcsafe.}
|
||||
|
||||
method withMainFork(cs: TransactionReOrgTest, fork: EngineFork): BaseSpec =
|
||||
var res = cs.clone()
|
||||
|
@ -153,7 +153,7 @@ method execute(cs: TransactionReOrgTest, env: TestEnv): bool =
|
|||
var shadow = ShadowTx()
|
||||
|
||||
# Send a transaction on each payload of the canonical chain
|
||||
shadow.sendTransaction = proc(i: int): Transaction {.gcsafe.} =
|
||||
shadow.sendTransaction = proc(i: int): PooledTransaction {.gcsafe.} =
|
||||
let sstoreContractAddr = hexToByteArray[20]("0000000000000000000000000000000000000317")
|
||||
var data: array[32, byte]
|
||||
data[^1] = i.byte
|
||||
|
@ -332,7 +332,7 @@ method execute(cs: TransactionReOrgTest, env: TestEnv): bool =
|
|||
txt.expectBlockHash(ethHash env.clMock.latestForkchoice.headBlockHash)
|
||||
|
||||
if cs.scenario != TransactionReOrgScenarioReOrgBackIn:
|
||||
shadow.tx = none(Transaction)
|
||||
shadow.tx = none(PooledTransaction)
|
||||
|
||||
if cs.scenario == TransactionReOrgScenarioReOrgBackIn and i > 0:
|
||||
# Reasoning: Most of the clients do not re-add blob transactions to the pool
|
||||
|
|
|
@ -512,7 +512,8 @@ proc namedHeader*(client: RpcClient, name: string): Result[common.BlockHeader, s
|
|||
return err("failed to get named blockHeader")
|
||||
return ok(res.toBlockHeader)
|
||||
|
||||
proc sendTransaction*(client: RpcClient, tx: common.Transaction): Result[void, string] =
|
||||
proc sendTransaction*(
|
||||
client: RpcClient, tx: common.PooledTransaction): Result[void, string] =
|
||||
wrapTry:
|
||||
let encodedTx = rlp.encode(tx)
|
||||
let res = waitFor client.eth_sendRawTransaction(encodedTx)
|
||||
|
@ -603,7 +604,10 @@ TraceOpts.useDefaultSerializationIn JrpcConv
|
|||
createRpcSigsFromNim(RpcClient):
|
||||
proc debug_traceTransaction(hash: TxHash, opts: TraceOpts): JsonNode
|
||||
|
||||
proc debugPrevRandaoTransaction*(client: RpcClient, tx: Transaction, expectedPrevRandao: Hash256): Result[void, string] =
|
||||
proc debugPrevRandaoTransaction*(
|
||||
client: RpcClient,
|
||||
tx: PooledTransaction,
|
||||
expectedPrevRandao: Hash256): Result[void, string] =
|
||||
wrapTry:
|
||||
let hash = w3Hash tx.rlpHash
|
||||
# we only interested in stack, disable all other elems
|
||||
|
|
|
@ -116,18 +116,20 @@ func numEngines*(env: TestEnv): int =
|
|||
func accounts*(env: TestEnv, idx: int): TestAccount =
|
||||
env.sender.getAccount(idx)
|
||||
|
||||
proc makeTx*(env: TestEnv, tc: BaseTx, nonce: AccountNonce): Transaction =
|
||||
proc makeTx*(
|
||||
env: TestEnv, tc: BaseTx, nonce: AccountNonce): PooledTransaction =
|
||||
env.sender.makeTx(tc, nonce)
|
||||
|
||||
proc makeTx*(env: TestEnv, tc: BigInitcodeTx, nonce: AccountNonce): Transaction =
|
||||
proc makeTx*(
|
||||
env: TestEnv, tc: BigInitcodeTx, nonce: AccountNonce): PooledTransaction =
|
||||
env.sender.makeTx(tc, nonce)
|
||||
|
||||
proc makeTxs*(env: TestEnv, tc: BaseTx, num: int): seq[Transaction] =
|
||||
result = newSeqOfCap[Transaction](num)
|
||||
proc makeTxs*(env: TestEnv, tc: BaseTx, num: int): seq[PooledTransaction] =
|
||||
result = newSeqOfCap[PooledTransaction](num)
|
||||
for _ in 0..<num:
|
||||
result.add env.sender.makeNextTx(tc)
|
||||
|
||||
proc makeNextTx*(env: TestEnv, tc: BaseTx): Transaction =
|
||||
proc makeNextTx*(env: TestEnv, tc: BaseTx): PooledTransaction =
|
||||
env.sender.makeNextTx(tc)
|
||||
|
||||
proc sendNextTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx): bool =
|
||||
|
@ -145,7 +147,8 @@ proc sendTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx, nonce: AccountNonce): boo
|
|||
proc sendTx*(env: TestEnv, eng: EngineEnv, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
||||
env.sender.sendTx(eng.client, tc, nonce)
|
||||
|
||||
proc sendTxs*(env: TestEnv, eng: EngineEnv, txs: openArray[Transaction]): bool =
|
||||
proc sendTxs*(
|
||||
env: TestEnv, eng: EngineEnv, txs: openArray[PooledTransaction]): bool =
|
||||
for tx in txs:
|
||||
if not sendTx(eng.client, tx):
|
||||
return false
|
||||
|
@ -163,17 +166,29 @@ proc sendTx*(env: TestEnv, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
|||
let client = env.engine.client
|
||||
env.sender.sendTx(client, tc, nonce)
|
||||
|
||||
proc sendTx*(env: TestEnv, tx: Transaction): bool =
|
||||
proc sendTx*(env: TestEnv, tx: PooledTransaction): bool =
|
||||
let client = env.engine.client
|
||||
sendTx(client, tx)
|
||||
|
||||
proc sendTx*(env: TestEnv, sender: TestAccount, eng: EngineEnv, tc: BlobTx): Result[Transaction, void] =
|
||||
proc sendTx*(
|
||||
env: TestEnv,
|
||||
sender: TestAccount,
|
||||
eng: EngineEnv,
|
||||
tc: BlobTx): Result[PooledTransaction, void] =
|
||||
env.sender.sendTx(sender, eng.client, tc)
|
||||
|
||||
proc replaceTx*(env: TestEnv, sender: TestAccount, eng: EngineEnv, tc: BlobTx): Result[Transaction, void] =
|
||||
proc replaceTx*(
|
||||
env: TestEnv,
|
||||
sender: TestAccount,
|
||||
eng: EngineEnv,
|
||||
tc: BlobTx): Result[PooledTransaction, void] =
|
||||
env.sender.replaceTx(sender, eng.client, tc)
|
||||
|
||||
proc makeTx*(env: TestEnv, tc: BaseTx, sender: TestAccount, nonce: AccountNonce): Transaction =
|
||||
proc makeTx*(
|
||||
env: TestEnv,
|
||||
tc: BaseTx,
|
||||
sender: TestAccount,
|
||||
nonce: AccountNonce): PooledTransaction =
|
||||
env.sender.makeTx(tc, sender, nonce)
|
||||
|
||||
proc customizeTransaction*(env: TestEnv,
|
||||
|
|
|
@ -130,7 +130,7 @@ proc getTxType(tc: BaseTx, nonce: uint64): TxType =
|
|||
else:
|
||||
tc.txType.get
|
||||
|
||||
proc makeTxOfType(params: MakeTxParams, tc: BaseTx): Transaction =
|
||||
proc makeTxOfType(params: MakeTxParams, tc: BaseTx): PooledTransaction =
|
||||
let
|
||||
gasFeeCap = if tc.gasFee != 0.GasInt: tc.gasFee
|
||||
else: gasPrice
|
||||
|
@ -140,26 +140,30 @@ proc makeTxOfType(params: MakeTxParams, tc: BaseTx): Transaction =
|
|||
let txType = tc.getTxType(params.nonce)
|
||||
case txType
|
||||
of TxLegacy:
|
||||
Transaction(
|
||||
txType : TxLegacy,
|
||||
nonce : params.nonce,
|
||||
to : tc.recipient,
|
||||
value : tc.amount,
|
||||
gasLimit: tc.gasLimit,
|
||||
gasPrice: gasPrice,
|
||||
payload : tc.payload
|
||||
PooledTransaction(
|
||||
tx: Transaction(
|
||||
txType : TxLegacy,
|
||||
nonce : params.nonce,
|
||||
to : tc.recipient,
|
||||
value : tc.amount,
|
||||
gasLimit: tc.gasLimit,
|
||||
gasPrice: gasPrice,
|
||||
payload : tc.payload
|
||||
)
|
||||
)
|
||||
of TxEip1559:
|
||||
Transaction(
|
||||
txType : TxEIP1559,
|
||||
nonce : params.nonce,
|
||||
gasLimit: tc.gasLimit,
|
||||
maxFee : gasFeeCap,
|
||||
maxPriorityFee: gasTipCap,
|
||||
to : tc.recipient,
|
||||
value : tc.amount,
|
||||
payload : tc.payload,
|
||||
chainId : params.chainId
|
||||
PooledTransaction(
|
||||
tx: Transaction(
|
||||
txType : TxEIP1559,
|
||||
nonce : params.nonce,
|
||||
gasLimit: tc.gasLimit,
|
||||
maxFee : gasFeeCap,
|
||||
maxPriorityFee: gasTipCap,
|
||||
to : tc.recipient,
|
||||
value : tc.amount,
|
||||
payload : tc.payload,
|
||||
chainId : params.chainId
|
||||
)
|
||||
)
|
||||
of TxEip4844:
|
||||
doAssert(tc.recipient.isSome, "recipient must be some")
|
||||
|
@ -173,19 +177,21 @@ proc makeTxOfType(params: MakeTxParams, tc: BaseTx): Transaction =
|
|||
var blobData = blobDataGenerator(tc.blobID, blobCount)
|
||||
#tc.blobID += BlobID(blobCount)
|
||||
|
||||
Transaction(
|
||||
txType : TxEIP4844,
|
||||
nonce : params.nonce,
|
||||
chainId : params.chainId,
|
||||
maxFee : gasFeeCap,
|
||||
maxPriorityFee: gasTipCap,
|
||||
gasLimit: tc.gasLimit,
|
||||
to : tc.recipient,
|
||||
value : tc.amount,
|
||||
payload : tc.payload,
|
||||
#AccessList: tc.AccessList,
|
||||
maxFeePerBlobGas: blobFeeCap,
|
||||
versionedHashes: system.move(blobData.hashes),
|
||||
PooledTransaction(
|
||||
tx: Transaction(
|
||||
txType : TxEIP4844,
|
||||
nonce : params.nonce,
|
||||
chainId : params.chainId,
|
||||
maxFee : gasFeeCap,
|
||||
maxPriorityFee: gasTipCap,
|
||||
gasLimit: tc.gasLimit,
|
||||
to : tc.recipient,
|
||||
value : tc.amount,
|
||||
payload : tc.payload,
|
||||
#AccessList: tc.AccessList,
|
||||
maxFeePerBlobGas: blobFeeCap,
|
||||
versionedHashes: system.move(blobData.hashes),
|
||||
),
|
||||
networkPayload: NetworkPayload(
|
||||
blobs: system.move(blobData.blobs),
|
||||
commitments: system.move(blobData.commitments),
|
||||
|
@ -193,15 +199,16 @@ proc makeTxOfType(params: MakeTxParams, tc: BaseTx): Transaction =
|
|||
)
|
||||
)
|
||||
else:
|
||||
doAssert(false, "unsupported tx type")
|
||||
Transaction()
|
||||
raiseAssert "unsupported tx type"
|
||||
|
||||
proc makeTx(params: MakeTxParams, tc: BaseTx): Transaction =
|
||||
proc makeTx(params: MakeTxParams, tc: BaseTx): PooledTransaction =
|
||||
# Build the transaction depending on the specified type
|
||||
let tx = makeTxOfType(params, tc)
|
||||
signTransaction(tx, params.key, params.chainId, eip155 = true)
|
||||
PooledTransaction(
|
||||
tx: signTransaction(tx.tx, params.key, params.chainId, eip155 = true),
|
||||
networkPayload: tx.networkPayload)
|
||||
|
||||
proc makeTx(params: MakeTxParams, tc: BigInitcodeTx): Transaction =
|
||||
proc makeTx(params: MakeTxParams, tc: BigInitcodeTx): PooledTransaction =
|
||||
var tx = tc
|
||||
if tx.payload.len == 0:
|
||||
# Prepare initcode payload
|
||||
|
@ -215,7 +222,8 @@ proc makeTx(params: MakeTxParams, tc: BigInitcodeTx): Transaction =
|
|||
doAssert(tx.recipient.isNone, "invalid configuration for big contract tx creator")
|
||||
params.makeTx(tx.BaseTx)
|
||||
|
||||
proc makeTx*(sender: TxSender, tc: BaseTx, nonce: AccountNonce): Transaction =
|
||||
proc makeTx*(
|
||||
sender: TxSender, tc: BaseTx, nonce: AccountNonce): PooledTransaction =
|
||||
let acc = sender.getNextAccount()
|
||||
let params = MakeTxParams(
|
||||
chainId: sender.chainId,
|
||||
|
@ -224,7 +232,10 @@ proc makeTx*(sender: TxSender, tc: BaseTx, nonce: AccountNonce): Transaction =
|
|||
)
|
||||
params.makeTx(tc)
|
||||
|
||||
proc makeTx*(sender: TxSender, tc: BigInitcodeTx, nonce: AccountNonce): Transaction =
|
||||
proc makeTx*(
|
||||
sender: TxSender,
|
||||
tc: BigInitcodeTx,
|
||||
nonce: AccountNonce): PooledTransaction =
|
||||
let acc = sender.getNextAccount()
|
||||
let params = MakeTxParams(
|
||||
chainId: sender.chainId,
|
||||
|
@ -233,7 +244,7 @@ proc makeTx*(sender: TxSender, tc: BigInitcodeTx, nonce: AccountNonce): Transact
|
|||
)
|
||||
params.makeTx(tc)
|
||||
|
||||
proc makeNextTx*(sender: TxSender, tc: BaseTx): Transaction =
|
||||
proc makeNextTx*(sender: TxSender, tc: BaseTx): PooledTransaction =
|
||||
let
|
||||
acc = sender.getNextAccount()
|
||||
nonce = sender.getNextNonce(acc.address)
|
||||
|
@ -290,14 +301,14 @@ proc sendTx*(sender: TxSender, client: RpcClient, tc: BigInitcodeTx, nonce: Acco
|
|||
inc sender.txSent
|
||||
return true
|
||||
|
||||
proc sendTx*(client: RpcClient, tx: Transaction): bool =
|
||||
proc sendTx*(client: RpcClient, tx: PooledTransaction): bool =
|
||||
let rr = client.sendTransaction(tx)
|
||||
if rr.isErr:
|
||||
error "Unable to send transaction", msg=rr.error
|
||||
return false
|
||||
return true
|
||||
|
||||
proc makeTx*(params: MakeTxParams, tc: BlobTx): Transaction =
|
||||
proc makeTx*(params: MakeTxParams, tc: BlobTx): PooledTransaction =
|
||||
# Need tx wrap data that will pass blob verification
|
||||
let data = blobDataGenerator(tc.blobID, tc.blobCount)
|
||||
doAssert(tc.recipient.isSome, "nil recipient address")
|
||||
|
@ -323,19 +334,23 @@ proc makeTx*(params: MakeTxParams, tc: BlobTx): Transaction =
|
|||
versionedHashes: data.hashes,
|
||||
)
|
||||
|
||||
var tx = signTransaction(unsignedTx, params.key, params.chainId, eip155 = true)
|
||||
tx.networkPayload = NetworkPayload(
|
||||
blobs : data.blobs,
|
||||
commitments: data.commitments,
|
||||
proofs : data.proofs,
|
||||
PooledTransaction(
|
||||
tx: signTransaction(unsignedTx, params.key, params.chainId, eip155 = true),
|
||||
networkPayload: NetworkPayload(
|
||||
blobs : data.blobs,
|
||||
commitments: data.commitments,
|
||||
proofs : data.proofs,
|
||||
),
|
||||
)
|
||||
|
||||
tx
|
||||
|
||||
proc getAccount*(sender: TxSender, idx: int): TestAccount =
|
||||
sender.accounts[idx]
|
||||
|
||||
proc sendTx*(sender: TxSender, acc: TestAccount, client: RpcClient, tc: BlobTx): Result[Transaction, void] =
|
||||
proc sendTx*(
|
||||
sender: TxSender,
|
||||
acc: TestAccount,
|
||||
client: RpcClient,
|
||||
tc: BlobTx): Result[PooledTransaction, void] =
|
||||
let
|
||||
params = MakeTxParams(
|
||||
chainId: sender.chainId,
|
||||
|
@ -352,7 +367,11 @@ proc sendTx*(sender: TxSender, acc: TestAccount, client: RpcClient, tc: BlobTx):
|
|||
inc sender.txSent
|
||||
return ok(tx)
|
||||
|
||||
proc replaceTx*(sender: TxSender, acc: TestAccount, client: RpcClient, tc: BlobTx): Result[Transaction, void] =
|
||||
proc replaceTx*(
|
||||
sender: TxSender,
|
||||
acc: TestAccount,
|
||||
client: RpcClient,
|
||||
tc: BlobTx): Result[PooledTransaction, void] =
|
||||
let
|
||||
params = MakeTxParams(
|
||||
chainId: sender.chainId,
|
||||
|
@ -369,7 +388,11 @@ proc replaceTx*(sender: TxSender, acc: TestAccount, client: RpcClient, tc: BlobT
|
|||
inc sender.txSent
|
||||
return ok(tx)
|
||||
|
||||
proc makeTx*(sender: TxSender, tc: BaseTx, acc: TestAccount, nonce: AccountNonce): Transaction =
|
||||
proc makeTx*(
|
||||
sender: TxSender,
|
||||
tc: BaseTx,
|
||||
acc: TestAccount,
|
||||
nonce: AccountNonce): PooledTransaction =
|
||||
let
|
||||
params = MakeTxParams(
|
||||
chainId: sender.chainId,
|
||||
|
|
|
@ -112,7 +112,7 @@ proc execute*(ws: MaxInitcodeSizeSpec, env: TestEnv): bool =
|
|||
# Customize the payload to include a tx with an invalid initcode
|
||||
let customizer = CustomPayloadData(
|
||||
parentBeaconRoot: ethHash env.clMock.latestPayloadAttributes.parentBeaconBlockRoot,
|
||||
transactions: some( @[invalidTx] ),
|
||||
transactions: some( @[invalidTx.tx] ),
|
||||
)
|
||||
|
||||
let customPayload = customizer.customizePayload(env.clMock.latestExecutableData).basePayload
|
||||
|
|
|
@ -18,7 +18,8 @@ import
|
|||
|
||||
export eth_api
|
||||
|
||||
proc sendTransaction*(client: RpcClient, tx: Transaction): Future[bool] {.async.} =
|
||||
proc sendTransaction*(
|
||||
client: RpcClient, tx: PooledTransaction): Future[bool] {.async.} =
|
||||
let data = rlp.encode(tx)
|
||||
let txHash = keccakHash(data)
|
||||
let hex = await client.eth_sendRawTransaction(data)
|
||||
|
|
|
@ -90,7 +90,7 @@ proc balanceAndNonceAtTest(t: TestEnv): Future[TestStatus] {.async.} =
|
|||
|
||||
let txHash = rlpHash(tx)
|
||||
echo "BalanceAt: send $1 wei from 0x$2 to 0x$3 in 0x$4" % [
|
||||
$tx.value, sourceAddr.toHex, targetAddr.toHex, txHash.data.toHex]
|
||||
$tx.tx.value, sourceAddr.toHex, targetAddr.toHex, txHash.data.toHex]
|
||||
|
||||
let ok = await client.sendTransaction(tx)
|
||||
if not ok:
|
||||
|
@ -117,14 +117,16 @@ proc balanceAndNonceAtTest(t: TestEnv): Future[TestStatus] {.async.} =
|
|||
let balanceTargetAccountAfter = await client.balanceAt(targetAddr)
|
||||
|
||||
# expected balance is previous balance - tx amount - tx fee (gasUsed * gasPrice)
|
||||
let exp = sourceAddressBalanceBefore - amount - (gasUsed * tx.gasPrice).u256
|
||||
let exp =
|
||||
sourceAddressBalanceBefore - amount - (gasUsed * tx.tx.gasPrice).u256
|
||||
|
||||
if exp != accountBalanceAfter:
|
||||
echo "Expected sender account to have a balance of $1, got $2" % [$exp, $accountBalanceAfter]
|
||||
return TestStatus.Failed
|
||||
|
||||
if balanceTargetAccountAfter != amount:
|
||||
echo "Expected new account to have a balance of $1, got $2" % [$tx.value, $balanceTargetAccountAfter]
|
||||
echo "Expected new account to have a balance of $1, got $2" % [
|
||||
$tx.tx.value, $balanceTargetAccountAfter]
|
||||
return TestStatus.Failed
|
||||
|
||||
# ensure nonce is incremented by 1
|
||||
|
|
|
@ -79,7 +79,8 @@ proc sendSome(address: EthAddress, amount: UInt256): seq[byte] =
|
|||
result.add amount.toBytesBE
|
||||
doAssert(result.len == 68) # 4 + 32 + 32
|
||||
|
||||
proc makeFundingTx*(v: Vault, recipient: EthAddress, amount: UInt256): Transaction =
|
||||
proc makeFundingTx*(
|
||||
v: Vault, recipient: EthAddress, amount: UInt256): PooledTransaction =
|
||||
let
|
||||
unsignedTx = Transaction(
|
||||
txType : TxLegacy,
|
||||
|
@ -92,7 +93,8 @@ proc makeFundingTx*(v: Vault, recipient: EthAddress, amount: UInt256): Transacti
|
|||
payload : sendSome(recipient, amount)
|
||||
)
|
||||
|
||||
signTransaction(unsignedTx, v.vaultKey, v.chainId, eip155 = true)
|
||||
PooledTransaction(
|
||||
tx: signTransaction(unsignedTx, v.vaultKey, v.chainId, eip155 = true))
|
||||
|
||||
proc signTx*(v: Vault,
|
||||
sender: EthAddress,
|
||||
|
@ -100,7 +102,7 @@ proc signTx*(v: Vault,
|
|||
recipient: EthAddress,
|
||||
amount: UInt256,
|
||||
gasLimit, gasPrice: GasInt,
|
||||
payload: seq[byte] = @[]): Transaction =
|
||||
payload: seq[byte] = @[]): PooledTransaction =
|
||||
|
||||
let
|
||||
unsignedTx = Transaction(
|
||||
|
@ -115,7 +117,8 @@ proc signTx*(v: Vault,
|
|||
)
|
||||
|
||||
let key = v.accounts[sender]
|
||||
signTransaction(unsignedTx, key, v.chainId, eip155 = true)
|
||||
PooledTransaction(
|
||||
tx: signTransaction(unsignedTx, key, v.chainId, eip155 = true))
|
||||
|
||||
# createAccount creates a new account that is funded from the vault contract.
|
||||
# It will panic when the account could not be created and funded.
|
||||
|
|
|
@ -188,17 +188,17 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef,
|
|||
let attrs = attrsOpt.get()
|
||||
validateVersion(attrs, com, apiVersion)
|
||||
|
||||
let payload = ben.generatePayload(attrs).valueOr:
|
||||
let bundle = ben.generatePayload(attrs).valueOr:
|
||||
error "Failed to create sealing payload", err = error
|
||||
raise invalidAttr(error)
|
||||
|
||||
let id = computePayloadId(blockHash, attrs)
|
||||
ben.put(id, ben.blockValue, payload)
|
||||
ben.put(id, ben.blockValue, bundle.executionPayload, bundle.blobsBundle)
|
||||
|
||||
info "Created payload for sealing",
|
||||
id = id.toHex,
|
||||
hash = payload.blockHash.short,
|
||||
number = payload.blockNumber
|
||||
hash = bundle.executionPayload.blockHash.short,
|
||||
number = bundle.executionPayload.blockNumber
|
||||
|
||||
return validFCU(some(id), blockHash)
|
||||
|
||||
|
|
|
@ -26,14 +26,18 @@ proc getPayload*(ben: BeaconEngineRef,
|
|||
|
||||
var payloadGeneric: ExecutionPayload
|
||||
var blockValue: UInt256
|
||||
if not ben.get(id, blockValue, payloadGeneric):
|
||||
var blobsBundle: Option[BlobsBundleV1]
|
||||
if not ben.get(id, blockValue, payloadGeneric, blobsBundle):
|
||||
raise unknownPayload("Unknown payload")
|
||||
|
||||
let version = payloadGeneric.version
|
||||
if version > expectedVersion:
|
||||
raise unsupportedFork("getPayload" & $expectedVersion &
|
||||
" expect ExecutionPayload" & $expectedVersion &
|
||||
" but get ExecutionPayload" & $version)
|
||||
" expect ExecutionPayload" & $expectedVersion &
|
||||
" but get ExecutionPayload" & $version)
|
||||
if blobsBundle.isSome:
|
||||
raise unsupportedFork("getPayload" & $expectedVersion &
|
||||
" contains unsupported BlobsBundleV1")
|
||||
|
||||
GetPayloadV2Response(
|
||||
executionPayload: payloadGeneric.V1V2,
|
||||
|
@ -46,38 +50,25 @@ proc getPayloadV3*(ben: BeaconEngineRef, id: PayloadID): GetPayloadV3Response =
|
|||
|
||||
var payloadGeneric: ExecutionPayload
|
||||
var blockValue: UInt256
|
||||
if not ben.get(id, blockValue, payloadGeneric):
|
||||
var blobsBundle: Option[BlobsBundleV1]
|
||||
if not ben.get(id, blockValue, payloadGeneric, blobsBundle):
|
||||
raise unknownPayload("Unknown payload")
|
||||
|
||||
let version = payloadGeneric.version
|
||||
if version != Version.V3:
|
||||
raise unsupportedFork("getPayloadV3 expect ExecutionPayloadV3 but get ExecutionPayload" & $version)
|
||||
if blobsBundle.isNone:
|
||||
raise unsupportedFork("getPayloadV3 is missing BlobsBundleV1")
|
||||
|
||||
let payload = payloadGeneric.V3
|
||||
let com = ben.com
|
||||
if not com.isCancunOrLater(ethTime payload.timestamp):
|
||||
raise unsupportedFork("payload timestamp is less than Cancun activation")
|
||||
|
||||
var
|
||||
blobsBundle: BlobsBundleV1
|
||||
|
||||
try:
|
||||
for ttx in payload.transactions:
|
||||
let tx = rlp.decode(distinctBase(ttx), Transaction)
|
||||
if tx.networkPayload.isNil.not:
|
||||
for blob in tx.networkPayload.blobs:
|
||||
blobsBundle.blobs.add Web3Blob(blob)
|
||||
for p in tx.networkPayload.proofs:
|
||||
blobsBundle.proofs.add Web3KZGProof(p)
|
||||
for k in tx.networkPayload.commitments:
|
||||
blobsBundle.commitments.add Web3KZGCommitment(k)
|
||||
except RlpError:
|
||||
doAssert(false, "found TypedTransaction that RLP failed to decode")
|
||||
|
||||
GetPayloadV3Response(
|
||||
executionPayload: payload,
|
||||
blockValue: blockValue,
|
||||
blobsBundle: blobsBundle,
|
||||
blobsBundle: blobsBundle.get,
|
||||
shouldOverrideBuilder: false
|
||||
)
|
||||
|
||||
|
@ -87,37 +78,24 @@ proc getPayloadV4*(ben: BeaconEngineRef, id: PayloadID): GetPayloadV4Response =
|
|||
|
||||
var payloadGeneric: ExecutionPayload
|
||||
var blockValue: UInt256
|
||||
if not ben.get(id, blockValue, payloadGeneric):
|
||||
var blobsBundle: Option[BlobsBundleV1]
|
||||
if not ben.get(id, blockValue, payloadGeneric, blobsBundle):
|
||||
raise unknownPayload("Unknown payload")
|
||||
|
||||
let version = payloadGeneric.version
|
||||
if version != Version.V4:
|
||||
raise unsupportedFork("getPayloadV4 expect ExecutionPayloadV4 but get ExecutionPayload" & $version)
|
||||
if blobsBundle.isNone:
|
||||
raise unsupportedFork("getPayloadV4 is missing BlobsBundleV1")
|
||||
|
||||
let payload = payloadGeneric.V4
|
||||
let com = ben.com
|
||||
if not com.isPragueOrLater(ethTime payload.timestamp):
|
||||
raise unsupportedFork("payload timestamp is less than Prague activation")
|
||||
|
||||
var
|
||||
blobsBundle: BlobsBundleV1
|
||||
|
||||
try:
|
||||
for ttx in payload.transactions:
|
||||
let tx = rlp.decode(distinctBase(ttx), Transaction)
|
||||
if tx.networkPayload.isNil.not:
|
||||
for blob in tx.networkPayload.blobs:
|
||||
blobsBundle.blobs.add Web3Blob(blob)
|
||||
for p in tx.networkPayload.proofs:
|
||||
blobsBundle.proofs.add Web3KZGProof(p)
|
||||
for k in tx.networkPayload.commitments:
|
||||
blobsBundle.commitments.add Web3KZGCommitment(k)
|
||||
except RlpError:
|
||||
doAssert(false, "found TypedTransaction that RLP failed to decode")
|
||||
|
||||
GetPayloadV4Response(
|
||||
executionPayload: payload,
|
||||
blockValue: blockValue,
|
||||
blobsBundle: blobsBundle,
|
||||
blobsBundle: blobsBundle.get,
|
||||
shouldOverrideBuilder: false
|
||||
)
|
||||
|
|
|
@ -118,20 +118,20 @@ proc newPayload*(ben: BeaconEngineRef,
|
|||
|
||||
validatePayload(apiVersion, version, payload)
|
||||
validateVersion(com, timestamp, version, apiVersion)
|
||||
|
||||
var header = blockHeader(payload, removeBlobs = true, beaconRoot = ethHash beaconRoot)
|
||||
|
||||
|
||||
var header = blockHeader(payload, beaconRoot = ethHash beaconRoot)
|
||||
|
||||
if apiVersion >= Version.V3:
|
||||
if versionedHashes.isNone:
|
||||
raise invalidParams("newPayload" & $apiVersion &
|
||||
" expect blobVersionedHashes but got none")
|
||||
if not validateVersionedHashed(payload, versionedHashes.get):
|
||||
return invalidStatus(header.parentHash, "invalid blob versionedHashes")
|
||||
|
||||
|
||||
let blockHash = ethHash payload.blockHash
|
||||
header.validateBlockHash(blockHash, version).isOkOr:
|
||||
return error
|
||||
|
||||
|
||||
# If we already have the block locally, ignore the entire execution and just
|
||||
# return a fake success.
|
||||
if db.getBlockHeader(blockHash, header):
|
||||
|
@ -195,7 +195,7 @@ proc newPayload*(ben: BeaconEngineRef,
|
|||
|
||||
trace "Inserting block without sethead",
|
||||
hash = blockHash, number = header.blockNumber
|
||||
let body = blockBody(payload, removeBlobs = true)
|
||||
let body = blockBody(payload)
|
||||
let vres = ben.chain.insertBlockWithoutSetHead(header, body)
|
||||
if vres != ValidationResult.OK:
|
||||
let blockHash = latestValidHash(db, parent, ttd)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
# those terms.
|
||||
|
||||
import
|
||||
std/sequtils,
|
||||
./web3_eth_conv,
|
||||
./payload_conv,
|
||||
web3/execution_types,
|
||||
|
@ -80,12 +81,22 @@ proc put*(ben: BeaconEngineRef,
|
|||
ben.queue.put(hash, header)
|
||||
|
||||
proc put*(ben: BeaconEngineRef, id: PayloadID,
|
||||
blockValue: UInt256, payload: ExecutionPayload) =
|
||||
ben.queue.put(id, blockValue, payload)
|
||||
blockValue: UInt256, payload: ExecutionPayload,
|
||||
blobsBundle: Option[BlobsBundleV1]) =
|
||||
ben.queue.put(id, blockValue, payload, blobsBundle)
|
||||
|
||||
proc put*(ben: BeaconEngineRef, id: PayloadID,
|
||||
blockValue: UInt256, payload: SomeExecutionPayload) =
|
||||
ben.queue.put(id, blockValue, payload)
|
||||
blockValue: UInt256, payload: SomeExecutionPayload,
|
||||
blobsBundle: Option[BlobsBundleV1]) =
|
||||
doAssert blobsBundle.isNone == (payload is
|
||||
ExecutionPayloadV1 | ExecutionPayloadV2)
|
||||
ben.queue.put(id, blockValue, payload, blobsBundle)
|
||||
|
||||
proc put*(ben: BeaconEngineRef, id: PayloadID,
|
||||
blockValue: UInt256,
|
||||
payload: ExecutionPayloadV1 | ExecutionPayloadV2) =
|
||||
ben.queue.put(
|
||||
id, blockValue, payload, blobsBundle = options.none(BlobsBundleV1))
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, getters
|
||||
|
@ -115,8 +126,9 @@ proc get*(ben: BeaconEngineRef, hash: common.Hash256,
|
|||
|
||||
proc get*(ben: BeaconEngineRef, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
payload: var ExecutionPayload): bool =
|
||||
ben.queue.get(id, blockValue, payload)
|
||||
payload: var ExecutionPayload,
|
||||
blobsBundle: var Option[BlobsBundleV1]): bool =
|
||||
ben.queue.get(id, blockValue, payload, blobsBundle)
|
||||
|
||||
proc get*(ben: BeaconEngineRef, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
|
@ -130,8 +142,9 @@ proc get*(ben: BeaconEngineRef, id: PayloadID,
|
|||
|
||||
proc get*(ben: BeaconEngineRef, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
payload: var ExecutionPayloadV3): bool =
|
||||
ben.queue.get(id, blockValue, payload)
|
||||
payload: var ExecutionPayloadV3,
|
||||
blobsBundle: var BlobsBundleV1): bool =
|
||||
ben.queue.get(id, blockValue, payload, blobsBundle)
|
||||
|
||||
proc get*(ben: BeaconEngineRef, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
|
@ -142,9 +155,13 @@ proc get*(ben: BeaconEngineRef, id: PayloadID,
|
|||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
type ExecutionPayloadAndBlobsBundle* = object
|
||||
executionPayload*: ExecutionPayload
|
||||
blobsBundle*: Option[BlobsBundleV1]
|
||||
|
||||
proc generatePayload*(ben: BeaconEngineRef,
|
||||
attrs: PayloadAttributes):
|
||||
Result[ExecutionPayload, string] =
|
||||
Result[ExecutionPayloadAndBlobsBundle, string] =
|
||||
wrapException:
|
||||
let
|
||||
xp = ben.txPool
|
||||
|
@ -168,12 +185,22 @@ proc generatePayload*(ben: BeaconEngineRef,
|
|||
if pos.timestamp <= headBlock.timestamp:
|
||||
return err "timestamp must be strictly later than parent"
|
||||
|
||||
# someBaseFee = true: make sure blk.header
|
||||
# someBaseFee = true: make sure bundle.blk.header
|
||||
# have the same blockHash with generated payload
|
||||
let blk = xp.assembleBlock(someBaseFee = true).valueOr:
|
||||
let bundle = xp.assembleBlock(someBaseFee = true).valueOr:
|
||||
return err(error)
|
||||
|
||||
if blk.header.extraData.len > 32:
|
||||
if bundle.blk.header.extraData.len > 32:
|
||||
return err "extraData length should not exceed 32 bytes"
|
||||
|
||||
ok(executionPayload(blk))
|
||||
var blobsBundle: Option[BlobsBundleV1]
|
||||
if bundle.blobsBundle.isSome:
|
||||
template blobData: untyped = bundle.blobsBundle.get
|
||||
blobsBundle = options.some BlobsBundleV1(
|
||||
commitments: blobData.commitments.mapIt it.Web3KZGCommitment,
|
||||
proofs: blobData.proofs.mapIt it.Web3KZGProof,
|
||||
blobs: blobData.blobs.mapIt it.Web3Blob)
|
||||
|
||||
ok ExecutionPayloadAndBlobsBundle(
|
||||
executionPayload: executionPayload(bundle.blk),
|
||||
blobsBundle: blobsBundle)
|
||||
|
|
|
@ -28,10 +28,10 @@ func wdRoot(x: Option[seq[WithdrawalV1]]): Option[common.Hash256]
|
|||
if x.isNone: none(common.Hash256)
|
||||
else: some(wdRoot x.get)
|
||||
|
||||
func txRoot(list: openArray[Web3Tx], removeBlobs: bool): common.Hash256
|
||||
func txRoot(list: openArray[Web3Tx]): common.Hash256
|
||||
{.gcsafe, raises:[RlpError].} =
|
||||
{.noSideEffect.}:
|
||||
calcTxRoot(ethTxs(list, removeBlobs))
|
||||
calcTxRoot(ethTxs(list))
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
|
@ -80,15 +80,14 @@ func executionPayloadV1V2*(blk: EthBlock): ExecutionPayloadV1OrV2 =
|
|||
)
|
||||
|
||||
func blockHeader*(p: ExecutionPayload,
|
||||
removeBlobs: bool,
|
||||
beaconRoot: Option[common.Hash256]):
|
||||
common.BlockHeader {.gcsafe, raises:[CatchableError].} =
|
||||
common.BlockHeader {.gcsafe, raises:[CatchableError].} =
|
||||
common.BlockHeader(
|
||||
parentHash : ethHash p.parentHash,
|
||||
ommersHash : EMPTY_UNCLE_HASH,
|
||||
coinbase : ethAddr p.feeRecipient,
|
||||
stateRoot : ethHash p.stateRoot,
|
||||
txRoot : txRoot(p.transactions, removeBlobs),
|
||||
txRoot : txRoot p.transactions,
|
||||
receiptRoot : ethHash p.receiptsRoot,
|
||||
bloom : ethBloom p.logsBloom,
|
||||
difficulty : 0.u256,
|
||||
|
@ -106,21 +105,20 @@ func blockHeader*(p: ExecutionPayload,
|
|||
parentBeaconBlockRoot: beaconRoot
|
||||
)
|
||||
|
||||
func blockBody*(p: ExecutionPayload, removeBlobs: bool):
|
||||
common.BlockBody {.gcsafe, raises:[RlpError].} =
|
||||
func blockBody*(p: ExecutionPayload):
|
||||
common.BlockBody {.gcsafe, raises:[RlpError].} =
|
||||
common.BlockBody(
|
||||
uncles : @[],
|
||||
transactions: ethTxs(p.transactions, removeBlobs),
|
||||
transactions: ethTxs p.transactions,
|
||||
withdrawals : ethWithdrawals p.withdrawals,
|
||||
)
|
||||
|
||||
func ethBlock*(p: ExecutionPayload,
|
||||
removeBlobs: bool,
|
||||
beaconRoot: Option[common.Hash256]):
|
||||
common.EthBlock {.gcsafe, raises:[CatchableError].} =
|
||||
common.Ethblock(
|
||||
header : blockHeader(p, removeBlobs, beaconRoot),
|
||||
common.EthBlock(
|
||||
header : blockHeader(p, beaconRoot),
|
||||
uncles : @[],
|
||||
txs : ethTxs(p.transactions, removeBlobs),
|
||||
txs : ethTxs p.transactions,
|
||||
withdrawals: ethWithdrawals p.withdrawals,
|
||||
)
|
||||
|
|
|
@ -35,6 +35,7 @@ type
|
|||
id: PayloadID
|
||||
payload: ExecutionPayload
|
||||
blockValue: UInt256
|
||||
blobsBundle: Option[BlobsBundleV1]
|
||||
|
||||
HeaderItem = object
|
||||
hash: common.Hash256
|
||||
|
@ -71,13 +72,22 @@ proc put*(api: var PayloadQueue,
|
|||
api.headerQueue.put(HeaderItem(hash: hash, header: header))
|
||||
|
||||
proc put*(api: var PayloadQueue, id: PayloadID,
|
||||
blockValue: UInt256, payload: ExecutionPayload) =
|
||||
blockValue: UInt256, payload: ExecutionPayload,
|
||||
blobsBundle: Option[BlobsBundleV1]) =
|
||||
api.payloadQueue.put(PayloadItem(id: id,
|
||||
payload: payload, blockValue: blockValue))
|
||||
payload: payload, blockValue: blockValue, blobsBundle: blobsBundle))
|
||||
|
||||
proc put*(api: var PayloadQueue, id: PayloadID,
|
||||
blockValue: UInt256, payload: SomeExecutionPayload) =
|
||||
api.put(id, blockValue, payload.executionPayload)
|
||||
blockValue: UInt256, payload: SomeExecutionPayload,
|
||||
blobsBundle: Option[BlobsBundleV1]) =
|
||||
doAssert blobsBundle.isNone == (payload is
|
||||
ExecutionPayloadV1 | ExecutionPayloadV2)
|
||||
api.put(id, blockValue, payload.executionPayload, blobsBundle: blobsBundle)
|
||||
|
||||
proc put*(api: var PayloadQueue, id: PayloadID,
|
||||
blockValue: UInt256,
|
||||
payload: ExecutionPayloadV1 | ExecutionPayloadV2) =
|
||||
api.put(id, blockValue, payload, blobsBundle = options.none(BlobsBundleV1))
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, getters
|
||||
|
@ -93,46 +103,66 @@ proc get*(api: PayloadQueue, hash: common.Hash256,
|
|||
|
||||
proc get*(api: PayloadQueue, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
payload: var ExecutionPayload): bool =
|
||||
payload: var ExecutionPayload,
|
||||
blobsBundle: var Option[BlobsBundleV1]): bool =
|
||||
for x in api.payloadQueue:
|
||||
if x.id == id:
|
||||
payload = x.payload
|
||||
blockValue = x.blockValue
|
||||
blobsBundle = x.blobsBundle
|
||||
return true
|
||||
false
|
||||
|
||||
proc get*(api: PayloadQueue, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
payload: var ExecutionPayloadV1): bool =
|
||||
var p: ExecutionPayload
|
||||
let found = api.get(id, blockValue, p)
|
||||
doAssert(p.version == Version.V1)
|
||||
payload = p.V1
|
||||
var
|
||||
p: ExecutionPayload
|
||||
blobsBundleOpt: Option[BlobsBundleV1]
|
||||
let found = api.get(id, blockValue, p, blobsBundleOpt)
|
||||
if found:
|
||||
doAssert(p.version == Version.V1)
|
||||
payload = p.V1
|
||||
doAssert(blobsBundleOpt.isNone)
|
||||
return found
|
||||
|
||||
proc get*(api: PayloadQueue, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
payload: var ExecutionPayloadV2): bool =
|
||||
var p: ExecutionPayload
|
||||
let found = api.get(id, blockValue, p)
|
||||
doAssert(p.version == Version.V2)
|
||||
payload = p.V2
|
||||
var
|
||||
p: ExecutionPayload
|
||||
blobsBundleOpt: Option[BlobsBundleV1]
|
||||
let found = api.get(id, blockValue, p, blobsBundleOpt)
|
||||
if found:
|
||||
doAssert(p.version == Version.V2)
|
||||
payload = p.V2
|
||||
doAssert(blobsBundleOpt.isNone)
|
||||
return found
|
||||
|
||||
proc get*(api: PayloadQueue, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
payload: var ExecutionPayloadV3): bool =
|
||||
var p: ExecutionPayload
|
||||
let found = api.get(id, blockValue, p)
|
||||
doAssert(p.version == Version.V3)
|
||||
payload = p.V3
|
||||
payload: var ExecutionPayloadV3,
|
||||
blobsBundle: var BlobsBundleV1): bool =
|
||||
var
|
||||
p: ExecutionPayload
|
||||
blobsBundleOpt: Option[BlobsBundleV1]
|
||||
let found = api.get(id, blockValue, p, blobsBundleOpt)
|
||||
if found:
|
||||
doAssert(p.version == Version.V3)
|
||||
payload = p.V3
|
||||
doAssert(blobsBundleOpt.isSome)
|
||||
blobsBundle = blobsBundleOpt.unsafeGet
|
||||
return found
|
||||
|
||||
proc get*(api: PayloadQueue, id: PayloadID,
|
||||
blockValue: var UInt256,
|
||||
payload: var ExecutionPayloadV1OrV2): bool =
|
||||
var p: ExecutionPayload
|
||||
let found = api.get(id, blockValue, p)
|
||||
doAssert(p.version in {Version.V1, Version.V2})
|
||||
payload = p.V1V2
|
||||
var
|
||||
p: ExecutionPayload
|
||||
blobsBundleOpt: Option[BlobsBundleV1]
|
||||
let found = api.get(id, blockValue, p, blobsBundleOpt)
|
||||
if found:
|
||||
doAssert(p.version in {Version.V1, Version.V2})
|
||||
payload = p.V1V2
|
||||
doAssert(blobsBundleOpt.isNone)
|
||||
return found
|
||||
|
|
|
@ -151,15 +151,11 @@ func ethWithdrawals*(x: Option[seq[WithdrawalV1]]):
|
|||
func ethTx*(x: Web3Tx): common.Transaction {.gcsafe, raises:[RlpError].} =
|
||||
result = rlp.decode(distinctBase x, common.Transaction)
|
||||
|
||||
func ethTxs*(list: openArray[Web3Tx], removeBlobs = false):
|
||||
func ethTxs*(list: openArray[Web3Tx]):
|
||||
seq[common.Transaction] {.gcsafe, raises:[RlpError].} =
|
||||
result = newSeqOfCap[common.Transaction](list.len)
|
||||
if removeBlobs:
|
||||
for x in list:
|
||||
result.add ethTx(x).removeNetworkPayload
|
||||
else:
|
||||
for x in list:
|
||||
result.add ethTx(x)
|
||||
for x in list:
|
||||
result.add ethTx(x)
|
||||
|
||||
func storageKeys(list: seq[FixedBytes[32]]): seq[StorageKey] =
|
||||
for x in list:
|
||||
|
|
|
@ -167,17 +167,17 @@ func validateEip4844Header*(
|
|||
|
||||
return ok()
|
||||
|
||||
proc validateBlobTransactionWrapper*(tx: Transaction):
|
||||
proc validateBlobTransactionWrapper*(tx: PooledTransaction):
|
||||
Result[void, string] {.raises: [].} =
|
||||
if tx.networkPayload.isNil:
|
||||
return err("tx wrapper is none")
|
||||
|
||||
# note: assert blobs are not malformatted
|
||||
let goodFormatted = tx.versionedHashes.len ==
|
||||
let goodFormatted = tx.tx.versionedHashes.len ==
|
||||
tx.networkPayload.commitments.len and
|
||||
tx.versionedHashes.len ==
|
||||
tx.tx.versionedHashes.len ==
|
||||
tx.networkPayload.blobs.len and
|
||||
tx.versionedHashes.len ==
|
||||
tx.tx.versionedHashes.len ==
|
||||
tx.networkPayload.proofs.len
|
||||
|
||||
if not goodFormatted:
|
||||
|
@ -194,12 +194,13 @@ proc validateBlobTransactionWrapper*(tx: Transaction):
|
|||
return err("Failed to verify network payload of a transaction")
|
||||
|
||||
# Now that all commitments have been verified, check that versionedHashes matches the commitments
|
||||
for i in 0 ..< tx.versionedHashes.len:
|
||||
for i in 0 ..< tx.tx.versionedHashes.len:
|
||||
# this additional check also done in tx validation
|
||||
if tx.versionedHashes[i].data[0] != VERSIONED_HASH_VERSION_KZG:
|
||||
if tx.tx.versionedHashes[i].data[0] != VERSIONED_HASH_VERSION_KZG:
|
||||
return err("wrong kzg version in versioned hash at index " & $i)
|
||||
|
||||
if tx.versionedHashes[i] != kzgToVersionedHash(tx.networkPayload.commitments[i]):
|
||||
if tx.tx.versionedHashes[i] !=
|
||||
kzgToVersionedHash(tx.networkPayload.commitments[i]):
|
||||
return err("tx versioned hash not match commitments at index " & $i)
|
||||
|
||||
ok()
|
||||
|
|
|
@ -61,8 +61,9 @@ proc validateSealer*(conf: NimbusConf, ctx: EthContext, chain: ChainRef): Result
|
|||
proc generateBlock(engine: SealingEngineRef,
|
||||
outBlock: var EthBlock): Result[void, string] =
|
||||
|
||||
outBlock = engine.txPool.assembleBlock().valueOr:
|
||||
let bundle = engine.txPool.assembleBlock().valueOr:
|
||||
return err(error)
|
||||
outBlock = bundle.blk
|
||||
|
||||
if engine.chain.com.consensus == ConsensusType.POS:
|
||||
# Stop the block generator if we reach TTD
|
||||
|
|
|
@ -423,7 +423,7 @@
|
|||
##
|
||||
|
||||
import
|
||||
std/[sequtils, tables],
|
||||
std/[options, sequtils, tables],
|
||||
./tx_pool/[tx_chain, tx_desc, tx_info, tx_item],
|
||||
./tx_pool/tx_tabs,
|
||||
./tx_pool/tx_tasks/[
|
||||
|
@ -517,7 +517,7 @@ proc new*(T: type TxPoolRef; com: CommonRef; miner: EthAddress): T
|
|||
|
||||
# core/tx_pool.go(848): func (pool *TxPool) AddLocals(txs []..
|
||||
# core/tx_pool.go(864): func (pool *TxPool) AddRemotes(txs []..
|
||||
proc add*(xp: TxPoolRef; txs: openArray[Transaction]; info = "")
|
||||
proc add*(xp: TxPoolRef; txs: openArray[PooledTransaction]; info = "")
|
||||
{.gcsafe,raises: [CatchableError].} =
|
||||
## Add a list of transactions to be processed and added to the buckets
|
||||
## database. It is OK pass an empty list in which case some maintenance
|
||||
|
@ -533,7 +533,7 @@ proc add*(xp: TxPoolRef; txs: openArray[Transaction]; info = "")
|
|||
|
||||
# core/tx_pool.go(854): func (pool *TxPool) AddLocals(txs []..
|
||||
# core/tx_pool.go(883): func (pool *TxPool) AddRemotes(txs []..
|
||||
proc add*(xp: TxPoolRef; tx: Transaction; info = "")
|
||||
proc add*(xp: TxPoolRef; tx: PooledTransaction; info = "")
|
||||
{.gcsafe,raises: [CatchableError].} =
|
||||
## Variant of `add()` for a single transaction.
|
||||
xp.add(@[tx], info)
|
||||
|
@ -607,8 +607,14 @@ proc dirtyBuckets*(xp: TxPoolRef): bool =
|
|||
## flag is also set.
|
||||
xp.pDirtyBuckets
|
||||
|
||||
proc assembleBlock*(xp: TxPoolRef, someBaseFee: bool = false): Result[EthBlock, string]
|
||||
{.gcsafe,raises: [CatchableError].} =
|
||||
type EthBlockAndBlobsBundle* = object
|
||||
blk*: EthBlock
|
||||
blobsBundle*: Option[BlobsBundle]
|
||||
|
||||
proc assembleBlock*(
|
||||
xp: TxPoolRef,
|
||||
someBaseFee: bool = false
|
||||
): Result[EthBlockAndBlobsBundle, string] {.gcsafe,raises: [CatchableError].} =
|
||||
## Getter, retrieves a packed block ready for mining and signing depending
|
||||
## on the internally cached block chain head, the txs in the pool and some
|
||||
## tuning parameters. The following block header fields are left
|
||||
|
@ -627,19 +633,40 @@ proc assembleBlock*(xp: TxPoolRef, someBaseFee: bool = false): Result[EthBlock,
|
|||
var blk = EthBlock(
|
||||
header: xp.chain.getHeader # uses updated vmState
|
||||
)
|
||||
var blobsBundle: BlobsBundle
|
||||
|
||||
for (_,nonceList) in xp.txDB.packingOrderAccounts(txItemPacked):
|
||||
blk.txs.add toSeq(nonceList.incNonce).mapIt(it.tx)
|
||||
for item in nonceList.incNonce:
|
||||
let tx = item.pooledTx
|
||||
blk.txs.add tx.tx
|
||||
for k in tx.networkPayload.commitments:
|
||||
blobsBundle.commitments.add k
|
||||
for p in tx.networkPayload.proofs:
|
||||
blobsBundle.proofs.add p
|
||||
for blob in tx.networkPayload.blobs:
|
||||
blobsBundle.blobs.add blob
|
||||
|
||||
let com = xp.chain.com
|
||||
if com.forkGTE(Shanghai):
|
||||
blk.withdrawals = some(com.pos.withdrawals)
|
||||
|
||||
if not com.forkGTE(Cancun) and blobsBundle.commitments.len > 0:
|
||||
return err("PooledTransaction contains blobs prior to Cancun")
|
||||
let blobsBundleOpt =
|
||||
if com.forkGTE(Cancun):
|
||||
doAssert blobsBundle.commitments.len == blobsBundle.blobs.len
|
||||
doAssert blobsBundle.proofs.len == blobsBundle.blobs.len
|
||||
options.some blobsBundle
|
||||
else:
|
||||
options.none BlobsBundle
|
||||
|
||||
if someBaseFee:
|
||||
# make sure baseFee always has something
|
||||
blk.header.fee = some(blk.header.fee.get(0.u256))
|
||||
|
||||
ok(blk)
|
||||
ok EthBlockAndBlobsBundle(
|
||||
blk: blk,
|
||||
blobsBundle: blobsBundleOpt)
|
||||
|
||||
proc gasCumulative*(xp: TxPoolRef): GasInt =
|
||||
## Getter, retrieves the gas that will be burned in the block after
|
||||
|
@ -856,7 +883,7 @@ proc accountRanks*(xp: TxPoolRef): TxTabsLocality =
|
|||
xp.txDB.locality
|
||||
|
||||
proc addRemote*(xp: TxPoolRef;
|
||||
tx: Transaction; force = false): Result[void,TxInfo]
|
||||
tx: PooledTransaction; force = false): Result[void,TxInfo]
|
||||
{.gcsafe,raises: [CatchableError].} =
|
||||
## Adds the argument transaction `tx` to the buckets database.
|
||||
##
|
||||
|
@ -890,7 +917,7 @@ proc addRemote*(xp: TxPoolRef;
|
|||
ok()
|
||||
|
||||
proc addLocal*(xp: TxPoolRef;
|
||||
tx: Transaction; force = false): Result[void,TxInfo]
|
||||
tx: PooledTransaction; force = false): Result[void,TxInfo]
|
||||
{.gcsafe,raises: [CatchableError].} =
|
||||
## Adds the argument transaction `tx` to the buckets database.
|
||||
##
|
||||
|
|
|
@ -42,7 +42,7 @@ type
|
|||
TxItemRef* = ref object of RootObj ##\
|
||||
## Data container with transaction and meta data. Entries are *read-only*\
|
||||
## by default, for some there is a setter available.
|
||||
tx: Transaction ## Transaction data
|
||||
tx: PooledTransaction ## Transaction data
|
||||
itemID: Hash256 ## Transaction hash
|
||||
timeStamp: Time ## Time when added
|
||||
sender: EthAddress ## Sender account address
|
||||
|
@ -112,10 +112,10 @@ proc init*(item: TxItemRef; status: TxItemStatus; info: string) =
|
|||
item.timeStamp = utcTime()
|
||||
item.reject = txInfoOk
|
||||
|
||||
proc new*(T: type TxItemRef; tx: Transaction; itemID: Hash256;
|
||||
proc new*(T: type TxItemRef; tx: PooledTransaction; itemID: Hash256;
|
||||
status: TxItemStatus; info: string): Result[T,void] {.gcsafe,raises: [].} =
|
||||
## Create item descriptor.
|
||||
let rc = tx.ecRecover
|
||||
let rc = tx.tx.ecRecover
|
||||
if rc.isErr:
|
||||
return err()
|
||||
ok(T(itemID: itemID,
|
||||
|
@ -125,7 +125,7 @@ proc new*(T: type TxItemRef; tx: Transaction; itemID: Hash256;
|
|||
info: info,
|
||||
status: status))
|
||||
|
||||
proc new*(T: type TxItemRef; tx: Transaction;
|
||||
proc new*(T: type TxItemRef; tx: PooledTransaction;
|
||||
reject: TxInfo; status: TxItemStatus; info: string): T {.gcsafe,raises: [].} =
|
||||
## Create incomplete item descriptor, so meta-data can be stored (e.g.
|
||||
## for holding in the waste basket to be investigated later.)
|
||||
|
@ -150,6 +150,10 @@ proc itemID*(tx: Transaction): Hash256 =
|
|||
## Getter, transaction ID
|
||||
tx.rlpHash
|
||||
|
||||
proc itemID*(tx: PooledTransaction): Hash256 =
|
||||
## Getter, transaction ID
|
||||
tx.tx.rlpHash
|
||||
|
||||
# core/types/transaction.go(297): func (tx *Transaction) Cost() *big.Int {
|
||||
proc cost*(tx: Transaction): UInt256 =
|
||||
## Getter (go/ref compat): gas * gasPrice + value.
|
||||
|
@ -210,10 +214,14 @@ proc timeStamp*(item: TxItemRef): Time =
|
|||
## Getter
|
||||
item.timeStamp
|
||||
|
||||
proc tx*(item: TxItemRef): Transaction =
|
||||
proc pooledTx*(item: TxItemRef): PooledTransaction =
|
||||
## Getter
|
||||
item.tx
|
||||
|
||||
proc tx*(item: TxItemRef): Transaction =
|
||||
## Getter
|
||||
item.tx.tx
|
||||
|
||||
func rejectInfo*(item: TxItemRef): string =
|
||||
## Getter
|
||||
result = $item.reject
|
||||
|
|
|
@ -138,7 +138,7 @@ proc new*(T: type TxTabsRef): T {.gcsafe,raises: [].} =
|
|||
|
||||
proc insert*(
|
||||
xp: TxTabsRef;
|
||||
tx: var Transaction;
|
||||
tx: var PooledTransaction;
|
||||
status = txItemPending;
|
||||
info = ""): Result[void,TxInfo]
|
||||
{.gcsafe,raises: [CatchableError].} =
|
||||
|
@ -221,7 +221,7 @@ proc dispose*(xp: TxTabsRef; item: TxItemRef; reason: TxInfo): bool
|
|||
xp.byRejects[item.itemID] = item
|
||||
return true
|
||||
|
||||
proc reject*(xp: TxTabsRef; tx: var Transaction;
|
||||
proc reject*(xp: TxTabsRef; tx: var PooledTransaction;
|
||||
reason: TxInfo; status = txItemPending; info = "") =
|
||||
## Similar to dispose but for a tx without the item wrapper, the function
|
||||
## imports the tx into the waste basket (e.g. after it could not
|
||||
|
@ -239,7 +239,7 @@ proc reject*(xp: TxTabsRef; item: TxItemRef; reason: TxInfo) =
|
|||
item.reject = reason
|
||||
xp.byRejects[item.itemID] = item
|
||||
|
||||
proc reject*(xp: TxTabsRef; tx: Transaction;
|
||||
proc reject*(xp: TxTabsRef; tx: PooledTransaction;
|
||||
reason: TxInfo; status = txItemPending; info = "") =
|
||||
## Variant of `reject()`
|
||||
var ty = tx
|
||||
|
|
|
@ -160,7 +160,7 @@ proc addTx*(xp: TxPoolRef; item: TxItemRef): bool
|
|||
# core/tx_pool.go(883): func (pool *TxPool) AddRemotes(txs []..
|
||||
# core/tx_pool.go(889): func (pool *TxPool) addTxs(txs []*types.Transaction, ..
|
||||
proc addTxs*(xp: TxPoolRef;
|
||||
txs: openArray[Transaction]; info = ""): TxAddStats
|
||||
txs: openArray[PooledTransaction]; info = ""): TxAddStats
|
||||
{.discardable,gcsafe,raises: [CatchableError].} =
|
||||
## Add a list of transactions. The list is sorted after nonces and txs are
|
||||
## tested and stored into either of the `pending` or `staged` buckets, or
|
||||
|
@ -181,7 +181,7 @@ proc addTxs*(xp: TxPoolRef;
|
|||
for tx in txs.items:
|
||||
var reason: TxInfo
|
||||
|
||||
if tx.txType == TxEip4844:
|
||||
if tx.tx.txType == TxEip4844:
|
||||
let res = tx.validateBlobTransactionWrapper()
|
||||
if res.isErr:
|
||||
# move item to waste basket
|
||||
|
|
|
@ -38,7 +38,7 @@ logScope:
|
|||
|
||||
proc checkTxBasic(xp: TxPoolRef; item: TxItemRef): bool =
|
||||
let res = validateTxBasic(
|
||||
item.tx.removeNetworkPayload,
|
||||
item.tx,
|
||||
xp.chain.nextFork,
|
||||
# A new transaction of the next fork may be
|
||||
# coming before the fork activated
|
||||
|
@ -234,7 +234,8 @@ proc classifyValidatePacked*(xp: TxPoolRef;
|
|||
tx = item.tx.eip1559TxNormalization(xp.chain.baseFee.GasInt)
|
||||
excessBlobGas = calcExcessBlobGas(vmState.parent)
|
||||
|
||||
roDB.validateTransaction(tx.removeNetworkPayload, item.sender, gasLimit, baseFee, excessBlobGas, fork).isOk
|
||||
roDB.validateTransaction(
|
||||
tx, item.sender, gasLimit, baseFee, excessBlobGas, fork).isOk
|
||||
|
||||
proc classifyPacked*(xp: TxPoolRef; gasBurned, moreBurned: GasInt): bool =
|
||||
## Classifier for *packing* (i.e. adding up `gasUsed` values after executing
|
||||
|
|
|
@ -31,7 +31,7 @@ type
|
|||
## Diff data, txs changes that apply after changing the head\
|
||||
## insertion point of the block chain
|
||||
|
||||
addTxs*: KeyedQueue[Hash256,Transaction] ##\
|
||||
addTxs*: KeyedQueue[Hash256, PooledTransaction] ##\
|
||||
## txs to add; using a queue makes it more intuive to delete
|
||||
## items while travesing the queue in a loop.
|
||||
|
||||
|
@ -50,7 +50,13 @@ proc insert(xp: TxPoolRef; kq: TxHeadDiffRef; blockHash: Hash256)
|
|||
{.gcsafe,raises: [CatchableError].} =
|
||||
let db = xp.chain.com.db
|
||||
for tx in db.getBlockBody(blockHash).transactions:
|
||||
kq.addTxs[tx.itemID] = tx
|
||||
if tx.versionedHashes.len > 0:
|
||||
# EIP-4844 blobs are not persisted and cannot be re-broadcasted.
|
||||
# Note that it is also not possible to crete a cache in all cases,
|
||||
# as we may have never seen the actual blob sidecar while syncing.
|
||||
# Only the consensus layer persists the blob sidecar.
|
||||
continue
|
||||
kq.addTxs[tx.itemID] = PooledTransaction(tx: tx)
|
||||
|
||||
proc remove(xp: TxPoolRef; kq: TxHeadDiffRef; blockHash: Hash256)
|
||||
{.gcsafe,raises: [CatchableError].} =
|
||||
|
|
|
@ -141,7 +141,7 @@ proc runTxCommit(pst: TxPackerStateRef; item: TxItemRef; gasBurned: GasInt)
|
|||
pst.blobGasUsed += item.tx.getTotalBlobGas
|
||||
|
||||
# Update txRoot
|
||||
pst.tr.put(rlp.encode(inx), rlp.encode(item.tx.removeNetworkPayload))
|
||||
pst.tr.put(rlp.encode(inx), rlp.encode(item.tx))
|
||||
|
||||
# Add the item to the `packed` bucket. This implicitely increases the
|
||||
# receipts index `inx` at the next visit of this function.
|
||||
|
|
|
@ -35,7 +35,7 @@ let
|
|||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc recoverItem*(xp: TxPoolRef; tx: Transaction; status = txItemPending;
|
||||
proc recoverItem*(xp: TxPoolRef; tx: PooledTransaction; status = txItemPending;
|
||||
info = ""; acceptExisting = false): Result[TxItemRef,TxInfo] =
|
||||
## Recover item from waste basket or create new. It is an error if the item
|
||||
## is in the buckets database, already.
|
||||
|
|
|
@ -267,9 +267,6 @@ proc validateTxBasic*(
|
|||
"index=$1, len=$2" % [$i, $acl.storageKeys.len])
|
||||
|
||||
if tx.txType >= TxEip4844:
|
||||
if tx.networkPayload.isNil.not:
|
||||
return err("invalid tx: network payload should not appear in block validation")
|
||||
|
||||
if tx.to.isNone:
|
||||
return err("invalid tx: destination must be not empty")
|
||||
|
||||
|
|
|
@ -558,8 +558,8 @@ proc persistTransactions*(
|
|||
for idx, tx in transactions:
|
||||
let
|
||||
encodedKey = rlp.encode(idx)
|
||||
encodedTx = rlp.encode(tx.removeNetworkPayload)
|
||||
txHash = rlpHash(tx) # beware EIP-4844
|
||||
encodedTx = rlp.encode(tx)
|
||||
txHash = rlpHash(tx)
|
||||
blockKey = transactionHashToBlockKey(txHash)
|
||||
txKey: TransactionKey = (blockNumber, idx)
|
||||
mpt.merge(encodedKey, encodedTx).isOkOr:
|
||||
|
|
|
@ -1364,8 +1364,8 @@ proc sendRawTransaction(ud: RootRef, params: Args, parent: Node): RespResult {.a
|
|||
let ctx = GraphqlContextRef(ud)
|
||||
try:
|
||||
let data = hexToSeqByte(params[0].val.stringVal)
|
||||
let tx = decodeTx(data) # we want to know if it is a valid tx blob
|
||||
let txHash = rlpHash(tx) # beware EIP-4844
|
||||
let tx = decodePooledTx(data) # we want to know if it is a valid tx blob
|
||||
let txHash = rlpHash(tx)
|
||||
|
||||
ctx.txPool.add(tx)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{.push raises: [].}
|
||||
|
||||
import
|
||||
std/[times, tables, typetraits],
|
||||
std/[sequtils, times, tables, typetraits],
|
||||
json_rpc/rpcserver, stint, stew/byteutils,
|
||||
json_serialization, web3/conversions, json_serialization/std/options,
|
||||
eth/common/eth_types_json_serialization,
|
||||
|
@ -282,8 +282,27 @@ proc setupEthRpc*(
|
|||
tx = unsignedTx(data, chainDB, accDB.getNonce(address) + 1)
|
||||
eip155 = com.isEIP155(com.syncCurrent)
|
||||
signedTx = signTransaction(tx, acc.privateKey, com.chainId, eip155)
|
||||
networkPayload =
|
||||
if signedTx.txType == TxEip4844:
|
||||
if data.blobs.isNone or data.commitments.isNone or data.proofs.isNone:
|
||||
raise newException(ValueError, "EIP-4844 transaction needs blobs")
|
||||
if data.blobs.get.len != signedTx.versionedHashes.len:
|
||||
raise newException(ValueError, "Incorrect number of blobs")
|
||||
if data.commitments.get.len != signedTx.versionedHashes.len:
|
||||
raise newException(ValueError, "Incorrect number of commitments")
|
||||
if data.proofs.get.len != signedTx.versionedHashes.len:
|
||||
raise newException(ValueError, "Incorrect number of proofs")
|
||||
NetworkPayload(
|
||||
blobs: data.blobs.get.mapIt it.NetworkBlob,
|
||||
commitments: data.commitments.get.mapIt eth_types.KzgCommitment(it),
|
||||
proofs: data.proofs.get.mapIt eth_types.KzgProof(it))
|
||||
else:
|
||||
if data.blobs.isSome or data.commitments.isSome or data.proofs.isSome:
|
||||
raise newException(ValueError, "Blobs require EIP-4844 transaction")
|
||||
nil
|
||||
pooledTx = PooledTransaction(tx: signedTx, networkPayload: networkPayload)
|
||||
|
||||
txPool.add(signedTx)
|
||||
txPool.add(pooledTx)
|
||||
result = rlpHash(signedTx).w3Hash
|
||||
|
||||
server.rpc("eth_sendRawTransaction") do(txBytes: seq[byte]) -> Web3Hash:
|
||||
|
@ -293,10 +312,10 @@ proc setupEthRpc*(
|
|||
## Returns the transaction hash, or the zero hash if the transaction is not yet available.
|
||||
## Note: Use eth_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.
|
||||
let
|
||||
signedTx = decodeTx(txBytes)
|
||||
txHash = rlpHash(signedTx)
|
||||
pooledTx = decodePooledTx(txBytes)
|
||||
txHash = rlpHash(pooledTx)
|
||||
|
||||
txPool.add(signedTx)
|
||||
txPool.add(pooledTx)
|
||||
let res = txPool.inPoolAndReason(txHash)
|
||||
if res.isErr:
|
||||
raise newException(ValueError, res.error)
|
||||
|
|
|
@ -442,14 +442,14 @@ method getReceipts*(ctx: EthWireRef,
|
|||
|
||||
method getPooledTxs*(ctx: EthWireRef,
|
||||
hashes: openArray[Hash256]):
|
||||
Result[seq[Transaction], string]
|
||||
Result[seq[PooledTransaction], string]
|
||||
{.gcsafe.} =
|
||||
let txPool = ctx.txPool
|
||||
var list: seq[Transaction]
|
||||
var list: seq[PooledTransaction]
|
||||
for txHash in hashes:
|
||||
let res = txPool.getItem(txHash)
|
||||
if res.isOk:
|
||||
list.add res.value.tx
|
||||
list.add res.value.pooledTx
|
||||
else:
|
||||
trace "handlers.getPooledTxs: tx not found", txHash
|
||||
ok(list)
|
||||
|
@ -522,7 +522,11 @@ method handleAnnouncedTxs*(ctx: EthWireRef,
|
|||
txHashes.add rlpHash(tx)
|
||||
|
||||
ctx.addToKnownByPeer(txHashes, peer)
|
||||
ctx.txPool.add(txs)
|
||||
for tx in txs:
|
||||
if tx.versionedHashes.len > 0:
|
||||
# EIP-4844 blobs are not persisted and cannot be broadcasted
|
||||
continue
|
||||
ctx.txPool.add PooledTransaction(tx: tx)
|
||||
|
||||
var newTxHashes = newSeqOfCap[Hash256](txHashes.len)
|
||||
var validTxs = newSeqOfCap[Transaction](txHashes.len)
|
||||
|
|
|
@ -65,7 +65,7 @@ method getReceipts*(ctx: EthWireBase,
|
|||
|
||||
method getPooledTxs*(ctx: EthWireBase,
|
||||
hashes: openArray[Hash256]):
|
||||
Result[seq[Transaction], string]
|
||||
Result[seq[PooledTransaction], string]
|
||||
{.base, gcsafe.} =
|
||||
notImplemented("getPooledTxs")
|
||||
|
||||
|
|
|
@ -266,7 +266,8 @@ p2pProtocol eth66(version = ethVersion,
|
|||
await response.send(txs.get)
|
||||
|
||||
# User message 0x0a: PooledTransactions.
|
||||
proc pooledTransactions(peer: Peer, transactions: openArray[Transaction])
|
||||
proc pooledTransactions(
|
||||
peer: Peer, transactions: openArray[PooledTransaction])
|
||||
|
||||
nextId 0x0d
|
||||
|
||||
|
|
|
@ -267,7 +267,8 @@ p2pProtocol eth67(version = ethVersion,
|
|||
await response.send(txs.get)
|
||||
|
||||
# User message 0x0a: PooledTransactions.
|
||||
proc pooledTransactions(peer: Peer, transactions: openArray[Transaction])
|
||||
proc pooledTransactions(
|
||||
peer: Peer, transactions: openArray[PooledTransaction])
|
||||
|
||||
# User message 0x0d: GetNodeData -- removed, was so 66ish
|
||||
# User message 0x0e: NodeData -- removed, was so 66ish
|
||||
|
|
|
@ -270,7 +270,8 @@ p2pProtocol eth68(version = ethVersion,
|
|||
await response.send(txs.get)
|
||||
|
||||
# User message 0x0a: PooledTransactions.
|
||||
proc pooledTransactions(peer: Peer, transactions: openArray[Transaction])
|
||||
proc pooledTransactions(
|
||||
peer: Peer, transactions: openArray[PooledTransaction])
|
||||
|
||||
# User message 0x0d: GetNodeData -- removed, was so 66ish
|
||||
# User message 0x0e: NodeData -- removed, was so 66ish
|
||||
|
|
|
@ -233,3 +233,9 @@ proc decodeTx*(bytes: openArray[byte]): Transaction =
|
|||
result = rlp.read(Transaction)
|
||||
if rlp.hasData:
|
||||
raise newException(RlpError, "rlp: input contains more than one value")
|
||||
|
||||
proc decodePooledTx*(bytes: openArray[byte]): PooledTransaction =
|
||||
var rlp = rlpFromBytes(bytes)
|
||||
result = rlp.read(PooledTransaction)
|
||||
if rlp.hasData:
|
||||
raise newException(RlpError, "rlp: input contains more than one value")
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d8209f623f837d14c43a9e3fd464b0e199c5d180
|
||||
Subproject commit a662fc1aa70c48c8ab9c18c6a25b1d8578925c3e
|
|
@ -1 +1 @@
|
|||
Subproject commit 9620fee53f630efcc4b6a2c0cd9f22bfcb376928
|
||||
Subproject commit de87f860874be944cdc3dfd08765c687fff736c4
|
Loading…
Reference in New Issue