-
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
Fix certificate update issue which cause subsequence object transfer fail #170
Conversation
7a932f1
to
89ad047
Compare
8d13173
to
84f38ba
Compare
This PR is ready for review, I will add more client side test for move calls in my next PR. |
101187c
to
1e59f57
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.
This is good.
I only have one architectural issue here: the client seems to not remember which certificates are "pending". These are certificates that the client knows BUT have not been confirmed by 2f+1 authorities. We should probably remember these, and re-submit them on restart of the client, or retry to send them if the network goes down. Most importantly the client must NEVER reuse the sequence number used in an order that has a signature from an authority.
fastpay/src/config.rs
Outdated
@@ -235,12 +232,12 @@ impl AccountsConfig { | |||
if let Address::FastPay(recipient) = &transfer.recipient { | |||
if let Some(config) = self.accounts.get_mut(recipient) { | |||
if let Err(position) = config | |||
.received_certificates | |||
.certificates | |||
.binary_search_by_key(&certificate.order.digest(), |cert| { |
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.
Why not store the certificates in a HashMap/Btree sorted by digest instead?
The client query the authorities and confirm all the missing certificates at the beginning of communicate_transfers https://github.com/MystenLabs/fastnft/blob/178a9fb289db3222fb4bf51208501513f13d41b5/fastpay_core/src/client.rs#L448 |
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.
Mostly nits, one comment on update_certificates
fastpay_core/src/authority.rs
Outdated
let requested_certificate = match request.request_sequence_number { | ||
Some(seq) => { | ||
// TODO(https://github.com/MystenLabs/fastnft/issues/123): Here we need to develop a strategy | ||
// to provide back to the client the object digest for specific objects requested. Probably, | ||
// we have to return the full ObjectRef and why not the actual full object here. | ||
|
||
// Get the Transaction Digest that created the object | ||
let parent_iterator = self | ||
.get_parent_iterator(request.object_id, Some(seq.increment()?)) | ||
.await?; | ||
let (_, transaction_digest) = parent_iterator | ||
.first() | ||
.ok_or(FastPayError::CertificateNotfound)?; | ||
// Get the cert from the transaction digest | ||
Some( | ||
self.read_certificate(transaction_digest) | ||
.await? | ||
.ok_or(FastPayError::CertificateNotfound)?, | ||
) | ||
} | ||
None => None, | ||
}; |
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: you're only doing something non-trivial with one arm of the match, so that's a good place to reformulate your :
let rc = match foo {
Some(bar) => {
...
Some(baz)
}
None => None
}
Into:
let rc = {
if let Some(bar) = foo {
...
Some(baz)
} else {
None
}
}
Or even
let rc = foo.map(|baz| {
...
baz
}
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 first attempt was .map, but couldn't get it working because of async and ?, are there any way to make it work?
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 was just mentioning it for completeness. It's actually hard, though not impossible, to work with a map in contexts where you're like to short-circuit with a ?
, you have to keep things as a Result
, thread operations through flat_map
/map
, extirpate your Result
out of whatever you're returning, and only ?
or return
at the end.
Sometimes the if let
construct is just simpler.
fastpay_core/src/client.rs
Outdated
.filter(|(id, _, _)| id == &object_id) | ||
.map(|(_, seq, _)| seq) |
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: consider
.filter(|(id, _, _)| id == &object_id) | |
.map(|(_, seq, _)| seq) | |
.filter_map(|(id, seq, _)| if id == &object_id { Some(seq) } else { None }) |
?
fastpay_core/src/client.rs
Outdated
.find(|(id, _, _)| object_id == id) | ||
.copied() | ||
.ok_or::<FastPayError>(FastPayError::ObjectNotFound) | ||
.unwrap(); |
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.
Are you looking for a ?
instead of the panicking .unwrap()
?
fastpay_core/src/client.rs
Outdated
@@ -920,15 +935,15 @@ where | |||
let transfer = Transfer { | |||
object_ref: ( | |||
object_id, | |||
self.next_sequence_number(object_id), | |||
self.next_sequence_number(&object_id).unwrap(), |
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.
You're returning a Result
here, is the panic appropriate?
fastpay_core/src/client.rs
Outdated
// TODO(https://github.com/MystenLabs/fastnft/issues/123): Include actual object digest here | ||
ObjectDigest::new([0; 32]), | ||
), | ||
sender: self.address, | ||
recipient: Address::FastPay(recipient), | ||
gas_payment: ( | ||
gas_payment, | ||
self.next_sequence_number(gas_payment), | ||
self.next_sequence_number(&gas_payment).unwrap(), |
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.
Same Q: You're returning a Result
here, is the panic appropriate?
), | ||
) | ||
.await?; | ||
} | ||
Ok(self.sent_certificates.last().unwrap().clone()) | ||
Ok(self.certificates(order.object_id()).last().unwrap().clone()) |
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: A comment on the safety of last().unwrap()
somewhere in this function, one that would refer to update_certificates
only growing the set, should help the next implementer reason locally.
…ause by incorrect certificate update. added extensive test to check the certificate update logic.
some code clean up
…ransactionDigest, CertifiedOrder>
9d9c2fe
to
01094ce
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.
thanks!
This PR address issues [fastx client] Key Certificates By ObjectRef #82 and [fastx client] Update Certificates For Multi Object Orders #173