forked from MystenLabs/sui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[fastx client] Check authority responses (Part 3) (MystenLabs#388)
* Added checks to authority responses Co-authored-by: George Danezis <[email protected]>
- Loading branch information
Showing
3 changed files
with
203 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
// Copyright (c) Facebook, Inc. and its affiliates. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use crate::authority_client::AuthorityAPI; | ||
use async_trait::async_trait; | ||
use fastx_types::{base_types::*, committee::*, fp_ensure}; | ||
|
||
use fastx_types::{ | ||
error::{FastPayError, FastPayResult}, | ||
messages::*, | ||
}; | ||
|
||
#[derive(Clone)] | ||
pub struct SafeClient<C> { | ||
authority_client: C, | ||
committee: Committee, | ||
address: FastPayAddress, | ||
} | ||
|
||
impl<C> SafeClient<C> { | ||
pub fn new(authority_client: C, committee: Committee, address: FastPayAddress) -> Self { | ||
Self { | ||
authority_client, | ||
committee, | ||
address, | ||
} | ||
} | ||
|
||
// Here we centralize all checks for order info responses | ||
fn check_order_response( | ||
&self, | ||
digest: TransactionDigest, | ||
response: &OrderInfoResponse, | ||
) -> FastPayResult { | ||
if let Some(signed_order) = &response.signed_order { | ||
// Check the order signature | ||
signed_order.check(&self.committee)?; | ||
// Check it has the right signer | ||
fp_ensure!( | ||
signed_order.authority == self.address, | ||
FastPayError::ByzantineAuthoritySuspicion { | ||
authority: self.address | ||
} | ||
); | ||
// Check it's the right order | ||
fp_ensure!( | ||
signed_order.order.digest() == digest, | ||
FastPayError::ByzantineAuthoritySuspicion { | ||
authority: self.address | ||
} | ||
); | ||
} | ||
|
||
if let Some(certificate) = &response.certified_order { | ||
// Check signatures and quorum | ||
certificate.check(&self.committee)?; | ||
// Check it's the right order | ||
fp_ensure!( | ||
certificate.order.digest() == digest, | ||
FastPayError::ByzantineAuthoritySuspicion { | ||
authority: self.address | ||
} | ||
); | ||
} | ||
|
||
if let Some(signed_effects) = &response.signed_effects { | ||
// Check signature | ||
signed_effects | ||
.signature | ||
.check(&signed_effects.effects, self.address)?; | ||
// Checks it concerns the right tx | ||
fp_ensure!( | ||
signed_effects.effects.transaction_digest == digest, | ||
FastPayError::ByzantineAuthoritySuspicion { | ||
authority: self.address | ||
} | ||
); | ||
// Check it has the right signer | ||
fp_ensure!( | ||
signed_effects.authority == self.address, | ||
FastPayError::ByzantineAuthoritySuspicion { | ||
authority: self.address | ||
} | ||
); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn check_object_response( | ||
&self, | ||
request: &ObjectInfoRequest, | ||
response: &ObjectInfoResponse, | ||
) -> FastPayResult { | ||
// If we get a certificate make sure it is a valid certificate | ||
if let Some(certificate) = &response.parent_certificate { | ||
certificate.check(&self.committee)?; | ||
} | ||
|
||
// Check the right version is returned | ||
if let Some(requested_version) = &request.request_sequence_number { | ||
if let Some(object_ref) = &response.requested_object_reference { | ||
fp_ensure!( | ||
object_ref.1 == *requested_version, | ||
FastPayError::ByzantineAuthoritySuspicion { | ||
authority: self.address | ||
} | ||
); | ||
} | ||
} | ||
|
||
// If an order lock is returned it is valid. | ||
if let Some(object_and_lock) = &response.object_and_lock { | ||
if let Some(signed_order) = &object_and_lock.lock { | ||
signed_order.check(&self.committee)?; | ||
// Check it has the right signer | ||
fp_ensure!( | ||
signed_order.authority == self.address, | ||
FastPayError::ByzantineAuthoritySuspicion { | ||
authority: self.address | ||
} | ||
); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<C> AuthorityAPI for SafeClient<C> | ||
where | ||
C: AuthorityAPI + Send + Sync + Clone + 'static, | ||
{ | ||
/// Initiate a new transfer to a FastPay or Primary account. | ||
async fn handle_order(&self, order: Order) -> Result<OrderInfoResponse, FastPayError> { | ||
let digest = order.digest(); | ||
let order_info = self.authority_client.handle_order(order).await?; | ||
self.check_order_response(digest, &order_info)?; | ||
Ok(order_info) | ||
} | ||
|
||
/// Confirm a transfer to a FastPay or Primary account. | ||
async fn handle_confirmation_order( | ||
&self, | ||
order: ConfirmationOrder, | ||
) -> Result<OrderInfoResponse, FastPayError> { | ||
let digest = order.certificate.order.digest(); | ||
let order_info = self | ||
.authority_client | ||
.handle_confirmation_order(order) | ||
.await?; | ||
self.check_order_response(digest, &order_info)?; | ||
Ok(order_info) | ||
} | ||
|
||
async fn handle_account_info_request( | ||
&self, | ||
request: AccountInfoRequest, | ||
) -> Result<AccountInfoResponse, FastPayError> { | ||
self.authority_client | ||
.handle_account_info_request(request) | ||
.await | ||
} | ||
|
||
async fn handle_object_info_request( | ||
&self, | ||
request: ObjectInfoRequest, | ||
) -> Result<ObjectInfoResponse, FastPayError> { | ||
let response = self | ||
.authority_client | ||
.handle_object_info_request(request.clone()) | ||
.await?; | ||
self.check_object_response(&request, &response)?; | ||
Ok(response) | ||
} | ||
|
||
/// Handle Object information requests for this account. | ||
async fn handle_order_info_request( | ||
&self, | ||
request: OrderInfoRequest, | ||
) -> Result<OrderInfoResponse, FastPayError> { | ||
let digest = request.transaction_digest; | ||
let order_info = self | ||
.authority_client | ||
.handle_order_info_request(request) | ||
.await?; | ||
self.check_order_response(digest, &order_info)?; | ||
Ok(order_info) | ||
} | ||
} |