Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedDocuments(documents) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedDocuments(documents) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedDocuments(documents) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ impl Sdk {
trace!("document_replace: broadcasting and awaiting response");
let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();
trace!("document_replace: broadcast completed");

match proof_result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedDocuments(documents) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedDocuments(documents) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/rs-sdk/src/platform/tokens/transitions/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedTokenBalance(owner_id, remaining_balance) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/rs-sdk/src/platform/tokens/transitions/claim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedTokenActionWithDocument(document) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedTokenActionWithDocument(document) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedTokenActionWithDocument(doc) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedTokenBalance(owner_id, balance) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedTokenActionWithDocument(document) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-sdk/src/platform/tokens/transitions/freeze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;

.await?
.into_inner();
match proof_result {
StateTransitionProofResult::VerifiedTokenIdentityInfo(owner_id_result, info) => {
Ok(FreezeResult::IdentityInfo(owner_id_result, info))
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-sdk/src/platform/tokens/transitions/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;

.await?
.into_inner();
match proof_result {
StateTransitionProofResult::VerifiedTokenBalance(recipient_id_result, new_balance) => {
Ok(MintResult::TokenBalance(recipient_id_result, new_balance))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;

.await?
.into_inner();
match proof_result {
StateTransitionProofResult::VerifiedTokenPricingSchedule(owner_id, schedule) => {
Ok(SetPriceResult::PricingSchedule(owner_id, schedule))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;
.await?
.into_inner();

match proof_result {
StateTransitionProofResult::VerifiedTokenIdentitiesBalances(balances) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-sdk/src/platform/tokens/transitions/unfreeze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ impl Sdk {

let proof_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, put_settings)
.await?;

.await?
.into_inner();
match proof_result {
StateTransitionProofResult::VerifiedTokenIdentityInfo(owner_id_result, info) => {
Ok(UnfreezeResult::IdentityInfo(owner_id_result, info))
Expand Down
2 changes: 2 additions & 0 deletions packages/rs-sdk/src/platform/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod put_contract;
pub mod put_document;
pub mod put_identity;
pub mod put_settings;
pub mod state_transition_result;
pub mod top_up_address;
pub mod top_up_identity;
pub mod top_up_identity_from_addresses;
Expand All @@ -22,4 +23,5 @@ pub(crate) mod validation;
pub mod vote;
pub mod waitable;
pub mod withdraw_from_identity;
pub use state_transition_result::StateTransitionResult;
pub use txid::TxId;
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl<S: Signer<PlatformAddress>> WithdrawAddressFunds<S> for Sdk {
match state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, settings)
.await?
.into_inner()
{
StateTransitionProofResult::VerifiedAddressInfos(address_infos_map) => {
let mut expected_addresses: BTreeSet<PlatformAddress> =
Expand Down
13 changes: 10 additions & 3 deletions packages/rs-sdk/src/platform/transition/broadcast.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::broadcast_request::BroadcastRequestForStateTransition;
use super::put_settings::PutSettings;
use super::state_transition_result::StateTransitionResult;
use crate::error::StateTransitionBroadcastError;
use crate::platform::block_info_from_metadata::block_info_from_metadata;
use crate::sync::retry;
Expand Down Expand Up @@ -30,7 +31,7 @@ pub trait BroadcastStateTransition {
&self,
sdk: &Sdk,
settings: Option<PutSettings>,
) -> Result<T, Error>;
) -> Result<StateTransitionResult<T>, Error>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -264,8 +265,14 @@ impl BroadcastStateTransition for StateTransition {
&self,
sdk: &Sdk,
settings: Option<PutSettings>,
) -> Result<T, Error> {
) -> Result<StateTransitionResult<T>, Error> {
trace!(state_transition = %self.name(), "broadcast_and_wait: start");

// Compute the transition hash deterministically BEFORE broadcast.
// This is a SHA-256 hash of the serialized StateTransition and does
// not depend on blockchain state, so there is no race condition.
let transition_hash = self.transaction_id()?;

trace!("broadcast_and_wait: step 1 - broadcasting");
self.broadcast(sdk, settings).await?;
trace!("broadcast_and_wait: step 2 - waiting for response");
Expand All @@ -274,6 +281,6 @@ impl BroadcastStateTransition for StateTransition {
Ok(_) => trace!("broadcast_and_wait: complete success"),
Err(e) => warn!(error = ?e, "broadcast_and_wait: failed"),
}
result
result.map(|inner| StateTransitionResult::new(inner, transition_hash))
}
}
1 change: 1 addition & 0 deletions packages/rs-sdk/src/platform/transition/put_identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ async fn put_identity_with_address_funding<
match state_transition
.broadcast_and_wait::<StateTransitionProofResult>(sdk, settings)
.await?
.into_inner()
{
StateTransitionProofResult::VerifiedIdentityFullWithAddressInfos(
proved_identity,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::ops::Deref;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Yes, it would be cleaner to include the transition hash directly in the result types (DocumentCreateResult, MintResult, etc.) rather than using a generic wrapper.

The wrapper approach (StateTransitionResult<T>) was chosen because:

  1. It avoids modifying 20+ result enums individually
  2. The hash is a property of the broadcast operation, not the result type itself

But Pasta's right that embedding it in T would be simpler for consumers — no .into_inner() calls, no wrapper to deal with. The downside is every result type needs a transition_hash field added.

I'd lean toward keeping the wrapper for now since it's non-invasive, but happy to refactor if you prefer the embedded approach. What's your preference?


/// Wrapper that bundles a state transition proof result with the transition hash.
///
/// The transition hash (also known as the transaction ID) is computed deterministically
/// from the serialized `StateTransition` before broadcast, so it does not depend on
/// blockchain state and there is no race condition.
///
/// `StateTransitionResult<T>` implements `Deref<Target = T>`, so existing code that
/// only needs the inner result can use it transparently.
#[derive(Debug, Clone)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "state_transition_result.rs" | head -5

Repository: dashpay/platform

Length of output: 128


🏁 Script executed:

cat -n packages/rs-sdk/src/platform/transition/state_transition_result.rs | head -50

Repository: dashpay/platform

Length of output: 2044


🏁 Script executed:

git log --oneline --all | grep -i "22fc89c1c\|state.transition.result" | head -10

Repository: dashpay/platform

Length of output: 144


🏁 Script executed:

git show --stat 22fc89c1c 2>/dev/null | head -30

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git log --all --oneline --decorate | grep -i "state.transition" | head -20

Repository: dashpay/platform

Length of output: 1741


🏁 Script executed:

git log --all --grep="PartialEq\|Eq" --oneline | head -10

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

rg "StateTransitionResult" packages/rs-sdk/src/platform/transition/ -A 5 -B 2

Repository: dashpay/platform

Length of output: 10366


🏁 Script executed:

git log --all --oneline packages/rs-sdk/src/platform/transition/state_transition_result.rs | head -10

Repository: dashpay/platform

Length of output: 130


🏁 Script executed:

git show d6f4eb9ac --stat | head -40

Repository: dashpay/platform

Length of output: 2283


🏁 Script executed:

git log --all --oneline --grep="22fc89c1c" | head -5

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git log --all --oneline | grep -E "22fc89c1c|3077" | head -5

Repository: dashpay/platform

Length of output: 135


🏁 Script executed:

git show d6f4eb9ac:packages/rs-sdk/src/platform/transition/state_transition_result.rs 2>/dev/null | head -20

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git show d6f4eb9ac --format=fuller | head -100

Repository: dashpay/platform

Length of output: 4611


🏁 Script executed:

git log --all --oneline -S "PartialEq" -- packages/rs-sdk/src/platform/transition/state_transition_result.rs | head -10

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git log --all --oneline -S "Eq" -- packages/rs-sdk/src/platform/transition/state_transition_result.rs | head -10

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git show d6f4eb9ac -- packages/rs-sdk/src/platform/transition/state_transition_result.rs | head -50

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git show d6f4eb9ac:packages/rs-sdk/src/platform/transition/state_transition_result.rs 2>&1 | cat

Repository: dashpay/platform

Length of output: 179


🏁 Script executed:

git log --all --pretty=format:"%H %s" | grep "3077"

Repository: dashpay/platform

Length of output: 408


🏁 Script executed:

git show --name-status d6f4eb9ac | grep "state_transition_result"

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git diff d6f4eb9ac~1 d6f4eb9ac -- packages/rs-sdk/src/platform/transition/state_transition_result.rs

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git log --all --oneline -S "StateTransitionResult" -- "**.rs" | head -20

Repository: dashpay/platform

Length of output: 146


🏁 Script executed:

git log --oneline --all packages/rs-sdk/src/platform/transition/ | head -20

Repository: dashpay/platform

Length of output: 1669


🏁 Script executed:

git show HEAD:packages/rs-sdk/src/platform/transition/state_transition_result.rs 2>&1 | head -30

Repository: dashpay/platform

Length of output: 1067


🏁 Script executed:

rg "PartialEq.*Eq" packages/rs-sdk/src/platform/transition/ -B 2

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git show 07b2e5cba --format=fuller | head -50

Repository: dashpay/platform

Length of output: 2109


🏁 Script executed:

git show 07b2e5cba -- packages/rs-sdk/src/platform/transition/state_transition_result.rs | head -80

Repository: dashpay/platform

Length of output: 2982


🏁 Script executed:

git log --all -p -- packages/rs-sdk/src/platform/transition/state_transition_result.rs | grep -A 3 -B 3 "PartialEq\|Eq" | head -40

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

git show 07b2e5cba --stat | grep "state_transition_result"

Repository: dashpay/platform

Length of output: 245


🏁 Script executed:

git log --all --oneline --grep="post-review\|22fc89c1c" | head -10

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

rg "StateTransitionResult" packages/rs-sdk/src/platform/transition/broadcast.rs -B 2 -A 2 | head -50

Repository: dashpay/platform

Length of output: 1363


Add PartialEq and Eq derives for test assertions.

The struct only derives Debug and Clone, but PartialEq and Eq would enable assert_eq! comparisons in tests. Both should be unconditionally derived.

🛠️ Proposed fix
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct StateTransitionResult<T> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-sdk/src/platform/transition/state_transition_result.rs` at line
11, Add PartialEq and Eq to the derive list for the StateTransitionResult struct
so tests can use assert_eq!; update the existing #[derive(Debug, Clone)] line to
#[derive(Debug, Clone, PartialEq, Eq)] (i.e., extend the derive on the struct
defined in state_transition_result.rs) and run cargo test to verify
equality-based assertions now work.

pub struct StateTransitionResult<T> {
Comment on lines 3 to 12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claw; would it make more sense for the T to just include the transition hash? is that possible?

inner: T,
transition_hash: [u8; 32],
}

impl<T> StateTransitionResult<T> {
/// Creates a new result bundling the proof result with the transition hash.
pub fn new(inner: T, transition_hash: [u8; 32]) -> Self {
Self {
inner,
transition_hash,
}
}

/// Returns the transition hash (transaction ID) as a 32-byte array.
pub fn transition_hash(&self) -> [u8; 32] {
self.transition_hash
}

/// Consumes this wrapper, returning the inner result and the transition hash.
pub fn into_parts(self) -> (T, [u8; 32]) {
(self.inner, self.transition_hash)
}

/// Consumes this wrapper, returning just the inner result.
pub fn into_inner(self) -> T {
self.inner
}

/// Maps the inner value, preserving the transition hash.
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> StateTransitionResult<U> {
StateTransitionResult {
inner: f(self.inner),
transition_hash: self.transition_hash,
}
}
}

impl<T> Deref for StateTransitionResult<T> {
type Target = T;

fn deref(&self) -> &T {
&self.inner
}
}
3 changes: 2 additions & 1 deletion packages/rs-sdk/src/platform/transition/top_up_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ impl<S: Signer<PlatformAddress>> TopUpAddress<S> for AddressesWithBalances {
ensure_valid_state_transition_structure(&state_transition, sdk.version())?;
let st_result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(sdk, settings)
.await?;
.await?
.into_inner();
match st_result {
StateTransitionProofResult::VerifiedAddressInfos(address_infos) => {
let expected_addresses =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ impl TopUpIdentity for Identity {
None,
)?;
ensure_valid_state_transition_structure(&state_transition, sdk.version())?;
let identity: PartialIdentity = state_transition.broadcast_and_wait(sdk, settings).await?;
let identity: PartialIdentity = state_transition
.broadcast_and_wait::<PartialIdentity>(sdk, settings)
.await?
.into_inner();

identity
.balance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl<S: Signer<PlatformAddress>> TopUpIdentityFromAddresses<S> for Identity {
match state_transition
.broadcast_and_wait::<StateTransitionProofResult>(sdk, settings)
.await?
.into_inner()
{
StateTransitionProofResult::VerifiedIdentityWithAddressInfos(
identity,
Expand Down
6 changes: 4 additions & 2 deletions packages/rs-sdk/src/platform/transition/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ impl TransferToIdentity for Identity {
)?;
ensure_valid_state_transition_structure(&state_transition, sdk.version())?;

let (sender, receiver): (PartialIdentity, PartialIdentity) =
state_transition.broadcast_and_wait(sdk, settings).await?;
let (sender, receiver): (PartialIdentity, PartialIdentity) = state_transition
.broadcast_and_wait::<(PartialIdentity, PartialIdentity)>(sdk, settings)
.await?
.into_inner();

let sender_balance = sender.balance.ok_or_else(|| {
Error::Generic("expected an identity balance after transfer (sender)".to_string())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ impl<S: Signer<PlatformAddress>> TransferAddressFunds<S> for Sdk {
match state_transition
.broadcast_and_wait::<StateTransitionProofResult>(self, settings)
.await?
.into_inner()
{
StateTransitionProofResult::VerifiedAddressInfos(address_infos_map) => {
collect_address_infos_from_proof(address_infos_map, &expected_addresses)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl TransferToAddresses for Identity {
match state_transition
.broadcast_and_wait::<StateTransitionProofResult>(sdk, settings)
.await?
.into_inner()
{
StateTransitionProofResult::VerifiedIdentityWithAddressInfos(
identity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ impl WithdrawFromIdentity for Identity {
)?;
ensure_valid_state_transition_structure(&state_transition, sdk.version())?;

let result = state_transition.broadcast_and_wait(sdk, settings).await?;
let result = state_transition
.broadcast_and_wait::<StateTransitionProofResult>(sdk, settings)
.await?
.into_inner();

match result {
StateTransitionProofResult::VerifiedPartialIdentity(identity) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/wasm-sdk/src/state_transitions/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,6 @@ impl WasmSdk {
.await
.map_err(|e| WasmSdkError::generic(format!("Failed to broadcast: {}", e)))?;

convert_proof_result(result).map_err(WasmSdkError::from)
convert_proof_result(result.into_inner()).map_err(WasmSdkError::from)
}
}
Loading