diff --git a/client/src/main.rs b/client/src/main.rs index 1a55edbb1..80e0dd5c7 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -4,7 +4,10 @@ use crate::cli::CliOpts; use avail_light_core::{ api, consts::EXPECTED_SYSTEM_VERSION, - data::{self, ClientIdKey, Database, IsFinalitySyncedKey, IsSyncedKey, LatestHeaderKey, DB}, + data::{ + self, ClientIdKey, Database, IsFinalitySyncedKey, IsSyncedKey, LatestHeaderKey, + SignerNonceKey, DB, + }, light_client::{self, OutputEvent as LcEvent}, maintenance::{self, OutputEvent as MaintenanceEvent}, network::{ @@ -137,6 +140,11 @@ async fn run( let (rpc_client, rpc_events, rpc_subscriptions) = rpc::init(db.clone(), &cfg.genesis_hash, &cfg.rpc, shutdown.clone()).await?; + let account_id = identity_cfg.avail_key_pair.public_key().to_account_id(); + let client = rpc_client.current_client().await; + let nonce = client.api.tx().account_nonce(&account_id).await?; + db.put(SignerNonceKey, nonce); + // Subscribing to RPC events before first event is published let publish_rpc_event_receiver = rpc_events.subscribe(); let first_header_rpc_event_receiver = rpc_events.subscribe(); diff --git a/core/src/data.rs b/core/src/data.rs index be73424cb..8a51fe960 100644 --- a/core/src/data.rs +++ b/core/src/data.rs @@ -296,3 +296,17 @@ impl RecordKey for P2PKeypairKey { P2P_KEYPAIR_KEY.into() } } + +pub struct SignerNonceKey; + +impl RecordKey for SignerNonceKey { + type Type = u64; + + fn space(&self) -> Option<&'static str> { + Some(APP_STATE_CF) + } + + fn key(&self) -> String { + SIGNER_NONCE.into() + } +} diff --git a/core/src/data/keys.rs b/core/src/data/keys.rs index 77c5951dc..499e2b020 100644 --- a/core/src/data/keys.rs +++ b/core/src/data/keys.rs @@ -33,3 +33,5 @@ pub const IS_SYNCED_KEY: &str = "is_synced"; pub const CLIENT_ID_KEY: &str = "client_id"; /// Key for storing P2P keypair pub const P2P_KEYPAIR_KEY: &str = "p2p_keypair"; +/// Key for storing signer nonce +pub const SIGNER_NONCE: &str = "signer_nonce"; diff --git a/core/src/network/rpc/client.rs b/core/src/network/rpc/client.rs index fe8005dfa..ca2e92f2f 100644 --- a/core/src/network/rpc/client.rs +++ b/core/src/network/rpc/client.rs @@ -25,7 +25,7 @@ use super::{configuration::RetryConfig, Node, Nodes, Subscription, WrappedProof} use crate::{ api::v2::types::Base64, consts::ExpectedNodeVariant, - data::{Database, RpcNodeKey}, + data::{Database, RpcNodeKey, SignerNonceKey}, shutdown::Controller, types::DEV_FLAG_GENHASH, }; @@ -549,18 +549,31 @@ impl Client { self.with_retries(|client| { let data = Data { 0: data.0.clone() }; async move { - let options = AvailExtrinsicParamsBuilder::new().app_id(app_id.0).build(); - client + let nonce = self.db.get(SignerNonceKey).unwrap_or(0_u64); + + let options = AvailExtrinsicParamsBuilder::new() + .nonce(nonce) + .app_id(app_id.0) + .build(); + + let data_submission = client .tx .data_availability .submit_data(data, WaitFor::BlockInclusion, signer, Some(options)) - .await - .map(|success| SubmitResponse { + .await; + + let submit_response = match data_submission { + Ok(success) => Ok(SubmitResponse { block_hash: success.block_hash, hash: success.tx_hash, index: success.tx_index, - }) - .map_err(|error| eyre!("{error}")) + }), + Err(error) => Err(eyre!("{error}")), + }; + + self.db.put(SignerNonceKey, nonce + 1); + + submit_response } }) .await