diff --git a/solana/restaking/programs/restaking/Cargo.toml b/solana/restaking/programs/restaking/Cargo.toml index ca817d2f..ffa4209d 100644 --- a/solana/restaking/programs/restaking/Cargo.toml +++ b/solana/restaking/programs/restaking/Cargo.toml @@ -15,6 +15,7 @@ no-entrypoint = [] no-idl = [] no-log-ix-name = [] cpi = ["no-entrypoint"] +witness = ["solana-ibc/witness"] default = [] [dependencies] diff --git a/solana/restaking/programs/restaking/src/lib.rs b/solana/restaking/programs/restaking/src/lib.rs index dcbd306e..f0f4ba80 100644 --- a/solana/restaking/programs/restaking/src/lib.rs +++ b/solana/restaking/programs/restaking/src/lib.rs @@ -53,6 +53,7 @@ pub mod restaking { /// sent in the same order as given below /// - Chain Data /// - trie + /// - witness (if compiled with `witness` Cargo feature) /// - Guest blockchain program ID pub fn deposit<'a, 'info>( ctx: Context<'a, 'a, 'a, 'info, Deposit<'info>>, @@ -106,8 +107,12 @@ pub mod restaking { let validator_key = match service { Service::GuestChain { validator } => validator, }; + let remaining_accounts = validation::validate_remaining_accounts( + ctx.remaining_accounts, + &guest_chain_program_id, + )?; let borrowed_chain_data = - ctx.remaining_accounts[0].data.try_borrow().unwrap(); + remaining_accounts.chain.try_borrow_data().unwrap(); let mut chain_data: &[u8] = &borrowed_chain_data; let chain = solana_ibc::chain::ChainData::try_deserialize(&mut chain_data) @@ -118,20 +123,19 @@ pub mod restaking { let amount = validator.map_or(u128::from(amount), |val| { u128::from(val.stake) + u128::from(amount) }); - validation::validate_remaining_accounts( - ctx.remaining_accounts, - &guest_chain_program_id, - )?; core::mem::drop(borrowed_chain_data); + let cpi_accounts = SetStake { sender: ctx.accounts.depositor.to_account_info(), - chain: ctx.remaining_accounts[0].clone(), - trie: ctx.remaining_accounts[1].clone(), + chain: remaining_accounts.chain.clone(), + trie: remaining_accounts.trie.clone(), + #[cfg(feature = "witness")] + witness: remaining_accounts.witness.clone(), system_program: ctx.accounts.system_program.to_account_info(), instruction: ctx.accounts.instruction.to_account_info(), }; - let cpi_program = ctx.remaining_accounts[2].clone(); - let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); + let cpi_ctx = + CpiContext::new(remaining_accounts.program.clone(), cpi_accounts); solana_ibc::cpi::set_stake(cpi_ctx, validator_key, amount) } @@ -359,6 +363,8 @@ pub mod restaking { sender: ctx.accounts.withdrawer.to_account_info(), chain: chain.to_account_info(), trie: ctx.accounts.trie.to_account_info(), + #[cfg(feature = "witness")] + witness: ctx.accounts.witness.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), instruction: validation::check_instructions_sysvar( &ctx.accounts.instruction, @@ -550,7 +556,6 @@ pub mod restaking { ) -> Result<()> { let vault_params = &mut ctx.accounts.vault_params; let staking_params = &mut ctx.accounts.staking_params; - let guest_chain = &ctx.remaining_accounts[0]; let token_account = &ctx.accounts.receipt_token_account; if token_account.amount < 1 { @@ -561,6 +566,10 @@ pub mod restaking { Some(id) => id, None => return Err(error!(ErrorCodes::OperationNotAllowed)), }; + let remaining_accounts = validation::validate_remaining_accounts( + ctx.remaining_accounts, + &guest_chain_program_id, + )?; if vault_params.service.is_some() { return Err(error!(ErrorCodes::ServiceAlreadySet)); } @@ -577,7 +586,8 @@ pub mod restaking { let validator_key = match service { Service::GuestChain { validator } => validator, }; - let borrowed_chain_data = guest_chain.data.try_borrow().unwrap(); + let borrowed_chain_data = + remaining_accounts.chain.try_borrow_data().unwrap(); let mut chain_data: &[u8] = &borrowed_chain_data; let chain = solana_ibc::chain::ChainData::try_deserialize(&mut chain_data) @@ -593,15 +603,17 @@ pub mod restaking { let cpi_accounts = SetStake { sender: ctx.accounts.depositor.to_account_info(), - chain: guest_chain.to_account_info(), - trie: ctx.remaining_accounts[1].clone(), + chain: remaining_accounts.chain.clone(), + trie: remaining_accounts.trie.clone(), + #[cfg(feature = "witness")] + witness: remaining_accounts.witness.clone(), system_program: ctx.accounts.system_program.to_account_info(), instruction: validation::check_instructions_sysvar( &ctx.accounts.instruction, )?, }; - let cpi_program = ctx.remaining_accounts[2].clone(); - let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); + let cpi_ctx = + CpiContext::new(remaining_accounts.program.clone(), cpi_accounts); solana_ibc::cpi::set_stake(cpi_ctx, validator_key, amount) } @@ -865,6 +877,10 @@ pub struct Withdraw<'info> { #[account(mut, seeds = [TRIE_SEED], bump, seeds::program = guest_chain_program.key())] /// CHECK: pub trie: AccountInfo<'info>, + #[cfg(feature = "witness")] + #[account(mut, seeds = [solana_ibc::WITNESS_SEED, trie.key().as_ref()], bump)] + /// CHECK: + pub witness: AccountInfo<'info>, pub token_mint: Box>, #[account(mut, token::mint = token_mint)] diff --git a/solana/restaking/programs/restaking/src/validation.rs b/solana/restaking/programs/restaking/src/validation.rs index c0ed6d19..1e3a2d7e 100644 --- a/solana/restaking/programs/restaking/src/validation.rs +++ b/solana/restaking/programs/restaking/src/validation.rs @@ -1,8 +1,15 @@ use anchor_lang::prelude::*; -use solana_ibc::{CHAIN_SEED, TRIE_SEED}; use crate::ErrorCodes; +pub(crate) struct RemainingAccounts<'a, 'info> { + pub chain: &'a AccountInfo<'info>, + pub trie: &'a AccountInfo<'info>, + #[cfg(feature = "witness")] + pub witness: &'a AccountInfo<'info>, + pub program: &'a AccountInfo<'info>, +} + /// Validates accounts needed for CPI call to the guest chain. /// /// Right now, this method would only validate accounts for calling `set_stake` @@ -10,42 +17,85 @@ use crate::ErrorCodes; /// extend this method below to do the validation for those accounts as well. /// /// Accounts needed for calling `set_stake` -/// - chain: PDA with seeds ["chain"]. Should be writable -/// - trie: PDA with seeds ["trie"] +/// - chain: PDA with seeds ["chain"]. Must be writable. +/// - trie: PDA with seeds ["trie"]. Must be writable. +/// - witness: Only if compiled with `witness` Cargo feature. PDA with seeds +/// `["witness", trie.key()]`. Must be writable. /// - guest chain program ID: Should match the expected guest chain program ID /// /// Note: The accounts should be sent in above order. -pub(crate) fn validate_remaining_accounts( - accounts: &[AccountInfo<'_>], +pub(crate) fn validate_remaining_accounts<'a, 'info>( + accounts: &'a [AccountInfo<'info>], expected_guest_chain_program_id: &Pubkey, -) -> Result<()> { +) -> Result> { + let accounts = &mut accounts.iter(); + // Chain account - let seeds = [CHAIN_SEED]; - let seeds = seeds.as_ref(); + let chain = next_pda_account( + accounts, + [solana_ibc::CHAIN_SEED].as_ref(), + expected_guest_chain_program_id, + true, + "chain", + )?; - let (storage_account, _bump) = - Pubkey::find_program_address(seeds, expected_guest_chain_program_id); - if &storage_account != accounts[0].key && accounts[0].is_writable { - return Err(error!(ErrorCodes::AccountValidationFailedForCPI)); - } // Trie account - let seeds = [TRIE_SEED]; - let seeds = seeds.as_ref(); + let trie = next_pda_account( + accounts, + [solana_ibc::TRIE_SEED].as_ref(), + expected_guest_chain_program_id, + true, + "trie", + )?; - let (storage_account, _bump) = - Pubkey::find_program_address(seeds, expected_guest_chain_program_id); - if &storage_account != accounts[1].key && accounts[1].is_writable { - return Err(error!(ErrorCodes::AccountValidationFailedForCPI)); - } + // Trie account + #[cfg(feature = "witness")] + let witness = next_pda_account( + accounts, + [solana_ibc::WITNESS_SEED, trie.key().as_ref()].as_ref(), + expected_guest_chain_program_id, + true, + "witness", + )?; // Guest chain program ID - if expected_guest_chain_program_id != accounts[2].key { - return Err(error!(ErrorCodes::AccountValidationFailedForCPI)); - } + let program = next_account_info(accounts) + .ok() + .filter(|info| expected_guest_chain_program_id == info.key) + .ok_or_else(|| error!(ErrorCodes::AccountValidationFailedForCPI))?; - Ok(()) + Ok(RemainingAccounts { + chain, + trie, + program, + #[cfg(feature = "witness")] + witness, + }) } +fn next_pda_account<'a, 'info>( + accounts: &mut impl core::iter::Iterator>, + seeds: &[&[u8]], + program_id: &Pubkey, + must_be_mut: bool, + account_name: &str, +) -> Result<&'a AccountInfo<'info>> { + (|| { + let info = next_account_info(accounts).ok()?; + let addr = Pubkey::try_find_program_address(seeds, program_id)?.0; + if &addr == info.key && (!must_be_mut || info.is_writable) { + Some(info) + } else { + None + } + })() + .ok_or_else(|| { + error!(ErrorCodes::AccountValidationFailedForCPI) + .with_account_name(account_name) + }) +} + + /// Verifies that given account is the Instruction sysvars and returns it if it /// is. pub(crate) fn check_instructions_sysvar<'info>( diff --git a/solana/solana-ibc/programs/solana-ibc/Cargo.toml b/solana/solana-ibc/programs/solana-ibc/Cargo.toml index d9c228c6..d2013aea 100644 --- a/solana/solana-ibc/programs/solana-ibc/Cargo.toml +++ b/solana/solana-ibc/programs/solana-ibc/Cargo.toml @@ -10,6 +10,7 @@ name = "solana_ibc" [features] default = ["custom-entrypoint", "custom-heap"] +witness = [] cpi = ["no-entrypoint"] custom-heap = ["solana-allocator"] custom-entrypoint = ["custom-heap"] diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 843e02bf..7c4caf91 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -21,6 +21,8 @@ pub const CHAIN_SEED: &[u8] = b"chain"; pub const PACKET_SEED: &[u8] = b"packet"; pub const SOLANA_IBC_STORAGE_SEED: &[u8] = b"private"; pub const TRIE_SEED: &[u8] = b"trie"; +#[cfg(feature = "witness")] +pub const WITNESS_SEED: &[u8] = b"witness"; pub const MINT_ESCROW_SEED: &[u8] = b"mint_escrow"; pub const MINT: &[u8] = b"mint"; pub const ESCROW: &[u8] = b"escrow"; @@ -116,6 +118,8 @@ pub mod solana_ibc { ) -> Result<()> { let mut provable = storage::get_provable_from( &ctx.accounts.trie, + #[cfg(feature = "witness")] + &ctx.accounts.witness, &ctx.accounts.sender, )?; ctx.accounts.chain.initialise( @@ -137,6 +141,8 @@ pub mod solana_ibc { pub fn generate_block(ctx: Context) -> Result<()> { let provable = storage::get_provable_from( &ctx.accounts.trie, + #[cfg(feature = "witness")] + &ctx.accounts.witness, &ctx.accounts.sender, )?; ctx.accounts.chain.generate_block(&provable) @@ -161,6 +167,8 @@ pub mod solana_ibc { ) -> Result<()> { let provable = storage::get_provable_from( &ctx.accounts.trie, + #[cfg(feature = "witness")] + &ctx.accounts.witness, &ctx.accounts.sender, )?; let mut verifier = sigverify::Verifier::default(); @@ -193,6 +201,8 @@ pub mod solana_ibc { let chain = &mut ctx.accounts.chain; let provable = storage::get_provable_from( &ctx.accounts.trie, + #[cfg(feature = "witness")] + &ctx.accounts.witness, &ctx.accounts.sender, )?; chain.maybe_generate_block(&provable)?; @@ -216,6 +226,8 @@ pub mod solana_ibc { let chain = &mut ctx.accounts.chain; let provable = storage::get_provable_from( &ctx.accounts.trie, + #[cfg(feature = "witness")] + &ctx.accounts.witness, &ctx.accounts.sender, )?; chain.maybe_generate_block(&provable)?; @@ -599,6 +611,15 @@ pub struct Initialise<'info> { #[account(init, payer = sender, seeds = [TRIE_SEED], bump, space = 10240)] trie: UncheckedAccount<'info>, + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(init, payer = sender, space = 40, + seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, + system_program: Program<'info, System>, } @@ -618,6 +639,14 @@ pub struct Chain<'info> { #[account(mut, seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(mut, seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, + system_program: Program<'info, System>, } @@ -637,6 +666,14 @@ pub struct SetStake<'info> { #[account(mut, seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(mut, seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, + system_program: Program<'info, System>, #[account(address = solana_program::sysvar::instructions::ID)] @@ -661,6 +698,14 @@ pub struct ChainWithVerifier<'info> { #[account(mut, seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(mut, seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, + #[account(address = solana_program::sysvar::instructions::ID)] /// CHECK: ix_sysvar: AccountInfo<'info>, @@ -759,6 +804,14 @@ pub struct Deliver<'info> { #[account(mut, seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(mut, seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, + /// The guest blockchain data. #[account(mut, seeds = [CHAIN_SEED], bump)] chain: Box>, @@ -799,6 +852,14 @@ pub struct MockDeliver<'info> { #[account(mut, seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(mut, seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, + /// The guest blockchain data. #[account(mut, seeds = [CHAIN_SEED], bump)] chain: Account<'info, chain::ChainData>, @@ -826,6 +887,14 @@ pub struct SendTransfer<'info> { #[account(mut, seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(mut, seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, + /// The guest blockchain data. #[account(mut, seeds = [CHAIN_SEED], bump)] chain: Box>, @@ -892,6 +961,14 @@ pub struct UpdateConnectionDelay<'info> { /// function. #[account(mut, seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, + + /// The witness account holding trie’s state root. + /// + /// CHECK: Account’s owner and address is checked by + /// [`storage::get_provable_from`] function. + #[cfg(feature = "witness")] + #[account(mut, seeds = [WITNESS_SEED, trie.key().as_ref()], bump)] + witness: UncheckedAccount<'info>, } impl ibc::Router for storage::IbcStorage<'_, '_> { diff --git a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs index 53489f09..8021b44c 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs @@ -15,6 +15,8 @@ pub(crate) fn mock_deliver<'a, 'info>( private: &mut ctx.accounts.storage, provable: storage::get_provable_from( &ctx.accounts.trie, + #[cfg(feature = "witness")] + &ctx.accounts.witness, &ctx.accounts.sender, )?, chain: &mut ctx.accounts.chain, diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage.rs b/solana/solana-ibc/programs/solana-ibc/src/storage.rs index 178f810f..712d80ba 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage.rs @@ -404,20 +404,29 @@ pub type TrieAccount<'a, 'b> = /// account will never be shrunk. pub fn get_provable_from<'a, 'info>( info: &'a UncheckedAccount<'info>, + #[cfg(feature = "witness")] witness: &'a UncheckedAccount<'info>, payer: &'a Signer<'info>, ) -> Result> { - TrieAccount::from_account_with_payer(info, &crate::ID, payer).map_err( - |err| { - let bad_owner = matches!(err, ProgramError::InvalidAccountOwner); - let err = Error::from(err); - let err = if bad_owner { - err.with_pubkeys((*info.owner, crate::ID)) - } else { - err - }; - err.with_account_name("trie") - }, - ) + let make_err = |err, info: &'a AccountInfo<'info>, name| { + let bad_owner = matches!(err, ProgramError::InvalidAccountOwner); + let mut err = Error::from(err); + if bad_owner { + err = err.with_pubkeys((*info.owner, crate::ID)); + } + err.with_account_name(name) + }; + + #[allow(unused_mut)] + let mut trie = + TrieAccount::from_account_with_payer(info, &crate::ID, payer) + .map_err(|err| make_err(err, info, "trie"))?; + #[cfg(feature = "witness")] + { + trie = trie + .with_witness_account(witness, &crate::ID) + .map_err(|err| make_err(err, witness, "witness"))?; + } + Ok(trie) } /// Used for finding the account info from the keys. @@ -542,7 +551,11 @@ macro_rules! from_ctx { }}; ($ctx:expr, accounts = $accounts:expr) => {{ let provable = $crate::storage::get_provable_from( - &$ctx.accounts.trie, &$ctx.accounts.sender)?; + &$ctx.accounts.trie, + #[cfg(feature = "witness")] + &$ctx.accounts.witness, + &$ctx.accounts.sender, + )?; let chain = &mut $ctx.accounts.chain; // Before anything else, try generating a new guest block. However, if diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 0f7ed436..0a7e7915 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -110,6 +110,12 @@ fn anchor_test_deliver() -> Result<()> { ) .0; let trie = Pubkey::find_program_address(&[crate::TRIE_SEED], &crate::ID).0; + #[cfg(feature = "witness")] + let witness = Pubkey::find_program_address( + &[crate::WITNESS_SEED, trie.as_ref()], + &crate::ID, + ) + .0; let chain = Pubkey::find_program_address(&[crate::CHAIN_SEED], &crate::ID).0; let fee_collector_pda = @@ -155,6 +161,8 @@ fn anchor_test_deliver() -> Result<()> { sender: authority.pubkey(), storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, }) @@ -251,6 +259,8 @@ fn anchor_test_deliver() -> Result<()> { receiver: None, storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, mint_authority: None, @@ -306,6 +316,8 @@ fn anchor_test_deliver() -> Result<()> { receiver: None, storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, mint_authority: None, @@ -343,6 +355,8 @@ fn anchor_test_deliver() -> Result<()> { sender: authority.pubkey(), storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, }) @@ -524,6 +538,8 @@ fn anchor_test_deliver() -> Result<()> { receiver: Some(receiver.pubkey()), storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, mint_authority: Some(mint_authority_key), @@ -609,6 +625,8 @@ fn anchor_test_deliver() -> Result<()> { receiver: Some(receiver.pubkey()), storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, mint_authority: Some(mint_authority_key), @@ -679,6 +697,8 @@ fn anchor_test_deliver() -> Result<()> { receiver: Some(authority.pubkey()), storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, mint_authority: Some(mint_authority_key), @@ -768,6 +788,8 @@ fn anchor_test_deliver() -> Result<()> { receiver: Some(receiver.pubkey()), storage, trie, + #[cfg(feature = "witness")] + witness, chain, system_program: system_program::ID, mint_authority: Some(mint_authority_key), diff --git a/validator/Cargo.toml b/validator/Cargo.toml index 6d048d0a..18273703 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -32,3 +32,6 @@ restaking.workspace = true solana-signature-verifier = { workspace = true, features = ["library"] } solana-ibc.workspace = true solana-trie.workspace = true + +[features] +witness = ["solana-ibc/witness"] diff --git a/validator/src/utils.rs b/validator/src/utils.rs index 280f08f9..6809c488 100644 --- a/validator/src/utils.rs +++ b/validator/src/utils.rs @@ -121,6 +121,13 @@ pub fn submit_call( max_retries: usize, priority_fees: &u64, ) -> Result { + #[cfg(feature = "witness")] + let witness = Pubkey::find_program_address( + [solana_ibc::WITNESS_SEED, trie.as_ref()].as_ref(), + &program.id(), + ) + .0; + let mut tx = Ok(signature); for tries in 0..max_retries { tx = program @@ -140,6 +147,8 @@ pub fn submit_call( sender: validator.pubkey(), chain, trie, + #[cfg(feature = "witness")] + witness, ix_sysvar: anchor_lang::solana_program::sysvar::instructions::ID, system_program: system_program::ID, @@ -168,6 +177,13 @@ pub fn submit_generate_block_call( max_retries: usize, priority_fees: &u64, ) -> Result { + #[cfg(feature = "witness")] + let witness = Pubkey::find_program_address( + [solana_ibc::WITNESS_SEED, trie.as_ref()].as_ref(), + &program.id(), + ) + .0; + let mut tx = Ok(Signature::new_unique()); for tries in 0..max_retries { tx = program @@ -182,6 +198,8 @@ pub fn submit_generate_block_call( sender: validator.pubkey(), chain, trie, + #[cfg(feature = "witness")] + witness, system_program: anchor_lang::system_program::ID, }) .args(instruction::GenerateBlock {})