Use optimistic confirmation in getSignatureStatuses, and various downstream client methods (#14430)

* Add optimistically_confirmed field to TransactionStatus

* Update docs

* Convert new field to confirmation_status

* Update docs to confirmationStatus

* Update variants

* Update docs

* Just Confirmed
This commit is contained in:
Tyera Eulberg
2021-01-15 09:05:05 -07:00
committed by GitHub
parent 299b3eb99d
commit 9a89689ad3
11 changed files with 162 additions and 30 deletions

View File

@ -20,7 +20,7 @@ use solana_account_decoder::parse_token::UiTokenAmount;
pub use solana_runtime::bank::RewardType;
use solana_sdk::{
clock::{Slot, UnixTimestamp},
commitment_config::CommitmentConfig,
commitment_config::{CommitmentConfig, CommitmentLevel},
deserialize_utils::default_on_eof,
instruction::CompiledInstruction,
message::{Message, MessageHeader},
@ -260,6 +260,14 @@ impl From<TransactionStatusMeta> for UiTransactionStatusMeta {
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TransactionConfirmationStatus {
Processed,
Confirmed,
Finalized,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionStatus {
@ -267,12 +275,28 @@ pub struct TransactionStatus {
pub confirmations: Option<usize>, // None = rooted
pub status: Result<()>, // legacy field
pub err: Option<TransactionError>,
pub confirmation_status: Option<TransactionConfirmationStatus>,
}
impl TransactionStatus {
pub fn satisfies_commitment(&self, commitment_config: CommitmentConfig) -> bool {
(commitment_config == CommitmentConfig::default() && self.confirmations.is_none())
|| commitment_config == CommitmentConfig::recent()
match commitment_config.commitment {
CommitmentLevel::Max | CommitmentLevel::Root => self.confirmations.is_none(),
CommitmentLevel::SingleGossip => {
if let Some(status) = &self.confirmation_status {
*status != TransactionConfirmationStatus::Processed
} else {
// These fallback cases handle TransactionStatus RPC responses from older software
self.confirmations.is_some() && self.confirmations.unwrap() > 1
|| self.confirmations.is_none()
}
}
CommitmentLevel::Single => match self.confirmations {
Some(confirmations) => confirmations >= 1,
None => true,
},
CommitmentLevel::Recent => true,
}
}
}
@ -545,9 +569,13 @@ mod test {
confirmations: None,
status: Ok(()),
err: None,
confirmation_status: Some(TransactionConfirmationStatus::Finalized),
};
assert!(status.satisfies_commitment(CommitmentConfig::default()));
assert!(status.satisfies_commitment(CommitmentConfig::root()));
assert!(status.satisfies_commitment(CommitmentConfig::single()));
assert!(status.satisfies_commitment(CommitmentConfig::single_gossip()));
assert!(status.satisfies_commitment(CommitmentConfig::recent()));
let status = TransactionStatus {
@ -555,9 +583,69 @@ mod test {
confirmations: Some(10),
status: Ok(()),
err: None,
confirmation_status: Some(TransactionConfirmationStatus::Confirmed),
};
assert!(!status.satisfies_commitment(CommitmentConfig::default()));
assert!(!status.satisfies_commitment(CommitmentConfig::root()));
assert!(status.satisfies_commitment(CommitmentConfig::single()));
assert!(status.satisfies_commitment(CommitmentConfig::single_gossip()));
assert!(status.satisfies_commitment(CommitmentConfig::recent()));
let status = TransactionStatus {
slot: 0,
confirmations: Some(1),
status: Ok(()),
err: None,
confirmation_status: Some(TransactionConfirmationStatus::Processed),
};
assert!(!status.satisfies_commitment(CommitmentConfig::default()));
assert!(!status.satisfies_commitment(CommitmentConfig::root()));
assert!(status.satisfies_commitment(CommitmentConfig::single()));
assert!(!status.satisfies_commitment(CommitmentConfig::single_gossip()));
assert!(status.satisfies_commitment(CommitmentConfig::recent()));
let status = TransactionStatus {
slot: 0,
confirmations: Some(0),
status: Ok(()),
err: None,
confirmation_status: None,
};
assert!(!status.satisfies_commitment(CommitmentConfig::default()));
assert!(!status.satisfies_commitment(CommitmentConfig::root()));
assert!(!status.satisfies_commitment(CommitmentConfig::single()));
assert!(!status.satisfies_commitment(CommitmentConfig::single_gossip()));
assert!(status.satisfies_commitment(CommitmentConfig::recent()));
// Test single_gossip fallback cases
let status = TransactionStatus {
slot: 0,
confirmations: Some(1),
status: Ok(()),
err: None,
confirmation_status: None,
};
assert!(!status.satisfies_commitment(CommitmentConfig::single_gossip()));
let status = TransactionStatus {
slot: 0,
confirmations: Some(2),
status: Ok(()),
err: None,
confirmation_status: None,
};
assert!(status.satisfies_commitment(CommitmentConfig::single_gossip()));
let status = TransactionStatus {
slot: 0,
confirmations: None,
status: Ok(()),
err: None,
confirmation_status: None,
};
assert!(status.satisfies_commitment(CommitmentConfig::single_gossip()));
}
}