Skip to content

Fix: zero-valued BigInt tx fields encode as non-canonical RLP (0x00)#34

Merged
mrtnetwork merged 1 commit into
mrtnetwork:mainfrom
KabaDH:fix/eth-rlp-canonical-zero-bigint
Jun 18, 2026
Merged

Fix: zero-valued BigInt tx fields encode as non-canonical RLP (0x00)#34
mrtnetwork merged 1 commit into
mrtnetwork:mainfrom
KabaDH:fix/eth-rlp-canonical-zero-bigint

Conversation

@KabaDH

@KabaDH KabaDH commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Fix: zero-valued BigInt tx fields encode as non-canonical RLP (0x00)

Summary

ETHTransactionUtils.bigintToBytes() encoded a zero BigInt as a single
0x00 byte instead of an empty byte string. RLP requires the canonical empty
form for integers, so nodes reject these transactions:

rlp: non-canonical integer (leading zero bytes), decoding into
(types.DynamicFeeTx).GasTipCap

The regression came in with the v8.0.0 bump of blockchain_utils to ^6.0.0:
bitlengthInBytes(0) changed from 0 to 1, so toBytes(0) now yields [0]
instead of []. It broke L2 transfers like Arbitrum, where
maxPriorityFeePerGas (GasTipCap) is normally 0; mainnet was unaffected
only because the tip there is effectively always > 0.

The fix guards the zero case in bigintToBytes, mirroring the guard already
present in the sibling intToBytes, so encoding is correct independent of the
dependency's internals.

Change

   static List<int> bigintToBytes(BigInt value) {
+    if (value == BigInt.zero) return [];
     final toBytes = BigintUtils.toBytes(
       value,
       length: BigintUtils.bitlengthInBytes(value),
     );

Impact

  • One centralized helper fixes every zero-able BigInt field across all tx
    types (legacy / 1559 / 2930 / 4844 / 7702 / 712) — including the commonly-zero
    EIP-7702 authorization nonce.
  • Non-zero encoding is bit-identical; decode round-trip is unaffected ([] and
    [0] both map back to 0).

Testing

Added tests in test/etherum/transaction_test.dart covering the helper and the
real Arbitrum zero-tip EIP-1559 case. They fail pre-fix, pass post-fix; the
test/etherum/ suite is green.

ETHTransactionUtils.bigintToBytes returned a single 0x00 byte for a zero
value, which RLP treats as a non-canonical integer. Nodes reject such
transactions with "rlp: non-canonical integer (leading zero bytes)".

This surfaced after bumping blockchain_utils to ^6.0.0, where
BigintUtils.bitlengthInBytes(0) now returns 1 (was 0), so toBytes(0)
yields [0] instead of []. It broke Arbitrum (and other L2) transfers
where maxPriorityFeePerGas is normally 0.

Guard zero before encoding, mirroring intToBytes. This fixes every
zero-able BigInt field across all tx types (including the commonly-zero
EIP-7702 authorization nonce).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@KabaDH

KabaDH commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Hi, @mrtnetwork ! When you have a chance, could you please take a look at #33 and #34 ?
I'd really appreciate your review. Thanks for your time!

@mrtnetwork mrtnetwork merged commit 88cc7ec into mrtnetwork:main Jun 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants