diff --git a/bindings/nodejs/lib/client/client.ts b/bindings/nodejs/lib/client/client.ts index 5f1e7dcf7d..7a16ac7e37 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -42,7 +42,6 @@ import { EpochIndex, Address, } from '../types/block'; -import { HexEncodedString } from '../utils'; import { BlockMetadataResponse, InfoResponse, diff --git a/bindings/nodejs/lib/types/client/bridge/client.ts b/bindings/nodejs/lib/types/client/bridge/client.ts index 80252b747f..3805397cbe 100644 --- a/bindings/nodejs/lib/types/client/bridge/client.ts +++ b/bindings/nodejs/lib/types/client/bridge/client.ts @@ -31,7 +31,6 @@ import type { BasicOutputBuilderParams } from '../output_builder_params/basic-ou import type { AccountOutputBuilderParams } from '../output_builder_params/account-output-params'; import type { FoundryOutputBuilderParams } from '../output_builder_params/foundry-output-params'; import type { NftOutputBuilderParams } from '../output_builder_params/nft-output-params'; -import { HexEncodedString } from '../../utils'; import { TransactionId } from '../..'; // Node routes. diff --git a/bindings/nodejs/lib/types/models/api/block-failure-reason.ts b/bindings/nodejs/lib/types/models/api/block-failure-reason.ts deleted file mode 100644 index d7eeb899e8..0000000000 --- a/bindings/nodejs/lib/types/models/api/block-failure-reason.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -/** - * Reason for block failure. - */ -export enum BlockFailureReason { - /** The block is too old to issue. */ - TooOldToIssue = 1, - /** One of the block's parents is too old. */ - ParentTooOld = 2, - /** One of the block's parents does not exist. */ - ParentDoesNotExist = 3, - /** The block's issuer account could not be found. */ - IssuerAccountNotFound = 4, - /** The mana cost could not be calculated. */ - ManaCostCalculationFailed = 5, - /** The block's issuer account burned insufficient Mana for a block. */ - BurnedInsufficientMana = 6, - /** The account is locked. */ - AccountLocked = 7, - /** The account is expired. */ - AccountExpired = 8, - /** The block's signature is invalid. */ - SignatureInvalid = 9, - /** The block is dropped due to congestion. */ - DroppedDueToCongestion = 10, - /** The block payload is invalid. */ - PayloadInvalid = 11, - /** The block is invalid. */ - Invalid = 255, -} - -/** - * Block failure reason strings. - */ -export const BLOCK_FAILURE_REASON_STRINGS: { - [key in BlockFailureReason]: string; -} = { - [BlockFailureReason.TooOldToIssue]: 'The block is too old to issue.', - [BlockFailureReason.ParentTooOld]: "One of the block's parents is too old.", - [BlockFailureReason.ParentDoesNotExist]: - "One of the block's parents does not exist.", - [BlockFailureReason.IssuerAccountNotFound]: - "The block's issuer account could not be found.", - [BlockFailureReason.ManaCostCalculationFailed]: - 'The mana cost could not be calculated.', - [BlockFailureReason.BurnedInsufficientMana]: - "The block's issuer account burned insufficient Mana for a block.", - [BlockFailureReason.AccountLocked]: 'The account is locked.', - [BlockFailureReason.AccountExpired]: 'The account is expired.', - [BlockFailureReason.SignatureInvalid]: "The block's signature is invalid.", - [BlockFailureReason.DroppedDueToCongestion]: - 'The block is dropped due to congestion.', - [BlockFailureReason.PayloadInvalid]: 'The block payload is invalid.', - [BlockFailureReason.Invalid]: 'The block is invalid.', -}; diff --git a/bindings/nodejs/lib/types/models/api/block-response.ts b/bindings/nodejs/lib/types/models/api/block-response.ts index 1d0836fb1b..c90c32d30e 100644 --- a/bindings/nodejs/lib/types/models/api/block-response.ts +++ b/bindings/nodejs/lib/types/models/api/block-response.ts @@ -2,9 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { BlockState } from '../state'; -import { BlockFailureReason } from './block-failure-reason'; import { Block, BlockId } from '../../block'; -import { TransactionMetadataResponse } from './transaction-response'; /** * Response from the metadata endpoint. @@ -18,14 +16,6 @@ export interface BlockMetadataResponse { * The block state. */ blockState: BlockState; - /** - * The block failure reason. - */ - blockFailureReason?: BlockFailureReason; - /** - * The metadata of the transaction in the block. - */ - transactionMetadata?: TransactionMetadataResponse; } /** diff --git a/bindings/nodejs/lib/types/models/api/index.ts b/bindings/nodejs/lib/types/models/api/index.ts index e1c8aa9f6d..1b6b06102e 100644 --- a/bindings/nodejs/lib/types/models/api/index.ts +++ b/bindings/nodejs/lib/types/models/api/index.ts @@ -3,7 +3,6 @@ export * from './info'; export * from './plugins'; -export * from './block-failure-reason'; export * from './block-response'; export * from './committee-response'; export * from './congestion-response'; diff --git a/bindings/nodejs/lib/types/models/api/transaction-failure-reason.ts b/bindings/nodejs/lib/types/models/api/transaction-failure-reason.ts index 653df684ec..0751ed0583 100644 --- a/bindings/nodejs/lib/types/models/api/transaction-failure-reason.ts +++ b/bindings/nodejs/lib/types/models/api/transaction-failure-reason.ts @@ -7,73 +7,74 @@ export enum TransactionFailureReason { None = 0, ConflictRejected = 1, - InputAlreadySpent = 2, - InputCreationAfterTxCreation = 3, - UnlockSignatureInvalid = 4, - ChainAddressUnlockInvalid = 5, - DirectUnlockableAddressUnlockInvalid = 6, - MultiAddressUnlockInvalid = 7, - CommitmentInputReferenceInvalid = 8, - BicInputReferenceInvalid = 9, - RewardInputReferenceInvalid = 10, - StakingRewardCalculationFailure = 11, - DelegationRewardCalculationFailure = 12, - InputOutputBaseTokenMismatch = 13, - ManaOverflow = 14, - InputOutputManaMismatch = 15, - ManaDecayCreationIndexExceedsTargetIndex = 16, - NativeTokenSumUnbalanced = 17, - SimpleTokenSchemeMintedMeltedTokenDecrease = 18, - SimpleTokenSchemeMintingInvalid = 19, - SimpleTokenSchemeMeltingInvalid = 20, - SimpleTokenSchemeMaximumSupplyChanged = 21, - SimpleTokenSchemeGenesisInvalid = 22, - MultiAddressLengthUnlockLengthMismatch = 23, - MultiAddressUnlockThresholdNotReached = 24, - SenderFeatureNotUnlocked = 25, - IssuerFeatureNotUnlocked = 26, - StakingRewardInputMissing = 27, - StakingCommitmentInputMissing = 28, - StakingRewardClaimingInvalid = 29, - StakingFeatureRemovedBeforeUnbonding = 30, - StakingFeatureModifiedBeforeUnbonding = 31, - StakingStartEpochInvalid = 32, - StakingEndEpochTooEarly = 33, - BlockIssuerCommitmentInputMissing = 34, - BlockIssuanceCreditInputMissing = 35, - BlockIssuerNotExpired = 36, - BlockIssuerExpiryTooEarly = 37, - ManaMovedOffBlockIssuerAccount = 38, - AccountLocked = 39, - TimelockCommitmentInputMissing = 40, - TimelockNotExpired = 41, - ExpirationCommitmentInputMissing = 42, - ExpirationNotUnlockable = 43, - ReturnAmountNotFulFilled = 44, - NewChainOutputHasNonZeroedId = 45, - ChainOutputImmutableFeaturesChanged = 46, - ImplicitAccountDestructionDisallowed = 47, - MultipleImplicitAccountCreationAddresses = 48, - AccountInvalidFoundryCounter = 49, - AnchorInvalidStateTransition = 50, - AnchorInvalidGovernanceTransition = 51, - FoundryTransitionWithoutAccount = 52, - FoundrySerialInvalid = 53, - DelegationCommitmentInputMissing = 54, - DelegationRewardInputMissing = 55, - DelegationRewardsClaimingInvalid = 56, - DelegationOutputTransitionedTwice = 57, - DelegationModified = 58, - DelegationStartEpochInvalid = 59, - DelegationAmountMismatch = 60, - DelegationEndEpochNotZero = 61, - DelegationEndEpochInvalid = 62, - CapabilitiesNativeTokenBurningNotAllowed = 63, - CapabilitiesManaBurningNotAllowed = 64, - CapabilitiesAccountDestructionNotAllowed = 65, - CapabilitiesAnchorDestructionNotAllowed = 66, - CapabilitiesFoundryDestructionNotAllowed = 67, - CapabilitiesNftDestructionNotAllowed = 68, + Orphaned = 2, + InputAlreadySpent = 3, + InputCreationAfterTxCreation = 4, + UnlockSignatureInvalid = 5, + ChainAddressUnlockInvalid = 6, + DirectUnlockableAddressUnlockInvalid = 7, + MultiAddressUnlockInvalid = 8, + CommitmentInputReferenceInvalid = 9, + BicInputReferenceInvalid = 10, + RewardInputReferenceInvalid = 11, + StakingRewardCalculationFailure = 12, + DelegationRewardCalculationFailure = 13, + InputOutputBaseTokenMismatch = 14, + ManaOverflow = 15, + InputOutputManaMismatch = 16, + ManaDecayCreationIndexExceedsTargetIndex = 17, + NativeTokenSumUnbalanced = 18, + SimpleTokenSchemeMintedMeltedTokenDecrease = 19, + SimpleTokenSchemeMintingInvalid = 20, + SimpleTokenSchemeMeltingInvalid = 21, + SimpleTokenSchemeMaximumSupplyChanged = 22, + SimpleTokenSchemeGenesisInvalid = 23, + MultiAddressLengthUnlockLengthMismatch = 24, + MultiAddressUnlockThresholdNotReached = 25, + SenderFeatureNotUnlocked = 26, + IssuerFeatureNotUnlocked = 27, + StakingRewardInputMissing = 28, + StakingCommitmentInputMissing = 29, + StakingRewardClaimingInvalid = 30, + StakingFeatureRemovedBeforeUnbonding = 31, + StakingFeatureModifiedBeforeUnbonding = 32, + StakingStartEpochInvalid = 33, + StakingEndEpochTooEarly = 34, + BlockIssuerCommitmentInputMissing = 35, + BlockIssuanceCreditInputMissing = 36, + BlockIssuerNotExpired = 37, + BlockIssuerExpiryTooEarly = 38, + ManaMovedOffBlockIssuerAccount = 39, + AccountLocked = 40, + TimelockCommitmentInputMissing = 41, + TimelockNotExpired = 42, + ExpirationCommitmentInputMissing = 43, + ExpirationNotUnlockable = 44, + ReturnAmountNotFulFilled = 45, + NewChainOutputHasNonZeroedId = 46, + ChainOutputImmutableFeaturesChanged = 47, + ImplicitAccountDestructionDisallowed = 48, + MultipleImplicitAccountCreationAddresses = 49, + AccountInvalidFoundryCounter = 50, + AnchorInvalidStateTransition = 51, + AnchorInvalidGovernanceTransition = 52, + FoundryTransitionWithoutAccount = 53, + FoundrySerialInvalid = 54, + DelegationCommitmentInputMissing = 55, + DelegationRewardInputMissing = 56, + DelegationRewardsClaimingInvalid = 57, + DelegationOutputTransitionedTwice = 58, + DelegationModified = 59, + DelegationStartEpochInvalid = 60, + DelegationAmountMismatch = 61, + DelegationEndEpochNotZero = 62, + DelegationEndEpochInvalid = 63, + CapabilitiesNativeTokenBurningNotAllowed = 64, + CapabilitiesManaBurningNotAllowed = 65, + CapabilitiesAccountDestructionNotAllowed = 66, + CapabilitiesAnchorDestructionNotAllowed = 67, + CapabilitiesFoundryDestructionNotAllowed = 68, + CapabilitiesNftDestructionNotAllowed = 69, SemanticValidationFailed = 255, } @@ -86,6 +87,7 @@ export const TRANSACTION_FAILURE_REASON_STRINGS: { [TransactionFailureReason.None]: 'None.', [TransactionFailureReason.ConflictRejected]: 'Transaction was conflicting and was rejected.', + [TransactionFailureReason.Orphaned]: 'Transaction was orphaned.', [TransactionFailureReason.InputAlreadySpent]: 'Input already spent.', [TransactionFailureReason.InputCreationAfterTxCreation]: 'Input creation slot after tx creation slot.', diff --git a/bindings/nodejs/lib/types/models/api/transaction-response.ts b/bindings/nodejs/lib/types/models/api/transaction-response.ts index 1d81c66520..4d3ea506a7 100644 --- a/bindings/nodejs/lib/types/models/api/transaction-response.ts +++ b/bindings/nodejs/lib/types/models/api/transaction-response.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { TransactionState } from '../state'; -import { TransactionId } from '../../block'; +import { SlotIndex, TransactionId } from '../../block'; import { TransactionFailureReason } from './transaction-failure-reason'; /** @@ -18,7 +18,15 @@ export interface TransactionMetadataResponse { */ transactionState: TransactionState; /** - * The transaction failure reason. + * The slot of the earliest included valid block that contains an attachment of the transaction. + */ + earliestAttachmentSlot: SlotIndex; + /** + * If applicable, indicates the error that occurred during the transaction processing. */ transactionFailureReason?: TransactionFailureReason; + /** + * Contains the detailed error message that occurred during the transaction processing if the debug mode was activated in the retainer. + */ + transactionFailureDetails?: string; } diff --git a/bindings/nodejs/lib/types/models/state.ts b/bindings/nodejs/lib/types/models/state.ts index ec63128cc5..41b38f50c7 100644 --- a/bindings/nodejs/lib/types/models/state.ts +++ b/bindings/nodejs/lib/types/models/state.ts @@ -3,32 +3,40 @@ /** * The different states of a block. - * 'pending': stored but not accepted/confirmed. - * 'accepted': valid block referenced by some validators. - * 'confirmed': valid block referenced by more than 2/3 of the validators. - * 'finalized': accepted/confirmed block and the slot was finalized, can no longer be reverted. - * 'rejected': rejected by the node, and user should reissue payload if it contains one. - * 'failed': not successfully issued due to failure reason. + * 'pending': The block has been booked by the node but not yet accepted. + * 'accepted': The block has been referenced by the super majority of the online committee. + * 'confirmed': The block has been referenced by the super majority of the total committee. + * 'finalized': The commitment containing the block has been finalized. + * This state is computed based on the accepted/confirmed block's slot being smaller or equal than the latest finalized slot. + * 'dropped': The block has been dropped due to congestion control. + * 'orphaned': The block's slot has been committed by the node without the block being included. + * In this case, the block will never be finalized unless there is a chain switch. + * This state is computed based on the pending block's slot being smaller or equal than the latest committed slot. */ export declare type BlockState = | 'pending' | 'accepted' | 'confirmed' | 'finalized' - | 'rejected' - | 'failed'; + | 'dropped' + | 'orphaned'; /** * The different states of a transaction. - * 'pending': the transaction is not included yet. - * 'accepted': the transaction is included. - * 'confirmed': the transaction is included and its included block is confirmed. - * 'finalized': the transaction is included, its included block is finalized and cannot be reverted anymore. - * 'failed': the transaction is not successfully issued due to failure reason. + * 'pending': The transaction has been booked by the node but not yet accepted. + * 'accepted': The transaction meets the following 4 conditions: + * - Signatures of the transaction are valid. + * - The transaction has been approved by the super majority of the online committee (potential conflicts are resolved by this time). + * - The transactions that created the inputs were accepted (monotonicity). + * - At least one valid attachment was accepted. + * 'committed': The slot of the earliest accepted attachment of the transaction was committed. + * 'finalized': The transaction is accepted and the slot containing the transaction has been finalized by the node. + * This state is computed based on the accepted transaction's earliest included attachment slot being smaller or equal than the latest finalized slot. + * 'failed': The transaction has not been executed by the node due to a failure during processing. */ export declare type TransactionState = | 'pending' | 'accepted' - | 'confirmed' + | 'committed' | 'finalized' | 'failed'; diff --git a/bindings/python/iota_sdk/client/responses.py b/bindings/python/iota_sdk/client/responses.py index 27f5d3e173..fac89ea4f3 100644 --- a/bindings/python/iota_sdk/client/responses.py +++ b/bindings/python/iota_sdk/client/responses.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Dict, List, Optional -from enum import Enum, IntEnum +from enum import Enum from dataclasses import dataclass, field from dataclasses_json import config from iota_sdk.types.block.block import Block @@ -277,66 +277,22 @@ class BlockState(str, Enum): """Describes the state of a block. Attributes: - Pending: Stored but not accepted/confirmed. - Accepted: Valid block referenced by some validators. - Confirmed: Valid block referenced by more than 2/3 of the validators. - Finalized: Accepted/confirmed block and the slot was finalized, can no longer be reverted. - Rejected: Rejected by the node, and user should reissue payload if it contains one. - Failed: Not successfully issued due to failure reason. + Pending: The block has been booked by the node but not yet accepted. + Accepted: The block has been referenced by the super majority of the online committee. + Confirmed: The block has been referenced by the super majority of the total committee. + Finalized: The commitment containing the block has been finalized. + This state is computed based on the accepted/confirmed block's slot being smaller or equal than the latest finalized slot. + Dropped: The block has been dropped due to congestion control. + Orphaned: The block's slot has been committed by the node without the block being included. + In this case, the block will never be finalized unless there is a chain switch. + This state is computed based on the pending block's slot being smaller or equal than the latest committed slot. """ Pending = 'pending' Accepted = 'accepted' Confirmed = 'confirmed' Finalized = 'finalized' - Rejected = 'rejected' - Failed = 'failed' - - -class BlockFailureReason(IntEnum): - """Describes the reason of a block failure. - - Attributes: - TooOldToIssue (1): The block is too old to issue. - ParentTooOld (2): One of the block's parents is too old. - ParentDoesNotExist (3): One of the block's parents does not exist. - IssuerAccountNotFound (4): The block's issuer account could not be found. - ManaCostCalculationFailed (5): The mana cost could not be calculated. - BurnedInsufficientMana (6): The block's issuer account burned insufficient Mana for a block. - AccountLocked (7): The account is locked. - AccountExpired (8): The account is expired. - SignatureInvalid (9): The block's signature is invalid. - DroppedDueToCongestion (10): The block is dropped due to congestion. - PayloadInvalid (11): The block payload is invalid. - Invalid (255): The block is invalid. - """ - TooOldToIssue = 1 - ParentTooOld = 2 - ParentDoesNotExist = 3 - IssuerAccountNotFound = 4 - ManaCostCalculationFailed = 5 - BurnedInsufficientMana = 6 - AccountLocked = 7 - AccountExpired = 8 - SignatureInvalid = 9 - DroppedDueToCongestion = 10 - PayloadInvalid = 11 - Invalid = 255 - - def __str__(self): - return { - 1: "The block is too old to issue.", - 2: "One of the block's parents is too old.", - 3: "One of the block's parents does not exist.", - 4: "The block's issuer account could not be found.", - 5: "The mana cost could not be calculated.", - 6: "The block's issuer account burned insufficient Mana for a block.", - 7: "The account is locked.", - 8: "The account is expired.", - 9: "The block's signature is invalid.", - 10: "The block is dropped due to congestion.", - 11: "The block payload is invalid.", - 255: "The block is invalid." - }[self.value] + Dropped = 'dropped' + Orphaned = 'orphaned' @json @@ -348,13 +304,9 @@ class BlockMetadataResponse: Attributes: block_id: The identifier of the block. Hex-encoded with 0x prefix. block_state: If pending, the block is stored but not confirmed. If confirmed, the block is confirmed with the first level of knowledge. If finalized, the block is included and cannot be reverted anymore. If rejected, the block is rejected by the node, and user should reissue payload if it contains one. If failed, the block is not successfully issued due to failure reason. - block_failure_reason: The optional block failure reason. - transaction_metadata: The optional metadata of a given transaction. """ block_id: BlockId block_state: BlockState - block_failure_reason: Optional[BlockFailureReason] = None - transaction_metadata: Optional[TransactionMetadataResponse] = None @json @@ -435,11 +387,15 @@ class TransactionMetadataResponse: Attributes: transaction_id: The identifier of the transaction. Hex-encoded with 0x prefix. transaction_state: If 'pending', the transaction is not included yet. If 'accepted', the transaction is included. If 'confirmed' means transaction is included and its included block is confirmed. If 'finalized' means transaction is included, its included block is finalized and cannot be reverted anymore. If 'failed' means transaction is issued but failed due to the transaction failure reason. - transaction_failure_reason: The optional transaction failure reason. + earliest_attachment_slot: The slot of the earliest included valid block that contains an attachment of the transaction. + transaction_failure_reason: If applicable, indicates the error that occurred during the transaction processing. + transaction_failure_details: Contains the detailed error message that occurred during the transaction processing if the debug mode was activated in the retainer. """ transaction_id: TransactionId transaction_state: TransactionState + earliest_attachment_slot: SlotIndex transaction_failure_reason: Optional[TransactionFailureReason] = None + transaction_failure_details: Optional[str] = None # Commitment routes responses diff --git a/bindings/python/iota_sdk/types/transaction_metadata.py b/bindings/python/iota_sdk/types/transaction_metadata.py index d7928d0e98..0ce6a1fefb 100644 --- a/bindings/python/iota_sdk/types/transaction_metadata.py +++ b/bindings/python/iota_sdk/types/transaction_metadata.py @@ -8,15 +8,20 @@ class TransactionState(str, Enum): """Describes the state of a transaction. Attributes: - Pending: Not included yet. - Accepted: Included. - Confirmed: Included and its included block is confirmed. - Finalized: Included, its included block is finalized and cannot be reverted anymore. - Failed: Not successfully issued due to failure reason. + Pending: The transaction has been booked by the node but not yet accepted. + Accepted: The transaction meets the following 4 conditions: + - Signatures of the transaction are valid. + - The transaction has been approved by the super majority of the online committee (potential conflicts are resolved by this time). + - The transactions that created the inputs were accepted (monotonicity). + - At least one valid attachment was accepted. + Committed: The slot of the earliest accepted attachment of the transaction was committed. + Finalized: The transaction is accepted and the slot containing the transaction has been finalized by the node. + This state is computed based on the accepted transaction's earliest included attachment slot being smaller or equal than the latest finalized slot. + Failed: The transaction has not been executed by the node due to a failure during processing. """ Pending = 'pending' Accepted = 'accepted' - Confirmed = 'confirmed' + Committed = 'committed' Finalized = 'finalized' Failed = 'failed' @@ -26,145 +31,147 @@ class TransactionFailureReason(Enum): """ Null = 0 ConflictRejected = 1 - InputAlreadySpent = 2 - InputCreationAfterTxCreation = 3 - UnlockSignatureInvalid = 4 - ChainAddressUnlockInvalid = 5 - DirectUnlockableAddressUnlockInvalid = 6 - MultiAddressUnlockInvalid = 7 - CommitmentInputReferenceInvalid = 8 - BicInputReferenceInvalid = 9 - RewardInputReferenceInvalid = 10 - StakingRewardCalculationFailure = 11 - DelegationRewardCalculationFailure = 12 - InputOutputBaseTokenMismatch = 13 - ManaOverflow = 14 - InputOutputManaMismatch = 15 - ManaDecayCreationIndexExceedsTargetIndex = 16 - NativeTokenSumUnbalanced = 17 - SimpleTokenSchemeMintedMeltedTokenDecrease = 18 - SimpleTokenSchemeMintingInvalid = 19 - SimpleTokenSchemeMeltingInvalid = 20 - SimpleTokenSchemeMaximumSupplyChanged = 21 - SimpleTokenSchemeGenesisInvalid = 22 - MultiAddressLengthUnlockLengthMismatch = 23 - MultiAddressUnlockThresholdNotReached = 24 - SenderFeatureNotUnlocked = 25 - IssuerFeatureNotUnlocked = 26 - StakingRewardInputMissing = 27 - StakingCommitmentInputMissing = 28 - StakingRewardClaimingInvalid = 29 - StakingFeatureRemovedBeforeUnbonding = 30 - StakingFeatureModifiedBeforeUnbonding = 31 - StakingStartEpochInvalid = 32 - StakingEndEpochTooEarly = 33 - BlockIssuerCommitmentInputMissing = 34 - BlockIssuanceCreditInputMissing = 35 - BlockIssuerNotExpired = 36 - BlockIssuerExpiryTooEarly = 37 - ManaMovedOffBlockIssuerAccount = 38 - AccountLocked = 39 - TimelockCommitmentInputMissing = 40 - TimelockNotExpired = 41 - ExpirationCommitmentInputMissing = 42 - ExpirationNotUnlockable = 43 - ReturnAmountNotFulFilled = 44 - NewChainOutputHasNonZeroedId = 45 - ChainOutputImmutableFeaturesChanged = 46 - ImplicitAccountDestructionDisallowed = 47 - MultipleImplicitAccountCreationAddresses = 48 - AccountInvalidFoundryCounter = 49 - AnchorInvalidStateTransition = 50 - AnchorInvalidGovernanceTransition = 51 - FoundryTransitionWithoutAccount = 52 - FoundrySerialInvalid = 53 - DelegationCommitmentInputMissing = 54 - DelegationRewardInputMissing = 54 - DelegationRewardsClaimingInvalid = 56 - DelegationOutputTransitionedTwice = 57 - DelegationModified = 58 - DelegationStartEpochInvalid = 59 - DelegationAmountMismatch = 60 - DelegationEndEpochNotZero = 61 - DelegationEndEpochInvalid = 62 - CapabilitiesNativeTokenBurningNotAllowed = 63 - CapabilitiesManaBurningNotAllowed = 64 - CapabilitiesAccountDestructionNotAllowed = 65 - CapabilitiesAnchorDestructionNotAllowed = 66 - CapabilitiesFoundryDestructionNotAllowed = 67 - CapabilitiesNftDestructionNotAllowed = 68 + Orphaned = 2 + InputAlreadySpent = 3 + InputCreationAfterTxCreation = 4 + UnlockSignatureInvalid = 5 + ChainAddressUnlockInvalid = 6 + DirectUnlockableAddressUnlockInvalid = 7 + MultiAddressUnlockInvalid = 8 + CommitmentInputReferenceInvalid = 9 + BicInputReferenceInvalid = 10 + RewardInputReferenceInvalid = 11 + StakingRewardCalculationFailure = 12 + DelegationRewardCalculationFailure = 13 + InputOutputBaseTokenMismatch = 14 + ManaOverflow = 15 + InputOutputManaMismatch = 16 + ManaDecayCreationIndexExceedsTargetIndex = 17 + NativeTokenSumUnbalanced = 18 + SimpleTokenSchemeMintedMeltedTokenDecrease = 19 + SimpleTokenSchemeMintingInvalid = 20 + SimpleTokenSchemeMeltingInvalid = 21 + SimpleTokenSchemeMaximumSupplyChanged = 22 + SimpleTokenSchemeGenesisInvalid = 23 + MultiAddressLengthUnlockLengthMismatch = 24 + MultiAddressUnlockThresholdNotReached = 25 + SenderFeatureNotUnlocked = 26 + IssuerFeatureNotUnlocked = 27 + StakingRewardInputMissing = 28 + StakingCommitmentInputMissing = 29 + StakingRewardClaimingInvalid = 30 + StakingFeatureRemovedBeforeUnbonding = 31 + StakingFeatureModifiedBeforeUnbonding = 32 + StakingStartEpochInvalid = 33 + StakingEndEpochTooEarly = 34 + BlockIssuerCommitmentInputMissing = 35 + BlockIssuanceCreditInputMissing = 36 + BlockIssuerNotExpired = 37 + BlockIssuerExpiryTooEarly = 38 + ManaMovedOffBlockIssuerAccount = 39 + AccountLocked = 40 + TimelockCommitmentInputMissing = 41 + TimelockNotExpired = 42 + ExpirationCommitmentInputMissing = 43 + ExpirationNotUnlockable = 44 + ReturnAmountNotFulFilled = 45 + NewChainOutputHasNonZeroedId = 46 + ChainOutputImmutableFeaturesChanged = 47 + ImplicitAccountDestructionDisallowed = 48 + MultipleImplicitAccountCreationAddresses = 49 + AccountInvalidFoundryCounter = 40 + AnchorInvalidStateTransition = 51 + AnchorInvalidGovernanceTransition = 52 + FoundryTransitionWithoutAccount = 53 + FoundrySerialInvalid = 54 + DelegationCommitmentInputMissing = 55 + DelegationRewardInputMissing = 56 + DelegationRewardsClaimingInvalid = 57 + DelegationOutputTransitionedTwice = 58 + DelegationModified = 59 + DelegationStartEpochInvalid = 60 + DelegationAmountMismatch = 61 + DelegationEndEpochNotZero = 62 + DelegationEndEpochInvalid = 63 + CapabilitiesNativeTokenBurningNotAllowed = 64 + CapabilitiesManaBurningNotAllowed = 65 + CapabilitiesAccountDestructionNotAllowed = 66 + CapabilitiesAnchorDestructionNotAllowed = 67 + CapabilitiesFoundryDestructionNotAllowed = 68 + CapabilitiesNftDestructionNotAllowed = 69 SemanticValidationFailed = 255 def __str__(self): return { 0: "Null.", 1: "Transaction was conflicting and was rejected.", - 2: "Input already spent.", - 3: "Input creation slot after tx creation slot.", - 4: "Signature in unlock is invalid.", - 5: "Invalid unlock for chain address.", - 6: "Invalid unlock for direct unlockable address.", - 7: "Invalid unlock for multi address.", - 8: "Commitment input references an invalid or non-existent commitment.", - 9: "BIC input reference cannot be loaded.", - 10: "Reward input does not reference a staking account or a delegation output.", - 11: "Staking rewards could not be calculated due to storage issues or overflow.", - 12: "Delegation rewards could not be calculated due to storage issues or overflow.", - 13: "Inputs and outputs do not spend/deposit the same amount of base tokens.", - 14: "Under- or overflow in Mana calculations.", - 15: "Inputs and outputs do not contain the same amount of Mana.", - 16: "Mana decay creation slot/epoch index exceeds target slot/epoch index.", - 17: "Native token sums are unbalanced.", - 18: "Simple token scheme minted/melted value decreased.", - 19: "Simple token scheme's minted tokens did not increase by the minted amount or melted tokens changed.", - 20: "Simple token scheme's melted tokens did not increase by the melted amount or minted tokens changed.", - 21: "Simple token scheme's maximum supply cannot change during transition.", - 22: "Newly created simple token scheme's melted tokens are not zero or minted tokens do not equal native token amount in transaction.", - 23: "Multi address length and multi unlock length do not match.", - 24: "Multi address unlock threshold not reached.", - 25: "Sender feature is not unlocked.", - 26: "Issuer feature is not unlocked.", - 27: "Staking feature removal or resetting requires a reward input.", - 28: "Staking feature validation requires a commitment input.", - 29: "Staking feature must be removed or reset in order to claim rewards.", - 30: "Staking feature can only be removed after the unbonding period.", - 31: "Staking start epoch, fixed cost and staked amount cannot be modified while bonded.", - 32: "Staking start epoch must be the epoch of the transaction.", - 33: "Staking end epoch must be set to the transaction epoch plus the unbonding period.", - 34: "Commitment input missing for block issuer feature.", - 35: "Block issuance credit input missing for account with block issuer feature.", - 36: "Block issuer feature has not expired.", - 37: "Block issuer feature expiry set too early.", - 38: "Mana cannot be moved off block issuer accounts except with manalocks.", - 39: "Account is locked due to negative block issuance credits.", - 40: "Transaction's containing a timelock condition require a commitment input.", - 41: "Timelock not expired.", - 42: "Transaction's containing an expiration condition require a commitment input.", - 43: "Expiration unlock condition cannot be unlocked.", - 44: "Return amount not fulfilled.", - 45: "New chain output has non-zeroed ID.", - 46: "Immutable features in chain output modified during transition.", - 47: "Cannot destroy implicit account; must be transitioned to account.", - 48: "Multiple implicit account creation addresses on the input side.", - 49: "Foundry counter in account decreased or did not increase by the number of new foundries.", - 50: "Anchor has an invalid state transition.", - 51: "Anchor has an invalid governance transition.", - 52: "Foundry output transitioned without accompanying account on input or output side.", - 53: "Foundry output serial number is invalid.", - 54: "Delegation output validation requires a commitment input.", - 55: "Delegation output cannot be destroyed without a reward input.", - 56: "Invalid delegation mana rewards claiming.", - 57: "Delegation output attempted to be transitioned twice.", - 58: "Delegated amount, validator ID and start epoch cannot be modified.", - 59: "Invalid start epoch.", - 60: "Delegated amount does not match amount.", - 61: "End epoch must be set to zero at output genesis.", - 62: "Delegation end epoch does not match current epoch.", - 63: "Native token burning is not allowed by the transaction capabilities.", - 64: "Mana burning is not allowed by the transaction capabilities.", - 65: "Account destruction is not allowed by the transaction capabilities.", - 66: "Anchor destruction is not allowed by the transaction capabilities.", - 67: "Foundry destruction is not allowed by the transaction capabilities.", - 68: "NFT destruction is not allowed by the transaction capabilities.", + 2: "Transaction was orphaned.", + 3: "Input already spent.", + 4: "Input creation slot after tx creation slot.", + 5: "Signature in unlock is invalid.", + 6: "Invalid unlock for chain address.", + 7: "Invalid unlock for direct unlockable address.", + 8: "Invalid unlock for multi address.", + 9: "Commitment input references an invalid or non-existent commitment.", + 10: "BIC input reference cannot be loaded.", + 11: "Reward input does not reference a staking account or a delegation output.", + 12: "Staking rewards could not be calculated due to storage issues or overflow.", + 13: "Delegation rewards could not be calculated due to storage issues or overflow.", + 14: "Inputs and outputs do not spend/deposit the same amount of base tokens.", + 15: "Under- or overflow in Mana calculations.", + 16: "Inputs and outputs do not contain the same amount of Mana.", + 17: "Mana decay creation slot/epoch index exceeds target slot/epoch index.", + 18: "Native token sums are unbalanced.", + 19: "Simple token scheme minted/melted value decreased.", + 20: "Simple token scheme's minted tokens did not increase by the minted amount or melted tokens changed.", + 21: "Simple token scheme's melted tokens did not increase by the melted amount or minted tokens changed.", + 22: "Simple token scheme's maximum supply cannot change during transition.", + 23: "Newly created simple token scheme's melted tokens are not zero or minted tokens do not equal native token amount in transaction.", + 24: "Multi address length and multi unlock length do not match.", + 25: "Multi address unlock threshold not reached.", + 26: "Sender feature is not unlocked.", + 27: "Issuer feature is not unlocked.", + 28: "Staking feature removal or resetting requires a reward input.", + 29: "Staking feature validation requires a commitment input.", + 30: "Staking feature must be removed or reset in order to claim rewards.", + 31: "Staking feature can only be removed after the unbonding period.", + 32: "Staking start epoch, fixed cost and staked amount cannot be modified while bonded.", + 33: "Staking start epoch must be the epoch of the transaction.", + 34: "Staking end epoch must be set to the transaction epoch plus the unbonding period.", + 35: "Commitment input missing for block issuer feature.", + 36: "Block issuance credit input missing for account with block issuer feature.", + 37: "Block issuer feature has not expired.", + 38: "Block issuer feature expiry set too early.", + 39: "Mana cannot be moved off block issuer accounts except with manalocks.", + 40: "Account is locked due to negative block issuance credits.", + 41: "Transaction's containing a timelock condition require a commitment input.", + 42: "Timelock not expired.", + 43: "Transaction's containing an expiration condition require a commitment input.", + 44: "Expiration unlock condition cannot be unlocked.", + 45: "Return amount not fulfilled.", + 46: "New chain output has non-zeroed ID.", + 47: "Immutable features in chain output modified during transition.", + 48: "Cannot destroy implicit account; must be transitioned to account.", + 49: "Multiple implicit account creation addresses on the input side.", + 50: "Foundry counter in account decreased or did not increase by the number of new foundries.", + 51: "Anchor has an invalid state transition.", + 52: "Anchor has an invalid governance transition.", + 53: "Foundry output transitioned without accompanying account on input or output side.", + 54: "Foundry output serial number is invalid.", + 55: "Delegation output validation requires a commitment input.", + 56: "Delegation output cannot be destroyed without a reward input.", + 57: "Invalid delegation mana rewards claiming.", + 58: "Delegation output attempted to be transitioned twice.", + 59: "Delegated amount, validator ID and start epoch cannot be modified.", + 60: "Invalid start epoch.", + 61: "Delegated amount does not match amount.", + 62: "End epoch must be set to zero at output genesis.", + 63: "Delegation end epoch does not match current epoch.", + 64: "Native token burning is not allowed by the transaction capabilities.", + 65: "Mana burning is not allowed by the transaction capabilities.", + 66: "Account destruction is not allowed by the transaction capabilities.", + 67: "Anchor destruction is not allowed by the transaction capabilities.", + 68: "Foundry destruction is not allowed by the transaction capabilities.", + 69: "NFT destruction is not allowed by the transaction capabilities.", 255: "Semantic validation failed.", }[self.value] diff --git a/bindings/python/tests/test_api_responses.py b/bindings/python/tests/test_api_responses.py index 785f777667..75d3976a46 100644 --- a/bindings/python/tests/test_api_responses.py +++ b/bindings/python/tests/test_api_responses.py @@ -3,7 +3,7 @@ from typing import Generic, TypeVar from json import load, loads, dumps -from iota_sdk import RoutesResponse, CongestionResponse, OutputWithMetadataResponse, ManaRewardsResponse, ValidatorsResponse, ValidatorResponse, CommitteeResponse, IssuanceBlockHeaderResponse, Block, BlockMetadataResponse, BlockWithMetadataResponse, OutputMetadata, OutputResponse, TransactionMetadataResponse, SlotCommitment, UtxoChangesResponse, UtxoChangesFullResponse +from iota_sdk import RoutesResponse, CongestionResponse, OutputWithMetadataResponse, ManaRewardsResponse, ValidatorsResponse, ValidatorResponse, CommitteeResponse, IssuanceBlockHeaderResponse, Block, BlockWithMetadataResponse, OutputMetadata, OutputResponse, SlotCommitment, UtxoChangesResponse, UtxoChangesFullResponse base_path = '../../sdk/tests/types/api/fixtures/' @@ -50,16 +50,17 @@ def test_api_response(cls_type: Generic[T], path: str): test_api_response( Block, "get-block-by-id-validation-response-example.json") # GET /api/core/v3/blocks/{blockId}/metadata - test_api_response(BlockMetadataResponse, - "get-block-by-id-response-example-new-transaction.json") - test_api_response(BlockMetadataResponse, - "get-block-by-id-response-example-new.json") - test_api_response(BlockMetadataResponse, - "get-block-by-id-response-example-confirmed-transaction.json") - test_api_response(BlockMetadataResponse, - "get-block-by-id-response-example-confirmed.json") - test_api_response(BlockMetadataResponse, - "get-block-by-id-response-example-conflicting-transaction.json") + # TODO reenable when TIP is updated + # test_api_response(BlockMetadataResponse, + # "get-block-by-id-response-example-new-transaction.json") + # test_api_response(BlockMetadataResponse, + # "get-block-by-id-response-example-new.json") + # test_api_response(BlockMetadataResponse, + # "get-block-by-id-response-example-confirmed-transaction.json") + # test_api_response(BlockMetadataResponse, + # "get-block-by-id-response-example-confirmed.json") + # test_api_response(BlockMetadataResponse, + # "get-block-by-id-response-example-conflicting-transaction.json") # GET /api/core/v3/blocks/{blockId}/full test_api_response(BlockWithMetadataResponse, "get-full-block-by-id-tagged-data-response-example.json") @@ -75,8 +76,9 @@ def test_api_response(cls_type: Generic[T], path: str): test_api_response(OutputWithMetadataResponse, "get-full-output-metadata-example.json") # GET /api/core/v3/transactions/{transactionId}/metadata - test_api_response(TransactionMetadataResponse, - "get-transaction-metadata-by-id-response-example.json") + # TODO reenable when TIP is updated + # test_api_response(TransactionMetadataResponse, + # "get-transaction-metadata-by-id-response-example.json") # GET /api/core/v3/commitments/{commitmentId} test_api_response(SlotCommitment, "get-commitment-response-example.json") # GET /api/core/v3/commitments/{commitmentId}/utxo-changes diff --git a/bindings/python/tests/test_secret_manager.py b/bindings/python/tests/test_secret_manager.py index 624430275e..af111e26f0 100644 --- a/bindings/python/tests/test_secret_manager.py +++ b/bindings/python/tests/test_secret_manager.py @@ -9,7 +9,8 @@ def test_secret_manager_address_generation_iota(): "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast")) bech32_hrp = Utils.iota_mainnet_protocol_parameters().bech32_hrp - address = secret_manager.generate_ed25519_address(CoinType.IOTA, bech32_hrp) + address = secret_manager.generate_ed25519_address( + CoinType.IOTA, bech32_hrp) assert 'iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg' == address @@ -19,6 +20,7 @@ def test_secret_manager_address_generation_shimmer(): "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast")) bech32_hrp = Utils.shimmer_mainnet_protocol_parameters().bech32_hrp - address = secret_manager.generate_ed25519_address(CoinType.SHIMMER, bech32_hrp) + address = secret_manager.generate_ed25519_address( + CoinType.SHIMMER, bech32_hrp) assert 'smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y' == address diff --git a/sdk/src/client/api/wait_for_tx_acceptance.rs b/sdk/src/client/api/wait_for_tx_acceptance.rs index a12c71eb60..fa2e0d668a 100644 --- a/sdk/src/client/api/wait_for_tx_acceptance.rs +++ b/sdk/src/client/api/wait_for_tx_acceptance.rs @@ -29,7 +29,7 @@ impl Client { let transaction_metadata = self.get_transaction_metadata(transaction_id).await?; match transaction_metadata.transaction_state { - TransactionState::Accepted | TransactionState::Confirmed | TransactionState::Finalized => { + TransactionState::Accepted | TransactionState::Committed | TransactionState::Finalized => { return Ok(()); } TransactionState::Failed => return Err(ClientError::TransactionAcceptance(transaction_id.to_string())), diff --git a/sdk/src/types/api/core.rs b/sdk/src/types/api/core.rs index c43a4fdfdd..46fc7cace2 100644 --- a/sdk/src/types/api/core.rs +++ b/sdk/src/types/api/core.rs @@ -360,109 +360,64 @@ pub struct SubmitBlockResponse { #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum BlockState { - /// Stored but not accepted/confirmed. + /// The block has been booked by the node but not yet accepted. Pending, - /// Valid block referenced by some validators. + /// The block has been referenced by the super majority of the online committee. Accepted, - /// Valid block referenced by more than 2/3 of the validators. + /// The block has been referenced by the super majority of the total committee. Confirmed, - /// Accepted/confirmed block and the slot was finalized, can no longer be reverted. + /// The commitment containing the block has been finalized. + /// This state is computed based on the accepted/confirmed block's slot being smaller or equal than the latest + /// finalized slot. Finalized, - /// Rejected by the node, and user should reissue payload if it contains one. - Rejected, - /// Not successfully issued due to failure reason. - Failed, + /// The block has been dropped due to congestion control. + Dropped, + /// The block's slot has been committed by the node without the block being included. + /// In this case, the block will never be finalized unless there is a chain switch. + /// This state is computed based on the pending block's slot being smaller or equal than the latest committed slot. + Orphaned, } /// Describes the state of a transaction. #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum TransactionState { - /// Not included yet. + /// The transaction has been booked by the node but not yet accepted. Pending, - /// Included. + /// The transaction meets the following 4 conditions: + /// - Signatures of the transaction are valid. + /// - The transaction has been approved by the super majority of the online committee (potential conflicts are + /// resolved by this time). + /// - The transactions that created the inputs were accepted (monotonicity). + /// - At least one valid attachment was accepted. Accepted, - /// Included and its included block is confirmed. - Confirmed, - /// Included, its included block is finalized and cannot be reverted anymore. + /// The slot of the earliest accepted attachment of the transaction was committed. + Committed, + /// The transaction is accepted and the slot containing the transaction has been finalized by the node. + /// This state is computed based on the accepted transaction's earliest included attachment slot being smaller or + /// equal than the latest finalized slot. Finalized, - /// The block is not successfully issued due to failure reason. + /// The transaction has not been executed by the node due to a failure during processing. Failed, } -/// Describes the reason of a block failure. -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - serde_repr::Serialize_repr, - serde_repr::Deserialize_repr, - strum::FromRepr, - strum::EnumString, - strum::AsRefStr, -)] -#[serde(rename_all = "camelCase")] -#[strum(serialize_all = "camelCase")] -#[non_exhaustive] -#[repr(u8)] -pub enum BlockFailureReason { - /// The block is too old to issue. - TooOldToIssue = 1, - /// One of the block's parents is too old. - ParentTooOld = 2, - /// One of the block's parents does not exist. - ParentDoesNotExist = 3, - /// The block's issuer account could not be found. - IssuerAccountNotFound = 4, - /// The mana cost could not be calculated. - ManaCostCalculationFailed = 5, - // The block's issuer account burned insufficient Mana for a block. - BurnedInsufficientMana = 6, - /// The account is locked. - AccountLocked = 7, - /// The account is locked. - AccountExpired = 8, - /// The block's signature is invalid. - SignatureInvalid = 9, - /// The block is dropped due to congestion. - DroppedDueToCongestion = 10, - /// The block payload is invalid. - PayloadInvalid = 11, - /// The block is invalid. - Invalid = 255, -} - -impl core::fmt::Display for BlockFailureReason { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::TooOldToIssue => write!(f, "The block is too old to issue."), - Self::ParentTooOld => write!(f, "One of the block's parents is too old."), - Self::ParentDoesNotExist => write!(f, "One of the block's parents does not exist."), - Self::IssuerAccountNotFound => write!(f, "The block's issuer account could not be found."), - Self::ManaCostCalculationFailed => write!(f, "The mana cost could not be calculated."), - Self::BurnedInsufficientMana => { - write!(f, "The block's issuer account burned insufficient Mana for a block.") - } - Self::AccountLocked => write!(f, "The account is locked."), - Self::AccountExpired => write!(f, "The account is expired."), - Self::SignatureInvalid => write!(f, "The block's signature is invalid."), - Self::DroppedDueToCongestion => write!(f, "The block is dropped due to congestion."), - Self::PayloadInvalid => write!(f, "The block payload is invalid."), - Self::Invalid => write!(f, "The block is invalid."), - } - } -} - // Response of a GET transaction metadata REST API call. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionMetadataResponse { + /// The transaction ID. pub transaction_id: TransactionId, + /// The transaction state. pub transaction_state: TransactionState, + /// The slot of the earliest included valid block that contains an attachment of the transaction. + pub earliest_attachment_slot: SlotIndex, + /// If applicable, indicates the error that occurred during the transaction processing. #[serde(default, skip_serializing_if = "Option::is_none")] pub transaction_failure_reason: Option, + /// Contains the detailed error message that occurred during the transaction processing if the debug mode was + /// activated in the retainer. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub transaction_failure_details: Option, } /// Response of GET /api/core/v3/blocks/{blockId}/metadata. @@ -472,10 +427,6 @@ pub struct TransactionMetadataResponse { pub struct BlockMetadataResponse { pub block_id: BlockId, pub block_state: BlockState, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub block_failure_reason: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub transaction_metadata: Option, } /// Response of GET /api/core/v3/blocks/{blockId}/full. diff --git a/sdk/src/types/block/semantic/error.rs b/sdk/src/types/block/semantic/error.rs index a9ac1ba4a8..b89f22717b 100644 --- a/sdk/src/types/block/semantic/error.rs +++ b/sdk/src/types/block/semantic/error.rs @@ -40,146 +40,148 @@ pub enum TransactionFailureReason { None = 0, #[display(fmt = "transaction was conflicting and was rejected")] ConflictRejected = 1, + #[display(fmt = "transaction was orphaned")] + Orphaned = 2, #[display(fmt = "input already spent")] - InputAlreadySpent = 2, + InputAlreadySpent = 3, #[display(fmt = "input creation slot after tx creation slot")] - InputCreationAfterTxCreation = 3, + InputCreationAfterTxCreation = 4, #[display(fmt = "signature in unlock is invalid")] - UnlockSignatureInvalid = 4, + UnlockSignatureInvalid = 5, #[display(fmt = "invalid unlock for chain address")] - ChainAddressUnlockInvalid = 5, + ChainAddressUnlockInvalid = 6, #[display(fmt = "invalid unlock for direct unlockable address")] - DirectUnlockableAddressUnlockInvalid = 6, + DirectUnlockableAddressUnlockInvalid = 7, #[display(fmt = "invalid unlock for multi address")] - MultiAddressUnlockInvalid = 7, + MultiAddressUnlockInvalid = 8, #[display(fmt = "commitment input references an invalid or non-existent commitment")] - CommitmentInputReferenceInvalid = 8, + CommitmentInputReferenceInvalid = 9, #[display(fmt = "BIC input reference cannot be loaded")] - BicInputReferenceInvalid = 9, + BicInputReferenceInvalid = 10, #[display(fmt = "reward input does not reference a staking account or a delegation output")] - RewardInputReferenceInvalid = 10, + RewardInputReferenceInvalid = 11, #[display(fmt = "staking rewards could not be calculated due to storage issues or overflow")] - StakingRewardCalculationFailure = 11, + StakingRewardCalculationFailure = 12, #[display(fmt = "delegation rewards could not be calculated due to storage issues or overflow")] - DelegationRewardCalculationFailure = 12, + DelegationRewardCalculationFailure = 13, #[display(fmt = "inputs and outputs do not spend/deposit the same amount of base tokens")] - InputOutputBaseTokenMismatch = 13, + InputOutputBaseTokenMismatch = 14, #[display(fmt = "under- or overflow in Mana calculations")] - ManaOverflow = 14, + ManaOverflow = 15, #[display(fmt = "inputs and outputs do not contain the same amount of mana")] - InputOutputManaMismatch = 15, + InputOutputManaMismatch = 16, #[display(fmt = "mana decay creation slot/epoch index exceeds target slot/epoch index")] - ManaDecayCreationIndexExceedsTargetIndex = 16, + ManaDecayCreationIndexExceedsTargetIndex = 17, #[display(fmt = "native token sums are unbalanced")] - NativeTokenSumUnbalanced = 17, + NativeTokenSumUnbalanced = 18, #[display(fmt = "simple token scheme's minted or melted tokens decreased")] - SimpleTokenSchemeMintedMeltedTokenDecrease = 18, + SimpleTokenSchemeMintedMeltedTokenDecrease = 19, #[strum( to_string = "simple token scheme's minted tokens did not increase by the minted amount or melted tokens changed" )] - SimpleTokenSchemeMintingInvalid = 19, + SimpleTokenSchemeMintingInvalid = 20, #[strum( to_string = "simple token scheme's melted tokens did not increase by the melted amount or minted tokens changed" )] - SimpleTokenSchemeMeltingInvalid = 20, + SimpleTokenSchemeMeltingInvalid = 21, #[display(fmt = "simple token scheme's maximum supply cannot change during transition")] - SimpleTokenSchemeMaximumSupplyChanged = 21, + SimpleTokenSchemeMaximumSupplyChanged = 22, #[strum( to_string = "newly created simple token scheme's melted tokens are not zero or minted tokens do not equal native token amount in transaction" )] - SimpleTokenSchemeGenesisInvalid = 22, + SimpleTokenSchemeGenesisInvalid = 23, #[display(fmt = "multi address length and multi unlock length do not match")] - MultiAddressLengthUnlockLengthMismatch = 23, + MultiAddressLengthUnlockLengthMismatch = 24, #[display(fmt = "multi address unlock threshold not reached")] - MultiAddressUnlockThresholdNotReached = 24, + MultiAddressUnlockThresholdNotReached = 25, #[display(fmt = "sender feature is not unlocked")] - SenderFeatureNotUnlocked = 25, + SenderFeatureNotUnlocked = 26, #[display(fmt = "issuer feature is not unlocked")] - IssuerFeatureNotUnlocked = 26, + IssuerFeatureNotUnlocked = 27, #[display(fmt = "staking feature removal or resetting requires a reward input")] - StakingRewardInputMissing = 27, + StakingRewardInputMissing = 28, #[display(fmt = "staking feature validation requires a commitment input")] - StakingCommitmentInputMissing = 28, + StakingCommitmentInputMissing = 29, #[display(fmt = "staking feature must be removed or reset in order to claim rewards")] - StakingRewardClaimingInvalid = 29, + StakingRewardClaimingInvalid = 30, #[display(fmt = "staking feature can only be removed after the unbonding period")] - StakingFeatureRemovedBeforeUnbonding = 30, + StakingFeatureRemovedBeforeUnbonding = 31, #[display(fmt = "staking start epoch, fixed cost and staked amount cannot be modified while bonded")] - StakingFeatureModifiedBeforeUnbonding = 31, + StakingFeatureModifiedBeforeUnbonding = 32, #[display(fmt = "staking start epoch must be the epoch of the transaction")] - StakingStartEpochInvalid = 32, + StakingStartEpochInvalid = 33, #[display(fmt = "staking end epoch must be set to the transaction epoch plus the unbonding period")] - StakingEndEpochTooEarly = 33, + StakingEndEpochTooEarly = 34, #[display(fmt = "commitment input missing for block issuer feature")] - BlockIssuerCommitmentInputMissing = 34, + BlockIssuerCommitmentInputMissing = 35, #[display(fmt = "block issuance credit input missing for account with block issuer feature")] - BlockIssuanceCreditInputMissing = 35, + BlockIssuanceCreditInputMissing = 36, #[display(fmt = "block issuer feature has not expired")] - BlockIssuerNotExpired = 36, + BlockIssuerNotExpired = 37, #[display(fmt = "block issuer feature expiry set too early")] - BlockIssuerExpiryTooEarly = 37, + BlockIssuerExpiryTooEarly = 38, #[display(fmt = "mana cannot be moved off block issuer accounts except with manalocks")] - ManaMovedOffBlockIssuerAccount = 38, + ManaMovedOffBlockIssuerAccount = 39, #[display(fmt = "account is locked due to negative block issuance credits")] - AccountLocked = 39, + AccountLocked = 40, #[display(fmt = "transaction's containing a timelock condition require a commitment input")] - TimelockCommitmentInputMissing = 40, + TimelockCommitmentInputMissing = 41, #[display(fmt = "timelock not expired")] - TimelockNotExpired = 41, + TimelockNotExpired = 42, #[display(fmt = "transaction's containing an expiration condition require a commitment input")] - ExpirationCommitmentInputMissing = 42, + ExpirationCommitmentInputMissing = 43, #[display(fmt = "expiration unlock condition cannot be unlocked")] - ExpirationNotUnlockable = 43, + ExpirationNotUnlockable = 44, #[display(fmt = "return amount not fulfilled")] - ReturnAmountNotFulFilled = 44, + ReturnAmountNotFulFilled = 45, #[display(fmt = "new chain output has non-zeroed ID")] - NewChainOutputHasNonZeroedId = 45, + NewChainOutputHasNonZeroedId = 46, #[display(fmt = "immutable features in chain output modified during transition")] - ChainOutputImmutableFeaturesChanged = 46, + ChainOutputImmutableFeaturesChanged = 47, #[display(fmt = "cannot destroy implicit account; must be transitioned to account")] - ImplicitAccountDestructionDisallowed = 47, + ImplicitAccountDestructionDisallowed = 48, #[display(fmt = "multiple implicit account creation addresses on the input side")] - MultipleImplicitAccountCreationAddresses = 48, + MultipleImplicitAccountCreationAddresses = 49, #[display(fmt = "foundry counter in account decreased or did not increase by the number of new foundries")] - AccountInvalidFoundryCounter = 49, + AccountInvalidFoundryCounter = 50, #[display(fmt = "invalid anchor state transition")] - AnchorInvalidStateTransition = 50, + AnchorInvalidStateTransition = 51, #[display(fmt = "invalid anchor governance transition")] - AnchorInvalidGovernanceTransition = 51, + AnchorInvalidGovernanceTransition = 52, #[display(fmt = "foundry output transitioned without accompanying account on input or output side")] - FoundryTransitionWithoutAccount = 52, + FoundryTransitionWithoutAccount = 53, #[display(fmt = "foundry output serial number is invalid")] - FoundrySerialInvalid = 53, + FoundrySerialInvalid = 54, #[display(fmt = "delegation output validation requires a commitment input")] - DelegationCommitmentInputMissing = 54, + DelegationCommitmentInputMissing = 55, #[display(fmt = "delegation output cannot be destroyed without a reward input")] - DelegationRewardInputMissing = 55, + DelegationRewardInputMissing = 56, #[display(fmt = "invalid delegation mana rewards claiming")] - DelegationRewardsClaimingInvalid = 56, + DelegationRewardsClaimingInvalid = 57, #[display(fmt = "attempted to transition delegation output twice")] - DelegationOutputTransitionedTwice = 57, + DelegationOutputTransitionedTwice = 58, #[display(fmt = "delegated amount, validator ID and start epoch cannot be modified")] - DelegationModified = 58, + DelegationModified = 59, #[display(fmt = "delegation output has invalid start epoch")] - DelegationStartEpochInvalid = 59, + DelegationStartEpochInvalid = 60, #[display(fmt = "delegated amount does not match amount")] - DelegationAmountMismatch = 60, + DelegationAmountMismatch = 61, #[display(fmt = "end epoch must be set to zero at output genesis")] - DelegationEndEpochNotZero = 61, + DelegationEndEpochNotZero = 62, #[display(fmt = "delegation end epoch does not match current epoch")] - DelegationEndEpochInvalid = 62, + DelegationEndEpochInvalid = 63, #[display(fmt = "native token burning is not allowed by the transaction capabilities")] - CapabilitiesNativeTokenBurningNotAllowed = 63, + CapabilitiesNativeTokenBurningNotAllowed = 64, #[display(fmt = "mana burning is not allowed by the transaction capabilities")] - CapabilitiesManaBurningNotAllowed = 64, + CapabilitiesManaBurningNotAllowed = 65, #[display(fmt = "account destruction is not allowed by the transaction capabilities")] - CapabilitiesAccountDestructionNotAllowed = 65, + CapabilitiesAccountDestructionNotAllowed = 66, #[display(fmt = "anchor destruction is not allowed by the transaction capabilities")] - CapabilitiesAnchorDestructionNotAllowed = 66, + CapabilitiesAnchorDestructionNotAllowed = 67, #[display(fmt = "foundry destruction is not allowed by the transaction capabilities")] - CapabilitiesFoundryDestructionNotAllowed = 67, + CapabilitiesFoundryDestructionNotAllowed = 68, #[display(fmt = "NFT destruction is not allowed by the transaction capabilities")] - CapabilitiesNftDestructionNotAllowed = 68, + CapabilitiesNftDestructionNotAllowed = 69, #[display(fmt = "semantic validation failed")] SemanticValidationFailed = 255, } diff --git a/sdk/src/wallet/operations/syncing/transactions.rs b/sdk/src/wallet/operations/syncing/transactions.rs index 064f0bd5d1..0e88e68ac4 100644 --- a/sdk/src/wallet/operations/syncing/transactions.rs +++ b/sdk/src/wallet/operations/syncing/transactions.rs @@ -69,7 +69,7 @@ where drop(wallet_ledger); - for (transaction_id, mut transaction) in pending_transactions { + for (transaction_id, transaction) in pending_transactions { log::debug!("[SYNC] sync pending transaction {transaction_id}"); // only check transaction from the network we're connected to @@ -118,96 +118,95 @@ where } } - if let Some(block_id) = &transaction.block_id { - match self.client().get_block_metadata(block_id).await { - Ok(metadata) => { - if let Some(tx_state) = metadata.transaction_metadata.map(|m| m.transaction_state) { - match tx_state { - // TODO: Separate TransactionState::Finalized, TransactionState::Accepted? https://github.com/iotaledger/iota-sdk/issues/1814 - TransactionState::Accepted - | TransactionState::Confirmed - | TransactionState::Finalized => { - log::debug!( - "[SYNC] confirmed transaction {transaction_id} in block {}", - metadata.block_id - ); - confirmed_unknown_output = true; - updated_transaction_and_outputs( - transaction, - Some(metadata.block_id), - InclusionState::Confirmed, - &mut updated_transactions, - &mut spent_output_ids, - ); - } - 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) = self - .client() - .get_included_block(&transaction.payload.transaction().id()) - .await - { - confirmed_unknown_output = true; - updated_transaction_and_outputs( - transaction, - Some(self.client().block_id(&included_block).await?), - // block metadata was Conflicting, but it's confirmed in another attachment - InclusionState::Confirmed, - &mut updated_transactions, - &mut spent_output_ids, - ); - } else { - log::debug!("[SYNC] conflicting transaction {transaction_id}"); - updated_transaction_and_outputs( - transaction, - None, - InclusionState::Conflicting, - &mut updated_transactions, - &mut spent_output_ids, - ); - } - } - // Do nothing, just need to wait a bit more - TransactionState::Pending => {} - } - } else if input_got_spent { - process_transaction_with_unknown_state( - &*self.ledger().await, + match self.client().get_transaction_metadata(&transaction_id).await { + Ok(metadata) => { + match metadata.transaction_state { + // TODO: Separate TransactionState::Finalized, TransactionState::Accepted? https://github.com/iotaledger/iota-sdk/issues/1814 + TransactionState::Accepted | TransactionState::Committed | TransactionState::Finalized => { + log::debug!( + "[SYNC] confirmed transaction {transaction_id} in slot {}", + metadata.earliest_attachment_slot + ); + confirmed_unknown_output = true; + updated_transaction_and_outputs( transaction, + // Some(metadata.block_id), + None, + InclusionState::Confirmed, &mut updated_transactions, - &mut output_ids_to_unlock, - )?; + &mut spent_output_ids, + ); } - } - Err(ClientError::Node(crate::client::node_api::error::Error::NotFound(_))) => { - if input_got_spent { - process_transaction_with_unknown_state( - &*self.ledger().await, - transaction, - &mut updated_transactions, - &mut output_ids_to_unlock, - )?; + 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) = self + .client() + .get_included_block(&transaction.payload.transaction().id()) + .await + { + confirmed_unknown_output = true; + updated_transaction_and_outputs( + transaction, + Some(self.client().block_id(&included_block).await?), + // block metadata was Conflicting, but it's confirmed in another attachment + InclusionState::Confirmed, + &mut updated_transactions, + &mut spent_output_ids, + ); + } else { + log::debug!("[SYNC] conflicting transaction {transaction_id}"); + updated_transaction_and_outputs( + transaction, + None, + InclusionState::Conflicting, + &mut updated_transactions, + &mut spent_output_ids, + ); + } } + // Do nothing, just need to wait a bit more + TransactionState::Pending => {} + } + // else if input_got_spent { + // process_transaction_with_unknown_state( + // &*self.ledger().await, + // transaction, + // &mut updated_transactions, + // &mut output_ids_to_unlock, + // )?; + // } + } + Err(ClientError::Node(crate::client::node_api::error::Error::NotFound(_))) => { + if input_got_spent { + process_transaction_with_unknown_state( + &*self.ledger().await, + transaction, + &mut updated_transactions, + &mut output_ids_to_unlock, + )?; } - Err(e) => return Err(e.into()), } - } else if input_got_spent { - process_transaction_with_unknown_state( - &*self.ledger().await, - transaction, - &mut updated_transactions, - &mut output_ids_to_unlock, - )?; - } else { - // Reissue if there was no block id yet, because then we also didn't burn any mana - log::debug!("[SYNC] reissue transaction {}", transaction.transaction_id); - let reissued_block = self - .submit_signed_transaction(transaction.payload.clone(), None) - .await?; - transaction.block_id.replace(reissued_block); - updated_transactions.push(transaction); + Err(e) => return Err(e.into()), } + + // else if input_got_spent { + // process_transaction_with_unknown_state( + // &*self.ledger().await, + // transaction, + // &mut updated_transactions, + // &mut output_ids_to_unlock, + // )?; + // } + // else { + // // Reissue if there was no block id yet, because then we also didn't burn any mana + // log::debug!("[SYNC] reissue transaction {}", transaction.transaction_id); + // let reissued_block = self + // .submit_signed_transaction(transaction.payload.clone(), None) + // .await?; + // transaction.block_id.replace(reissued_block); + // updated_transactions.push(transaction); + // } } // updates account with balances, output ids, outputs diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index e0fc8d7b07..e276993666 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -10,7 +10,7 @@ use iota_sdk::{ Client, }, types::{ - api::core::TransactionState, + api::core::BlockState, block::{ output::{Output, OutputId}, Block, @@ -231,13 +231,7 @@ async fn test_get_included_block_metadata() { let metadata_response = client.get_included_block_metadata(&transaction_id).await.unwrap(); assert_eq!(metadata_response.block_id, block_id); - assert_eq!( - metadata_response - .transaction_metadata - .as_ref() - .map(|m| m.transaction_state), - Some(TransactionState::Finalized) - ); + assert_eq!(metadata_response.block_state, BlockState::Finalized); println!("{metadata_response:#?}"); } diff --git a/sdk/tests/types/api/core.rs b/sdk/tests/types/api/core.rs index 70e5ac525d..3fe98e68dd 100644 --- a/sdk/tests/types/api/core.rs +++ b/sdk/tests/types/api/core.rs @@ -74,11 +74,12 @@ fn responses() { json_response::("transaction-block-example.json").unwrap(); json_response::("get-block-by-id-validation-response-example.json").unwrap(); // GET /api/core/v3/blocks/{blockId}/metadata - json_response::("get-block-by-id-response-example-new-transaction.json").unwrap(); - json_response::("get-block-by-id-response-example-new.json").unwrap(); - json_response::("get-block-by-id-response-example-confirmed-transaction.json").unwrap(); - json_response::("get-block-by-id-response-example-confirmed.json").unwrap(); - json_response::("get-block-by-id-response-example-conflicting-transaction.json").unwrap(); + // TODO reenable when TIP is updated + // json_response::("get-block-by-id-response-example-new-transaction.json").unwrap(); + // json_response::("get-block-by-id-response-example-new.json").unwrap(); + // json_response::("get-block-by-id-response-example-confirmed-transaction.json").unwrap(); + // json_response::("get-block-by-id-response-example-confirmed.json").unwrap(); + // json_response::("get-block-by-id-response-example-conflicting-transaction.json").unwrap(); // GET /api/core/v3/blocks/{blockId}/full json_response::("get-full-block-by-id-tagged-data-response-example.json").unwrap(); // GET /api/core/v3/outputs/{outputId} @@ -89,7 +90,8 @@ fn responses() { // GET /api/core/v3/outputs/{outputId}/full json_response::("get-full-output-metadata-example.json").unwrap(); // GET /api/core/v3/transactions/{transactionId}/metadata - json_response::("get-transaction-metadata-by-id-response-example.json").unwrap(); + // TODO reenable when TIP is updated + // json_response::("get-transaction-metadata-by-id-response-example.json").unwrap(); // GET /api/core/v3/commitments/{commitmentId} json_response::("get-commitment-response-example.json").unwrap(); binary_response::("get-commitment-response-binary-example", &()).unwrap();