Skip to content

Commit 2c54d24

Browse files
authored
Merge pull request #2431 from subspace/oldest-er-number
Correctly derive the oldest receipt number
2 parents b986d86 + b3aa3b1 commit 2c54d24

File tree

14 files changed

+229
-139
lines changed

14 files changed

+229
-139
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pallet-domains/src/benchmarking.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ mod benchmarks {
8686
Domains::<T>::head_receipt_number(domain_id),
8787
(block_tree_pruning_depth + 1).into()
8888
);
89-
assert_eq!(Domains::<T>::oldest_receipt_number(domain_id), 1u32.into());
89+
assert_eq!(
90+
Domains::<T>::oldest_unconfirmed_receipt_number(domain_id),
91+
Some(1u32.into())
92+
);
9093
}
9194

9295
/// Benchmark pending staking operation with the worst possible conditions:

crates/pallet-domains/src/block_tree.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::pallet::StateRoots;
44
use crate::{
55
BalanceOf, BlockTree, BlockTreeNodes, Config, ConsensusBlockHash, DomainBlockNumberFor,
66
DomainHashingFor, ExecutionInbox, ExecutionReceiptOf, HeadReceiptExtended, HeadReceiptNumber,
7-
InboxedBundleAuthor, ReceiptHashFor,
7+
InboxedBundleAuthor, LatestConfirmedDomainBlockNumber, ReceiptHashFor,
88
};
99
use codec::{Decode, Encode};
1010
use frame_support::{ensure, PalletError};
@@ -107,15 +107,17 @@ pub(crate) fn execution_receipt_type<T: Config>(
107107
let receipt_number = execution_receipt.domain_block_number;
108108
let head_receipt_number = HeadReceiptNumber::<T>::get(domain_id);
109109
let next_receipt_number = head_receipt_number.saturating_add(One::one());
110+
let latest_confirmed_domain_block_number =
111+
LatestConfirmedDomainBlockNumber::<T>::get(domain_id);
110112

111113
match receipt_number.cmp(&next_receipt_number) {
112114
Ordering::Greater => ReceiptType::Rejected(RejectedReceiptType::InFuture),
113115
Ordering::Equal => ReceiptType::Accepted(AcceptedReceiptType::NewHead),
114116
Ordering::Less => {
115-
// Reject receipt that already pruned/confirmed
116-
let oldest_receipt_number =
117-
head_receipt_number.saturating_sub(T::BlockTreePruningDepth::get());
118-
if receipt_number < oldest_receipt_number {
117+
// Reject receipt that already confirmed
118+
if !latest_confirmed_domain_block_number.is_zero()
119+
&& receipt_number <= latest_confirmed_domain_block_number
120+
{
119121
return ReceiptType::Rejected(RejectedReceiptType::Pruned);
120122
}
121123

crates/pallet-domains/src/lib.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use sp_domains_fraud_proof::verification::{
5959
verify_invalid_domain_extrinsics_root_fraud_proof, verify_invalid_state_transition_fraud_proof,
6060
verify_valid_bundle_fraud_proof,
6161
};
62-
use sp_runtime::traits::{CheckedSub, Hash, Header, One, Zero};
62+
use sp_runtime::traits::{Hash, Header, One, Zero};
6363
use sp_runtime::{RuntimeAppPublic, SaturatedConversion, Saturating};
6464
use sp_std::boxed::Box;
6565
use sp_std::collections::btree_map::BTreeMap;
@@ -1860,16 +1860,23 @@ impl<T: Config> Pallet<T> {
18601860
HeadReceiptNumber::<T>::get(domain_id)
18611861
}
18621862

1863-
/// Returns the block number of oldest execution receipt.
1864-
// FIXME: the `oldest_receipt_number` may not be correct if fraud proof is submitted
1865-
// and bad ER were pruned, see https://github.com/subspace/subspace/issues/2354
1866-
pub fn oldest_receipt_number(domain_id: DomainId) -> DomainBlockNumberFor<T> {
1867-
Self::head_receipt_number(domain_id).saturating_sub(Self::block_tree_pruning_depth())
1868-
}
1869-
1870-
/// Returns the block tree pruning depth.
1871-
pub fn block_tree_pruning_depth() -> DomainBlockNumberFor<T> {
1872-
T::BlockTreePruningDepth::get()
1863+
/// Returns the block number of the oldest existing unconfirmed execution receipt, return `None`
1864+
/// means there is no unconfirmed ER exist or submitted yet.
1865+
pub fn oldest_unconfirmed_receipt_number(
1866+
domain_id: DomainId,
1867+
) -> Option<DomainBlockNumberFor<T>> {
1868+
let oldest_nonconfirmed_er_number =
1869+
LatestConfirmedDomainBlockNumber::<T>::get(domain_id).saturating_add(One::one());
1870+
1871+
if BlockTree::<T>::get(domain_id, oldest_nonconfirmed_er_number).is_some() {
1872+
Some(oldest_nonconfirmed_er_number)
1873+
} else {
1874+
// The `oldest_nonconfirmed_er_number` ER may not exist if
1875+
// - The domain just started and no ER submitted yet
1876+
// - The oldest ER just pruned by fraud proof and no new ER submitted yet
1877+
// - When using consensus block to derive the challenge period forward (unimplemented yet)
1878+
None
1879+
}
18731880
}
18741881

18751882
/// Returns the domain block limit of the given domain.
@@ -1887,10 +1894,10 @@ impl<T: Config> Pallet<T> {
18871894
return true;
18881895
}
18891896

1897+
// Start from the oldest non-confirmed ER to the head domain number
1898+
let mut to_check =
1899+
LatestConfirmedDomainBlockNumber::<T>::get(domain_id).saturating_add(One::one());
18901900
let head_number = HeadDomainNumber::<T>::get(domain_id);
1891-
let mut to_check = head_number
1892-
.checked_sub(&T::BlockTreePruningDepth::get())
1893-
.unwrap_or(Zero::zero());
18941901

18951902
while to_check <= head_number {
18961903
if !ExecutionInbox::<T>::iter_prefix_values((domain_id, to_check)).all(|digests| {

crates/sp-domains-fraud-proof/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ libsecp256k1 = { version = "0.7.1", features = ["static-context", "hmac"] }
5151
pallet-balances = { version = "4.0.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
5252
pallet-ethereum = { version = "4.0.0-dev", git = "https://github.com/subspace/frontier", rev = "7627e61d80275a4cf24d06f27491f6c31eadb7b7", features = ['default'] }
5353
pallet-evm = { version = "6.0.0-dev", git = "https://github.com/subspace/frontier", rev = "7627e61d80275a4cf24d06f27491f6c31eadb7b7", default-features = false }
54+
parking_lot = "0.12.1"
5455
rand = { version = "0.8.5", features = ["min_const_gen"] }
5556
rlp = "0.5.2"
5657
sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
@@ -59,7 +60,6 @@ sc-service = { version = "0.10.0-dev", git = "https://github.com/subspace/polkad
5960
subspace-test-client = { version = "0.1.0", path = "../../test/subspace-test-client" }
6061
subspace-test-service = { version = "0.1.0", path = "../../test/subspace-test-service" }
6162
subspace-runtime-primitives = { version = "0.1.0", path = "../../crates/subspace-runtime-primitives" }
62-
substrate-test-runtime-client = { version = "2.0.0", git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
6363
tempfile = "3.9.0"
6464
tokio = "1.35.1"
6565

crates/sp-domains-fraud-proof/src/bundle_equivocation.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,14 @@ where
156156
mod test {
157157
use super::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND};
158158
use domain_runtime_primitives::opaque::Header as DomainHeader;
159+
use parking_lot::Mutex;
160+
use sc_client_api::backend::AuxStore;
159161
use sp_core::crypto::UncheckedFrom;
160162
use sp_domains::{
161163
BundleHeader, DomainId, ExecutionReceipt, OperatorId, OperatorSignature, ProofOfElection,
162164
SealedBundleHeader,
163165
};
166+
use std::collections::HashMap;
164167
use std::sync::Arc;
165168
use subspace_runtime_primitives::opaque::Block;
166169
use subspace_runtime_primitives::{Balance, BlockNumber, Hash};
@@ -197,9 +200,39 @@ mod test {
197200
}
198201
}
199202

203+
#[derive(Default)]
204+
struct TestClient(Mutex<HashMap<Vec<u8>, Vec<u8>>>);
205+
206+
impl AuxStore for TestClient {
207+
fn insert_aux<
208+
'a,
209+
'b: 'a,
210+
'c: 'a,
211+
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
212+
D: IntoIterator<Item = &'a &'b [u8]>,
213+
>(
214+
&self,
215+
insert: I,
216+
delete: D,
217+
) -> sp_blockchain::Result<()> {
218+
let mut map = self.0.lock();
219+
for d in delete {
220+
map.remove(&d.to_vec());
221+
}
222+
for (k, v) in insert {
223+
map.insert(k.to_vec(), v.to_vec());
224+
}
225+
Ok(())
226+
}
227+
228+
fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
229+
Ok(self.0.lock().get(key).cloned())
230+
}
231+
}
232+
200233
#[test]
201234
fn test_check_equivocation() {
202-
let client = Arc::new(substrate_test_runtime_client::new());
235+
let client = Arc::new(TestClient::default());
203236
let domain_id = DomainId::new(0);
204237
let operator_id = 1;
205238

crates/sp-domains/src/lib.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -994,11 +994,8 @@ sp_api::decl_runtime_apis! {
994994
/// Returns the best execution chain number.
995995
fn head_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;
996996

997-
/// Returns the block number of oldest execution receipt.
998-
fn oldest_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;
999-
1000-
/// Returns the block tree pruning depth.
1001-
fn block_tree_pruning_depth() -> HeaderNumberFor<DomainHeader>;
997+
/// Returns the block number of oldest unconfirmed execution receipt.
998+
fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1002999

10031000
/// Returns the domain block limit of the given domain.
10041001
fn domain_block_limit(domain_id: DomainId) -> Option<DomainBlockLimit>;

crates/subspace-runtime/src/lib.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,12 +1012,8 @@ impl_runtime_apis! {
10121012
Domains::head_receipt_number(domain_id)
10131013
}
10141014

1015-
fn oldest_receipt_number(domain_id: DomainId) -> DomainNumber {
1016-
Domains::oldest_receipt_number(domain_id)
1017-
}
1018-
1019-
fn block_tree_pruning_depth() -> DomainNumber {
1020-
Domains::block_tree_pruning_depth()
1015+
fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<DomainNumber> {
1016+
Domains::oldest_unconfirmed_receipt_number(domain_id)
10211017
}
10221018

10231019
fn domain_block_limit(domain_id: DomainId) -> Option<sp_domains::DomainBlockLimit> {

domains/client/domain-operator/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,4 @@ sp-state-machine = { version = "0.28.0", git = "https://github.com/subspace/polk
5555
subspace-core-primitives = { version = "0.1.0", default-features = false, path = "../../../crates/subspace-core-primitives" }
5656
subspace-test-runtime = { version = "0.1.0", path = "../../../test/subspace-test-runtime" }
5757
subspace-test-service = { version = "0.1.0", path = "../../../test/subspace-test-service" }
58-
substrate-test-runtime-client = { version = "2.0.0", git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
5958
tempfile = "3.9.0"

0 commit comments

Comments
 (0)