-
Notifications
You must be signed in to change notification settings - Fork 11
Implement the RPCBlockHeaderSubscriber
for indexing finalized results
#728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThis change introduces experimental support for indexing EVM execution data from unsealed finalized blocks using a polling mechanism, with optional sealing verification. It adds new command-line flags, configuration fields, storage for event hashes, and implements new event subscriber and verifier components to enable and manage this feature. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI
participant Bootstrap
participant Config
participant Storage
participant CrossSporkClient
participant RPCBlockTrackingSubscriber
participant SealingVerifier
CLI->>Bootstrap: StartEventIngestion()
Bootstrap->>Config: Check ExperimentalSoftFinalityEnabled
alt Soft Finality Enabled
Bootstrap->>Config: Check ExperimentalSealingVerificationEnabled
alt Sealing Verification Enabled
Bootstrap->>Storage: Init EventsHash
Bootstrap->>SealingVerifier: NewSealingVerifier(...)
Bootstrap->>RPCBlockTrackingSubscriber: NewRPCBlockTrackingSubscriber(..., verifier)
else Not Enabled
Bootstrap->>RPCBlockTrackingSubscriber: NewRPCBlockTrackingSubscriber(..., nil)
end
Bootstrap->>RPCBlockTrackingSubscriber: Subscribe(ctx)
alt Sealing Verification Enabled
SealingVerifier->>CrossSporkClient: Subscribe to block events
SealingVerifier->>Storage: Store/Get event hashes
SealingVerifier->>RPCBlockTrackingSubscriber: Verify events
end
else Not Enabled
Bootstrap->>RPCEventSubscriber: NewRPCEventSubscriber(...)
RPCEventSubscriber->>CrossSporkClient: Subscribe to sealed events
end
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip ⚡️ Faster reviews with caching
Enjoy the performance boost—your workflow just got faster. ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
10a8bdd
to
4fd4a5d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a couple small comments, but otherwise this looks good. let's get it running against one of the live networks.
@peterargue Thanks for the review 🙌 I've addressed all the comments. |
…ersFromStartHeight
…or function resuse
314e7cc
to
bfe6188
Compare
Co-authored-by: Peter Argue <[email protected]>
…poc-backport Add flag to disable enforcing the minimum gas price
…pectra-upgrade-soft-finality-backport
…ity-backport Back-port EVM Pectra hard-fork to soft finality
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🔭 Outside diff range comments (1)
services/requester/requester.go (1)
320-333
:⚠️ Potential issueTransaction type is hard-wired to Legacy – breaks Blob / Dynamic-Fee / Set-Code calls
txArgs.ToTransaction(types.LegacyTxType, ...)
forces everyeth_call
request to be encoded as a legacy transaction, ignoring thetype
field the
caller may have supplied.
Blob (0x05), Dynamic-Fee (0x02) and upcoming Set-Code (0x7E) transactions will
thus be simulated with the wrong rules and gas accounting.- tx := txArgs.ToTransaction(types.LegacyTxType, blockGasLimit) + txType := types.LegacyTxType + if txArgs.Type != nil { + txType = uint8(*txArgs.Type) + } + tx := txArgs.ToTransaction(txType, blockGasLimit)The same fix is needed in
EstimateGas
.
♻️ Duplicate comments (2)
tests/web3js/eth_pectra_upgrade_test.js (1)
24-41
: Same flakiness & timeout issues as in the 7702 test suiteApply the receipt-polling + extended Mocha timeout advice here as well (lines 24-29 & 36-41).
Also applies to: 36-37
services/requester/requester.go (1)
345-356
: Repeat the tx-type fix inEstimateGas
EstimateGas
suffers from the same hard-coded legacy type.
Apply the patch suggested above before eachToTransaction
invocation to keep
the estimator accurate for EIP-1559 and blob transactions.
🧹 Nitpick comments (7)
tests/web3js/viem/config.js (1)
23-24
: Caution: Hardcoded private key in source code.While acceptable for testing purposes, hardcoding private keys in source code is generally not a best practice. Consider using environment variables or test configurations in the future.
tests/web3js/eth_eip_7702_contract_write_test.js (1)
10-39
: Fixed timeouts could lead to flaky tests.The before hook uses fixed timeouts (e.g., line 20, 32) which could cause intermittent failures if network conditions vary. Consider using a polling mechanism or transaction confirmation callback instead.
- await new Promise((res) => setTimeout(() => res(), 1500)) + // Poll until transaction is confirmed or timeout occurs + const maxAttempts = 10 + let attempts = 0 + while (attempts < maxAttempts) { + const receipt = await publicClient.getTransactionReceipt({hash}) + if (receipt) { + break + } + await new Promise((res) => setTimeout(() => res(), 500)) + attempts++ + }api/utils.go (1)
70-84
: Guard against unknown negative block tagsThe
switch
exhaustively lists the known special tags, but a malformed client
could still submit another negative value (e.g.-6
).
Such input currently falls through toreturn uint64(blockNumber), nil
, which
under-flows to a very large positive height.Consider adding a sanity check:
return height, nil } // fallback for explicit block heights -if blockNumber < 0 { - return 0, fmt.Errorf("%w: unsupported block tag %v", errs.ErrInvalid, blockNumber) -} return uint64(blockNumber), niltests/web3js/eth_pectra_upgrade_test.js (1)
65-68
: Make the rejection assertion resilient to error-message changes
assert.equal(errMsg, 'transaction type not supported: type 4 rejected, pool not yet in Prague')
is brittle – any wording tweak, punctuation change or upstream library i18n will break the test.
Prefer a substring / regex check:
-assert.equal(errMsg, 'transaction type not supported: type 4 rejected, pool not yet in Prague') +assert.match(errMsg, /transaction type .*type 4 .*not.*supported/i)api/debug.go (1)
474-479
: Pass a non-nilChainConfig
– but consider network upgrades
emulator.MakeChainConfig(config.EVMNetworkID)
bakes the current rules, yetTracer.New
may need fork-specific params (Prague vs Pectra).
Ensure the config passed here is dynamically fork-aware (e.g. viaChainConfig.Copy()
+Config.AtBlock(forkHeight)
), otherwise tracers will mis-interpret op-codes around upgrades.api/api.go (1)
965-980
: Receipt fetching is duplicated – cache or reuse to save I/O
fetchBlockTransactions
already callsprepareTransactionResponse
, which loads
each receipt once.
In the second loop (buildingreceipts
to computeLogsBloom
) the same
b.receipts.GetByTransactionID
call is executed again, doubling the database
round-trips for large blocks.Consider passing the previously fetched receipt slice back from
fetchBlockTransactions
(or retrieving it there) and re-using it here:- for _, tx := range transactions { - txReceipt, err := b.receipts.GetByTransactionID(tx.Hash) + receiptsGeth := types.Receipts{} + for i, tx := range transactions { + txReceipt := tx.Receipt // assuming fetched earlier ... - receipts = append(receipts, txReceipt.ToGethReceipt()) + receiptsGeth = append(receiptsGeth, txReceipt.ToGethReceipt()) } - blockResponse.LogsBloom = types.MergeBloom(receipts).Bytes() + blockResponse.LogsBloom = types.MergeBloom(receiptsGeth).Bytes()This removes redundant reads and cuts latency roughly in half for
eth_getBlockBy*
withfullTx=true
.services/requester/requester.go (1)
447-453
: Authorisation-list gas add-on: guard against integer overflow
passingGasLimit += uint64(len(txArgs.AuthorizationList)) * gethParams.CallNewAccountGas
len(AuthorizationList)
is unbounded input. While overflow is unlikely in
practice, it will wrap silently. Consider:extraGas := uint64(len(txArgs.AuthorizationList)) * gethParams.CallNewAccountGas if math.MaxUint64-extraGas < passingGasLimit { return 0, fmt.Errorf("gas estimate overflow") } passingGasLimit += extraGas
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
go.sum
is excluded by!**/*.sum
tests/go.sum
is excluded by!**/*.sum
tests/web3js/package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (29)
api/api.go
(13 hunks)api/debug.go
(14 hunks)api/stream.go
(2 hunks)api/utils.go
(1 hunks)bootstrap/bootstrap.go
(5 hunks)eth/types/types.go
(3 hunks)go.mod
(8 hunks)models/block.go
(1 hunks)models/receipt.go
(1 hunks)models/transaction.go
(1 hunks)models/transaction_test.go
(5 hunks)services/logs/filter_test.go
(1 hunks)services/replayer/blocks_provider_test.go
(2 hunks)services/replayer/call_tracer_collector.go
(5 hunks)services/requester/requester.go
(12 hunks)tests/e2e_web3js_test.go
(3 hunks)tests/go.mod
(8 hunks)tests/web3js/build_evm_state_test.js
(2 hunks)tests/web3js/contract_call_overrides_test.js
(1 hunks)tests/web3js/debug_traces_test.js
(8 hunks)tests/web3js/eth_batch_tx_logs_test.js
(2 hunks)tests/web3js/eth_deploy_contract_and_interact_test.js
(1 hunks)tests/web3js/eth_eip_7702_contract_write_test.js
(1 hunks)tests/web3js/eth_eip_7702_sending_transactions_test.js
(1 hunks)tests/web3js/eth_pectra_upgrade_test.js
(1 hunks)tests/web3js/package.json
(1 hunks)tests/web3js/viem/Delegation.sol
(1 hunks)tests/web3js/viem/config.js
(1 hunks)tests/web3js/viem/contract.js
(1 hunks)
✅ Files skipped from review due to trivial changes (7)
- tests/web3js/eth_deploy_contract_and_interact_test.js
- tests/web3js/package.json
- tests/web3js/viem/contract.js
- tests/web3js/viem/Delegation.sol
- services/replayer/blocks_provider_test.go
- models/block.go
- tests/go.mod
🚧 Files skipped from review as they are similar to previous changes (2)
- bootstrap/bootstrap.go
- go.mod
🧰 Additional context used
🧬 Code Graph Analysis (7)
tests/web3js/build_evm_state_test.js (2)
tests/web3js/eth_deploy_contract_and_interact_test.js (2)
callRetrieve
(45-45)deployed
(7-7)tests/web3js/eth_get_storage_at_test.js (2)
callRetrieve
(14-14)deployed
(7-7)
tests/web3js/eth_batch_tx_logs_test.js (4)
tests/web3js/contract_call_overrides_test.js (4)
receipt
(19-19)receipt
(101-101)block
(53-53)block
(144-144)tests/web3js/debug_traces_test.js (2)
receipt
(19-19)receipt
(381-381)tests/e2e-network/e2e_test.js (1)
assert
(3-3)tests/web3js/eth_deploy_contract_and_interact_test.js (1)
block
(105-105)
api/stream.go (2)
models/receipt.go (1)
Receipt
(18-36)storage/pebble/receipts.go (1)
Receipts
(20-22)
tests/web3js/viem/config.js (2)
tests/web3js/eth_eip_7702_contract_write_test.js (4)
require
(1-1)require
(2-2)require
(3-3)require
(4-4)tests/web3js/eth_eip_7702_sending_transactions_test.js (5)
require
(1-1)require
(2-2)require
(3-3)require
(4-4)require
(5-5)
api/utils.go (1)
models/block.go (5)
EarliestBlockNumber
(17-17)SafeBlockNumber
(18-18)FinalizedBlockNumber
(19-19)LatestBlockNumber
(20-20)PendingBlockNumber
(21-21)
eth/types/types.go (1)
models/transaction.go (1)
Transaction
(34-53)
api/api.go (5)
models/transaction.go (1)
Transaction
(34-53)eth/types/types.go (3)
Transaction
(276-301)Block
(422-444)MarshalReceipt
(473-529)models/block.go (3)
Block
(45-55)EarliestBlockNumber
(17-17)PendingBlockNumber
(21-21)models/receipt.go (1)
Receipt
(18-36)storage/pebble/receipts.go (1)
Receipts
(20-22)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: build
- GitHub Check: Test
🔇 Additional comments (31)
tests/web3js/build_evm_state_test.js (2)
159-159
: Gas estimation value updatedThe assertion for estimated gas has been increased from 21358n to 21646n, which aligns with the updated gas calculation logic that likely includes additional costs for authorization lists and new transaction types.
178-178
: Fixed incorrect await usageThe
await
keyword has been correctly removed fromencodeABI()
call since this method is synchronous and does not return a Promise.models/transaction.go (1)
210-210
: Updated bloom filter creation method signatureChanged from passing a slice of receipts
[]*gethTypes.Receipt{gethReceipt}
to passing a single receiptgethReceipt
directly toCreateBloom
. This aligns with similar changes elsewhere in the codebase for consistent bloom filter computation.Let's verify that this change is consistent with other bloom filter creations in the codebase:
#!/bin/bash # Check other usages of CreateBloom in the codebase rg "CreateBloom\(" --type goservices/logs/filter_test.go (1)
116-116
: Updated bloom filter creation method signatureChanged from passing a slice of receipts
[]*gethTypes.Receipt{rcp}
to passing a single receiptrcp
directly toCreateBloom
. This aligns with the similar change in models/transaction.go for consistent bloom filter computation across the codebase.models/receipt.go (1)
38-56
: New conversion method looks good!The
ToGethReceipt()
method correctly maps all relevant fields from the customReceipt
struct to the go-ethereumgethTypes.Receipt
struct. The implementation is straightforward and will facilitate interoperability between the custom and go-ethereum receipt types.tests/web3js/eth_batch_tx_logs_test.js (4)
15-15
: Enhanced test coverage for bloom filters.Adding an array to store individual transaction receipt bloom filters is a good approach for the verification logic that follows.
45-46
: Collecting bloom filters for verification.Good approach to collect all receipt bloom filters for later verification against the block bloom filter.
48-52
: Block level bloom filter verification.This assertion verifies that the block's overall
logsBloom
matches the expected hardcoded value, ensuring that the bloom aggregation logic works correctly.
54-59
: Individual vs. aggregated bloom verification.This test ensures that none of the individual transaction bloom filters match the block-level bloom filter, which is expected since the block bloom should be an aggregation of all transaction blooms rather than equal to any single one.
models/transaction_test.go (5)
364-369
: Updated Header initialization for test.Setting the
Difficulty
to zero is appropriate for compatibility with modern consensus mechanisms.
377-384
: Added support for SetCodeTxType.The
ValidationOptions.Accept
bitmask has been extended to include theSetCodeTxType
transaction type, which is necessary for testing the new transaction type support.
414-419
: Consistent Header updates in TestValidateConsensusRules.Same changes as in
TestValidateTransaction
for header initialization, ensuring consistency across tests.
427-437
: Consistent validation options for consensus rules test.Same update to the
ValidationOptions.Accept
bitmask as seen earlier, ensuring consistent transaction type support across tests.
478-478
: Increased gas limit for transaction size tests.The gas limit has been increased from 2,500,000 to 5,500,000, which aligns with the system updates to handle larger or more complex transactions, particularly with the new transaction types support.
tests/web3js/debug_traces_test.js (3)
33-33
: Updated return value assertion.Changed from a null check to asserting the length equals
9806n
, providing more precise validation.
189-189
: Standardized empty return value representation.Updated all empty return value assertions from empty string
''
to'0x'
, which is the standard hex representation for empty data in Ethereum. This ensures consistent empty value handling across the codebase.Also applies to: 198-198, 264-264, 273-273, 412-412
358-359
: Updated gas usage expectations.The gas and gasUsed values have been adjusted to reflect the current behavior of the system, likely due to changes in transaction processing or gas calculation logic.
Also applies to: 366-366, 688-688, 696-696
tests/e2e_web3js_test.go (4)
8-8
: LGTM: Required imports for new tests.The addition of the time package and the flow-go/fvm/evm/emulator package are necessary for the new EIP-7702 and pre-Pectra tests added in this PR.
Also applies to: 12-12
200-201
: Improved test robustness.Replacing fixed input values with dynamic inputs derived from the loop index creates more varied test cases and better coverage.
357-363
: LGTM: Added EIP-7702 tests.These new test cases correctly test the contract write and transaction sending functionality using EIP-7702 authorization mechanisms, which is central to the PR's purpose.
365-374
: Smart temporal test setup for pre-Pectra upgrade.This test correctly sets the Prague hard-fork activation timestamp to the future (24 hours from now) to ensure the code behaves appropriately before the upgrade. The deferred reset ensures clean test isolation.
tests/web3js/viem/config.js (2)
1-21
: LGTM: Well-structured Viem client configuration.The configuration correctly defines a custom Flow EVM Local blockchain with the appropriate chain ID, native currency details, and RPC endpoint for testing.
26-39
: LGTM: Proper client setup and exports.The wallet and public clients are correctly initialized with the appropriate configuration, and all necessary objects are exported for use in the test files.
tests/web3js/eth_eip_7702_contract_write_test.js (3)
1-9
: LGTM: Well-structured imports and account setup.The test file correctly imports necessary dependencies and sets up the test account with a private key.
41-75
: LGTM: Comprehensive relay account testing.The test correctly validates the contract write workflow with relay authorization, verifying both transaction success and transaction types.
77-111
: LGTM: Self-execution testing covers important flow.The self-execution test complements the relay account test by covering an alternative authorization model, providing good coverage of the EIP-7702 functionality.
api/stream.go (2)
139-139
: Improved bloom filter initialization.Changed from using empty logs to using an empty receipt for initializing the bloom filter, which is more consistent with Ethereum's standard approach.
150-151
: Optimized bloom filter calculation from receipts.The implementation now:
- Uses
gethTypes.Receipts{}
to collect receipts- Converts each custom receipt to a Geth receipt with
ToGethReceipt()
- Uses
MergeBloom(receipts)
to generate the combined bloom filterThis approach is more efficient and aligns better with how Geth processes bloom filters.
Also applies to: 157-158, 161-161
tests/web3js/eth_eip_7702_sending_transactions_test.js (1)
42-80
: Increase Mocha timeout or the suite will time-out before receipts arriveMocha’s default timeout is 2 seconds per test; each transaction round-trip plus the extra delay already exceeds that on moderately loaded runners.
Add at the top of the file (or inside each
it
) :// top-level this.timeout?.(20_000); // Node <18 guard // OR mochaTimeout(20_000); // If using cross-env wrapper(or pass
--timeout 20000
to the mocha CLI).Without it CI intermittently reports
Error: Timeout of 2000ms exceeded
.Also applies to: 82-120
api/api.go (1)
298-304
: Use ofresolveBlockNumber
looks good, but propagate “earliest” correctly
resolveBlockNumber
replaces the older ad-hoc logic, which is great for consistency.
Please double-check that every negative constant (Latest
,Finalized
,Safe
,Earliest
) is covered in the helper; otherwise callers likeGetTransactionByBlockNumberAndIndex
will silently fall through to an incorrect height.No code change required if the helper is already complete.
services/requester/requester.go (1)
157-161
: Hard-coded header.Number may drift from actual chain height
Number: big.NewInt(20_182_324)
is embedded at start-up.
If the gateway runs long enough the real Cadence height will surpass this
constant, making nonce/gas validation pessimistic.Instead query the latest EVM height once during
NewEVM
construction and use
that value.
@@ -179,7 +179,7 @@ it('should apply block overrides on debug_traceCall', async () => { | |||
|
|||
// Override the `block.prevrandao` value to `0x7914bb5b13bac6f621bc37bbf6e406fbf4472aaaaf17ec2f309a92aca4e27fc0`. | |||
let random = '0x7914bb5b13bac6f621bc37bbf6e406fbf4472aaaaf17ec2f309a92aca4e27fc0' | |||
callTracer.blockOverrides = { random: random } | |||
callTracer.blockOverrides = { prevRandao: random } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Updated block override property name from 'random' to 'prevRandao'
This change correctly updates the property name to match Ethereum's post-Merge terminology, where the previous "random" field is now correctly called "prevRandao".
The update maintains consistency with line 90 where the field name is still "random" for the eth_call
method, which might need a similar update for consistency across API methods.
🏁 Script executed:
#!/bin/bash
# Check if random is used consistently elsewhere
rg "\brandom\s*:" --type js
Length of output: 125
Ensure consistency: update eth_call
override property to prevRandao
The block override rename to prevRandao
is correct for post-Merge terminology, but the test for the eth_call
method still uses random
. Please update it to match:
• File: tests/web3js/contract_call_overrides_test.js
Replace at line ~182:
- [call, 'latest', null, { random: random }]
+ [call, 'latest', null, { prevRandao: random }]
This will keep all override properties consistent across API methods.
Committable suggestion skipped: line range outside the PR's diff.
func DefaultCallTracer(evmChainID *big.Int) (*tracers.Tracer, error) { | ||
evmChainConfig := emulator.MakeChainConfig(evmChainID) | ||
|
||
tracer, err := tracers.DefaultDirectory.New( | ||
TracerName, | ||
&tracers.Context{}, | ||
json.RawMessage(TracerConfig), | ||
evmChainConfig, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle nil
Chain-ID to avoid panics
emulator.MakeChainConfig
will dereference the supplied *big.Int
.
If evmChainID
is ever nil
(e.g. config error, tests), the process will panic long before
an error can be returned.
func DefaultCallTracer(evmChainID *big.Int) (*tracers.Tracer, error) {
- evmChainConfig := emulator.MakeChainConfig(evmChainID)
+ if evmChainID == nil {
+ return nil, fmt.Errorf("evmChainID must not be nil")
+ }
+ evmChainConfig := emulator.MakeChainConfig(evmChainID)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func DefaultCallTracer(evmChainID *big.Int) (*tracers.Tracer, error) { | |
evmChainConfig := emulator.MakeChainConfig(evmChainID) | |
tracer, err := tracers.DefaultDirectory.New( | |
TracerName, | |
&tracers.Context{}, | |
json.RawMessage(TracerConfig), | |
evmChainConfig, | |
) | |
func DefaultCallTracer(evmChainID *big.Int) (*tracers.Tracer, error) { | |
if evmChainID == nil { | |
return nil, fmt.Errorf("evmChainID must not be nil") | |
} | |
evmChainConfig := emulator.MakeChainConfig(evmChainID) | |
tracer, err := tracers.DefaultDirectory.New( | |
TracerName, | |
&tracers.Context{}, | |
json.RawMessage(TracerConfig), | |
evmChainConfig, | |
) | |
// … remainder of function … | |
} |
func (t *CallTracerCollector) ResetTracer() error { | ||
var err error | ||
t.tracer, err = DefaultCallTracer() | ||
t.tracer, err = DefaultCallTracer(t.evmChainID) | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preserve the previous tracer when reset fails
If DefaultCallTracer
returns an error, t.tracer
is replaced with nil
,
leaving the collector unusable and causing a nil
-pointer panic on the next
callback invocation.
- t.tracer, err = DefaultCallTracer(t.evmChainID)
- return err
+ newTracer, err := DefaultCallTracer(t.evmChainID)
+ if err != nil {
+ // keep the previous tracer to remain operational
+ return err
+ }
+ t.tracer = newTracer
+ return nil
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func (t *CallTracerCollector) ResetTracer() error { | |
var err error | |
t.tracer, err = DefaultCallTracer() | |
t.tracer, err = DefaultCallTracer(t.evmChainID) | |
return err | |
func (t *CallTracerCollector) ResetTracer() error { | |
var err error | |
newTracer, err := DefaultCallTracer(t.evmChainID) | |
if err != nil { | |
// keep the previous tracer to remain operational | |
return err | |
} | |
t.tracer = newTracer | |
return nil | |
} |
case types.SetCodeTxType: | ||
al := types.AccessList{} | ||
if txArgs.AccessList != nil { | ||
al = *txArgs.AccessList | ||
} | ||
authList := []types.SetCodeAuthorization{} | ||
if txArgs.AuthorizationList != nil { | ||
authList = txArgs.AuthorizationList | ||
} | ||
data = &types.SetCodeTx{ | ||
To: *txArgs.To, | ||
ChainID: uint256.MustFromBig(txArgs.ChainID.ToInt()), | ||
Nonce: nonce, | ||
Gas: uint64(*txArgs.Gas), | ||
GasFeeCap: uint256.MustFromBig((*big.Int)(txArgs.MaxFeePerGas)), | ||
GasTipCap: uint256.MustFromBig((*big.Int)(txArgs.MaxPriorityFeePerGas)), | ||
Value: uint256.MustFromBig((*big.Int)(txArgs.Value)), | ||
Data: txArgs.data(), | ||
AccessList: al, | ||
AuthList: authList, | ||
} | ||
|
||
case types.BlobTxType: | ||
al := types.AccessList{} | ||
if txArgs.AccessList != nil { | ||
al = *txArgs.AccessList | ||
} | ||
data = &types.BlobTx{ | ||
To: *txArgs.To, | ||
ChainID: uint256.MustFromBig((*big.Int)(txArgs.ChainID)), | ||
Nonce: nonce, | ||
Gas: uint64(*txArgs.Gas), | ||
GasFeeCap: uint256.MustFromBig((*big.Int)(txArgs.MaxFeePerGas)), | ||
GasTipCap: uint256.MustFromBig((*big.Int)(txArgs.MaxPriorityFeePerGas)), | ||
Value: uint256.MustFromBig((*big.Int)(txArgs.Value)), | ||
Data: txArgs.data(), | ||
AccessList: al, | ||
BlobHashes: txArgs.BlobHashes, | ||
BlobFeeCap: uint256.MustFromBig((*big.Int)(txArgs.BlobFeeCap)), | ||
} | ||
if txArgs.Blobs != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nil-pointer panics when optional fees / chain-ID are omitted
uint256.MustFromBig
panics on a nil
argument.
Fields such as ChainID
, MaxFeePerGas
, MaxPriorityFeePerGas
, Value
,
BlobFeeCap
, and To
are all optional according to the JSON-RPC spec, but they
are blindly dereferenced here for SetCodeTx and BlobTx construction.
This makes the gateway crash on perfectly valid user input (e.g. blob tx with
default fee caps).
- ChainID: uint256.MustFromBig(txArgs.ChainID.ToInt()),
+ ChainID: uint256.MustFromBig(models.BigOrZero(txArgs.ChainID)),
...
- GasFeeCap: uint256.MustFromBig((*big.Int)(txArgs.MaxFeePerGas)),
+ GasFeeCap: uint256.MustFromBig(models.BigOrZero(txArgs.MaxFeePerGas)),
Where models.BigOrZero
is a tiny helper:
// models/helpers.go
func BigOrZero(h *hexutil.Big) *big.Int {
if h == nil {
return big.NewInt(0)
}
return h.ToInt()
}
Apply the same defensive conversion for all fee / value fields and check
txArgs.To != nil
before dereferencing.
Failing fast with a descriptive error (or defaulting to zero as go-ethereum
does) will make the API robust.
let hash = await walletClient.sendRawTransaction({ serializedTransaction }) | ||
|
||
await new Promise((res) => setTimeout(() => res(), 1500)) | ||
let transaction = await publicClient.getTransactionReceipt({ | ||
hash: hash | ||
}) | ||
assert.equal(transaction.status, 'success') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace fixed setTimeout
delays with receipt-polling utilities to avoid flaky tests
The test waits a hard-coded 1.5 second delay after every send.
Block-time, local dev speed, CI load or network latency can all vary and turn the suite red/green nondeterministically.
Recommend waiting for the receipt instead, e.g.:
-await new Promise((res) => setTimeout(() => res(), 1500))
-const transaction = await publicClient.getTransactionReceipt({ hash })
+const transaction = await publicClient.waitForTransactionReceipt({ hash })
(or expose a tiny helper that polls getTransactionReceipt
until status !== undefined
with a timeout).
Besides stability you shave ~6 s off this file alone.
Also applies to: 33-37, 59-60, 74-75, 98-100, 114-115
// submit a transaction that calls verifyArchCallToFlowBlockHeight() | ||
let flowBlockHeightData = deployed.contract.methods.verifyArchCallToFlowBlockHeight().encodeABI() | ||
res = await helpers.signAndSend({ | ||
from: conf.eoa.address, | ||
to: contractAddress, | ||
data: flowBlockHeightData, | ||
value: '0', | ||
gasPrice: conf.minGasPrice, | ||
}) | ||
assert.equal(res.receipt.status, conf.successStatus) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
res
is written without let/const
– creates an implicit global and fails under "use strict"
- res = await helpers.signAndSend({
+ const res = await helpers.signAndSend({
Running Node with --strict
or under ESM will throw ReferenceError: res is not defined
.
Even in sloppy mode you end up mutating the global object and leaking state across tests.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// submit a transaction that calls verifyArchCallToFlowBlockHeight() | |
let flowBlockHeightData = deployed.contract.methods.verifyArchCallToFlowBlockHeight().encodeABI() | |
res = await helpers.signAndSend({ | |
from: conf.eoa.address, | |
to: contractAddress, | |
data: flowBlockHeightData, | |
value: '0', | |
gasPrice: conf.minGasPrice, | |
}) | |
assert.equal(res.receipt.status, conf.successStatus) | |
// submit a transaction that calls verifyArchCallToFlowBlockHeight() | |
let flowBlockHeightData = deployed.contract.methods.verifyArchCallToFlowBlockHeight().encodeABI() | |
const res = await helpers.signAndSend({ | |
from: conf.eoa.address, | |
to: contractAddress, | |
data: flowBlockHeightData, | |
value: '0', | |
gasPrice: conf.minGasPrice, | |
}) | |
assert.equal(res.receipt.status, conf.successStatus) |
tx := args.ToTransaction(gethTypes.LegacyTxType, BlockGasLimit) | ||
|
||
// Default address in case user does not provide one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User-supplied gas limit is ignored – every trace uses the full block gas limit
args.ToTransaction(gethTypes.LegacyTxType, BlockGasLimit)
overwrites any gas
field provided in the RPC call.
Downstream you pass tx.Gas()
to DryCall
, so the simulation may:
- succeed locally but OOG on-chain (or vice-versa);
- hide genuine optimisation issues.
Patch suggestion:
- tx := args.ToTransaction(gethTypes.LegacyTxType, BlockGasLimit)
+gasLimit := BlockGasLimit
+if args.Gas != nil {
+ gasLimit = uint64(*args.Gas)
+}
+tx := args.ToTransaction(gethTypes.LegacyTxType, gasLimit)
…and keep passing tx.Gas()
further down.
Please verify other call-paths that relied on the old encodeTxFromArgs
helper.
Also applies to: 242-245
to := gethCommon.Address{} | ||
if tx.To != nil { | ||
to = *tx.To | ||
if tx.To() != nil { | ||
to = *tx.To() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Contract-creation calls are converted into calls to the zero address
When args.To == nil
(contract creation) the code sets
to := gethCommon.Address{}
so the dry-run executes a message call to 0x00…00
, not a create.
That changes execution semantics (init code vs runtime code, value handling, etc.).
Either:
- propagate
nil
and teach the view layer to treat it as CREATE, or - call the EVM’s
Create
path directly.
At minimum, reject unsupported contract-creation traces to avoid silent mis-simulation.
// if special value, use latest block number | ||
if from.Cmp(models.EarliestBlockNumber) < 0 { | ||
if from.Cmp(models.EarliestBlockNumber) == 0 { | ||
from = big.NewInt(0) | ||
} else if from.Cmp(models.PendingBlockNumber) < 0 { | ||
from = latest | ||
} | ||
if to.Cmp(models.EarliestBlockNumber) < 0 { | ||
|
||
if to.Cmp(models.EarliestBlockNumber) == 0 { | ||
to = big.NewInt(0) | ||
} else if to.Cmp(models.PendingBlockNumber) < 0 { | ||
to = latest | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Earliest
handled, but Finalized
and Safe
silently map to latest
The new branch keeps the previous rule “anything < Pending
⇒ latest”, then adds a special‐case for Earliest
.
Consequences:
-3
(finalized) and-4
(safe) are now treated exactly the same as-2
(latest).- That deviates from the semantics exposed by other endpoints (see comment above
GetBlockByNumber
).
If the intention is to support finalized
/safe
later, the current behaviour may mis-lead API users.
-} else if from.Cmp(models.PendingBlockNumber) < 0 {
- from = latest
+} else if from.Cmp(models.FinalizedBlockNumber) == 0 {
+ // map to the most recent finalized height
+ from = latest // TODO: replace once finalized height is tracked
+} else if from.Cmp(models.SafeBlockNumber) == 0 {
+ // map to the most recent safe height
+ from = latest // TODO: replace once safe height is tracked
+} else if from.Cmp(models.PendingBlockNumber) < 0 {
+ from = latest
}
Introduce dedicated branches (even if the value ultimately falls back to
latest
) to make the intent explicit and future refactors safer.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// if special value, use latest block number | |
if from.Cmp(models.EarliestBlockNumber) < 0 { | |
if from.Cmp(models.EarliestBlockNumber) == 0 { | |
from = big.NewInt(0) | |
} else if from.Cmp(models.PendingBlockNumber) < 0 { | |
from = latest | |
} | |
if to.Cmp(models.EarliestBlockNumber) < 0 { | |
if to.Cmp(models.EarliestBlockNumber) == 0 { | |
to = big.NewInt(0) | |
} else if to.Cmp(models.PendingBlockNumber) < 0 { | |
to = latest | |
} | |
// if special value, use latest block number | |
if from.Cmp(models.EarliestBlockNumber) == 0 { | |
from = big.NewInt(0) | |
} else if from.Cmp(models.FinalizedBlockNumber) == 0 { | |
// map to the most recent finalized height | |
from = latest // TODO: replace once finalized height is tracked | |
} else if from.Cmp(models.SafeBlockNumber) == 0 { | |
// map to the most recent safe height | |
from = latest // TODO: replace once safe height is tracked | |
} else if from.Cmp(models.PendingBlockNumber) < 0 { | |
from = latest | |
} | |
if to.Cmp(models.EarliestBlockNumber) == 0 { | |
to = big.NewInt(0) | |
} else if to.Cmp(models.PendingBlockNumber) < 0 { | |
to = latest | |
} |
…tion-back-port Create `ValidationOptions` for each tx submission
…ist-backport Return authorization list for `SetCodeTx` type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
eth/types/types.go (2)
135-155
:⚠️ Potential issueFix nil pointer dereferences in SetCodeTx construction
The SetCodeTx constructor doesn't handle nil pointer cases for optional fields like
To
,ChainID
,MaxFeePerGas
,MaxPriorityFeePerGas
, andValue
. This can cause panics when these fields are omitted, which is valid according to the JSON-RPC spec.Apply this defensive conversion pattern:
data = &types.SetCodeTx{ - To: *txArgs.To, + To: *txArgs.To, // To is required for SetCodeTx - ChainID: uint256.MustFromBig(txArgs.ChainID.ToInt()), + ChainID: uint256.MustFromBig(models.BigOrZero(txArgs.ChainID)), Nonce: nonce, Gas: uint64(*txArgs.Gas), - GasFeeCap: uint256.MustFromBig((*big.Int)(txArgs.MaxFeePerGas)), - GasTipCap: uint256.MustFromBig((*big.Int)(txArgs.MaxPriorityFeePerGas)), - Value: uint256.MustFromBig((*big.Int)(txArgs.Value)), + GasFeeCap: uint256.MustFromBig(models.BigOrZero(txArgs.MaxFeePerGas)), + GasTipCap: uint256.MustFromBig(models.BigOrZero(txArgs.MaxPriorityFeePerGas)), + Value: uint256.MustFromBig(models.BigOrZero(txArgs.Value)), Data: txArgs.data(), AccessList: al, AuthList: authList, }Where
models.BigOrZero
is the helper:// models/helpers.go func BigOrZero(h *hexutil.Big) *big.Int { if h == nil { return big.NewInt(0) } return h.ToInt() }
157-174
:⚠️ Potential issueFix nil pointer dereferences in BlobTx construction
Similar to the SetCodeTx issue, the BlobTx constructor doesn't handle nil pointer cases for optional fields like
To
,ChainID
,MaxFeePerGas
,MaxPriorityFeePerGas
,Value
, andBlobFeeCap
. This can cause panics when these fields are omitted.Apply this defensive conversion pattern:
data = &types.BlobTx{ - To: *txArgs.To, + To: *txArgs.To, // To is required for BlobTx - ChainID: uint256.MustFromBig((*big.Int)(txArgs.ChainID)), + ChainID: uint256.MustFromBig(models.BigOrZero(txArgs.ChainID)), Nonce: nonce, Gas: uint64(*txArgs.Gas), - GasFeeCap: uint256.MustFromBig((*big.Int)(txArgs.MaxFeePerGas)), - GasTipCap: uint256.MustFromBig((*big.Int)(txArgs.MaxPriorityFeePerGas)), - Value: uint256.MustFromBig((*big.Int)(txArgs.Value)), + GasFeeCap: uint256.MustFromBig(models.BigOrZero(txArgs.MaxFeePerGas)), + GasTipCap: uint256.MustFromBig(models.BigOrZero(txArgs.MaxPriorityFeePerGas)), + Value: uint256.MustFromBig(models.BigOrZero(txArgs.Value)), Data: txArgs.data(), AccessList: al, BlobHashes: txArgs.BlobHashes, - BlobFeeCap: uint256.MustFromBig((*big.Int)(txArgs.BlobFeeCap)), + BlobFeeCap: uint256.MustFromBig(models.BigOrZero(txArgs.BlobFeeCap)), }
🧹 Nitpick comments (1)
eth/types/types.go (1)
103-104
: Consider returning errors rather than panickingThe
ToTransaction
method doesn't return an error, which means any failure conditions like nil pointer dereferences will cause panics rather than graceful error handling.Consider changing the function signature to:
-func (txArgs TransactionArgs) ToTransaction(defaultType int, defaultGas uint64) *types.Transaction { +func (txArgs TransactionArgs) ToTransaction(defaultType int, defaultGas uint64) (*types.Transaction, error) {This would allow proper error handling and propagation throughout the call stack.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
eth/types/types.go
(7 hunks)models/transaction.go
(3 hunks)tests/web3js/eth_eip_7702_contract_write_test.js
(1 hunks)tests/web3js/eth_eip_7702_sending_transactions_test.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- models/transaction.go
- tests/web3js/eth_eip_7702_contract_write_test.js
- tests/web3js/eth_eip_7702_sending_transactions_test.js
🧰 Additional context used
🧬 Code Graph Analysis (1)
eth/types/types.go (1)
models/transaction.go (1)
Transaction
(34-54)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Test
🔇 Additional comments (3)
eth/types/types.go (3)
409-413
: LGTM - SetCodeAuthorizations handlingThe conditional check for transaction types and accessing SetCodeAuthorizations is correct. This ensures proper display of authorization lists for EIP-7702 transactions.
366-388
: Excellent documentation of transaction type hierarchyThe comments explaining the transaction type hierarchy and backward compatibility are very helpful for understanding how different transaction types relate to each other. This will aid future developers in maintaining the code.
231-240
: LGTM - data helper method implementationThe
data
helper method correctly handles the precedence of Input over Data, following Ethereum conventions. It also properly handles nil pointers.
usedType := types.LegacyTxType | ||
switch { | ||
case txArgs.AuthorizationList != nil || defaultType == types.SetCodeTxType: | ||
usedType = types.SetCodeTxType | ||
case txArgs.BlobHashes != nil || defaultType == types.BlobTxType: | ||
usedType = types.BlobTxType | ||
case txArgs.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType: | ||
usedType = types.DynamicFeeTxType | ||
case txArgs.AccessList != nil || defaultType == types.AccessListTxType: | ||
usedType = types.AccessListTxType | ||
} | ||
// Make it possible to default to newer tx, but use legacy if gasprice is provided | ||
if txArgs.GasPrice != nil { | ||
usedType = types.LegacyTxType | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider validating fields before transaction construction
The transaction type selection logic prioritizes legacy transactions when GasPrice is set, but doesn't validate that required fields for each type are present. For example, SetCodeTx requires a non-nil To field, but this isn't checked until dereferencing.
Consider validating that required fields exist before constructing the transaction:
usedType := types.LegacyTxType
switch {
case txArgs.AuthorizationList != nil || defaultType == types.SetCodeTxType:
+ if txArgs.To == nil {
+ // Fall back to legacy or return error
+ }
usedType = types.SetCodeTxType
case txArgs.BlobHashes != nil || defaultType == types.BlobTxType:
+ if txArgs.To == nil {
+ // Fall back to legacy or return error
+ }
usedType = types.BlobTxType
// ... other cases
}
// Return descriptive errors if required fields are missing
This would enable the API to fail with descriptive errors rather than panicking.
Committable suggestion skipped: line range outside the PR's diff.
if txArgs.Blobs != nil { | ||
data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{ | ||
Blobs: txArgs.Blobs, | ||
Commitments: txArgs.Commitments, | ||
Proofs: txArgs.Proofs, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Verify BlobTx sidecar field validation
The code assigns the sidecar if Blobs are present, but there's no validation that Commitments and Proofs are also present or have matching lengths.
Ensure that the BlobTx sidecar construction properly validates:
- All three fields (Blobs, Commitments, Proofs) are present
- All three fields have the same length
- The length matches the BlobHashes length
Consider adding validation before constructing the sidecar:
🏁 Script executed:
#!/bin/bash
# Check if there are any validations for blob sidecar fields elsewhere in the codebase
rg -A 5 "func.*BlobTxSidecar" --type go
rg -A 5 "BlobTxSidecar.*validate" --type go
rg -A 5 "BlobTx.*validate" --type go
Length of output: 126
🏁 Script executed:
#!/bin/bash
# Inspect the BlobTx and BlobTxSidecar type definitions and search for any Validate methods (case-insensitive)
rg -A 5 'type BlobTxSidecar' --type go
rg -A 5 'type BlobTx ' --type go
rg -i -A 5 'func .*BlobTxSidecar.*validate' --type go
rg -i -A 5 'func .*BlobTx.*validate' --type go
Length of output: 180
Add validation for BlobTx sidecar fields
We didn’t find any existing checks for matching lengths or presence of all three slices. Before assigning the sidecar, validate that:
Blobs
,Commitments
andProofs
are all non-nil- They all have the same length
- That length matches
data.(*types.BlobTx).BlobHashes
Suggested patch:
--- a/eth/types/types.go
+++ b/eth/types/types.go
@@ -175,6 +175,17 @@ func convertTxArgsToCore(txArgs TxArgs, data core.TxData) error {
if txArgs.Blobs != nil {
+ // Validate blob sidecar fields
+ if txArgs.Commitments == nil || txArgs.Proofs == nil {
+ return fmt.Errorf("blob sidecar requires commitments and proofs when blobs are provided")
+ }
+ if len(txArgs.Blobs) != len(txArgs.Commitments) || len(txArgs.Blobs) != len(txArgs.Proofs) {
+ return fmt.Errorf(
+ "invalid blob sidecar lengths: blobs=%d, commitments=%d, proofs=%d",
+ len(txArgs.Blobs), len(txArgs.Commitments), len(txArgs.Proofs),
+ )
+ }
+ if len(txArgs.Blobs) != len(data.(*types.BlobTx).BlobHashes) {
+ return fmt.Errorf(
+ "blob count %d does not match BlobHashes count %d",
+ len(txArgs.Blobs), len(data.(*types.BlobTx).BlobHashes),
+ )
+ }
data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{
Blobs: txArgs.Blobs,
Commitments: txArgs.Commitments,
Proofs: txArgs.Proofs,
}
Don’t forget to import fmt
.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if txArgs.Blobs != nil { | |
data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{ | |
Blobs: txArgs.Blobs, | |
Commitments: txArgs.Commitments, | |
Proofs: txArgs.Proofs, | |
} | |
} | |
if txArgs.Blobs != nil { | |
+ // Validate blob sidecar fields | |
+ if txArgs.Commitments == nil || txArgs.Proofs == nil { | |
+ return fmt.Errorf("blob sidecar requires commitments and proofs when blobs are provided") | |
+ } | |
+ if len(txArgs.Blobs) != len(txArgs.Commitments) || len(txArgs.Blobs) != len(txArgs.Proofs) { | |
+ return fmt.Errorf( | |
+ "invalid blob sidecar lengths: blobs=%d, commitments=%d, proofs=%d", | |
+ len(txArgs.Blobs), len(txArgs.Commitments), len(txArgs.Proofs), | |
+ ) | |
+ } | |
+ if len(txArgs.Blobs) != len(data.(*types.BlobTx).BlobHashes) { | |
+ return fmt.Errorf( | |
+ "blob count %d does not match BlobHashes count %d", | |
+ len(txArgs.Blobs), len(data.(*types.BlobTx).BlobHashes), | |
+ ) | |
+ } | |
data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{ | |
Blobs: txArgs.Blobs, | |
Commitments: txArgs.Commitments, | |
Proofs: txArgs.Proofs, | |
} | |
} |
Closes: #727
Description
For contributor use:
master
branchFiles changed
in the Github PR explorerSummary by CodeRabbit
New Features
Improvements
Dependency Updates