-
Notifications
You must be signed in to change notification settings - Fork 4.5k
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
Web3.js transaction serialize => deserialize => serialize can produce "Signature verification failed" due to bug in Message serialization #21722
Comments
Created a PR to fix this issue |
Hey, do you think you can help me? #22391 |
Hmm. After this change (#21724) , I can't sign offline transaction, generating by solana cli tool. As soon as solana cli tool generate transaction with this order:
this is example of transaction(done by this code with version 1.31): My workscenario:
Same issue as #22391 PS. this is not a support message. Looks like sorting account breaks some working code. solana/sdk/program/src/message/legacy.rs Line 87 in 7ba57e7
Here sorting is stable, so order of all accounts is determined by transaction list. |
|
Hi @jstarry! |
I don't think it's useful to enforce or follow any kind of canonical account key sorting method. The way |
Hi! |
What would be the next step? |
IMO the next step is what jstarry mentioned above, deser needs to not be reordering anything. That's the fix. Generally I question the motivation for doing a ser -> deser -> ser loop. There's not really any valid reason to do that. Only a compiled |
Thanks. then, e.g. what a canonical way to sign offline nonced transaction, like here from web3? With cli I just write (in code with rust lib the same)
But, if one ot this signature are generating by web3 - I got different order of accounts - diffrent transaction and Signature verification failed. |
also, this reordering broke order of transaction for complex transaction. E.g. we always have first account - is payer, second is new NFT address &etc. |
I faced the same problem with the latest version of @solana/web3.js. So I have a temporary solution Instead of Sign => Serialize => Deserialize => Serialize. I choose Serialize => Deserialize => Sign => Serialize. |
I dug into the code and came up with what I think is causing this. Related: #23641, #23610, anza-xyz/wallet-adapter#350
In short, because of 1), |
Cool, this is what I was referring above when I said that "The way Transaction.populate is decompiling the message account keys is losing the ordering used by the processed transaction so I think we have to get rid of that." So I think we're all in agreement that |
I think most of the So we'd have something like...
|
Thanks for investigating this all! @jstarry fwiw, I missed the implications of your comment so it was helpful to have @jordansexton's longer explanation.
I wonder if it makes sense to remove the Btw, another thing that @jordansexton and I were talking about is that when you set an account to not writable for an instruction, you expect it to stay that way. But if another instruction increases permission levels (makes an account writable) then you lose that guarantee in your first instruction. |
No. Wrong direction. |
What if we throw an error if a I think populating a transaction from a message is still valuable for inspecting the instructions, fee payer, etc. but it needs to be clear that you can't sign it that way.
This seems consistent with what I'm thinking. |
PR attempt @ #23720, please review! |
So what's about this issue? As for me, I'm still getting "Signature verification failed" sometimes. It's very strange, sometimes transactions are passed, sometimes not, despite the fact that algorithm of building on backend-side is the same in all the cases. |
Do you mean that signing "pre-signed -> serialized -> deserilized" transaction is the dead-concept at all? Maybe you can suggest something else? Sorry, I just trying to overcome this bug, but can't find any 100% working solution. |
Fix should be released in |
I'm still seeing a similar issue when signing with backpack and phantom wallets |
Problem
The logic here https://github.com/solana-labs/solana-web3.js/blob/74007a55afa29b36e0535bb9bcff3b64dda9b19e/src/transaction.ts#L261-L281
Can lead to different orderings to accountMetas after serializing and deserializing. The "content" of the transaction is the same, however the accountKeys flipped around. So long as the indices still hold true for writable accounts, the transaction will function the same.
The issue is that this is then serialized and used to create a transaction signature. So this non-determinism can mean that a previously correct signature is now incorrect.
Code to reproduce:
A workaround is to, before pre-signing the transaction, run Transaction.from(tx.serialize({ requireAllSignatures: false })). Then sign the transaction and serialize. This ensures the ordering doesn't get jumbled.
Proposed Solution
Add a default sorting here based on the alphabetical (or just numerical) sorting of the public keys so that this function is deterministic.
https://github.com/solana-labs/solana-web3.js/blob/74007a55afa29b36e0535bb9bcff3b64dda9b19e/src/transaction.ts#L261
The text was updated successfully, but these errors were encountered: