dash_sdk/platform/transition/
waitable.rsuse std::collections::BTreeMap;
use super::broadcast::BroadcastStateTransition;
use super::put_settings::PutSettings;
use crate::platform::Fetch;
use crate::Error;
use crate::Sdk;
use dpp::document::Document;
use dpp::prelude::{DataContract, Identifier, Identity};
use dpp::state_transition::identity_create_transition::accessors::IdentityCreateTransitionAccessorsV0;
use dpp::state_transition::StateTransition;
use dpp::state_transition::StateTransitionLike;
use dpp::voting::votes::Vote;
use dpp::ProtocolError;
#[async_trait::async_trait]
pub trait Waitable: Sized {
async fn wait_for_response(
sdk: &Sdk,
state_transition: StateTransition,
settings: Option<PutSettings>,
) -> Result<Self, Error>;
}
#[async_trait::async_trait]
impl Waitable for DataContract {
async fn wait_for_response(
sdk: &Sdk,
state_transition: StateTransition,
settings: Option<PutSettings>,
) -> Result<DataContract, Error> {
state_transition.wait_for_response(sdk, settings).await
}
}
#[async_trait::async_trait]
impl Waitable for Document {
async fn wait_for_response(
sdk: &Sdk,
state_transition: StateTransition,
settings: Option<PutSettings>,
) -> Result<Self, Error> {
let doc_id = if let StateTransition::DocumentsBatch(transition) = &state_transition {
let ids = transition.modified_data_ids();
if ids.len() != 1 {
return Err(Error::Protocol(
dpp::ProtocolError::InvalidStateTransitionType(format!(
"expected state transition with exactly one document, got {}",
ids.into_iter()
.map(|id| id
.to_string(dpp::platform_value::string_encoding::Encoding::Base58))
.collect::<Vec<_>>()
.join(", ")
)),
));
}
ids[0]
} else {
return Err(Error::Protocol(ProtocolError::InvalidStateTransitionType(
format!(
"expected state transition to be a DocumentsBatchTransition, got {}",
state_transition.name()
),
)));
};
let mut documents: BTreeMap<Identifier, Option<Document>> =
state_transition.wait_for_response(sdk, settings).await?;
let document: Document = documents
.remove(&doc_id)
.ok_or(Error::InvalidProvedResponse(
"did not prove the sent document".to_string(),
))?
.ok_or(Error::InvalidProvedResponse(
"expected there to actually be a document".to_string(),
))?;
Ok(document)
}
}
#[async_trait::async_trait]
impl Waitable for Identity {
async fn wait_for_response(
sdk: &Sdk,
state_transition: StateTransition,
settings: Option<PutSettings>,
) -> Result<Self, Error> {
let result: Result<Self, Error> = state_transition.wait_for_response(sdk, settings).await;
match result {
Ok(identity) => Ok(identity),
Err(Error::AlreadyExists(_)) => {
let identity_id = if let StateTransition::IdentityCreate(st) = state_transition {
st.identity_id()
} else {
return Err(Error::Generic(format!(
"expected identity create state transition, got {:?}",
state_transition.name()
)));
};
tracing::debug!(
?identity_id,
"attempt to create identity that already exists"
);
let identity = Identity::fetch(sdk, identity_id).await?;
identity.ok_or(Error::DapiClientError(
"identity was proved to not exist but was said to exist".to_string(),
))
}
Err(e) => Err(e),
}
}
}
#[async_trait::async_trait]
impl Waitable for Vote {
async fn wait_for_response(
sdk: &Sdk,
state_transition: StateTransition,
settings: Option<PutSettings>,
) -> Result<Self, Error> {
state_transition.wait_for_response(sdk, settings).await
}
}