From 9db07c2c62a89b1d75681e3ad569bac97df61761 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 8 Oct 2024 09:18:50 +0200 Subject: [PATCH 01/12] - Move Retractec from UnexpectedTxStatus to XtStatus - Provide is_final method for TransactionStatus - Return from watch method as soon as a final state is reached - Provide separate method to populate events for an ExtrinsicReport --- src/api/mod.rs | 67 ++++++++++++++++++++++----------------- src/api/rpc_api/author.rs | 22 +++++++++++-- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 42ba95870..516ce1399 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -70,6 +70,7 @@ pub enum XtStatus { Ready = 1, Broadcast = 2, InBlock = 3, + Retracted = 4, Finalized = 6, } @@ -78,7 +79,6 @@ pub enum XtStatus { #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum UnexpectedTxStatus { Future, - Retracted, FinalityTimeout, Usurped, Dropped, @@ -119,36 +119,32 @@ pub enum TransactionStatus { impl TransactionStatus { pub fn as_u8(&self) -> u8 { match self { - TransactionStatus::Future => 0, - TransactionStatus::Ready => 1, - TransactionStatus::Broadcast(_) => 2, - TransactionStatus::InBlock(_) => 3, - TransactionStatus::Retracted(_) => 4, - TransactionStatus::FinalityTimeout(_) => 5, - TransactionStatus::Finalized(_) => 6, - TransactionStatus::Usurped(_) => 7, - TransactionStatus::Dropped => 8, - TransactionStatus::Invalid => 9, + Self::Future => 0, + Self::Ready => 1, + Self::Broadcast(_) => 2, + Self::InBlock(_) => 3, + Self::Retracted(_) => 4, + Self::FinalityTimeout(_) => 5, + Self::Finalized(_) => 6, + Self::Usurped(_) => 7, + Self::Dropped => 8, + Self::Invalid => 9, } } pub fn is_expected(&self) -> Result<()> { match self { - TransactionStatus::Ready - | TransactionStatus::Broadcast(_) - | TransactionStatus::InBlock(_) - | TransactionStatus::Finalized(_) => Ok(()), - TransactionStatus::Future => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Future)), - TransactionStatus::Retracted(_) => - Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Retracted)), - TransactionStatus::FinalityTimeout(_) => + Self::Ready + | Self::Broadcast(_) + | Self::InBlock(_) + | Self::Retracted(_) + | Self::Finalized(_) => Ok(()), + Self::Future => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Future)), + Self::FinalityTimeout(_) => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::FinalityTimeout)), - TransactionStatus::Usurped(_) => - Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Usurped)), - TransactionStatus::Dropped => - Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Dropped)), - TransactionStatus::Invalid => - Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Invalid)), + Self::Usurped(_) => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Usurped)), + Self::Dropped => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Dropped)), + Self::Invalid => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Invalid)), } } @@ -160,13 +156,26 @@ impl TransactionStatus Option<&BlockHash> { match self { - TransactionStatus::InBlock(block_hash) => Some(block_hash), - TransactionStatus::Retracted(block_hash) => Some(block_hash), - TransactionStatus::FinalityTimeout(block_hash) => Some(block_hash), - TransactionStatus::Finalized(block_hash) => Some(block_hash), + Self::InBlock(block_hash) => Some(block_hash), + Self::Retracted(block_hash) => Some(block_hash), + Self::FinalityTimeout(block_hash) => Some(block_hash), + Self::Finalized(block_hash) => Some(block_hash), _ => None, } } + + /// Returns true if the Transaction reached its final Status + // See https://github.com/paritytech/polkadot-sdk/blob/289f5bbf7a45dc0380904a435464b15ec711ed03/substrate/client/transaction-pool/api/src/lib.rs#L161 + pub fn is_final(&self) -> bool { + matches!( + self, + Self::Usurped(_) + | Self::Finalized(_) + | Self::FinalityTimeout(_) + | Self::Invalid + | Self::Dropped + ) + } } // Exact structure from diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index a5fcdcf25..35046d996 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -17,7 +17,7 @@ use crate::{ api::{rpc_api::events::FetchEvents, Error, Result}, error::FailedExtrinsicError, rpc::{HandleSubscription, Request, Subscribe}, - Api, ExtrinsicReport, TransactionStatus, XtStatus, + Api, ExtrinsicReport, TransactionStatus, UnexpectedTxStatus, XtStatus, }; use ac_compose_macros::rpc_params; use ac_primitives::{config::Config, UncheckedExtrinsicV4}; @@ -211,6 +211,12 @@ pub trait SubmitAndWatch { encoded_extrinsic: &Bytes, watch_until: XtStatus, ) -> Result>; + + /// Query the events for the specified `report` and attach them. + async fn populate_events( + &self, + report: ExtrinsicReport, + ) -> Result>; } #[maybe_async::maybe_async(?Send)] @@ -269,18 +275,25 @@ where encoded_extrinsic: &Bytes, watch_until: XtStatus, ) -> Result> { - let mut report = self + let report = self .submit_and_watch_opaque_extrinsic_until_without_events(encoded_extrinsic, watch_until) .await?; if watch_until < XtStatus::InBlock { return Ok(report) } + self.populate_events(report).await + } + + async fn populate_events( + &self, + mut report: ExtrinsicReport, + ) -> Result> { let block_hash = report.block_hash.ok_or(Error::BlockHashNotFound)?; let extrinsic_events = self.fetch_events_for_extrinsic(block_hash, report.extrinsic_hash).await?; - // Check if the extrinsic was succesfull or not. + // Check if the extrinsic was successful or not. let mut maybe_dispatch_error = None; for event in &extrinsic_events { if let Some(dispatch_error) = event.get_associated_dispatch_error() { @@ -352,6 +365,9 @@ where return Err(e) }, } + if transaction_status.is_final() { + return Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Usurped)) + } } Err(Error::NoStream) } From 7ce954d7967ba0dd8f5a78451809c75a5fb5a1a1 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 8 Oct 2024 10:14:02 +0200 Subject: [PATCH 02/12] Fix unittest --- src/api/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 516ce1399..d4c4dd946 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -225,11 +225,11 @@ mod tests { assert!(TransactionStatus::Ready.is_expected().is_ok()); assert!(TransactionStatus::Broadcast(vec![]).is_expected().is_ok()); assert!(TransactionStatus::InBlock(H256::random()).is_expected().is_ok()); + assert!(TransactionStatus::Retracted(H256::random()).is_expected().is_ok()); assert!(TransactionStatus::Finalized(H256::random()).is_expected().is_ok()); // Not supported. assert!(TransactionStatus::Future.is_expected().is_err()); - assert!(TransactionStatus::Retracted(H256::random()).is_expected().is_err()); assert!(TransactionStatus::FinalityTimeout(H256::random()).is_expected().is_err()); assert!(TransactionStatus::Usurped(H256::random()).is_expected().is_err()); assert!(TransactionStatus::Dropped.is_expected().is_err()); From b5e0b6d584f9e58ac354337dc1f0bfe094a9b4f4 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 8 Oct 2024 11:28:11 +0200 Subject: [PATCH 03/12] Remove unreachable handling of states with is_final() == True --- src/api/rpc_api/author.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index 35046d996..eb7399f5e 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -17,7 +17,7 @@ use crate::{ api::{rpc_api::events::FetchEvents, Error, Result}, error::FailedExtrinsicError, rpc::{HandleSubscription, Request, Subscribe}, - Api, ExtrinsicReport, TransactionStatus, UnexpectedTxStatus, XtStatus, + Api, ExtrinsicReport, TransactionStatus, XtStatus, }; use ac_compose_macros::rpc_params; use ac_primitives::{config::Config, UncheckedExtrinsicV4}; @@ -365,9 +365,6 @@ where return Err(e) }, } - if transaction_status.is_final() { - return Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Usurped)) - } } Err(Error::NoStream) } From 6191cb8e6918fbcd76916d76e314518fa5f3db19 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 9 Oct 2024 08:00:16 +0200 Subject: [PATCH 04/12] Improve testing and error handling --- src/api/rpc_api/author.rs | 3 +++ testing/async/examples/author_tests.rs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index eb7399f5e..1f1471bad 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -289,6 +289,9 @@ where &self, mut report: ExtrinsicReport, ) -> Result> { + if report.events.is_some() { + return Err(Error::Other("Report already contains events".into())) + } let block_hash = report.block_hash.ok_or(Error::BlockHashNotFound)?; let extrinsic_events = self.fetch_events_for_extrinsic(block_hash, report.extrinsic_hash).await?; diff --git a/testing/async/examples/author_tests.rs b/testing/async/examples/author_tests.rs index 585495af5..0757c6164 100644 --- a/testing/async/examples/author_tests.rs +++ b/testing/async/examples/author_tests.rs @@ -174,6 +174,13 @@ async fn test_submit_and_watch_extrinsic_until_in_block_without_events( println!("Extrinsic got successfully included in Block!"); assert!(report.block_hash.is_some()); assert!(report.events.is_none()); + + // Now we fetch the events separately + let report = api.populate_events(report).await.unwrap(); + assert!(report.events.is_some()); + + // Can populate events only once + assert!(api.populate_events(report).await.is_err()); } fn assert_associated_events_match_expected(events: Vec>) { From 833db41729e6f5914db932a2453ce3b53f190ae7 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 9 Oct 2024 08:33:06 +0200 Subject: [PATCH 05/12] Improve tests --- testing/async/examples/author_tests.rs | 29 +++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/testing/async/examples/author_tests.rs b/testing/async/examples/author_tests.rs index 0757c6164..926cef6f8 100644 --- a/testing/async/examples/author_tests.rs +++ b/testing/async/examples/author_tests.rs @@ -58,17 +58,18 @@ async fn main() { test_submit_and_watch_until_broadcast(&api, transfer_call.clone(), signer_nonce + 3), test_submit_and_watch_until_in_block(&api, transfer_call.clone(), signer_nonce + 4), test_submit_and_watch_until_finalized(&api, transfer_call.clone(), signer_nonce + 5), + test_submit_and_watch_until_retracted(&api, transfer_call.clone(), signer_nonce + 6), // Test some _watch_untils_without_events. We don't need to test all, because it is tested implicitly by `submit_and_watch_extrinsic_until` // as internal call. test_submit_and_watch_extrinsic_until_ready_without_events( &api, transfer_call.clone(), - signer_nonce + 6 + signer_nonce + 7 ), test_submit_and_watch_extrinsic_until_in_block_without_events( &api, transfer_call.clone(), - signer_nonce + 7 + signer_nonce + 8 ) ); } @@ -125,7 +126,7 @@ async fn test_submit_and_watch_until_in_block( let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await.unwrap(); assert!(report.block_hash.is_some()); assert!(matches!(report.status, TransactionStatus::InBlock(_))); - assert_associated_events_match_expected(report.events.unwrap()); + assert_associated_events_match_expected(&report.events.unwrap()); println!("Success: submit_and_watch_extrinsic_until {:?}", report.status); } @@ -139,7 +140,23 @@ async fn test_submit_and_watch_until_finalized( let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await.unwrap(); assert!(report.block_hash.is_some()); assert!(matches!(report.status, TransactionStatus::Finalized(_))); - assert_associated_events_match_expected(report.events.unwrap()); + assert_associated_events_match_expected(&report.events.unwrap()); + println!("Success: submit_and_watch_extrinsic_until {:?}", report.status); +} + +async fn test_submit_and_watch_until_retracted( + api: &MyApi, + transfer_call: RuntimeCall, + nonce: Index, +) { + std::thread::sleep(std::time::Duration::from_secs(1)); + let xt = api.compose_extrinsic_offline(transfer_call, nonce); + // We wait for `Retracted`` but we cannot simulate this in a test. Therefore we will receive the status after `Retracted` + // which is `Finalized` + let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Retracted).await.unwrap(); + assert!(report.block_hash.is_some()); + assert!(matches!(report.status, TransactionStatus::Finalized(_))); + assert_associated_events_match_expected(&report.events.unwrap()); println!("Success: submit_and_watch_extrinsic_until {:?}", report.status); } @@ -178,12 +195,14 @@ async fn test_submit_and_watch_extrinsic_until_in_block_without_events( // Now we fetch the events separately let report = api.populate_events(report).await.unwrap(); assert!(report.events.is_some()); + let events = report.events.as_ref().unwrap(); + assert_associated_events_match_expected(&events); // Can populate events only once assert!(api.populate_events(report).await.is_err()); } -fn assert_associated_events_match_expected(events: Vec>) { +fn assert_associated_events_match_expected(events: &[RawEventDetails]) { // First event assert_eq!(events[0].pallet_name(), "Balances"); assert_eq!(events[0].variant_name(), "Withdraw"); From 96696ac403e5684c0e1c513af4b3235fcb7e7d82 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 9 Oct 2024 09:15:21 +0200 Subject: [PATCH 06/12] Change API for `populate_events` function --- src/api/rpc_api/author.rs | 27 +++++++++++--------------- testing/async/examples/author_tests.rs | 7 ++++--- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index 1f1471bad..062fed414 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -212,11 +212,11 @@ pub trait SubmitAndWatch { watch_until: XtStatus, ) -> Result>; - /// Query the events for the specified `report` and attach them. - async fn populate_events( - &self, - report: ExtrinsicReport, - ) -> Result>; + /// Query the events for the specified `report` and attaches them to the returned report. + /// If the function fails the report is not modified. + /// + /// This method is blocking if the sync-api feature is activated + async fn populate_events(&self, report: &mut ExtrinsicReport) -> Result<()>; } #[maybe_async::maybe_async(?Send)] @@ -275,20 +275,18 @@ where encoded_extrinsic: &Bytes, watch_until: XtStatus, ) -> Result> { - let report = self + let mut report = self .submit_and_watch_opaque_extrinsic_until_without_events(encoded_extrinsic, watch_until) .await?; if watch_until < XtStatus::InBlock { return Ok(report) } - self.populate_events(report).await + self.populate_events(&mut report).await?; + return Ok(report); } - async fn populate_events( - &self, - mut report: ExtrinsicReport, - ) -> Result> { + async fn populate_events(&self, report: &mut ExtrinsicReport) -> Result<()> { if report.events.is_some() { return Err(Error::Other("Report already contains events".into())) } @@ -304,17 +302,14 @@ where break } } - - report.events = Some(extrinsic_events.into_iter().map(|event| event.to_raw()).collect()); - if let Some(dispatch_error) = maybe_dispatch_error { return Err(Error::FailedExtrinsic(FailedExtrinsicError::new( dispatch_error, report.encode(), ))) } - - Ok(report) + report.events = Some(extrinsic_events.into_iter().map(|event| event.to_raw()).collect()); + Ok(()) } async fn submit_and_watch_extrinsic_until_without_events< diff --git a/testing/async/examples/author_tests.rs b/testing/async/examples/author_tests.rs index 926cef6f8..2e9fa1f41 100644 --- a/testing/async/examples/author_tests.rs +++ b/testing/async/examples/author_tests.rs @@ -184,7 +184,7 @@ async fn test_submit_and_watch_extrinsic_until_in_block_without_events( // Wait a little, otherwise we may run into future std::thread::sleep(std::time::Duration::from_secs(1)); let xt = api.compose_extrinsic_offline(transfer_call, nonce); - let report = api + let mut report = api .submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock) .await .unwrap(); @@ -193,13 +193,14 @@ async fn test_submit_and_watch_extrinsic_until_in_block_without_events( assert!(report.events.is_none()); // Now we fetch the events separately - let report = api.populate_events(report).await.unwrap(); + api.populate_events(&mut report).await.unwrap(); assert!(report.events.is_some()); let events = report.events.as_ref().unwrap(); assert_associated_events_match_expected(&events); // Can populate events only once - assert!(api.populate_events(report).await.is_err()); + let result = api.populate_events(&mut report).await; + assert!(result.is_err()); } fn assert_associated_events_match_expected(events: &[RawEventDetails]) { From 089f013eab9ab300f561d3ca03cbf2ed318276c3 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 9 Oct 2024 11:32:03 +0200 Subject: [PATCH 07/12] Fix failing test --- src/api/rpc_api/author.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index 062fed414..c9c345877 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -213,7 +213,7 @@ pub trait SubmitAndWatch { ) -> Result>; /// Query the events for the specified `report` and attaches them to the returned report. - /// If the function fails the report is not modified. + /// If the function fails events might still be added to the report. /// /// This method is blocking if the sync-api feature is activated async fn populate_events(&self, report: &mut ExtrinsicReport) -> Result<()>; @@ -302,13 +302,13 @@ where break } } + report.events = Some(extrinsic_events.into_iter().map(|event| event.to_raw()).collect()); if let Some(dispatch_error) = maybe_dispatch_error { return Err(Error::FailedExtrinsic(FailedExtrinsicError::new( dispatch_error, report.encode(), ))) } - report.events = Some(extrinsic_events.into_iter().map(|event| event.to_raw()).collect()); Ok(()) } From 413c5e577cc3cac90992057803e6f35fd9c86a56 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Thu, 24 Oct 2024 10:28:41 +0200 Subject: [PATCH 08/12] Split populate_events into two separate methods --- src/api/mod.rs | 24 +++++++++++++++++++++++- src/api/rpc_api/author.rs | 19 ++----------------- testing/async/examples/author_tests.rs | 4 ++++ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index d4c4dd946..13d88c0a4 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -15,7 +15,8 @@ */ -use ac_node_api::events::RawEventDetails; +use crate::error::FailedExtrinsicError; +use ac_node_api::{events::RawEventDetails, EventDetails, Metadata}; use alloc::{string::String, vec::Vec}; use codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -60,6 +61,27 @@ impl ExtrinsicReport { ) -> Self { Self { extrinsic_hash, block_hash, status, events } } + + pub fn add_events(&mut self, events: Vec>) { + self.events = Some(events.into_iter().map(|event| event.to_raw()).collect()); + } + + pub fn status_based_on_events(&self, metadata: &Metadata) -> Result<()> { + if self.events.is_none() { + return Err(Error::Other("Report does not contain any events".into())) + } + // Check if the extrinsic was successful or not. + let events = self.events.as_ref().unwrap(); + for event in events { + if let Some(dispatch_error) = event.get_associated_dispatch_error(metadata) { + return Err(Error::FailedExtrinsic(FailedExtrinsicError::new( + dispatch_error, + self.encode(), + ))) + } + } + Ok(()) + } } /// Simplified TransactionStatus to allow the user to choose until when to watch diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index c9c345877..d67097df8 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -15,7 +15,6 @@ use crate::{ api::{rpc_api::events::FetchEvents, Error, Result}, - error::FailedExtrinsicError, rpc::{HandleSubscription, Request, Subscribe}, Api, ExtrinsicReport, TransactionStatus, XtStatus, }; @@ -283,6 +282,7 @@ where return Ok(report) } self.populate_events(&mut report).await?; + report.status_based_on_events(self.metadata())?; return Ok(report); } @@ -293,22 +293,7 @@ where let block_hash = report.block_hash.ok_or(Error::BlockHashNotFound)?; let extrinsic_events = self.fetch_events_for_extrinsic(block_hash, report.extrinsic_hash).await?; - - // Check if the extrinsic was successful or not. - let mut maybe_dispatch_error = None; - for event in &extrinsic_events { - if let Some(dispatch_error) = event.get_associated_dispatch_error() { - maybe_dispatch_error = Some(dispatch_error); - break - } - } - report.events = Some(extrinsic_events.into_iter().map(|event| event.to_raw()).collect()); - if let Some(dispatch_error) = maybe_dispatch_error { - return Err(Error::FailedExtrinsic(FailedExtrinsicError::new( - dispatch_error, - report.encode(), - ))) - } + report.add_events(extrinsic_events); Ok(()) } diff --git a/testing/async/examples/author_tests.rs b/testing/async/examples/author_tests.rs index 2e9fa1f41..22a2d6710 100644 --- a/testing/async/examples/author_tests.rs +++ b/testing/async/examples/author_tests.rs @@ -192,9 +192,13 @@ async fn test_submit_and_watch_extrinsic_until_in_block_without_events( assert!(report.block_hash.is_some()); assert!(report.events.is_none()); + // Should fail without events + assert!(report.status_based_on_events(&api.metadata()).is_err()); + // Now we fetch the events separately api.populate_events(&mut report).await.unwrap(); assert!(report.events.is_some()); + assert!(report.status_based_on_events(&api.metadata()).is_ok()); let events = report.events.as_ref().unwrap(); assert_associated_events_match_expected(&events); From 838b5816c7a573eec80c407196fb1878b713057e Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Thu, 24 Oct 2024 13:54:07 +0200 Subject: [PATCH 09/12] Add documentation --- src/api/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/mod.rs b/src/api/mod.rs index 13d88c0a4..9492cd062 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -66,6 +66,8 @@ impl ExtrinsicReport { self.events = Some(events.into_iter().map(|event| event.to_raw()).collect()); } + /// Checks the status of the extrinsic by evaluating the events attached to the report. + /// Returns an error if the events are missing or if one of the events indicates a problem. pub fn status_based_on_events(&self, metadata: &Metadata) -> Result<()> { if self.events.is_none() { return Err(Error::Other("Report does not contain any events".into())) From e5dcf75e5afb8351057920368ac10ea75ee2627e Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Mon, 28 Oct 2024 07:58:05 +0100 Subject: [PATCH 10/12] Rename function --- src/api/mod.rs | 2 +- src/api/rpc_api/author.rs | 2 +- testing/async/examples/author_tests.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 9492cd062..279c1f8a1 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -68,7 +68,7 @@ impl ExtrinsicReport { /// Checks the status of the extrinsic by evaluating the events attached to the report. /// Returns an error if the events are missing or if one of the events indicates a problem. - pub fn status_based_on_events(&self, metadata: &Metadata) -> Result<()> { + pub fn check_events_for_dispatch_error(&self, metadata: &Metadata) -> Result<()> { if self.events.is_none() { return Err(Error::Other("Report does not contain any events".into())) } diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index d67097df8..599e3a70e 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -282,7 +282,7 @@ where return Ok(report) } self.populate_events(&mut report).await?; - report.status_based_on_events(self.metadata())?; + report.check_events_for_dispatch_error(self.metadata())?; return Ok(report); } diff --git a/testing/async/examples/author_tests.rs b/testing/async/examples/author_tests.rs index 22a2d6710..f53712945 100644 --- a/testing/async/examples/author_tests.rs +++ b/testing/async/examples/author_tests.rs @@ -193,12 +193,12 @@ async fn test_submit_and_watch_extrinsic_until_in_block_without_events( assert!(report.events.is_none()); // Should fail without events - assert!(report.status_based_on_events(&api.metadata()).is_err()); + assert!(report.check_events_for_dispatch_error(&api.metadata()).is_err()); // Now we fetch the events separately api.populate_events(&mut report).await.unwrap(); assert!(report.events.is_some()); - assert!(report.status_based_on_events(&api.metadata()).is_ok()); + assert!(report.check_events_for_dispatch_error(&api.metadata()).is_ok()); let events = report.events.as_ref().unwrap(); assert_associated_events_match_expected(&events); From 5e593e375a578f8442a86f77e2be899e66ce96b2 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Mon, 28 Oct 2024 09:11:13 +0100 Subject: [PATCH 11/12] Expand Error type for event related problems --- src/api/error.rs | 4 ++++ src/api/mod.rs | 2 +- src/api/rpc_api/author.rs | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/error.rs b/src/api/error.rs index b738d3bc1..ea4f92397 100644 --- a/src/api/error.rs +++ b/src/api/error.rs @@ -56,6 +56,10 @@ pub enum Error { BlockHashNotFound, /// Could not find the expected block. BlockNotFound, + /// Operation needs events but events are missing. + EventsMissing, + /// Operation wants to add events but they are already present. + EventsAlreadyPresent, /// Any custom Error. Other(Box), } diff --git a/src/api/mod.rs b/src/api/mod.rs index 279c1f8a1..4a35f5abd 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -70,7 +70,7 @@ impl ExtrinsicReport { /// Returns an error if the events are missing or if one of the events indicates a problem. pub fn check_events_for_dispatch_error(&self, metadata: &Metadata) -> Result<()> { if self.events.is_none() { - return Err(Error::Other("Report does not contain any events".into())) + return Err(Error::EventsMissing) } // Check if the extrinsic was successful or not. let events = self.events.as_ref().unwrap(); diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index 599e3a70e..21eeadaa1 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -288,7 +288,7 @@ where async fn populate_events(&self, report: &mut ExtrinsicReport) -> Result<()> { if report.events.is_some() { - return Err(Error::Other("Report already contains events".into())) + return Err(Error::EventsAlreadyPresent) } let block_hash = report.block_hash.ok_or(Error::BlockHashNotFound)?; let extrinsic_events = From ae65f6ca8a754eda096a41161876f13033593584 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger <781000+Niederb@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:31:30 +0100 Subject: [PATCH 12/12] Improve documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bigna Härdi --- src/api/rpc_api/author.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index 21eeadaa1..0ffad6ded 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -211,7 +211,7 @@ pub trait SubmitAndWatch { watch_until: XtStatus, ) -> Result>; - /// Query the events for the specified `report` and attaches them to the returned report. + /// Query the events for the specified `report` and attaches them to the mutable report. /// If the function fails events might still be added to the report. /// /// This method is blocking if the sync-api feature is activated