Skip to content

Commit

Permalink
Start taking it over from iotaledger#700
Browse files Browse the repository at this point in the history
  • Loading branch information
Thoralf-M committed Aug 14, 2023
1 parent 2d65df0 commit 501adbe
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 41 deletions.
12 changes: 6 additions & 6 deletions sdk/src/client/node_api/core/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl ClientInner {
}

/// Finds a block by its ID and returns it as object.
/// GET /api/core/v3/blocks/{BlockId}
/// GET /api/core/v3/blocks/{blockId}
pub async fn get_block(&self, block_id: &BlockId) -> Result<Block> {
let path = &format!("api/core/v3/blocks/{block_id}");

Expand All @@ -160,7 +160,7 @@ impl ClientInner {
}

/// Finds a block by its ID and returns it as raw bytes.
/// GET /api/core/v3/blocks/{BlockId}
/// GET /api/core/v3/blocks/{blockId}
pub async fn get_block_raw(&self, block_id: &BlockId) -> Result<Vec<u8>> {
let path = &format!("api/core/v3/blocks/{block_id}");

Expand All @@ -172,7 +172,7 @@ impl ClientInner {
}

/// Returns the metadata of a block.
/// GET /api/core/v3/blocks/{BlockId}/metadata
/// GET /api/core/v3/blocks/{blockId}/metadata
pub async fn get_block_metadata(&self, block_id: &BlockId) -> Result<BlockMetadataResponse> {
let path = &format!("api/core/v3/blocks/{block_id}/metadata");

Expand Down Expand Up @@ -225,7 +225,7 @@ impl ClientInner {
.await
}

/// Returns the block that was included in the ledger for a given transaction ID, as object.
/// Returns the earliest block containing the transaction that get confirmed, as object.
/// GET /api/core/v3/transactions/{transactionId}/included-block
pub async fn get_included_block(&self, transaction_id: &TransactionId) -> Result<Block> {
let path = &format!("api/core/v3/transactions/{transaction_id}/included-block");
Expand All @@ -243,7 +243,7 @@ impl ClientInner {
)?)
}

/// Returns the block that was included in the ledger for a given transaction ID, as object, as raw bytes.
/// Returns earliest the block containing the transaction that get confirmed, as raw bytes.
/// GET /api/core/v3/transactions/{transactionId}/included-block
pub async fn get_included_block_raw(&self, transaction_id: &TransactionId) -> Result<Vec<u8>> {
let path = &format!("api/core/v3/transactions/{transaction_id}/included-block");
Expand All @@ -255,7 +255,7 @@ impl ClientInner {
.await
}

/// Returns the metadata of the block that was included in the ledger for a given TransactionId.
/// Returns the metadata of the earliest block containing the tx that get confirmed.
/// GET /api/core/v3/transactions/{transactionId}/included-block/metadata
pub async fn get_included_block_metadata(&self, transaction_id: &TransactionId) -> Result<BlockMetadataResponse> {
let path = &format!("api/core/v3/transactions/{transaction_id}/included-block/metadata");
Expand Down
70 changes: 53 additions & 17 deletions sdk/src/types/api/core/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use alloc::{string::String, vec::Vec};
use crate::types::block::{
output::{dto::OutputDto, OutputId, OutputMetadata, OutputWithMetadata},
protocol::ProtocolParameters,
semantic::ConflictReason,
slot::SlotIndex,
BlockId,
};
Expand Down Expand Up @@ -117,20 +118,60 @@ pub struct SubmitBlockResponse {
pub block_id: BlockId,
}

/// Describes the ledger inclusion state of a transaction.
/// Describes the state of a block.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "camelCase")
)]
pub enum LedgerInclusionState {
Conflicting,
Included,
NoTransaction,
pub enum BlockState {
// Stored but not confirmed or contains not yet included transaction.
Pending,
// Confirmed with the first level of knowledge.
Confirmed,
// Included and cannot be reverted anymore.
Finalized,
// Rejected by the node, and user should reissue payload if it contains one.
Rejected,
// Not successfully issued due to failure reason.
Failed,
}

/// Response of GET /api/core/v3/blocks/{block_id}/metadata.
/// Describes the state of a transaction.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "camelCase")
)]
pub enum TransactionState {
// Stored but not confirmed or contains not yet included transaction.
Pending,
// Confirmed with the first level of knowledge.
Confirmed,
// Included and cannot be reverted anymore.
Finalized,
// The block is not successfully issued due to failure reason.
Failed,
}

/// Describes the reason of a block state.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "camelCase")
)]
#[non_exhaustive]
#[repr(u8)]
pub enum BlockStateReason {
Invalid = 1,
OrphanedCongestionControl = 2,
OrphanedNegativeManaBalance = 3,
}

/// Response of GET /api/core/v3/blocks/{blockId}/metadata.
/// Returns the metadata of a block.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(
Expand All @@ -140,22 +181,17 @@ pub enum LedgerInclusionState {
)]
pub struct BlockMetadataResponse {
pub block_id: BlockId,
pub parents: Vec<BlockId>,
pub is_solid: bool,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub referenced_by_milestone_index: Option<u32>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub milestone_index: Option<u32>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ledger_inclusion_state: Option<LedgerInclusionState>,
pub block_state: Option<BlockState>,
pub strong_parents: Vec<BlockId>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub conflict_reason: Option<u8>,
pub weak_parents: Option<Vec<BlockId>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub white_flag_index: Option<u32>,
pub shallow_like_parents: Option<Vec<BlockId>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub should_promote: Option<bool>,
pub tx_state: Option<TransactionState>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub should_reattach: Option<bool>,
pub tx_state_reason: Option<ConflictReason>,
}

/// Response of GET /api/core/v3/outputs/{output_id}.
Expand Down
3 changes: 3 additions & 0 deletions sdk/src/types/block/semantic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,15 @@ impl std::error::Error for ConflictError {}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[packable(unpack_error = ConflictError)]
#[packable(tag_type = u8, with_error = ConflictError::InvalidConflict)]
// TODO may want to rename this to TransactionStateReason
pub enum ConflictReason {
/// The block has no conflict.
None = 0,
/// The referenced Utxo was already spent.
InputUtxoAlreadySpent = 1,
/// The referenced Utxo was already spent while confirming this milestone.
/// TODO weird
/// * `2` - denotes that the transaction is conflicting with another transaction.
InputUtxoAlreadySpentInThisMilestone = 2,
/// The referenced Utxo cannot be found.
InputUtxoNotFound = 3,
Expand Down
20 changes: 12 additions & 8 deletions sdk/src/wallet/account/operations/reissue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use crate::{
client::{secret::SecretManage, Error as ClientError},
types::{
api::core::response::LedgerInclusionState,
api::core::response::{BlockState, TransactionState},
block::{
payload::{transaction::TransactionId, Payload},
BlockId,
Expand Down Expand Up @@ -86,18 +86,22 @@ where
let mut conflicting = false;
for (index, block_id_) in block_ids.clone().iter().enumerate() {
let block_metadata = self.client().get_block_metadata(block_id_).await?;
if let Some(inclusion_state) = block_metadata.ledger_inclusion_state {
match inclusion_state {
LedgerInclusionState::Included | LedgerInclusionState::NoTransaction => {
return Ok(*block_id_);
}
if let Some(transaction_state) = block_metadata.tx_state {
match transaction_state {
TransactionState::Finalized => return Ok(*block_id_),
// only set it as conflicting here and don't return, because another reissued block could
// have the included transaction
LedgerInclusionState::Conflicting => conflicting = true,
// TODO: check if the comment above is still correct with IOTA 2.0
TransactionState::Failed => conflicting = true,
// TODO: what to do when confirmed?
_ => {}
};
}
// Only reissue latest attachment of the block
if index == block_ids_len - 1 && block_metadata.should_reattach.unwrap_or(false) {
let should_reissue = block_metadata
.block_state
.map_or(false, |block_state| block_state == BlockState::Rejected);
if index == block_ids_len - 1 && should_reissue {
let reissued_block = self
.client()
.finish_basic_block_builder(
Expand Down
18 changes: 8 additions & 10 deletions sdk/src/wallet/account/operations/syncing/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use crate::{
client::secret::SecretManage,
types::{
api::core::response::LedgerInclusionState,
api::core::response::TransactionState,
block::{input::Input, output::OutputId, payload::transaction::TransactionEssence, BlockId},
},
utils::unix_timestamp_now,
Expand Down Expand Up @@ -102,9 +102,10 @@ where
if let Some(block_id) = transaction.block_id {
match self.client().get_block_metadata(&block_id).await {
Ok(metadata) => {
if let Some(inclusion_state) = metadata.ledger_inclusion_state {
match inclusion_state {
LedgerInclusionState::Included => {
// TODO: use tx_state or block_state?
if let Some(tx_state) = metadata.tx_state {
match tx_state {
TransactionState::Finalized | TransactionState::Confirmed => {
log::debug!(
"[SYNC] confirmed transaction {transaction_id} in block {}",
metadata.block_id
Expand All @@ -118,7 +119,7 @@ where
&mut spent_output_ids,
);
}
LedgerInclusionState::Conflicting => {
TransactionState::Failed => {
// try to get the included block, because maybe only this attachment is
// conflicting because it got confirmed in another block
if let Ok(included_block) =
Expand All @@ -144,11 +145,8 @@ where
);
}
}
LedgerInclusionState::NoTransaction => {
unreachable!(
"We should only get the metadata for blocks with a transaction payload"
)
}
// Do nothing, just need to wait a bit more
TransactionState::Pending => {}
}
} else {
// no need to reissue if one input got spent
Expand Down

0 comments on commit 501adbe

Please sign in to comment.