Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

feat(hyperdrive): rework merkle root submission #63

Merged
merged 4 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
toolchain: nightly-2023-03-14
components: rustfmt, clippy
target: wasm32-unknown-unknown
override: true
Expand All @@ -33,6 +33,12 @@ jobs:
# - name: Check and Lint Code
# run: cargo clippy -- -D warnings

- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --check

- name: Run cargo check for release
uses: actions-rs/cargo@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion pallets/acurast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ pub type JobRegistrationFor<T> =
#[frame_support::pallet]
pub mod pallet {
use acurast_common::*;
use core::ops::AddAssign;
use frame_support::{
dispatch::DispatchResultWithPostInfo, ensure, pallet_prelude::*, traits::UnixTime,
Blake2_128Concat, PalletId,
};
use frame_system::pallet_prelude::*;
use sp_std::prelude::*;
use core::ops::AddAssign;

use crate::{traits::*, utils::*, JobRegistrationFor};

Expand Down
5 changes: 3 additions & 2 deletions pallets/hyperdrive/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ benchmarks_instance_pallet! {
submit_state_merkle_root {
// add the transmitters and submit before benchmarked extrinsic
let (caller, _) = update_state_transmitters_helper::<T, I>(1, true);
}: _(RawOrigin::Signed(caller.clone()), 5.into(), HASH.into())
}: _(RawOrigin::Signed(caller.clone()), 1.into(), HASH.into())
verify {
assert_event::<T, I>(Event::StateMerkleRootSubmitted{
block: 5.into(),
source: caller.clone(),
snapshot: 1.into(),
state_merkle_root: HASH.into()
}.into());
}
Expand Down
80 changes: 57 additions & 23 deletions pallets/hyperdrive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ pub mod pallet {
use frame_system::pallet_prelude::*;
use sp_arithmetic::traits::{CheckedRem, Zero};
use sp_runtime::traits::Hash;
use sp_std::collections::btree_set::BTreeSet;
use sp_std::prelude::*;
use sp_std::vec;

use types::*;

Expand Down Expand Up @@ -79,6 +82,7 @@ pub mod pallet {
+ MaxEncodedLen
+ TypeInfo
+ Zero
+ From<u8>
+ CheckedRem;
/// The hashing system (algorithm) being used in the runtime (e.g. Blake2).
type TargetChainHashing: Hash<Output = Self::TargetChainHash> + TypeInfo;
Expand Down Expand Up @@ -106,11 +110,12 @@ pub mod pallet {
removed: Vec<T::AccountId>,
},
StateMerkleRootSubmitted {
block: T::TargetChainBlockNumber,
source: T::AccountId,
snapshot: T::TargetChainBlockNumber,
state_merkle_root: T::TargetChainHash,
},
StateMerkleRootAccepted {
block: T::TargetChainBlockNumber,
snapshot: T::TargetChainBlockNumber,
state_merkle_root: T::TargetChainHash,
},
}
Expand All @@ -129,6 +134,17 @@ pub mod pallet {
ValueQuery,
>;

#[pallet::type_value]
pub fn FirstSnapshot<T: Config<I>, I: 'static>() -> T::TargetChainBlockNumber {
1u8.into()
}

/// This storage field contains the latest validated snapshot number.
#[pallet::storage]
#[pallet::getter(fn latest_snapshot)]
pub type CurrentSnapshot<T: Config<I>, I: 'static = ()> =
StorageValue<_, T::TargetChainBlockNumber, ValueQuery, FirstSnapshot<T, I>>;

#[pallet::storage]
#[pallet::getter(fn state_merkle_root)]
pub type StateMerkleRootCount<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
Expand All @@ -137,15 +153,15 @@ pub mod pallet {
T::TargetChainBlockNumber,
Identity,
T::TargetChainHash,
u8,
BTreeSet<T::AccountId>,
>;

#[pallet::error]
pub enum Error<T, I = ()> {
/// A known transmitter submits outside the window of activity he is permissioned to.
SubmitOutsideTransmitterActivityWindow,
SubmitOutsideTransmissionRate,
CalculationOverflow,
UnexpectedSnapshot,
}

#[pallet::call]
Expand Down Expand Up @@ -206,10 +222,17 @@ pub mod pallet {
#[pallet::weight(< T as Config<I>>::WeightInfo::submit_state_merkle_root())]
pub fn submit_state_merkle_root(
origin: OriginFor<T>,
block: T::TargetChainBlockNumber,
snapshot: T::TargetChainBlockNumber,
state_merkle_root: T::TargetChainHash,
) -> DispatchResult {
let who = ensure_signed(origin)?;
let expected_snapshot = Self::latest_snapshot();

// Ensure merkle roots are submitted sequentially
ensure!(
snapshot == expected_snapshot,
Error::<T, I>::UnexpectedSnapshot
);

let activity_window = <StateTransmitter<T, I>>::get(&who);
let current_block = <frame_system::Pallet<T>>::block_number();
Expand All @@ -219,32 +242,42 @@ pub mod pallet {
&& current_block < activity_window.end_block,
Error::<T, I>::SubmitOutsideTransmitterActivityWindow
);
ensure!(
block
.checked_rem(&T::TransmissionRate::get())
.ok_or(Error::<T, I>::CalculationOverflow)?
.is_zero(),
Error::<T, I>::SubmitOutsideTransmissionRate
);

// insert merkle root proposal since all checks passed
// allows for constant-time validity checks
let accepted =
StateMerkleRootCount::<T, I>::mutate(&block, &state_merkle_root, |count| {
let count_ = count.unwrap_or(0) + 1;
*count = Some(count_);
count_ >= <T as Config<I>>::TransmissionQuorum::get()
});
let accepted = StateMerkleRootCount::<T, I>::mutate(
&snapshot,
&state_merkle_root,
|submissions| {
// This can be improved once [let chains feature](https://github.com/rust-lang/rust/issues/53667) lands
if let Some(transmitters) = submissions {
if !transmitters.contains(&who) {
RomarQ marked this conversation as resolved.
Show resolved Hide resolved
transmitters.insert(who.clone());
}
} else {
let mut set = BTreeSet::<T::AccountId>::new();
set.insert(who.clone());
*submissions = Some(set);
}

let submissions_count = submissions
.as_ref()
.map_or(0usize, |transmitters| transmitters.len());
return submissions_count >= T::TransmissionQuorum::get().into();
},
);

// Emit event to inform that the state merkle root has been sumitted
Self::deposit_event(Event::StateMerkleRootSubmitted {
block,
source: who,
snapshot,
state_merkle_root,
});

if accepted {
CurrentSnapshot::<T, I>::set(expected_snapshot + T::TransmissionRate::get());
Self::deposit_event(Event::StateMerkleRootAccepted {
block,
snapshot,
state_merkle_root,
});
}
Expand All @@ -259,9 +292,10 @@ pub mod pallet {
block: T::TargetChainBlockNumber,
state_merkle_root: T::TargetChainHash,
) -> bool {
StateMerkleRootCount::<T, I>::get(&block, &state_merkle_root).map_or(false, |count| {
count >= <T as Config<I>>::TransmissionQuorum::get()
})
StateMerkleRootCount::<T, I>::get(&block, &state_merkle_root)
.map_or(false, |submissions| {
submissions.len() >= T::TransmissionQuorum::get().into()
})
}
}
}
68 changes: 31 additions & 37 deletions pallets/hyperdrive/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,35 +149,28 @@ fn submit_outside_activity_window() {
assert_err!(
TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(alice_account_id()),
5,
1,
HASH
),
Error::<Test, ()>::SubmitOutsideTransmitterActivityWindow
);

System::set_block_number(10);
assert_ok!(TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(alice_account_id()),
10,
HASH
));

System::set_block_number(19);
assert_ok!(TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(alice_account_id()),
10,
HASH
));

System::set_block_number(20);
assert_err!(
TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(bob_account_id()),
5,
RuntimeOrigin::signed(alice_account_id()),
1,
HASH
),
Error::<Test, ()>::SubmitOutsideTransmitterActivityWindow
);

System::set_block_number(10);
assert_ok!(TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(alice_account_id()),
1,
HASH
));
});
}

Expand Down Expand Up @@ -206,7 +199,7 @@ fn submit_outside_transmission_rate() {
6,
HASH
),
Error::<Test, ()>::SubmitOutsideTransmitterActivityWindow
Error::<Test, ()>::UnexpectedSnapshot
);
});
}
Expand Down Expand Up @@ -240,30 +233,33 @@ fn submit_state_merkle_root() {

System::set_block_number(10);

// first submission for target chain block 10
// first submission for target chain snapshot 1
assert_ok!(TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(alice_account_id()),
10,
1,
HASH
));
// does not validate until quorum reached
assert_eq!(TezosHyperdrive::validate_state_merkle_root(10, HASH), false);
assert_eq!(TezosHyperdrive::validate_state_merkle_root(1, HASH), false);

// intermitted submission for different block is allowed!
assert_ok!(TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(bob_account_id()),
15,
HASH
));
// intermitted submission for different snapshot is not allowed!
assert_err!(
TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(bob_account_id()),
2,
HASH
),
Error::<Test, ()>::UnexpectedSnapshot
);

// second submission for target chain block 10
// second submission for target chain snapshot 1
assert_ok!(TezosHyperdrive::submit_state_merkle_root(
RuntimeOrigin::signed(bob_account_id()),
10,
1,
HASH
));
// does validate since quorum reached
assert_eq!(TezosHyperdrive::validate_state_merkle_root(10, HASH), true);
assert_eq!(TezosHyperdrive::validate_state_merkle_root(1, HASH), true);

assert_eq!(
events(),
Expand All @@ -289,19 +285,17 @@ fn submit_state_merkle_root() {
removed: vec![],
}),
RuntimeEvent::TezosHyperdrive(crate::Event::StateMerkleRootSubmitted {
block: 10,
state_merkle_root: HASH
}),
RuntimeEvent::TezosHyperdrive(crate::Event::StateMerkleRootSubmitted {
block: 15,
source: alice_account_id(),
snapshot: 1,
state_merkle_root: HASH
}),
RuntimeEvent::TezosHyperdrive(crate::Event::StateMerkleRootSubmitted {
block: 10,
source: bob_account_id(),
snapshot: 1,
state_merkle_root: HASH
}),
RuntimeEvent::TezosHyperdrive(crate::Event::StateMerkleRootAccepted {
block: 10,
snapshot: 1,
state_merkle_root: HASH
})
]
Expand Down
2 changes: 1 addition & 1 deletion pallets/marketplace/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use sp_runtime::BoundedVec;
use sp_std::prelude::*;

pub use pallet::Config;
use pallet_acurast::{Event as AcurastEvent, JobRegistrationFor, Script, MultiOrigin};
use pallet_acurast::{Event as AcurastEvent, JobRegistrationFor, MultiOrigin, Script};
use pallet_acurast::{Pallet as Acurast, Schedule};

pub use crate::stub::*;
Expand Down