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

Unable to decode event Instruction: X #2827

Open
arijoon opened this issue Feb 28, 2024 · 5 comments
Open

Unable to decode event Instruction: X #2827

arijoon opened this issue Feb 28, 2024 · 5 comments
Labels

Comments

@arijoon
Copy link

arijoon commented Feb 28, 2024

When using event parsers parseLogs if errorOnDecodeFailure is set to true the parser throws on the very first log which is always Program logged: "Instruction: X", X being whatever instruction is being executed. Is this an intended feature?

Additionally is it possible for another program to spoof the logs pretending to be a different program we're interested in?

@acheroncrypto
Copy link
Collaborator

When using event parsers parseLogs if errorOnDecodeFailure is set to true the parser throws on the very first log which is always Program logged: "Instruction: X", X being whatever instruction is being executed. Is this an intended feature?

It's most likely not the intended behavior if it always throws.

Additionally is it possible for another program to spoof the logs pretending to be a different program we're interested in?

We're essentially parsing the logs so I think it's possible to spoof it, but if you'd like to avoid that, there is event-cpi feature which requires "signing" an invocation with a PDA.

@arijoon
Copy link
Author

arijoon commented Feb 29, 2024

We're essentially parsing the logs so I think it's possible to spoof it, but if you'd like to avoid that, there is event-cpi feature which requires "signing" an invocation with a PDA.

Oh thanks for this. I saw that feature but based on original docs assumed its only used to guarantee its available when logs are truncated. If that is far more secure then would certainly opt for it. Assuming it can be parsed with the Anchor event parser in a similar way or it needs to be parsed differently?

@acheroncrypto
Copy link
Collaborator

It needs to be parsed differently because it's not log based like the normal events. Here is an example:

const ixData = anchor.utils.bytes.bs58.decode(
txResult.meta.innerInstructions[0].instructions[0].data
);
const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8));
const event = program.coder.events.decode(eventData);

@arijoon
Copy link
Author

arijoon commented Mar 3, 2024

It needs to be parsed differently because it's not log based like the normal events. Here is an example:

Thanks a lot this is much appreciated, indeed the event in the tx data looks a lot more secure than just parsing logs. One final question. Is checking the innerInstructions and ensuring account (__event_authority of our program) and programId are correct, then parsing the data enough to guarantee no other program could have spoofed this? Basically wondering if any other program can cause this cpi into our program (which has the event) without going through the top level instructions and somehow emit this CPI inner tx?

@acheroncrypto
Copy link
Collaborator

Is checking the innerInstructions and ensuring account (__event_authority of our program) and programId are correct, then parsing the data enough to guarantee no other program could have spoofed this?

Yes, checking those accounts should be enough because the event authority needs to "sign" to make self-CPI work.

Basically wondering if any other program can cause this cpi into our program (which has the event) without going through the top level instructions and somehow emit this CPI inner tx?

They shouldn't be able to do this because of the same reason above, the event authority needs to "sign" the invocation. We also have a test for this case:

it("Throws on unauthorized invocation", async () => {
const tx = new anchor.web3.Transaction();
tx.add(
new anchor.web3.TransactionInstruction({
programId: program.programId,
keys: [
{
pubkey: anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("__event_authority")],
program.programId
)[0],
isSigner: false,
isWritable: false,
},
{
pubkey: program.programId,
isSigner: false,
isWritable: false,
},
],
data: Buffer.from([0xe4, 0x45, 0xa5, 0x2e, 0x51, 0xcb, 0x9a, 0x1d]),
})
);
try {
await program.provider.sendAndConfirm(tx, []);
} catch (e) {
if (e.logs.some((log) => log.includes("ConstraintSigner"))) return;
console.log(e);
}
throw new Error("Was able to invoke the self-CPI instruction");
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants