-
Notifications
You must be signed in to change notification settings - Fork 4.6k
fix: transactions populated from RPC requests retain original account key order #23720
fix: transactions populated from RPC requests retain original account key order #23720
Conversation
I think this gets the job done. Kinda sucks carrying the duplicate data around, but given the rest of the inefficiencies in the lib, probably a small price to pay for compatibility |
Current fix looks great!
What if we cache the fields which affect message compilation ( |
b3918c6
to
2bee371
Compare
2bee371
to
97158ba
Compare
Hmm, we could do that. My instinctual preference is to fail fast if someone tries to modify a Transaction that shouldn't be modified rather than wait until it's serialized. But throwing errors inside of setters is kind of gross on multiple levels. @steveluscher thoughts? |
That was what motivated me to suggest not being able to deser into |
I've only thought about this for three seconds, but this strikes me as a worthwhile project. You'd have to upgrade all consumers of If you did it this way, TypeScript will prevent you from trying to modify such a transaction, saving you from having to find out at runtime, which is nice. More work though. |
Cool, I think we all agree that overhauling the transaction class is the way to go but this PR is still a good incremental fix. I'm fine with it as is. |
Codecov Report
@@ Coverage Diff @@
## master #23720 +/- ##
===========================================
- Coverage 81.8% 70.0% -11.8%
===========================================
Files 581 36 -545
Lines 158312 2255 -156057
Branches 0 322 +322
===========================================
- Hits 129518 1580 -127938
+ Misses 28794 560 -28234
- Partials 0 115 +115 |
@steveluscher @jstarry this has been done. Implementation is pretty ugly, but I'm not sure how to make it cleaner and still check everything. |
0ab12bf
to
b9d69f5
Compare
b9d69f5
to
e1e9c02
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Since there are so many throws
you might consider doing something like…
function fail(): never {
throw new Error(...);
}
if (transaction.foo !== originalTransaction.foo) {
fail();
}
…but ¯\_(ツ)_/¯
I think I came up with something that would be cleaner here: jordaaash#1. What do you think? (cc @steveluscher to take a look) |
Nice; yeah, at one point I had thought about hashing properties of the transaction to be able to detect modifications, but then I forgot. You could even use one of these ‘stable stringify’ implementations and just throw a giant bundle of properties at it. https://www.npmjs.com/search?q=stable%20stringify Pluses: easy way to get a unique identifier Either way, if any material property ever gets added to |
I believe we will deprecate this |
Pull request has been modified.
Haha that approach is so much cleaner. I merged your stringify change, though I'm not sure offhand how the objects, especially |
If this need to stringify objects in a way that's stable – regardless of whether keys are in different orders – ever comes up again, this is one of my favs. |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
@Mergifyio rebase |
❌ Base branch update has failedGit reported the following error:
err-code: 8C36A |
@jordansexton do you mind rebasing and merging this when you get the chance? |
Pull request has been modified.
24cbbba
to
c81f047
Compare
@jstarry unfortunately there's a failing test which surfaced this issue: solana/web3.js/src/connection.ts Lines 3897 to 3905 in 6c5a3ca
Transaction simulation from a Message relies on modifying the transaction after populating it. If I merge this change as is, it will break transaction simulation. I did something very hacky and unset the internal properties in this instance to keep the current behavior of If tests pass now, I'll merge away. |
c81f047
to
de58333
Compare
… key order (solana-labs#23720) * fix: transaction populate * chore: web3: fix tx serialization test * chore: web3: run prettier * fix: web3: transaction populate * fix: web3: handle nonce info * add hash calc config.use_write_cache (solana-labs#24005) * restore existing overlapping overflow (solana-labs#24010) * Stringify populated transaction fields * fix: web3: compare stringified JSON * chore: web3: remove eslint indent rule that conflicts with prettier * fix: web3: explicitly call toJSON * fix: web3: add test for compileMessage * fix: web3: make JSON internal * fix: web3: connection simulation from message relies on mutating transaction Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com> Co-authored-by: Jack May <jack@solana.com> Co-authored-by: Justin Starry <justin@solana.com>
… key order (solana-labs#23720) * fix: transaction populate * chore: web3: fix tx serialization test * chore: web3: run prettier * fix: web3: transaction populate * fix: web3: handle nonce info * add hash calc config.use_write_cache (solana-labs#24005) * restore existing overlapping overflow (solana-labs#24010) * Stringify populated transaction fields * fix: web3: compare stringified JSON * chore: web3: remove eslint indent rule that conflicts with prettier * fix: web3: explicitly call toJSON * fix: web3: add test for compileMessage * fix: web3: make JSON internal * fix: web3: connection simulation from message relies on mutating transaction Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com> Co-authored-by: Jack May <jack@solana.com> Co-authored-by: Justin Starry <justin@solana.com>
… key order (solana-labs#23720) * fix: transaction populate * chore: web3: fix tx serialization test * chore: web3: run prettier * fix: web3: transaction populate * fix: web3: handle nonce info * add hash calc config.use_write_cache (solana-labs#24005) * restore existing overlapping overflow (solana-labs#24010) * Stringify populated transaction fields * fix: web3: compare stringified JSON * chore: web3: remove eslint indent rule that conflicts with prettier * fix: web3: explicitly call toJSON * fix: web3: add test for compileMessage * fix: web3: make JSON internal * fix: web3: connection simulation from message relies on mutating transaction Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com> Co-authored-by: Jack May <jack@solana.com> Co-authored-by: Justin Starry <justin@solana.com>
* fix: backport solana-labs/solana#23720 * fix: backport solana-labs/solana#24475 * fix: backport solana-labs/solana#25141
Problem
Transaction.populate
is kind of broken (see #21722). It's not so much that the implementation ofpopulate
itself is broken, but rather that attempting to reserialize a transaction that was deserialized from a message is conceptually invalid.Summary of Changes
This PR attempts to fix the issue in a surgical and slightly hacky fashion, without adding to or changing the public API, or breaking correctly behaving applications.
This is accomplished by setting an internal
Message
property if theTransaction
was created withpopulate
. If thisMessage
exists, it will be used instead of recompiling the message from the transaction, which is what causes the account key order to change.Instructions cannot be added to a populated transaction. This will throw an error at runtime. Since correctly behaving applications should not add instructions to a compiled message, I regard this as non-breaking. YMMV. If there are concerns about this, it could be limited to populated transactions with non-null signature values.
I haven't added getters/setters for
feePayer
,recentBlockhash
,nonceInfo
, orinstructions
. If added, these could throw errors if these are set on a populated transaction. I wanted to first propose these changes and gather feedback.Fixes #21722
Closes #23684 (duplicate, but also adds to the public API which I don't think we should do for this)