There are two programs: master
and puppet
.
On the client side the puppet is called in order to initialize an account on the puppet using an uuid v4 as seed.
Then, the client calls the master
to proxy a "set instruction" to the puppet, which will update some attribute on this previously created account.
The odd behavior is the following:
- using this seed (split in two because it exceeds the max length) it works fine
const pdaId = "37f9b205-998c-4583-8d58-ebb7db846755";
- using this seed, does not
const pdaId = "25df58b2-e5a7-46c7-9803-fdfd2a3895d4";
Master program
#[program]
pub mod pupper_master {
use super::*;
pub fn pull_strings(
ctx: Context<PullStrings>,
pda_id: String,
base_bump: u8,
data: u16,
) -> Result<()> {
msg!("making a cpi call");
let seeds = &[
pda_id.as_bytes()[..18].as_ref(),
pda_id.as_bytes()[18..].as_ref(),
&[base_bump],
];
let signer = &[&seeds[..]];
let cpi_accounts = SetData {
puppet: ctx.accounts.puppet_account.to_account_info(),
};
let cpi_program = ctx.accounts.puppet_program.to_account_info();
let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer);
puppet_cpi::cpi::set_data(
cpi_ctx,
pda_id.clone(),
base_bump,
data
)?;
Ok(())
}
}
#[derive(Accounts)]
#[instruction(pda_id: String, base_bump: u8)]
pub struct PullStrings<'info> {
#[account(mut, seeds = [pda_id.as_bytes()[..18].as_ref(), pda_id.as_bytes()[18..].as_ref()],bump = base_bump, seeds::program = puppet_program.key())]
pub puppet_account: Account<'info, Data>,
pub puppet_program: Program<'info, PuppetCpi>,
}
Puppet program
#[program]
pub mod puppet_cpi {
use super::*;
pub fn initialize(ctx: Context<Initialize>, _pda_id: String, authority: Pubkey) -> Result<()> {
ctx.accounts.puppet.authority = authority;
Ok(())
}
pub fn set_data(ctx: Context<SetData>, _pda_id: String, _base_bump: u8, data: u16) -> Result<()> {
let puppet = &mut ctx.accounts.puppet;
puppet.data = data;
Ok(())
}
}
#[derive(Accounts)]
#[instruction(pda_id: String)]
pub struct Initialize<'info> {
#[account(init, payer = user, seeds = [pda_id.as_bytes()[..18].as_ref(), pda_id.as_bytes()[18..].as_ref()],bump, space = 9000)]
pub puppet: Account<'info, Data>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>
}
#[derive(Accounts)]
#[instruction(pda_id: String, base_bump: u8)]
pub struct SetData<'info> {
#[account(mut, seeds = [pda_id.as_bytes()[..18].as_ref(), pda_id.as_bytes()[18..].as_ref()],bump = base_bump)]
pub puppet: Account<'info, Data>,
}
#[account]
pub struct Data{
pub data: u16,
pub authority: Pubkey
}
And the test on the client side does:
it("funds the user", async () => {
await provider.connection.confirmTransaction(
await provider.connection.requestAirdrop(admin.publicKey, 10000000000),
"confirmed"
);
const adminUserBalance = await provider.connection.getBalance(
admin.publicKey
);
assert.strictEqual(10000000000, adminUserBalance);
});
it("Initialize the pupper", async () => {
const [puppetPDA, puppetBump] =
await anchor.web3.PublicKey.findProgramAddress(
[
Buffer.from(pdaId.substring(0, 18)),
Buffer.from(pdaId.substring(18, 36)),
],
puppet.programId
);
const tx = await puppet.methods.initialize(pdaId, admin.publicKey).accounts({
puppet: puppetPDA,
user: admin.publicKey,
systemProgram: anchor.web3.SystemProgram.programId
}).signers([admin]).rpc();
});
it("make a cpi call", async() => {
const [puppetPDA, puppetBump] =
await anchor.web3.PublicKey.findProgramAddress(
[
Buffer.from(pdaId.substring(0, 18)),
Buffer.from(pdaId.substring(18, 36)),
],
puppet.programId
);
const tx = await master.methods.pullStrings(pdaId, puppetBump, new anchor.BN(10)).accounts({
puppetAccount: puppetPDA,
puppetProgram: puppet.programId
}).rpc();
console.log(tx)
})
And finally the error
puppet_cpi
✔ funds the user (304ms)
✔ Initialize the pupper (471ms)
1) make a cpi call
2 passing (872ms)
1 failing
1) puppet_cpi
make a cpi call:
Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Program failed to complete
at Connection.sendEncodedTransaction (node_modules/@solana/web3.js/src/connection.ts:4068:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Connection.sendRawTransaction (node_modules/@solana/web3.js/src/connection.ts:4030:20)
at sendAndConfirmRawTransaction (node_modules/@project-serum/anchor/src/provider.ts:286:21)
at Provider.send (node_modules/@project-serum/anchor/src/provider.ts:120:14)
at MethodsBuilder.rpc [as _rpcFn] (node_modules/@project-serum/anchor/src/program/namespace/rpc.ts:24:16)
The repo/branch is https://github.com/dhruvja/test-cpi-with-pda/tree/testing_uid_with_cpi
anchor_lang
version in each Cargo.toml to > 0.24.2 I just pulled down your repo and got the same errors as you but once I changed anchor_lang to 0.25 it went awayProgram failed to complete: Could not create program address with signer seeds: Provided seeds do not result in a valid address