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

[fastx adapter] making move execution work end-to-end #88

Merged
merged 1 commit into from
Dec 29, 2021

Conversation

sblackshear
Copy link
Collaborator

Using the new VM API in diem/diem@346301f to make the Move-powered execution work as intended. At a high level:

  • The adapter takes some FastX objects, some pure values (e.g., addresses), and a Move function to call as input as input
  • It takes extracts a Move value from each object and type-checks the objects against the function signature
  • It invokes the function on the Move values and pure values
  • It processes the effects produced from executing the function to update the input objects, as well as updating the store with freshly created and deleted objects.

This is intricate logic that will need much more testing in time. But wanted to get this functionality out as early as possible to unblock the client workstream, which will need to send MoveCall orders and observe their effects.

@sblackshear sblackshear changed the title [RFC][fastx adapter] making move execution work end-to-end [fastx adapter] making move execution work end-to-end Dec 23, 2021
@sblackshear sblackshear force-pushed the use_new_move_vm_api branch 4 times, most recently from 24b17d1 to 0b46af2 Compare December 26, 2021 18:03
Copy link
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty darn amazing to me, but I'm a bit of a Move noob, so I'll just comment.

This introduces 8 new TODOs not covered by a subsequent PR: should we introduce an umbrella issue to track them? "Leftovers in adapter logic", perhaps?

fastpay_core/src/authority.rs Show resolved Hide resolved
fastx_programmability/adapter/src/adapter.rs Outdated Show resolved Hide resolved
for (mut obj, new_contents) in mutable_refs {
match &mut obj.data {
Data::Move(m) => m.contents = new_contents,
_ => unreachable!(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this unreachable or is this an API invariant violation? Should a panic here involve a message?

Also, consider using pre, perhaps.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • It is unreachable--we checked earlier than mutable_refs only had Move objects. Will change to panic with an appropriate message.
  • pre looks very interesting/useful. But I am trying to weigh the risk/reward of adding this as a dep in a system that's currently pretty dependency-minimal--thoughts on that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pre is:

  • pretty darn safe, because it's itself small, it disappears at release and is dependency-minimal,
  • really useful when you're committed to using a specific set of preconditions that should be enforced by callers, rather than a one-off.

So it may be just early (in this PR), if you do have a battery invariants in mind, or pre may not be for you if you don't.

}
// any object left in `by_value_objects` is an input passed by value that was not transferred or frozen.
// this means that either the object was (1) deleted from the FastX system altogether, or
// (2) wrapped inside another object that is in the FastX object pool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remind me: what's the logic for deleting wrapped objects in this case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A wrapped object was either:

  1. Passed in via by_value_objects and not subsequently transferred
  2. Created by the transaction and subsequently transferred or deleted
  • In case (1), the wrapped object will be present in by_value_objects and thus deleted from the object pool here.
  • In case (2), the wrapped object was never in the object pool, so there's no need to delete it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks!

fastx_programmability/adapter/src/adapter.rs Show resolved Hide resolved
}
}
debug_assert!(
by_value_objects.len() + mutable_ref_objects.len() + num_immutable_objects == num_objects
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -0,0 +1,30 @@
/// Test CTURD object basics (create, transfer, update, read, delete)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💩 ?
(nit : consider a different acronym)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol, this was the most memorable one I could think of

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRUD is a well-known acronym in databases, so that CRUDT, TCRUD would ring a bell.

@@ -118,6 +142,11 @@ impl TransactionDigest {
SequenceNumber::new(),
)
}

// for testing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: #[cfg(test)] ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would do this, but then it can't be used outside of the base_types crate (unless there is a way to allow this?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, the only way to allow this is with a feature, which dependent crates would have to activate when appropriate. Sigh.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably makes sense for us to do this eventually because we have several functions that look like this... but in a future PR

fastx_types/src/object.rs Outdated Show resolved Hide resolved
@sblackshear
Copy link
Collaborator Author

This introduces 8 new TODOs not covered by a subsequent PR: should we introduce an umbrella issue to track them? "Leftovers in adapter logic", perhaps?

Good call + will do!

Using the new VM API in diem/diem@346301f to make the Move-powered execution work as intended. At a high level:
- The adapter takes some FastX objects, some pure values (e.g., addresses), and a Move function to call as input as input
- It takes extracts a Move value from each object and type-checks the objects against the function signature
- It invokes the function on the Move values and pure values
- It processes the effects produced from executing the function to update the input objects, as well as updating the store with freshly created and deleted objects.

This is intricate logic that will need much more testing in time. But wanted to get this functionality out as early as possible to unblock the client workstream, which will need to send `MoveCall` orders and observe their effects.
Copy link
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One Q: where (would|does)a the sequence number management that happens during the creation of an object from an unwrap live?

old_object.next_sequence_number = sequence_number;
old_object
} else {
Object::new_move(move_obj, recipient, SequenceNumber::new())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One Q: where (would|does)a the sequence number management that happens during the creation of an object from an unwrap live?

@huitseeker : this is it--same code path as object creation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth noting that this is (as @gdanezis pointed out in the preso this morning) completely unsafe if sequence numbers are used for replay prevention (as they are today ...).

But it is fine in the (future, proposed world) where keys in the order_lock map are (ObjectId, TxDigest) (or a commitment to this pair).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#98 for much more detail on this.

@sblackshear
Copy link
Collaborator Author

I'm going to go ahead and land this because there are a few outstanding PR's that are tough to review by virtue of being based on it. Happy to address any/all other comments async!

@sblackshear sblackshear merged commit 3a3575a into MystenLabs:main Dec 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants