in fastpay_core/src/authority.rs [133:202]
fn handle_confirmation_order(
&mut self,
confirmation_order: ConfirmationOrder,
) -> Result<(AccountInfoResponse, Option<CrossShardUpdate>), FastPayError> {
let certificate = confirmation_order.transfer_certificate;
// Check the certificate and retrieve the transfer data.
fp_ensure!(
self.in_shard(&certificate.value.transfer.sender),
FastPayError::WrongShard
);
certificate.check(&self.committee)?;
let transfer = certificate.value.transfer.clone();
// First we copy all relevant data from sender.
let mut sender_account = self
.accounts
.entry(transfer.sender)
.or_insert_with(AccountOffchainState::new);
let mut sender_sequence_number = sender_account.next_sequence_number;
let mut sender_balance = sender_account.balance;
// Check and update the copied state
if sender_sequence_number < transfer.sequence_number {
fp_bail!(FastPayError::MissingEalierConfirmations {
current_sequence_number: sender_sequence_number
});
}
if sender_sequence_number > transfer.sequence_number {
// Transfer was already confirmed.
return Ok((sender_account.make_account_info(transfer.sender), None));
}
sender_balance = sender_balance.try_sub(transfer.amount.into())?;
sender_sequence_number = sender_sequence_number.increment()?;
// Commit sender state back to the database (Must never fail!)
sender_account.balance = sender_balance;
sender_account.next_sequence_number = sender_sequence_number;
sender_account.pending_confirmation = None;
sender_account.confirmed_log.push(certificate.clone());
let info = sender_account.make_account_info(transfer.sender);
// Update FastPay recipient state locally or issue a cross-shard update (Must never fail!)
let recipient = match transfer.recipient {
Address::FastPay(recipient) => recipient,
Address::Primary(_) => {
// Nothing else to do for Primary recipients.
return Ok((info, None));
}
};
// If the recipient is in the same shard, read and update the account.
if self.in_shard(&recipient) {
let recipient_account = self
.accounts
.entry(recipient)
.or_insert_with(AccountOffchainState::new);
recipient_account.balance = recipient_account
.balance
.try_add(transfer.amount.into())
.unwrap_or_else(|_| Balance::max());
recipient_account.received_log.push(certificate);
// Done updating recipient.
return Ok((info, None));
}
// Otherwise, we need to send a cross-shard update.
let cross_shard = Some(CrossShardUpdate {
shard_id: self.which_shard(&recipient),
transfer_certificate: certificate,
});
Ok((info, cross_shard))
}