Skip to content
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

solana: Add check for no registered transceivers #298

Conversation

johnsaigle
Copy link
Collaborator

@johnsaigle johnsaigle commented Mar 12, 2024

Add guard on transfer instructions to prevent a transfer from being processed when no transceivers are registered. This is done by checking the next_transceiver_id field in the Config. This field auto-increments when a transceiver is added. If this value is 0, then the program is in a state where no transceivers have been registered.

See also #289 for equivalent checks on the EVM side.

Note that, at this point, there is no ability for Transceivers to be disabled within the Solana implementation. This reduces the risk explored in #289 as the only moment where no Transceivers are registered occurs just after deployment.

@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch 2 times, most recently from 59c79af to 518dceb Compare March 18, 2024 14:48
// ensure that, if all transceivers have been disabled, that an error is returned. Otherwise it
// may be possible to permanently lose funds.
// No transceivers have been registered yet
if accs.common.config.next_transceiver_id == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this check be put in the common account context, maybe in the NotPausedConfig:

#[derive(Accounts)]
pub struct NotPausedConfig<'info> {
    #[account(
        constraint = !config.paused @ crate::error::NTTError::Paused,
        constraint = config.next_transceiver_id != 0 @ NTTError::NoRegisteredTransceivers
    )]
    config: Account<'info, Config>,
}

This would avoid having to put this check in each transfer instruction.

Copy link
Contributor

@a5-pickle a5-pickle Mar 18, 2024

Choose a reason for hiding this comment

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

If it is undesirable to do this check for everything that uses NotPausedConfig btw, adding a constraint in the common transfer context works, too:

    #[account(
        constraint = config.next_transceiver_id != 0 @ NTTError::NoRegisteredTransceivers
    )]
    pub config: NotPausedConfig<'info>,

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the review!
Yeah my intention is just to guard the Transfer functions so adding that constraint in the transfer context makes sense. I'll modify the code.

@johnsaigle johnsaigle self-assigned this Mar 18, 2024
@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch from 518dceb to 1ba37bd Compare March 19, 2024 15:19
@johnsaigle
Copy link
Collaborator Author

johnsaigle commented Mar 19, 2024

EDIT: I made a mistake and it's fixed in the latest commit. I think this should fix the issues with the tests


@a5-pickle I changed the code to add an account constraint instead of the ad-hoc check. Now that it exists, the unit tests is failing. I'm not sure whether this is revealing that we have a real bug in the transfer code or if this is instead an issue with mocking and that the problem exists in the way tests are set-up.

@kcsongor when you have time I'd appreciate if you could maybe checkout the branch and take a look at the tests. I tried poking around the test suite for a while but didn't make much progress. While a transceiver appears to be registered during the SDK's setup() function, I'm not sure that the test/mock (NotPaused)Config is updated, in particular its enabled_transceivers and next_transceiver_id fields.

@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch from 1ba37bd to a1ebc8b Compare March 20, 2024 13:18
@@ -22,6 +22,10 @@ pub struct Redeem<'info> {
pub payer: Signer<'info>,

// NOTE: this works when the contract is paused
#[account(
constraint = config.next_transceiver_id != 0 @ NTTError::NoRegisteredTransceivers,
constraint = config.enabled_transceivers.is_empty() @ NTTError::NoRegisteredTransceivers,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

redeem() will fail if there aren't enough votes/attestations on a message and it's not possible to have attestations without transceivers, so we might as well fail early and with a more accurate error message.

@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch from c6d0161 to 7e19197 Compare March 20, 2024 20:46
@nik-suri nik-suri added the solana Change to Solana programs label Mar 25, 2024
@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch from 7e19197 to 42dddf7 Compare March 26, 2024 16:10
@johnsaigle johnsaigle requested a review from a5-pickle March 27, 2024 13:43
Copy link
Contributor

@kcsongor kcsongor left a comment

Choose a reason for hiding this comment

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

looks good overall, left a couple of minor comments

@@ -101,7 +110,8 @@ describe('example-native-token-transfers', () => {
amount,
recipientChain: 'ethereum',
recipientAddress: Array.from(user.publicKey.toBuffer()), // TODO: dummy
shouldQueue: false
shouldQueue: false,
config: await ntt.getConfig()
Copy link
Contributor

Choose a reason for hiding this comment

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

is this necessary? the function internally will make this exact function call anyway

@@ -180,6 +190,7 @@ describe('example-native-token-transfers', () => {
const released = await ntt.redeem({
payer,
vaa: vaaBuf,
config: await ntt.getConfig()
Copy link
Contributor

Choose a reason for hiding this comment

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

same as above

@johnsaigle
Copy link
Collaborator Author

@kcsongor thanks for the review. You're right that the arguments are redundant and don't seem to affect the test results. I've removed them in the latest commit.

a5-pickle
a5-pickle previously approved these changes Mar 30, 2024
@johnsaigle johnsaigle requested a review from kcsongor April 1, 2024 12:38
@johnsaigle johnsaigle dismissed kcsongor’s stale review April 11, 2024 17:50

Stale; changes have been addressed

@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch from 9918acd to f0cf7e2 Compare April 12, 2024 19:30
@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch from f0cf7e2 to aaf1e43 Compare May 3, 2024 18:06
@nik-suri nik-suri added enhancement New feature or request P1 labels May 8, 2024
@johnsaigle johnsaigle force-pushed the solana/empty-transceiver-guard branch from aaf1e43 to 2e6c3be Compare May 9, 2024 14:05
@nik-suri nik-suri requested a review from a5-pickle May 15, 2024 18:15
Add guard on transfer instructions to prevent a transfer from being
processed when no transceivers are registered. This is done by checking
the `next_transceiver_id` field in the Config. This field
auto-increments when a transceiver is added. If this value is 0, then
the program is in a state where no transceivers have been registered.
@nvsriram
Copy link
Collaborator

Changes merged through #514

@nvsriram nvsriram closed this Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request P1 solana Change to Solana programs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants