-
Notifications
You must be signed in to change notification settings - Fork 11.3k
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
[move][test_scenario] Fix bug in test_scenario
where we weren't returning allocated tickets
#17991
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
3 Skipped Deployments
|
add2a37
to
131c6c7
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.
I think I understand the core change, but would appreciate some more context on the broader changes!
sender, | ||
scenario.txn_number, | ||
test_random_tx_hash, |
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.
Could you share some context on how the (pseudo-)random tx digest generation fits into the overall fix?
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.
(Might be worth adding some of that context as a code comment around this change).
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.
Happy to add a code comment.
Basically:
- Object IDs are generated from the transaction context based on the transaction hash + number of generated IDs thus far in the transaction.
- In
test_scenario
we always generate the transaction context with the same initial state of for a given sender. - This means that each Move unit test using the test scenario will generate the same sequence of object IDs when calling
new_object
. - The object runtime (and storage) is shared across all Move unit tests, and Move unit tests are executed in parallel.
This set of things leads to situations where multiple Move unit tests using test scenario can read/write to the shared object runtime/storage with the same object ID and different values in parallel leading to race conditions on the state of the object runtime.
By seeding the tx digest pseudo-randomly whenever we start a transaction we make it basically impossible to run into this type of "multiple objects with the same ID being read/written in parallel to the shared runtime" in Move unit tests.
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.
Got it -- thanks for explaining! Happy with this for now, but it kind of seems like the right long-term solution is to use a different scenario object per test or something (to graduate this from "basically impossible" to "actually impossible"), how difficult would something like that be?
crates/sui-framework/packages/sui-framework/tests/test_scenario_tests.move
Outdated
Show resolved
Hide resolved
assert!(parent.value == 10, EValueMismatch); | ||
assert!(obj2.value == 20, EValueMismatch); |
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.
Can we use clever errors for this?
assert!(parent.value == 10, EValueMismatch); | |
assert!(obj2.value == 20, EValueMismatch); | |
assert!(parent.value == 10); | |
assert!(obj2.value == 20); |
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.
I noticed that in another place you were able to get rid of the abort code but not in this file -- is it just a change waiting to be pushed?
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.
ah darn forgot to add these changes. Will update!
// Make sure that we properly handle the case where we receive an object | ||
// when dealing with allocated tickets. |
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.
nit: doc comment? Also could you describe what happens when we don't properly handle that case, for posterity?
crates/sui-framework/packages/sui-framework/tests/test_scenario_tests.move
Outdated
Show resolved
Hide resolved
crates/sui-framework/packages/sui-framework/tests/test_scenario_tests.move
Outdated
Show resolved
Hide resolved
131c6c7
to
18a359e
Compare
@@ -51,7 +51,8 @@ module sui::random_tests { | |||
scenario.ctx(), | |||
); | |||
scenario.next_tx(@0x0); | |||
let gen1 = random_state.new_generator(scenario.ctx()); | |||
let mut ctx = tx_context::new_from_hint(@0x0, 1, 0, 0, 0); |
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.
Note the changes here: it was previously using the fact that the object IDs derived from the context were stable which is no longer the case so we manually stabilize them here.
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.
I don't fully understand, what happens if this isn't stable?
@@ -442,8 +456,10 @@ module sui::random_tests { | |||
let _output = gen.generate_u128_in_range(0, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | |||
let mut i = 0; | |||
while (i < 50) { | |||
let min = gen.generate_u128(); | |||
let max = min + (gen.generate_u64() as u128); | |||
let (min, max) = (gen.generate_u128(), gen.generate_u128()); |
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.
Fixed logic here since this was incorrect and subject to overflow (and the tests were in fact failing for this).
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.
Looks good! Some questions from me, and perhaps some final clean-ups on abort codes to get pushed still, but this is good to go, thanks @tzakian !
@@ -103,6 +106,9 @@ module sui::random_tests { | |||
scenario.ctx(), | |||
); | |||
|
|||
// Deterministically set tx context so the RNG seeded by the ctx below is deterministic. |
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.
Here, we're kind of hoping that someone doesn't create an object using this ctx in later code, right? Because if they did, we could be in that bad situation where two tests run in parallel and write different contents for the same object.
FWIW, I preferred the explicit use of the ctx you get from new_from_hint
instead of overwriting the scenario's context for that reason.
assert!(parent.value == 10, EValueMismatch); | ||
assert!(obj2.value == 20, EValueMismatch); |
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.
I noticed that in another place you were able to get rid of the abort code but not in this file -- is it just a change waiting to be pushed?
18a359e
to
ab6928a
Compare
// Randomly seed the transaction context's transaction hash to avoid | ||
// object ID collisions in parallel Move tests. | ||
// |
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.
I'd remove this comment, since it won't be true long term.
I would just summarize here that the transaction digest is randomized to better help simulate real execution environments. Not sure we need to say more than that?
I think this block of comments would be a lot better placed in some rust file if possible
@@ -51,7 +51,8 @@ module sui::random_tests { | |||
scenario.ctx(), | |||
); | |||
scenario.next_tx(@0x0); | |||
let gen1 = random_state.new_generator(scenario.ctx()); | |||
let mut ctx = tx_context::new_from_hint(@0x0, 1, 0, 0, 0); |
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.
I don't fully understand, what happens if this isn't stable?
*scenario.ctx() = tx_context::new_from_hint(@0x0, 1, 0, 0, 0); | ||
|
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.
I am afraid
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.
When the Rng
is generated, it takes the source of randomness that is shared between transactions in a checkpoint (Random
) and mixes it with its own transaction digest (by generating a new address and then using that), so if the digest is not stable in this case, you'll get different random numbers each time.
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.
My fear was from writing to scenario.ctx()
, not the hard coding of the context itself
ab6928a
to
09ca36e
Compare
09ca36e
to
4e2cf6e
Compare
4e2cf6e
to
ff47f40
Compare
ff47f40
to
4028c93
Compare
pub struct InMemoryTestStore(pub &'static RwLock<InMemoryStorage>); | ||
pub struct InMemoryTestStore(pub &'static LocalKey<RefCell<InMemoryStorage>>); |
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.
Approving to unblock, but this still feels like a crime.
4028c93
to
a430508
Compare
…urning allocated tickets (#17991) ## Description Fixes a bug where we weren't returning allocated receiving tickets in a transaction at the end of the transaction. This fixes the bug, and adds tests to make sure allocated tickets are properly handled at the end of a test scenario transaction. ## Test plan Added new tests to test the failing behavior and made sure they pass.
[move][test_scenario] Fix bug in test_scenario where we weren't returning allocated tickets (#17991) MystenLabs/sui#17991
[move][test_scenario] Fix bug in test_scenario where we weren't returning allocated tickets (#17991) MystenLabs/sui#17991
Description
Fixes a bug where we weren't returning allocated receiving tickets in a transaction at the end of the transaction. This fixes the bug, and adds tests to make sure allocated tickets are properly handled at the end of a test scenario transaction.
Test plan
Added new tests to test the failing behavior and made sure they pass.