Skip to content

Check guarded relayer on interceptor#7669

Merged
sstanculeanu merged 7 commits into
feat/supernova-async-execfrom
check-guarded-relayer
Feb 5, 2026
Merged

Check guarded relayer on interceptor#7669
sstanculeanu merged 7 commits into
feat/supernova-async-execfrom
check-guarded-relayer

Conversation

@sstanculeanu

Copy link
Copy Markdown
Collaborator

Reasoning behind the pull request

  • guarded relayer check can be added on interceptor as well

Proposed changes

  • add the check

Testing procedure

  • with feat branch, relayed tx v3 with guarded relayer

Pre-requisites

Based on the Contributing Guidelines the PR author and the reviewers must check the following requirements are met:

  • was the PR targeted to the correct branch?
  • if this is a larger feature that probably needs more than one PR, is there a feat branch created?
  • if this is a feat branch merging, do all satellite projects have a proper tag inside go.mod?

return nil
}

func (inTx *InterceptedTransaction) checkGuardedRelayer(tx *transaction.Transaction) error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you instead move the checks into func (txv *txValidator) CheckTxValidity(interceptedTx process.InterceptedTransactionHandler) error ?

this should already be called on the intercepted transactions, and has access to the accounts adapter, so no need to add extra dependencies

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

indeed an easier approach.. pushed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 adds a guarded relayer check to the transaction interceptor for relayed transactions v3. The check prevents guarded accounts from being used as relayers, ensuring consistency between the interceptor validation phase and the transaction processing phase.

Changes:

  • Added AccountsAdapter field to InterceptedTransaction and its factory
  • Implemented checkGuardedRelayer method to validate that relayers are not guarded accounts
  • Updated all call sites and test cases to pass the new AccountsAdapter parameter

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
process/transaction/interceptedTransaction.go Added AccountsAdapter field and checkGuardedRelayer method to validate relayers aren't guarded
process/interceptors/factory/interceptedTxDataFactory.go Updated factory to accept and pass AccountsAdapter to intercepted transactions
process/interceptors/factory/argInterceptedDataFactory.go Added AccountsAdapter field to factory arguments
process/factory/interceptorscontainer/shardInterceptorsContainerFactory.go Added AccountsAdapter from args.Accounts to factory arguments
process/factory/interceptorscontainer/metaInterceptorsContainerFactory.go Added AccountsAdapter from args.Accounts to factory arguments
update/factory/fullSyncInterceptors.go Added AccountsAdapter from args.Accounts to factory arguments
node/node.go Updated NewInterceptedTransaction call to include stateComponents.AccountsAdapter()
epochStart/bootstrap/syncEpochStartMeta.go Added disabled.NewAccountsAdapter() for bootstrap scenario
integrationTests/testHeartbeatNode.go Added AccountsStub to test setup
node/nodeTesting_test.go Enhanced AccountsStub mock with GetExistingAccountCalled implementation
process/transaction/interceptedTransaction_test.go Added test for nil AccountsAdapter, updated all test helpers, added guarded relayer test case
process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go Added AccountsStub to test mocks
process/interceptors/factory/interceptedEquivalentProofsFactory_test.go Added AccountsStub to test mocks

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

Comment on lines 201 to 203
shardCoordinator.ComputeIdCalled = func(address []byte) uint32 {
return 0
}

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

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

The ComputeIdCalled function is assigned twice in this test helper function. The first assignment (lines 184-195) contains the actual logic to handle different addresses, but the second assignment (lines 201-203) unconditionally overwrites it to always return 0. This means the first assignment's logic for distinguishing between senderAddress, relayerAddress, guardedRelayerAddress, recvAddress, and other addresses is never executed. This could cause test failures or incorrect test behavior because the shard coordinator won't properly route addresses to their expected shards.

Suggested change
shardCoordinator.ComputeIdCalled = func(address []byte) uint32 {
return 0
}

Copilot uses AI. Check for mistakes.
Comment on lines 196 to +200
shardCoordinator.SameShardCalled = func(firstAddress, secondAddress []byte) bool {
return string(firstAddress) == string(relayerAddress) &&
string(secondAddress) == string(senderAddress)
string(secondAddress) == string(senderAddress) ||
string(firstAddress) == string(guardedRelayerAddress)
}

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

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

The logic for SameShardCalled is incomplete and may not behave as intended. The condition should have parentheses to clarify operator precedence. Currently, it's evaluated as (string(firstAddress) == string(relayerAddress) && string(secondAddress) == string(senderAddress)) || (string(firstAddress) == string(guardedRelayerAddress)), which returns true if firstAddress is guardedRelayerAddress regardless of secondAddress. This is likely incorrect - it should probably check if both addresses are in the same shard, possibly using (firstAddress == relayerAddress && secondAddress == senderAddress) || (firstAddress == guardedRelayerAddress && secondAddress == senderAddress) or a similar symmetric check.

Copilot uses AI. Check for mistakes.
Comment on lines +309 to +312
relayerAcc, err := inTx.accountsAdapter.GetExistingAccount(tx.RelayerAddr)
if err != nil {
return err
}

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

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

The checkGuardedRelayer method uses GetExistingAccount which returns an error if the account doesn't exist. However, this creates an inconsistency with the transaction processor (shardProcess.go line 730-737) which uses getAccountFromAddress followed by LoadAccount. The processor creates a new account if it doesn't exist, and a new account won't be guarded, so the transaction would be accepted. In the interceptor, a non-existent relayer account will cause GetExistingAccount to return ErrAccNotFound, rejecting the transaction. This means the interceptor could reject valid transactions from new relayers that the processor would accept. Consider using LoadAccount instead or handling the ErrAccNotFound case specifically to allow non-existent accounts (which by definition cannot be guarded).

Copilot uses AI. Check for mistakes.
Comment on lines +309 to +317
relayerAcc, err := inTx.accountsAdapter.GetExistingAccount(tx.RelayerAddr)
if err != nil {
return err
}

relayerAccount, ok := relayerAcc.(state.UserAccountHandler)
if !ok {
return process.ErrWrongTypeAssertion
}

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

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

The checkGuardedRelayer method doesn't handle the case where GetExistingAccount returns nil, nil (no error but nil account). The disabled accounts adapter used during bootstrap (epochStart/bootstrap/disabled/disabledAccountsAdapter.go) returns nil, nil for all account operations. If a relayed transaction v3 is processed during bootstrap when the relayer is in the same shard, this would cause line 314's type assertion to fail (nil cannot be asserted to UserAccountHandler) and return ErrWrongTypeAssertion. Consider adding a nil check after getting the account: if check.IfNil(relayerAcc) { return nil } before the type assertion.

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 3 out of 3 changed files in this pull request and generated no new comments.


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

@sstanculeanu sstanculeanu merged commit ca09b18 into feat/supernova-async-exec Feb 5, 2026
8 of 9 checks passed
@sstanculeanu sstanculeanu deleted the check-guarded-relayer branch February 5, 2026 11:08
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