Introduce wrapper type for EIP-4844 transactions (#682)

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:
Etan Kissling 2024-05-13 11:19:00 +03:00 committed by GitHub
parent 4cd9e27c09
commit c482b4c5b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 226 additions and 183 deletions

View File

@ -1,4 +1,4 @@
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -75,10 +75,6 @@ type
TxEip1559 # 2 TxEip1559 # 2
TxEip4844 # 3 TxEip4844 # 3
# instead of wrap Transaction with
# NetworkPayload, we embed it to Transaction
# the rest of magic happened in RLP
# encoding decoding
NetworkPayload* = ref object NetworkPayload* = ref object
blobs* : seq[NetworkBlob] blobs* : seq[NetworkBlob]
commitments* : seq[KzgCommitment] commitments* : seq[KzgCommitment]
@ -98,10 +94,13 @@ type
accessList* : AccessList # EIP-2930 accessList* : AccessList # EIP-2930
maxFeePerBlobGas*: UInt256 # EIP-4844 maxFeePerBlobGas*: UInt256 # EIP-4844
versionedHashes*: VersionedHashes # EIP-4844 versionedHashes*: VersionedHashes # EIP-4844
networkPayload*: NetworkPayload # EIP-4844
V* : int64 V* : int64
R*, S* : UInt256 R*, S* : UInt256
PooledTransaction* = object
tx*: Transaction
networkPayload*: NetworkPayload # EIP-4844
TransactionStatus* = enum TransactionStatus* = enum
Unknown, Unknown,
Queued, Queued,
@ -176,6 +175,11 @@ type
uncles* : seq[BlockHeader] uncles* : seq[BlockHeader]
withdrawals*: Option[seq[Withdrawal]] # EIP-4895 withdrawals*: Option[seq[Withdrawal]] # EIP-4895
BlobsBundle* = object
commitments*: seq[KzgCommitment]
proofs*: seq[KzgProof]
blobs*: seq[NetworkBlob]
# TODO: Make BlockNumber a uint64 and deprecate either this or BlockHashOrNumber # TODO: Make BlockNumber a uint64 and deprecate either this or BlockHashOrNumber
HashOrNum* = object HashOrNum* = object
case isHash*: bool case isHash*: bool
@ -294,12 +298,6 @@ func destination*(tx: Transaction): EthAddress =
if tx.to.isSome: if tx.to.isSome:
return tx.to.get return tx.to.get
func removeNetworkPayload*(tx: Transaction): Transaction =
if tx.networkPayload.isNil:
return tx
result = tx
result.networkPayload = nil
func init*(T: type BlockHashOrNumber, str: string): T func init*(T: type BlockHashOrNumber, str: string): T
{.raises: [ValueError].} = {.raises: [ValueError].} =
if str.startsWith "0x": if str.startsWith "0x":
@ -330,4 +328,3 @@ func `==`*(a, b: NetworkId): bool =
func `$`*(x: NetworkId): string = func `$`*(x: NetworkId): string =
`$`(uint(x)) `$`(uint(x))

View File

@ -83,7 +83,6 @@ proc appendTxLegacy(w: var RlpWriter, tx: Transaction) =
w.append(tx.S) w.append(tx.S)
proc appendTxEip2930(w: var RlpWriter, tx: Transaction) = proc appendTxEip2930(w: var RlpWriter, tx: Transaction) =
w.append(TxEip2930)
w.startList(11) w.startList(11)
w.append(tx.chainId.uint64) w.append(tx.chainId.uint64)
w.append(tx.nonce) w.append(tx.nonce)
@ -98,7 +97,6 @@ proc appendTxEip2930(w: var RlpWriter, tx: Transaction) =
w.append(tx.S) w.append(tx.S)
proc appendTxEip1559(w: var RlpWriter, tx: Transaction) = proc appendTxEip1559(w: var RlpWriter, tx: Transaction) =
w.append(TxEip1559)
w.startList(12) w.startList(12)
w.append(tx.chainId.uint64) w.append(tx.chainId.uint64)
w.append(tx.nonce) w.append(tx.nonce)
@ -113,8 +111,7 @@ proc appendTxEip1559(w: var RlpWriter, tx: Transaction) =
w.append(tx.R) w.append(tx.R)
w.append(tx.S) w.append(tx.S)
proc appendTxEip4844Signed(w: var RlpWriter, tx: Transaction) = proc appendTxEip4844(w: var RlpWriter, tx: Transaction) =
# exclude tx type
w.startList(14) w.startList(14)
w.append(tx.chainId.uint64) w.append(tx.chainId.uint64)
w.append(tx.nonce) w.append(tx.nonce)
@ -131,25 +128,7 @@ proc appendTxEip4844Signed(w: var RlpWriter, tx: Transaction) =
w.append(tx.R) w.append(tx.R)
w.append(tx.S) w.append(tx.S)
proc appendTxEip4844Network(w: var RlpWriter, tx: Transaction) = proc appendTxPayload(w: var RlpWriter, tx: Transaction) =
# exclude tx type
# spec: rlp([tx_payload, blobs, commitments, proofs])
w.startList(4)
w.appendTxEip4844Signed(tx)
w.append(tx.networkPayload.blobs)
w.append(tx.networkPayload.commitments)
w.append(tx.networkPayload.proofs)
proc appendTxEip4844(w: var RlpWriter, tx: Transaction) =
# append the tx type first
w.append(TxEip4844)
if tx.networkPayload.isNil:
w.appendTxEip4844Signed(tx)
else:
w.appendTxEip4844Network(tx)
proc append*(w: var RlpWriter, tx: Transaction) =
case tx.txType case tx.txType
of TxLegacy: of TxLegacy:
w.appendTxLegacy(tx) w.appendTxLegacy(tx)
@ -160,6 +139,25 @@ proc append*(w: var RlpWriter, tx: Transaction) =
of TxEip4844: of TxEip4844:
w.appendTxEip4844(tx) w.appendTxEip4844(tx)
proc append*(w: var RlpWriter, tx: Transaction) =
if tx.txType != TxLegacy:
w.append(tx.txType)
w.appendTxPayload(tx)
proc append(w: var RlpWriter, networkPayload: NetworkPayload) =
w.append(networkPayload.blobs)
w.append(networkPayload.commitments)
w.append(networkPayload.proofs)
proc append*(w: var RlpWriter, tx: PooledTransaction) =
if tx.tx.txType != TxLegacy:
w.append(tx.tx.txType)
if tx.networkPayload != nil:
w.startList(4) # spec: rlp([tx_payload, blobs, commitments, proofs])
w.appendTxPayload(tx.tx)
if tx.networkPayload != nil:
w.append(tx.networkPayload)
template read[T](rlp: var Rlp, val: var T) = template read[T](rlp: var Rlp, val: var T) =
val = rlp.read(type val) val = rlp.read(type val)
@ -213,7 +211,8 @@ proc readTxEip1559(rlp: var Rlp, tx: var Transaction)=
rlp.read(tx.R) rlp.read(tx.R)
rlp.read(tx.S) rlp.read(tx.S)
proc readTxEip4844Signed(rlp: var Rlp, tx: var Transaction) = proc readTxEip4844(rlp: var Rlp, tx: var Transaction) =
tx.txType = TxEip4844
rlp.tryEnterList() rlp.tryEnterList()
tx.chainId = rlp.read(uint64).ChainId tx.chainId = rlp.read(uint64).ChainId
rlp.read(tx.nonce) rlp.read(tx.nonce)
@ -230,28 +229,11 @@ proc readTxEip4844Signed(rlp: var Rlp, tx: var Transaction) =
rlp.read(tx.R) rlp.read(tx.R)
rlp.read(tx.S) rlp.read(tx.S)
proc readTxEip4844Network(rlp: var Rlp, tx: var Transaction) = proc readTxType(rlp: var Rlp): TxType =
# spec: rlp([tx_payload, blobs, commitments, proofs]) if rlp.isList:
rlp.tryEnterList() raise newException(RlpTypeMismatch,
rlp.readTxEip4844Signed(tx) "Transaction type expected, but source RLP is a list")
var np = NetworkPayload()
rlp.read(np.blobs)
rlp.read(np.commitments)
rlp.read(np.proofs)
tx.networkPayload = np
proc readTxEip4844(rlp: var Rlp, tx: var Transaction) =
tx.txType = TxEip4844
let listLen = rlp.listLen
if listLen == 4:
rlp.readTxEip4844Network(tx)
elif listLen == 14:
rlp.readTxEip4844Signed(tx)
else:
raise newException(MalformedRlpError,
"Invalid EIP-4844 transaction: listLen should be in 4 or 14, got: " & $listLen)
proc readTxTyped(rlp: var Rlp, tx: var Transaction) {.inline.} =
# EIP-2718: We MUST decode the first byte as a byte, not `rlp.read(int)`. # 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) # If decoded with `rlp.read(int)`, bad transaction data (from the network)
# or even just incorrectly framed data for other reasons fails with # or even just incorrectly framed data for other reasons fails with
@ -273,22 +255,27 @@ proc readTxTyped(rlp: var Rlp, tx: var Transaction) {.inline.} =
var txVal: TxType var txVal: TxType
if checkedEnumAssign(txVal, txType): if checkedEnumAssign(txVal, txType):
case txVal: return txVal
of TxEip2930:
rlp.readTxEip2930(tx)
return
of TxEip1559:
rlp.readTxEip1559(tx)
return
of TxEip4844:
rlp.readTxEip4844(tx)
return
else:
discard
raise newException(UnsupportedRlpError, raise newException(UnsupportedRlpError,
"TypedTransaction type must be 1, 2, or 3 in this version, got " & $txType) "TypedTransaction type must be 1, 2, or 3 in this version, got " & $txType)
proc readTxPayload(rlp: var Rlp, tx: var Transaction, txType: TxType) =
case txType
of TxLegacy:
raise newException(RlpTypeMismatch,
"LegacyTransaction should not be wrapped in a list")
of TxEip2930:
rlp.readTxEip2930(tx)
of TxEip1559:
rlp.readTxEip1559(tx)
of TxEip4844:
rlp.readTxEip4844(tx)
proc readTxTyped(rlp: var Rlp, tx: var Transaction) =
let txType = rlp.readTxType()
rlp.readTxPayload(tx, txType)
proc read*(rlp: var Rlp, T: type Transaction): T = proc read*(rlp: var Rlp, T: type Transaction): T =
# Individual transactions are encoded and stored as either `RLP([fields..])` # Individual transactions are encoded and stored as either `RLP([fields..])`
# for legacy transactions, or `Type || RLP([fields..])`. Both of these # for legacy transactions, or `Type || RLP([fields..])`. Both of these
@ -299,8 +286,36 @@ proc read*(rlp: var Rlp, T: type Transaction): T =
else: else:
rlp.readTxTyped(result) rlp.readTxTyped(result)
proc read*(rlp: var Rlp, proc read(rlp: var Rlp, T: type NetworkPayload): T =
T: (type seq[Transaction]) | (type openArray[Transaction])): seq[Transaction] = result = NetworkPayload()
rlp.read(result.blobs)
rlp.read(result.commitments)
rlp.read(result.proofs)
proc readTxTyped(rlp: var Rlp, tx: var PooledTransaction) =
let
txType = rlp.readTxType()
hasNetworkPayload =
if txType == TxEip4844:
rlp.listLen == 4
else:
false
if hasNetworkPayload:
rlp.tryEnterList() # spec: rlp([tx_payload, blobs, commitments, proofs])
rlp.readTxPayload(tx.tx, txType)
if hasNetworkPayload:
rlp.read(tx.networkPayload)
proc read*(rlp: var Rlp, T: type PooledTransaction): T =
if rlp.isList:
rlp.readTxLegacy(result.tx)
else:
rlp.readTxTyped(result)
proc read*(
rlp: var Rlp,
T: (type seq[Transaction]) | (type openArray[Transaction])
): seq[Transaction] =
# In arrays (sequences), transactions are encoded as either `RLP([fields..])` # In arrays (sequences), transactions are encoded as either `RLP([fields..])`
# for legacy transactions, or `RLP(Type || RLP([fields..]))` for all typed # for legacy transactions, or `RLP(Type || RLP([fields..]))` for all typed
# transactions to date. Spot the extra `RLP(..)` blob encoding, to make it # transactions to date. Spot the extra `RLP(..)` blob encoding, to make it
@ -325,6 +340,22 @@ proc read*(rlp: var Rlp,
rr.readTxTyped(tx) rr.readTxTyped(tx)
result.add tx result.add tx
proc read*(
rlp: var Rlp,
T: (type seq[PooledTransaction]) | (type openArray[PooledTransaction])
): seq[PooledTransaction] =
if not rlp.isList:
raise newException(RlpTypeMismatch,
"PooledTransaction list expected, but source RLP is not a list")
for item in rlp:
var tx: PooledTransaction
if item.isList:
item.readTxLegacy(tx.tx)
else:
var rr = rlpFromBytes(rlp.read(Blob))
rr.readTxTyped(tx)
result.add tx
proc append*(rlpWriter: var RlpWriter, proc append*(rlpWriter: var RlpWriter,
txs: seq[Transaction] | openArray[Transaction]) {.inline.} = txs: seq[Transaction] | openArray[Transaction]) {.inline.} =
# See above about encoding arrays/sequences of transactions. # See above about encoding arrays/sequences of transactions.
@ -335,6 +366,16 @@ proc append*(rlpWriter: var RlpWriter,
else: else:
rlpWriter.append(rlp.encode(tx)) rlpWriter.append(rlp.encode(tx))
proc append*(
rlpWriter: var RlpWriter,
txs: seq[PooledTransaction] | openArray[PooledTransaction]) {.inline.} =
rlpWriter.startList(txs.len)
for tx in txs:
if tx.tx.txType == TxLegacy:
rlpWriter.append(tx)
else:
rlpWriter.append(rlp.encode(tx))
proc append*(w: var RlpWriter, rec: Receipt) = proc append*(w: var RlpWriter, rec: Receipt) =
if rec.receiptType in {Eip2930Receipt, Eip1559Receipt, Eip4844Receipt}: if rec.receiptType in {Eip2930Receipt, Eip1559Receipt, Eip4844Receipt}:
w.append(rec.receiptType.int) w.append(rec.receiptType.int)
@ -477,8 +518,8 @@ proc append*(rlpWriter: var RlpWriter, t: EthTime) {.inline.} =
proc rlpHash*[T](v: T): Hash256 = proc rlpHash*[T](v: T): Hash256 =
keccakHash(rlp.encode(v)) keccakHash(rlp.encode(v))
proc rlpHash*(tx: Transaction): Hash256 = proc rlpHash*(tx: PooledTransaction): Hash256 =
keccakHash(rlp.encode(tx.removeNetworkPayload)) keccakHash(rlp.encode(tx.tx))
func blockHash*(h: BlockHeader): KeccakHash {.inline.} = rlpHash(h) func blockHash*(h: BlockHeader): KeccakHash {.inline.} = rlpHash(h)

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -26,26 +26,29 @@ const
blob = default(NetworkBlob) blob = default(NetworkBlob)
abcdef = hexToSeqByte("abcdef") abcdef = hexToSeqByte("abcdef")
proc tx0(i: int): Transaction = proc tx0(i: int): PooledTransaction =
Transaction( PooledTransaction(
tx: Transaction(
txType: TxLegacy, txType: TxLegacy,
nonce: i.AccountNonce, nonce: i.AccountNonce,
to: recipient.some, to: recipient.some,
gasLimit: 1.GasInt, gasLimit: 1.GasInt,
gasPrice: 2.GasInt, gasPrice: 2.GasInt,
payload: abcdef) payload: abcdef))
proc tx1(i: int): Transaction = proc tx1(i: int): PooledTransaction =
Transaction( PooledTransaction(
tx: Transaction(
# Legacy tx contract creation. # Legacy tx contract creation.
txType: TxLegacy, txType: TxLegacy,
nonce: i.AccountNonce, nonce: i.AccountNonce,
gasLimit: 1.GasInt, gasLimit: 1.GasInt,
gasPrice: 2.GasInt, gasPrice: 2.GasInt,
payload: abcdef) payload: abcdef))
proc tx2(i: int): Transaction = proc tx2(i: int): PooledTransaction =
Transaction( PooledTransaction(
tx: Transaction(
# Tx with non-zero access list. # Tx with non-zero access list.
txType: TxEip2930, txType: TxEip2930,
chainId: 1.ChainId, chainId: 1.ChainId,
@ -54,10 +57,11 @@ proc tx2(i: int): Transaction =
gasLimit: 123457.GasInt, gasLimit: 123457.GasInt,
gasPrice: 10.GasInt, gasPrice: 10.GasInt,
accessList: accesses, accessList: accesses,
payload: abcdef) payload: abcdef))
proc tx3(i: int): Transaction = proc tx3(i: int): PooledTransaction =
Transaction( PooledTransaction(
tx: Transaction(
# Tx with empty access list. # Tx with empty access list.
txType: TxEip2930, txType: TxEip2930,
chainId: 1.ChainId, chainId: 1.ChainId,
@ -65,33 +69,36 @@ proc tx3(i: int): Transaction =
to: recipient.some, to: recipient.some,
gasLimit: 123457.GasInt, gasLimit: 123457.GasInt,
gasPrice: 10.GasInt, gasPrice: 10.GasInt,
payload: abcdef) payload: abcdef))
proc tx4(i: int): Transaction = proc tx4(i: int): PooledTransaction =
Transaction( PooledTransaction(
tx: Transaction(
# Contract creation with access list. # Contract creation with access list.
txType: TxEip2930, txType: TxEip2930,
chainId: 1.ChainId, chainId: 1.ChainId,
nonce: i.AccountNonce, nonce: i.AccountNonce,
gasLimit: 123457.GasInt, gasLimit: 123457.GasInt,
gasPrice: 10.GasInt, gasPrice: 10.GasInt,
accessList: accesses) accessList: accesses))
proc tx5(i: int): Transaction = proc tx5(i: int): PooledTransaction =
Transaction( PooledTransaction(
tx: Transaction(
txType: TxEip1559, txType: TxEip1559,
chainId: 1.ChainId, chainId: 1.ChainId,
nonce: i.AccountNonce, nonce: i.AccountNonce,
gasLimit: 123457.GasInt, gasLimit: 123457.GasInt,
maxPriorityFee: 42.GasInt, maxPriorityFee: 42.GasInt,
maxFee: 10.GasInt, maxFee: 10.GasInt,
accessList: accesses) accessList: accesses))
proc tx6(i: int): Transaction = proc tx6(i: int): PooledTransaction =
const const
digest = "010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014".toDigest digest = "010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014".toDigest
Transaction( PooledTransaction(
tx: Transaction(
txType: TxEip4844, txType: TxEip4844,
chainId: 1.ChainId, chainId: 1.ChainId,
nonce: i.AccountNonce, nonce: i.AccountNonce,
@ -99,19 +106,18 @@ proc tx6(i: int): Transaction =
maxPriorityFee: 42.GasInt, maxPriorityFee: 42.GasInt,
maxFee: 10.GasInt, maxFee: 10.GasInt,
accessList: accesses, accessList: accesses,
versionedHashes: @[digest], versionedHashes: @[digest]),
networkPayload: NetworkPayload( networkPayload: NetworkPayload(
blobs: @[blob], blobs: @[blob],
commitments: @[zeroG1], commitments: @[zeroG1],
proofs: @[zeroG1], proofs: @[zeroG1]))
)
)
proc tx7(i: int): Transaction = proc tx7(i: int): PooledTransaction =
const const
digest = "01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e".toDigest digest = "01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e".toDigest
Transaction( PooledTransaction(
tx: Transaction(
txType: TxEip4844, txType: TxEip4844,
chainID: 1.ChainId, chainID: 1.ChainId,
nonce: i.AccountNonce, nonce: i.AccountNonce,
@ -120,14 +126,14 @@ proc tx7(i: int): Transaction =
maxFee: 10.GasInt, maxFee: 10.GasInt,
accessList: accesses, accessList: accesses,
versionedHashes: @[digest], versionedHashes: @[digest],
maxFeePerBlobGas: 10000000.u256, maxFeePerBlobGas: 10000000.u256))
)
proc tx8(i: int): Transaction = proc tx8(i: int): PooledTransaction =
const const
digest = "01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e".toDigest digest = "01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e".toDigest
Transaction( PooledTransaction(
tx: Transaction(
txType: TxEip4844, txType: TxEip4844,
chainID: 1.ChainId, chainID: 1.ChainId,
nonce: i.AccountNonce, nonce: i.AccountNonce,
@ -137,13 +143,12 @@ proc tx8(i: int): Transaction =
maxFee: 10.GasInt, maxFee: 10.GasInt,
accessList: accesses, accessList: accesses,
versionedHashes: @[digest], versionedHashes: @[digest],
maxFeePerBlobGas: 10000000.u256, maxFeePerBlobGas: 10000000.u256))
)
template roundTrip(txFunc: untyped, i: int) = template roundTrip(txFunc: untyped, i: int) =
let tx = txFunc(i) let tx = txFunc(i)
let bytes = rlp.encode(tx) let bytes = rlp.encode(tx)
let tx2 = rlp.decode(bytes, Transaction) let tx2 = rlp.decode(bytes, PooledTransaction)
let bytes2 = rlp.encode(tx2) let bytes2 = rlp.encode(tx2)
check bytes == bytes2 check bytes == bytes2
@ -178,7 +183,7 @@ suite "Transaction RLP Encoding":
test "Network payload survive encode decode": test "Network payload survive encode decode":
let tx = tx6(10) let tx = tx6(10)
let bytes = rlp.encode(tx) let bytes = rlp.encode(tx)
let zz = rlp.decode(bytes, Transaction) let zz = rlp.decode(bytes, PooledTransaction)
check not zz.networkPayload.isNil check not zz.networkPayload.isNil
check zz.networkPayload.proofs == tx.networkPayload.proofs check zz.networkPayload.proofs == tx.networkPayload.proofs
check zz.networkPayload.blobs == tx.networkPayload.blobs check zz.networkPayload.blobs == tx.networkPayload.blobs
@ -187,21 +192,21 @@ suite "Transaction RLP Encoding":
test "No Network payload still no network payload": test "No Network payload still no network payload":
let tx = tx7(11) let tx = tx7(11)
let bytes = rlp.encode(tx) let bytes = rlp.encode(tx)
let zz = rlp.decode(bytes, Transaction) let zz = rlp.decode(bytes, PooledTransaction)
check zz.networkPayload.isNil check zz.networkPayload.isNil
test "Minimal Blob tx recipient survive encode decode": test "Minimal Blob tx recipient survive encode decode":
let tx = tx8(12) let tx = tx8(12)
let bytes = rlp.encode(tx) let bytes = rlp.encode(tx)
let zz = rlp.decode(bytes, Transaction) let zz = rlp.decode(bytes, PooledTransaction)
check zz.to.isSome check zz.tx.to.isSome
test "Tx List 0,1,2,3,4,5,6,7,8": test "Tx List 0,1,2,3,4,5,6,7,8":
let txs = @[tx0(3), tx1(3), tx2(3), tx3(3), tx4(3), let txs = @[tx0(3), tx1(3), tx2(3), tx3(3), tx4(3),
tx5(3), tx6(3), tx7(3), tx8(3)] tx5(3), tx6(3), tx7(3), tx8(3)]
let bytes = rlp.encode(txs) let bytes = rlp.encode(txs)
let zz = rlp.decode(bytes, seq[Transaction]) let zz = rlp.decode(bytes, seq[PooledTransaction])
let bytes2 = rlp.encode(zz) let bytes2 = rlp.encode(zz)
check bytes2 == bytes check bytes2 == bytes
@ -210,7 +215,7 @@ suite "Transaction RLP Encoding":
tx3(3), tx2(3), tx1(3), tx0(3)] tx3(3), tx2(3), tx1(3), tx0(3)]
let bytes = rlp.encode(txs) let bytes = rlp.encode(txs)
let zz = rlp.decode(bytes, seq[Transaction]) let zz = rlp.decode(bytes, seq[PooledTransaction])
let bytes2 = rlp.encode(zz) let bytes2 = rlp.encode(zz)
check bytes2 == bytes check bytes2 == bytes
@ -219,7 +224,7 @@ suite "Transaction RLP Encoding":
tx4(3), tx3(3), tx2(3), tx1(3)] tx4(3), tx3(3), tx2(3), tx1(3)]
let bytes = rlp.encode(txs) let bytes = rlp.encode(txs)
let zz = rlp.decode(bytes, seq[Transaction]) let zz = rlp.decode(bytes, seq[PooledTransaction])
let bytes2 = rlp.encode(zz) let bytes2 = rlp.encode(zz)
check bytes2 == bytes check bytes2 == bytes