diff --git a/cli/artifacts/metadata.scale b/cli/artifacts/metadata.scale index f4d0af93..68a84527 100644 Binary files a/cli/artifacts/metadata.scale and b/cli/artifacts/metadata.scale differ diff --git a/cli/polka-storage-provider/server/src/rpc.rs b/cli/polka-storage-provider/server/src/rpc.rs index ab968f4a..c8df6bb6 100644 --- a/cli/polka-storage-provider/server/src/rpc.rs +++ b/cli/polka-storage-provider/server/src/rpc.rs @@ -110,16 +110,26 @@ impl StorageProviderRpcServer for RpcServerState { let published_deals = result .events - .find::() - .collect::, _>>() + .find_first::() .map_err(|err| RpcError::internal_error(err, None))?; + let Some(published_deals) = published_deals else { + return Err(RpcError::internal_error( + "failed to find any published deals", + None, + )); + }; // We currently just support a single deal and if there's no published deals, // an error MUST've happened - debug_assert_eq!(published_deals.len(), 1); + debug_assert_eq!(published_deals.deals.0.len(), 1); // We always publish only 1 deal - let deal_id = published_deals[0].deal_id; + let deal_id = published_deals + .deals + .0 + .first() + .expect("we only support a single deal") + .deal_id; let commitment = Commitment::from_cid(&piece_cid).map_err(|e| { RpcError::invalid_params( diff --git a/cli/polka-storage/storagext/src/runtime/display/market.rs b/cli/polka-storage/storagext/src/runtime/display/market.rs index e10870ee..8ba4a67e 100644 --- a/cli/polka-storage/storagext/src/runtime/display/market.rs +++ b/cli/polka-storage/storagext/src/runtime/display/market.rs @@ -27,14 +27,27 @@ impl std::fmt::Display for Event { who, amount )) } - Event::DealPublished { - deal_id, - client, + Event::DealsPublished { provider, - } => f.write_fmt(format_args!( - "Deal Published: {{ deal_id: {}, provider_account: {}, client_account: {} }}", - deal_id, provider, client, - )), + deals + } => { + // This should show something like + // Deals Published: { + // provider_account: ..., + // deals: [ + // { client_account: ..., deal_id: ... }, + // { client_account: ..., deal_id: ... }, + // ] + // } + f.write_fmt(format_args!( + "Deal Published: {{\n provider_account: {},\n deals: [\n", + provider + ))?; + for deal in deals.0.iter() { + f.write_fmt(format_args!(" {{ client_account: {}, deal_id: {} }},\n", deal.client, deal.deal_id))?; + } + f.write_str(" ]\n}") + } Event::DealActivated { deal_id, client, diff --git a/cli/polka-storage/storagext/src/runtime/mod.rs b/cli/polka-storage/storagext/src/runtime/mod.rs index a9ad37fb..e73651eb 100644 --- a/cli/polka-storage/storagext/src/runtime/mod.rs +++ b/cli/polka-storage/storagext/src/runtime/mod.rs @@ -41,6 +41,10 @@ pub mod display; path = "pallet_market::pallet::DealState", derive = "::serde::Deserialize" ), + derive_for_type( + path = "pallet_market::pallet::PublishedDeal", + derive = "::serde::Deserialize" + ), // impl Serialize derive_for_type( path = "pallet_market::pallet::BalanceEntry", @@ -112,6 +116,10 @@ pub mod display; path = "pallet_market::pallet::DealState", derive = "::serde::Serialize" ), + derive_for_type( + path = "pallet_market::pallet::PublishedDeal", + derive = "::serde::Serialize" + ), )] mod polka_storage_runtime {} diff --git a/maat/tests/real_world.rs b/maat/tests/real_world.rs index 3872195b..3073e207 100644 --- a/maat/tests/real_world.rs +++ b/maat/tests/real_world.rs @@ -191,14 +191,15 @@ async fn publish_storage_deals( for event in deal_result .events - .find::() + .find::() { let event = event.unwrap(); tracing::debug!(?event); - assert_eq!(event.client, alice.account_id().clone().into()); assert_eq!(event.provider, charlie.account_id().clone().into()); - assert_eq!(event.deal_id, 0); // first deal ever + assert_eq!(event.deals.0.len(), 1); + assert_eq!(event.deals.0[0].client, alice.account_id().clone().into()); + assert_eq!(event.deals.0[0].deal_id, 0); // first deal ever } } diff --git a/pallets/market/src/lib.rs b/pallets/market/src/lib.rs index d2e24e49..279a3437 100644 --- a/pallets/market/src/lib.rs +++ b/pallets/market/src/lib.rs @@ -362,13 +362,7 @@ pub mod pallet { who: T::AccountId, amount: BalanceOf, }, - /// Deal has been successfully published between a client and a provider. - DealPublished { - deal_id: DealId, - client: T::AccountId, - provider: T::AccountId, - }, - // Deal has been successfully activated. + /// Deal has been successfully activated. DealActivated { deal_id: DealId, client: T::AccountId, @@ -404,11 +398,35 @@ pub mod pallet { client: T::AccountId, provider: T::AccountId, }, + + /// Batch of published deals. + DealsPublished { + provider: T::AccountId, + deals: BoundedVec, T::MaxDeals>, + }, } /// Utility type to ensure that the bound for deal settlement is in sync. pub type MaxSettleDeals = ::MaxDeals; + #[derive(TypeInfo, Encode, Decode, Clone, PartialEq)] + pub struct PublishedDeal { + pub client: T::AccountId, + pub deal_id: DealId, + } + + impl core::fmt::Debug for PublishedDeal + where + T: Config, + { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PublishedDeal") + .field("deal_id", &self.deal_id) + .field("client", &self.client) + .finish() + } + } + /// The data part of the event pushed when the deal is successfully settled. #[derive(TypeInfo, Encode, Decode, Clone, PartialEq)] pub struct SettledDealData { @@ -890,6 +908,8 @@ pub mod pallet { let (valid_deals, total_provider_lockup) = Self::validate_deals(provider.clone(), deals, current_block)?; + let mut published_deals = BoundedVec::new(); + // Lock up funds for the clients and emit events for deal in valid_deals.into_iter() { // PRE-COND: always succeeds, validated by `validate_deals` @@ -913,9 +933,9 @@ pub mod pallet { Proposals::::insert(deal_id, deal.clone()); // Only deposit the event after storing everything - Self::deposit_event(Event::::DealPublished { + // force_push is ok since the bound is the same as the input one + published_deals.force_push(PublishedDeal { client: deal.client, - provider: provider.clone(), deal_id, }); } @@ -924,6 +944,11 @@ pub mod pallet { // PRE-COND: always succeeds, validated by `validate_deals` lock_funds::(&provider, total_provider_lockup)?; + Self::deposit_event(Event::::DealsPublished { + deals: published_deals, + provider, + }); + Ok(()) } } diff --git a/pallets/market/src/test.rs b/pallets/market/src/test.rs index 430aa559..ba0044ab 100644 --- a/pallets/market/src/test.rs +++ b/pallets/market/src/test.rs @@ -20,8 +20,8 @@ use crate::{ mock::*, pallet::{lock_funds, slash_and_burn, unlock_funds}, ActiveDealState, BalanceEntry, BalanceTable, Config, DealSettlementError, DealState, - DealsForBlock, Error, Event, PendingProposals, Proposals, SectorDeals, SectorTerminateError, - SettledDealData, + DealsForBlock, Error, Event, PendingProposals, Proposals, PublishedDeal, SectorDeals, + SectorTerminateError, SettledDealData, }; #[test] fn initial_state() { @@ -391,10 +391,12 @@ fn publish_storage_deals_fails_different_providers() { )); assert_eq!( events(), - [RuntimeEvent::Market(Event::::DealPublished { - deal_id: 0, - client: account::(ALICE), + [RuntimeEvent::Market(Event::::DealsPublished { provider: account::(PROVIDER), + deals: bounded_vec!(PublishedDeal { + deal_id: 0, + client: account::(ALICE), + }) })] ); }); @@ -421,10 +423,12 @@ fn publish_storage_deals_fails_client_not_enough_funds_for_second_deal() { )); assert_eq!( events(), - [RuntimeEvent::Market(Event::::DealPublished { - deal_id: 0, - client: account::(ALICE), + [RuntimeEvent::Market(Event::::DealsPublished { provider: account::(PROVIDER), + deals: bounded_vec!(PublishedDeal { + deal_id: 0, + client: account::(ALICE), + }) })] ); }); @@ -453,10 +457,12 @@ fn publish_storage_deals_fails_provider_not_enough_funds_for_second_deal() { )); assert_eq!( events(), - [RuntimeEvent::Market(Event::::DealPublished { - deal_id: 0, - client: account::(ALICE), + [RuntimeEvent::Market(Event::::DealsPublished { provider: account::(PROVIDER), + deals: bounded_vec!(PublishedDeal { + deal_id: 0, + client: account::(ALICE), + }) })] ); }); @@ -483,10 +489,12 @@ fn publish_storage_deals_fails_duplicate_deal_in_message() { )); assert_eq!( events(), - [RuntimeEvent::Market(Event::::DealPublished { - deal_id: 0, - client: account::(ALICE), + [RuntimeEvent::Market(Event::::DealsPublished { provider: account::(PROVIDER), + deals: bounded_vec!(PublishedDeal { + deal_id: 0, + client: account::(ALICE), + }) })] ); }); @@ -508,10 +516,12 @@ fn publish_storage_deals_fails_duplicate_deal_in_state() { )); assert_eq!( events(), - [RuntimeEvent::Market(Event::::DealPublished { - deal_id: 0, - client: account::(ALICE), + [RuntimeEvent::Market(Event::::DealsPublished { provider: account::(PROVIDER), + deals: bounded_vec!(PublishedDeal { + deal_id: 0, + client: account::(ALICE), + }) })] ); assert_noop!( @@ -583,18 +593,19 @@ fn publish_storage_deals() { assert_eq!( events(), - [ - RuntimeEvent::Market(Event::::DealPublished { - deal_id: alice_deal_id, - client: account::(ALICE), - provider: account::(PROVIDER), - }), - RuntimeEvent::Market(Event::::DealPublished { - deal_id: bob_deal_id, - client: account::(BOB), - provider: account::(PROVIDER), - }), - ] + [RuntimeEvent::Market(Event::::DealsPublished { + provider: account::(PROVIDER), + deals: bounded_vec!( + PublishedDeal { + deal_id: alice_deal_id, + client: account::(ALICE), + }, + PublishedDeal { + deal_id: bob_deal_id, + client: account::(BOB), + } + ) + }),] ); assert!(PendingProposals::::get().contains(&alice_hash)); assert!(PendingProposals::::get().contains(&bob_hash));