Skip to content

execution, rlp: switch total difficulty and chainID to uint256.Int#21119

Merged
yperbasis merged 20 commits into
mainfrom
yperbasis/bounty10
May 18, 2026
Merged

execution, rlp: switch total difficulty and chainID to uint256.Int#21119
yperbasis merged 20 commits into
mainfrom
yperbasis/bounty10

Conversation

@yperbasis
Copy link
Copy Markdown
Member

@yperbasis yperbasis commented May 11, 2026

Summary

Migrate total difficulty and chain ID from *big.Int to *uint256.Int (or uint256.Int) across the codebase, and drop the rlp package's reflect-based big.Int support that's no longer needed.

Total difficulty

  • On-wire / on-disk: NewBlockPacket.TD and rawdb.ReadTd / ReadTdByHash / WriteTd use uint256.Int. Wire and DB bytes are unchanged — uint256.Int encodes to the same canonical big-endian RLP as big.Int.
  • chain.Config.TerminalTotalDifficulty *uint256.Int. Existing chainspec JSON parses without changes (uint256's UnmarshalJSON accepts both unquoted decimal numbers and quoted strings); the DB-stored config round-trips through Erigon. Re-marshaling emits a quoted decimal string instead of an unquoted JSON number; Erigon reads either.
  • In-memory APIs migrated: rules.ChainHeaderReader.GetTd, ethash.ShouldReorg, headerdownload.HeaderInserter (incl. FeedHeaderFunc / FeedHeaderPoW / GetLocalTd), execmodule.ExecutionModule.GetTD, polygon ExecutionClient.GetTd, p2p.Publisher.PublishNewBlock + publishTask.td, sentry_multi_client.BroadcastNewBlock, bodydownload.BlockPropagator, ethstats.assembleBlockStats, rawdb.Transitioned, chainspec.IsChainPoS / currentTDProvider, the engineapi newPayload TD var, tracing.BlockEvent.TD, eth.NodeInfo.Difficulty, and the testFork comparator in execution/tests/blockchain_test.go.
  • Every TD summation (FeedHeaderPoW, InsertBlocks, rawdbreset snapshot fill, checkPrefetchedBlock, import_cmd.go side-chain accumulator) uses AddOverflow and surfaces overflow as an error (or a logged skip on the propagator's best-effort path) — uint256.Int.Add silently wraps, unlike big.Int.Add.

Transaction chainID

  • chain.Config.ChainID *uint256.Int and chain.Rules.ChainID *uint256.Int. Same JSON-shape concession as TerminalTotalDifficulty — existing chainspec JSON parses unchanged.
  • Transaction.SigningHash(chainID *uint256.Int) interface + 7 implementations; the 5 *SigHash structs' ChainID fields are *uint256.Int. LatestSignerForChainID and NewKeyedTransactorWithChainID take *uint256.Int directly.
  • evmtypes.BlockContext.Rules builds chain.Rules in uint256 directly (drops math/big).
  • cmd/evm/t8ntool ChainIDFlag switched from cli.Int64Flag to cli.Uint64Flag to match the type now consumed downstream.
  • Rationale for the uint256 ceiling: EIP-7702 caps authorization chain_id < 2**256; the stagnant EIP-2294 even proposes a ~2^63 chainID bound. uint256 strictly contains every chainID the protocol can use. Largest in-tree chainID is sepolia at 11,155,111.

RLP big.Int support removed

With every production TD and chainID off *big.Int, no type in this repo encodes/decodes *big.Int via the rlp package anymore. Removed:

  • exported rlp.EncodeBigInt, rlp.BigIntLen, rlp.ErrNegativeBigInt
  • reflect-based writeBigIntPtr, writeBigIntNoPtr, decodeBigInt, decodeBigIntNoPtr, the bigInt reflect type var, and the dispatch entries in makeWriter / makeDecoder
  • Stream.BigInt, Stream.decodeBigInt, encBuffer.writeBigInt, EncoderBuffer.WriteBigInt
  • the cmd/rlpgen bigIntHandle / bigIntPtrHandle code paths and the big.Int / *big.Int fields in the rlpgen testing fixture (regenerated)

The legacy ethereum/tests rlptest.json/bigint vector encodes 2^256 — above the uint256 ceiling — so TestRLP SkipLoads it with a comment citing EIP-7702 / EIP-2294. The other mediumint* vectors fit in uint256 and round-trip through translateJSON via uint256.FromBig.

JSON-RPC carve-outs (intentionally kept *hexutil.Big)

Hex-encoded JSON-RPC wire types remain *hexutil.Big (which is *big.Int under the hood) since the JSON-RPC convention is hex-encoded big numbers. Conversion to *uint256.Int happens internally at the boundary:

  • rpc/ethapi/api.go CallArgs.ChainID (and the 43 other *hexutil.Big fields in the same struct family)
  • eth_simulation args.ChainID
  • NewRPCBorTransaction chainId field on the JSON response

Introducing a hexutil.U256 shim to migrate these would be a separate refactor.

Downstream impact

  • Erigon-internal: none beyond this PR.
  • Downstream tracers implementing tracing.Hooks.OnBlockStart(event tracing.BlockEvent) against Erigon's tracing package see a compile error on event.TD if they treat it as *big.Int; one-line fix is event.TD.ToBig() at the read site.
  • Downstream importers of github.com/erigontech/erigon/execution/rlp that call the removed rlp.EncodeBigInt / rlp.BigIntLen / Stream.BigInt helpers will break; switch to the uint256 equivalents or do the conversion at the boundary.
  • admin_nodeInfo JSON output for the difficulty field shifts from an unquoted decimal number to a quoted decimal string (same shape as terminalTotalDifficulty). Most consumers treating it as a big number string already accept both.

Test plan

  • make lint — 0 issues
  • make erigon integration — clean build
  • go test -short ./... — passes locally
  • Manually verified chain.Config JSON round-trip: existing unquoted-decimal genesis input parses; new quoted-string output re-parses
  • CI

Diff size

124 files, +432 / −765 — more code removed than added.

🤖 Generated with Claude Code

yperbasis and others added 4 commits May 11, 2026 21:46
The on-wire total difficulty fits in 256 bits, so store it as a
uint256.Int directly. Decoding no longer round-trips through *big.Int,
and the encoder uses rlp.Uint256Len / rlp.EncodeUint256.

Call sites that hold a *big.Int convert at the packet boundary via
uint256.FromBig (broadcastNewBlock, publisher) — outer pipeline
signatures are left unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Moves the conversion from *big.Int to uint256.Int up to where the TD is
computed (parent TD + header difficulty in checkPrefetchedBlock), so
BroadcastNewBlock and the BlockPropagator type both take uint256.Int
directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
publishTask.td, Publisher.PublishNewBlock and the polygon p2pService
interface (plus mock) now use uint256.Int. The *big.Int -> uint256.Int
conversion moves up to polygon/sync near the GetTd call, matching the
shape of the BlockPropagator change in body_algos.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ReadTd and ReadTdByHash now return *uint256.Int; WriteTd takes
uint256.Int by value. Total difficulty fits in 256 bits and the on-disk
RLP bytes are unchanged (uint256.Int encodes to the same canonical
big-endian bytes as big.Int).

Direct rawdb callers were updated to use uint256 arithmetic where they
already had access to uint256 inputs (header.Difficulty,
checkPrefetchedBlock, reset_stages.go, exec_module.go inserter). Where
the surrounding API still hands around *big.Int (chain reader GetTd
methods, ShouldReorg, NewHeaderInserter, ethstats), the conversion sits
at the rawdb boundary via ToBig() / MustFromBig().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yperbasis yperbasis changed the title p2p/protocols/eth: switch NewBlockPacket.TD to uint256.Int Switch total difficulty to uint256.Int May 12, 2026
yperbasis and others added 5 commits May 12, 2026 12:44
Migrate total-difficulty types to *uint256.Int across internal call
surfaces:

- rules.ChainHeaderReader.GetTd and all implementations (stagedsync,
  exec, consensuschain, polygon, FakeChainReader, test mocks).
- ethash.ShouldReorg (callers convert *big.Int -> uint256.Int at the
  boundary).
- headerdownload.HeaderInserter (localTd, FeedHeaderFunc,
  FeedHeaderPoW, GetLocalTd) and the InsertHeader returnTd accumulator.
- execmodule.ExecutionModule.GetTD interface + impl, ExecModule.getTD,
  ChainReaderWriterEth1.GetTd.
- polygon ExecutionClient.GetTd and the executionClient impl.
- engineapi engine_server.go newPayload TD var (uses CmpBig against
  the *big.Int TerminalTotalDifficulty in chain.Config).
- ethstats.assembleBlockStats.

chain.Config.TerminalTotalDifficulty stays *big.Int to preserve the
existing genesis/chain-spec JSON wire shape; comparisons use
uint256.Int.CmpBig at the boundary. Tracing BlockEvent.TD remains
*big.Int (external API parity); converted in protocol/block_exec.go
and stagedsync/exec3.go.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
parentTd / currentHeadTd / importedTipTd were left as *big.Int with
round-trip conversions to uint256.Int at the ShouldReorg and WriteTd
call sites. Since rawdb.ReadTd returns *uint256.Int and ShouldReorg /
WriteTd now take uint256.Int directly, those conversions are pointless
- compute the sums natively against header.Difficulty (already
uint256.Int).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
uint256.Int.Add silently wraps on overflow (unlike big.Int.Add). Use
AddOverflow on every TD accumulation introduced by the uint256
migration:

- headerdownload.FeedHeaderPoW (parentTd + header.Difficulty)
- execmodule.InsertBlocks (parentTd + header.Difficulty)
- rawdbreset header range (running TD over snapshot headers)
- bodydownload.checkPrefetchedBlock (header.Difficulty + parent)
- cmd/utils/app/import_cmd.go (importedTipTd + Difficulty, side-chain
  td + Difficulty)

Functions with an error return propagate the overflow as an error;
the body-propagator path (no error return) logs and skips propagating
the block, matching its existing best-effort semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After the uint256 migration, no production struct uses *big.Int as an
RLP-encoded field via the code generator, so the only callers of
rlp.EncodeBigInt and rlp.BigIntLen are dead. Drop the helpers along
with the rlpgen big.Int handler and the *big.Int fields in the
rlpgen testing fixture (regenerated).

Reflect-based encoding/decoding of *big.Int (writeBigInt*, decodeBigInt,
Stream.BigInt, Stream.decodeBigInt) is kept, since the legacy
ethereum/tests RLPTests include test vectors with values >= 2^256
that don't fit in uint256.Int and the SigHash struct fields used in
transaction signing still rely on the reflect path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ig.Int RLP

Total difficulty already migrated to uint256.Int; now do the same for
transaction chainID. EIP-7702 caps chainID at < 2**256, and the
stagnant EIP-2294 even proposes ~2**63 — so a uint256 ceiling is
strictly above what the Ethereum protocol can use.

Changes:

- Transaction.SigningHash(chainID *uint256.Int) interface + 7 impls
  (LegacyTx, AccessListTx, DynamicFeeTransaction, BlobTx,
  SetCodeTransaction, BlobTxWrapper, AccountAbstractionTransaction).
- The 5 *SigHash structs' ChainID fields are now *uint256.Int, so
  RLP-encoded sig hashes no longer depend on reflect-based *big.Int.
- transaction_signing.go SignTx / SignNewTx / SenderWithContext pass
  &s.chainID (already uint256.Int) directly.
- abi/bind/auth.go and txpool test convert at the boundary via
  uint256.MustFromBig.

With chainID off *big.Int, the rlp package's reflect-based *big.Int
support is no longer needed:

- Remove EncodeBigInt / BigIntLen exported helpers (no callers).
- Remove writeBigIntPtr / writeBigIntNoPtr / encBuffer.writeBigInt /
  EncoderBuffer.WriteBigInt and the reflect dispatch in makeWriter.
- Remove decodeBigInt / decodeBigIntNoPtr / Stream.BigInt /
  Stream.decodeBigInt and the reflect dispatch in makeDecoder.
- Remove ErrNegativeBigInt and the bigInt reflect type var.
- Drop big.Int test cases / fixtures in rlp encode/decode tests.

The legacy ethereum/tests RLPTests rlptest.json/bigint vector encodes
2**256 and exceeds the new uint256 ceiling; SkipLoad it in TestRLP
with an EIP-7702 / EIP-2294 rationale comment. The other "mediumint"
fixtures fit in uint256 and round-trip through translateJSON via
uint256.FromBig.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yperbasis yperbasis changed the title Switch total difficulty to uint256.Int execution, rlp: switch TD and chainID to uint256.Int May 12, 2026
@yperbasis yperbasis requested a review from Copilot May 12, 2026 12:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates total difficulty (TD) and transaction chain ID usage from *big.Int to *uint256.Int / uint256.Int across execution, P2P, and Polygon components, and removes the execution RLP package’s reflect-based big.Int encoding/decoding support that becomes unnecessary after the migration.

Changes:

  • Switch TD plumbing (DB accessors, wire types, sync/execution APIs) to uint256 with explicit overflow handling via AddOverflow.
  • Switch transaction signing APIs and RLP signing payload fields from *big.Int chain IDs to *uint256.Int.
  • Remove big.Int support from execution/rlp and regenerate/update rlpgen fixtures and related tests.

Reviewed changes

Copilot reviewed 74 out of 75 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
txnprovider/txpool/pool_txn_parser_test.go Update tx signing-hash test to pass *uint256.Int chain ID.
rpc/jsonrpc/graphql_api.go Convert TD uint256 to big.Int for hexutil.Big JSON output.
polygon/sync/sync.go Ensure TD is present before publishing; pass TD by value.
polygon/sync/p2p_service.go Update Polygon sync P2P service interface to TD uint256.Int.
polygon/sync/p2p_service_mock.go Update gomock for new TD uint256.Int signature.
polygon/sync/execution_client.go Update execution client TD return type to *uint256.Int.
polygon/p2p/service.go Update PublishNewBlock to accept TD uint256.Int.
polygon/bor/bor_test.go Update bor tests for NewBlockPacket.TD as uint256.Int.
p2p/sentry/status_data_provider.go Use TD *uint256.Int directly from rawdb and default missing TD to 0.
p2p/sentry/status_data_provider_test.go Update test TD writes to uint256.Int.
p2p/sentry/sentry_multi_client/broadcast.go Update broadcast new-block TD parameter to uint256.Int.
p2p/sentry/sentry_grpc_server_test.go Use *uint256.Int TD directly for status data conversion.
p2p/protocols/eth/protocol.go Change NewBlockPacket.TD to uint256.Int; update RLP encode/decode.
p2p/protocols/eth/handler.go Convert TD *uint256.Int to *big.Int at geth-compat boundary for NodeInfo.
node/ethstats/ethstats.go Accept TD as *uint256.Int and stringify for ethstats payload.
node/eth/backend.go Convert stored TD *uint256.Int to *big.Int for existing callers.
execution/vm/runtime/runtime_test.go Update fake chain reader TD signature to *uint256.Int.
execution/types/transaction.go Change Transaction.SigningHash to accept *uint256.Int.
execution/types/transaction_test.go Update signing-hash tests to uint256 chain ID.
execution/types/transaction_signing.go Pass signer chain ID as *uint256.Int into SigningHash.
execution/types/set_code_tx.go Switch set-code tx signing payload ChainID type to *uint256.Int.
execution/types/legacy_tx.go Switch legacy tx signing payload ChainID type to *uint256.Int.
execution/types/dynamic_fee_tx.go Switch 1559 tx signing payload ChainID type to *uint256.Int.
execution/types/block_test.go Rename/update panic-prevention test to target EncodeUint256.
execution/types/blob_tx.go Switch blob tx signing payload ChainID type to *uint256.Int.
execution/types/blob_tx_wrapper.go Update wrapper SigningHash signature to *uint256.Int.
execution/types/access_list_tx.go Switch 2930 tx signing payload ChainID type to *uint256.Int.
execution/types/aa_transaction.go Update AA SigningHash signature and convert big chainID at call sites.
execution/tests/testutil/rlp_test_util.go Update RLP JSON test translation/decoding to use uint256.
execution/tests/rlp_test.go Skip legacy bigint vector that exceeds uint256 ceiling.
execution/tests/blockgen/chain_makers.go Update fake chain reader TD signature to *uint256.Int.
execution/tests/blockchain_test.go Convert TD reads to uint256, compare accordingly, and bridge to big.Int where needed.
execution/state/genesiswrite/genesis_write.go Write genesis TD using uint256.Int value.
execution/stagedsync/rawdbreset/reset_stages.go Accumulate TD as uint256.Int with overflow checks when filling DB from snapshots.
execution/stagedsync/headerdownload/header_data_struct.go Update HeaderInserter local TD to *uint256.Int.
execution/stagedsync/headerdownload/header_algos.go Update feed/insert TD plumbing to uint256 + overflow errors and CmpBig at TTD boundary.
execution/stagedsync/headerdownload/header_algo_test.go Update header download tests for uint256 TD and comparisons.
execution/stagedsync/exec3.go Convert *uint256.Int TD to *big.Int for tracing hook compatibility.
execution/stagedsync/chain_reader.go Change ChainReader.GetTd return type to *uint256.Int.
execution/stagedsync/bodydownload/body_algos.go Compute propagated TD as uint256.Int with overflow handling.
execution/stagedsync/bodydownload/block_propagator.go Change block propagator TD parameter to uint256.Int.
execution/rlp/encode.go Remove reflect-based big.Int encoding and exported helpers; keep uint256 encoding.
execution/rlp/encode_test.go Remove big.Int encoding tests; add/keep uint256 tests and benchmark.
execution/rlp/encbuffer.go Remove big.Int buffer-writing helpers; keep uint256 support.
execution/rlp/decode.go Remove reflect-based big.Int decoding and Stream big-int APIs; keep uint256.
execution/rlp/decode_test.go Remove big.Int decoding tests/fixtures; keep uint256 coverage.
execution/protocol/rules/rules.go Update ChainHeaderReader.GetTd to return *uint256.Int.
execution/protocol/rules/merge/merge.go Compare TD vs TTD via uint256.Int.CmpBig.
execution/protocol/rules/merge/merge_test.go Update merge rule tests for uint256 TD reader signature.
execution/protocol/rules/ethash/forkchoice.go Update forkchoice ShouldReorg to compare *uint256.Int TD values.
execution/protocol/rules/ethash/forkchoice_test.go Update forkchoice tests to use uint256 TDs.
execution/protocol/block_exec.go Convert *uint256.Int TD to *big.Int for tracer boundary.
execution/p2p/publisher.go Publish NewBlock with TD as uint256.Int value.
execution/p2p/publisher_test.go Update publisher tests for NewBlockPacket.TD as uint256.Int.
execution/p2p/message_sender_test.go Update message sender tests for NewBlockPacket.TD as uint256.Int.
execution/execmodule/interface.go Change ExecutionModule.GetTD return type to *uint256.Int.
execution/execmodule/inserters.go Compute and store TD in overlay as uint256 with overflow checks.
execution/execmodule/getters.go Update GetTD signature to return *uint256.Int.
execution/execmodule/execmoduletester/exec_module_tester.go Update block propagator test hook signature for uint256.Int TD.
execution/execmodule/exec_module.go Update internal getTD helper to return *uint256.Int.
execution/execmodule/chainreader/chain_reader.go Update engine chain reader GetTd to return *uint256.Int.
execution/exec/chain_reader.go Update execution chain reader GetTd to return *uint256.Int.
execution/engineapi/testing_api_test.go Update stub GetTD signature to return *uint256.Int.
execution/engineapi/engine_server.go Use CmpBig for TD vs TTD comparisons with *uint256.Int.
execution/engineapi/engine_server_getpayload_test.go Update stub GetTD signature to return *uint256.Int.
execution/abi/bind/auth.go Convert *big.Int chainID to *uint256.Int at signing boundary.
db/rawdb/accessors_chain.go Store/read TD as uint256 (encoding unchanged); compare to TTD via CmpBig.
db/rawdb/accessors_chain_test.go Update TD storage tests to use uint256.
db/consensuschain/consensus_chain_reader.go Update consensus chain reader GetTd to return *uint256.Int.
cmd/utils/app/import_cmd.go Sum side-chain TD with uint256 + overflow checks and persist via new rawdb API.
cmd/rlpgen/testing/testing_struct.go Remove big.Int fields from rlpgen test fixture.
cmd/rlpgen/testing/gen_testingstruct_rlp.go Regenerate fixture RLP code without big.Int paths.
cmd/rlpgen/testing/encdec_test.go Remove big.Int random generation/comparisons from rlpgen tests.
cmd/rlpgen/matcher.go Remove big.Int / *big.Int handler mapping from rlpgen.
cmd/rlpgen/handlers.go Remove big.Int handlers from rlpgen generator.
Files not reviewed (1)
  • cmd/rlpgen/testing/gen_testingstruct_rlp.go: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread execution/tests/testutil/rlp_test_util.go
yperbasis and others added 4 commits May 12, 2026 14:46
Removed in the prior commit's simplification of ReadChainHeadWithTx
(rawdb.ReadTd now returns *uint256.Int directly) but the helper was
left behind.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The earlier hedge — keeping TerminalTotalDifficulty as *big.Int for
JSON wire compatibility — was unnecessary. uint256.Int.UnmarshalJSON
accepts both quoted decimal strings and unquoted decimal numbers, so
every existing chainspec / DB-stored chain config still parses. The
only output-side change is that re-marshaling a Config now emits the
field as a quoted decimal string instead of an unquoted JSON number;
Erigon round-trips its own writes fine, and external consumers that
deal with TTD already need string/BigInt handling since 5.9e22+ does
not fit in a JS Number.

Side effects of the migration:

- All 5 TTD comparisons drop CmpBig in favor of plain Cmp.
- Transitioned(..., terminalTotalDifficulty *uint256.Int) and
  HeaderDownload.InsertHeader / InsertHeaders take *uint256.Int.
- header_algos blocksToTTD estimation is now pure uint256 (no
  big.Int conversion of lastD or returnTd).
- chainspec.IsChainPoS / hasChainPassedTerminalTD and
  readCurrentTotalDifficulty / currentTDProvider thread *uint256.Int.
- TestChain/testforks initializers use uint256.NewInt(0).

Verified manually that existing chainspec JSON (mainnet, gnosis,
chiado, sepolia, bloatnet) all fit comfortably in uint256 and parse
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…pers

The earlier hedge — keeping LatestSignerForChainID and
NewKeyedTransactorWithChainID on *big.Int while the rest of the
signing stack moved to uint256 — was leftover lint. Both helpers
already converted *big.Int to uint256.Int internally, so callers
were paying for a pointless round-trip.

Migrate both helpers to *uint256.Int. Callers either:
- drop a redundant `.ToBig()` (where the local was already uint256),
- replace `big.NewInt(N)` literals with `uint256.NewInt(N)`,
- or wrap a *big.Int chain.Config.ChainID at the call site via
  `uint256.MustFromBig(...)` (chain.Config.ChainID stays *big.Int
  for now — separate scope, similar JSON wire shape concern).

Touches signer/test plumbing across cmd/rpcdaemontest, cmd/pics,
db/snapshotsync, execution/{engineapi,execmodule,state,tests,types,
abi/bind,verify}, rpc/{ethapi,jsonrpc}, polygon, txnprovider/{txpool,
shutter}, and a few other test helpers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The last *big.Int holdout in the TD/chainID migration. Existing
chainspec JSON parses fine (uint256.Int.UnmarshalJSON accepts both
unquoted decimal numbers and quoted strings); the WriteChainConfig DB
JSON round-trips since the read side accepts both. All known chainIDs
(mainnet=1, sepolia=11155111, gnosis=100, chiado=10200, hoodi=560048,
holesky=17000) are well within uint256.

Touches 54 files:

- chain.Config.ChainID and chain.Rules.ChainID typed *uint256.Int
- evmtypes.BlockContext.Rules uses uint256 directly; drops math/big
- All ChainID: big.NewInt(N) initializers in chain spec + tests
  switched to uint256.NewInt(N)
- uint256.MustFromBig(cfg.ChainID) round-trips dropped throughout
  (signer construction, transaction signing, RPC, txpool, etc.)
- aa_transaction.PaymasterFrame/ValidationFrame now take *uint256.Int
- GraphQLAPI.GetChainID returns *uint256.Int
- engineapitester.{Transactor, EngineApiTester.ChainId()} return
  *uint256.Int; testhelpers.NewContractsDeployer takes *uint256.Int
- TransactionTest.Run(chainID *uint256.Int)

Boundary carve-outs kept as *big.Int (geth-compat / JSON-RPC):

- eth_simulation args.ChainID: (*hexutil.Big)(cfg.ChainID.ToBig())
- NewRPCBorTransaction emits (*hexutil.Big)(chainId.ToBig())

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 121 out of 122 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • cmd/rlpgen/testing/gen_testingstruct_rlp.go: Language not supported
Comments suppressed due to low confidence (1)

execution/abi/bind/auth.go:47

  • After changing NewKeyedTransactorWithChainID to accept *uint256.Int, there are still call sites passing *big.Int (e.g., execution/abi/bind/bind_test.go uses big.NewInt(1337)), which will cause compile failures in tests. Update remaining callers/imports to use uint256.NewInt / uint256.MustFromBig at the boundary.
// NewKeyedTransactorWithChainID is a utility method to easily create a transaction signer
// from a single private key.
func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *uint256.Int) (*TransactOpts, error) {
	keyAddr := crypto.PubkeyToAddress(key.PublicKey)
	if chainID == nil {
		return nil, ErrNoChainID
	}
	signer := types.LatestSignerForChainID(chainID)
	return &TransactOpts{

Comment thread rpc/jsonrpc/send_transaction.go
…ansaction

uint256.Int.Format is defined on *Int, not Int. Passing a dereferenced
value (*txnChainId) to %d boxes it into interface{}, fmt cannot take
its address, and the format reverts to the underlying [4]uint64 array
("[42 0 0 0]" instead of "42"). Pass the pointer (txnChainId)
directly so the Formatter method on *Int is invoked.

Caught by Copilot reviewer on the prior ChainID -> *uint256.Int
migration commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yperbasis yperbasis changed the title execution, rlp: switch TD and chainID to uint256.Int execution, rlp: switch total difficulty and chainID to uint256.Int May 12, 2026
Last big.Int TD field in the migration. No in-tree readers — only the
two OnBlockStart construction sites in protocol/block_exec.go and
stagedsync/exec3.go, both of which now pass chainReader.GetTd(...)
directly without the .ToBig() / tdBig dance.

Drops one allocation per traced block. Mechanical break for downstream
tracers that implement OnBlockStart against this package; the fix is
event.TD.ToBig() at the reader.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yperbasis yperbasis requested a review from Copilot May 13, 2026 07:00
@yperbasis yperbasis marked this pull request as ready for review May 13, 2026 07:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 122 out of 123 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • cmd/rlpgen/testing/gen_testingstruct_rlp.go: Language not supported

Comment thread cmd/evm/internal/t8ntool/transition.go
yperbasis and others added 3 commits May 13, 2026 09:37
Leftover lint from the rawdb.ReadTd -> *uint256.Int migration: the
testFork callback was still typed func(td1, td2 *big.Int), so the
TD values had to be round-tripped via .ToBig() at the rawdb boundary
to feed into the comparator. Migrate the comparator and the local
tdPre/tdPost vars to *uint256.Int directly, and assign tdPre/tdPost
straight from rawdb.ReadTd. No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match the flag's declared type to its usage. The ChainID accessor was
already migrated to ctx.Uint64(...) when chain.Config.ChainID became
*uint256.Int; declaring the flag itself as cli.Uint64Flag closes the
mismatch and (per Copilot review) avoids any subtle accessor-type
quirk in urfave/cli.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two leftovers from the migration:

- execution/types/transaction_test.go: TestEIP2930Signer's table-driven
  chainID was *big.Int with `uint256.MustFromBig(test.chainID)` at the
  SigningHash call. Re-type to *uint256.Int and drop the wrapper.
- p2p/protocols/eth/handler.go: NodeInfo.Difficulty was *big.Int with
  td256.ToBig() at the assign site. Re-type to *uint256.Int — same
  JSON wire-shape concession as TerminalTotalDifficulty (UnmarshalJSON
  accepts both unquoted decimal and quoted strings).

CallArgs.ChainID in rpc/ethapi/api.go intentionally stays *hexutil.Big:
that file has 44 *hexutil.Big fields representing the hex-encoded
JSON-RPC wire convention; introducing a hexutil.U256 to migrate ChainID
alone would be asymmetric and is well out of scope for this PR. The
conversion to uint256 happens internally at the boundary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts:
#	execution/chain/chain_config.go
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 123 out of 124 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • cmd/rlpgen/testing/gen_testingstruct_rlp.go: Language not supported

@yperbasis yperbasis enabled auto-merge May 13, 2026 10:14
@yperbasis yperbasis added this pull request to the merge queue May 18, 2026
Merged via the queue into main with commit fd47df9 May 18, 2026
69 checks passed
@yperbasis yperbasis deleted the yperbasis/bounty10 branch May 18, 2026 08:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants