-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
1,252 additions
and
1,352 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
crates/skw-blockchain-pallets/pallet-parentchain/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
[package] | ||
authors = ['SkyeKiwi <https://github.com/skyekiwi>'] | ||
description = 'offchain vm chain sycner' | ||
edition = '2021' | ||
homepage = 'https://skye.kiwi' | ||
license = 'GPL-3.0' | ||
name = 'pallet-parentchain' | ||
readme = 'README.md' | ||
repository = 'https://github.com/skyekiwi/skyekiwi-network' | ||
version = '3.0.0' | ||
|
||
[package.metadata.docs.rs] | ||
targets = ['x86_64-unknown-linux-gnu'] | ||
|
||
[dev-dependencies] | ||
test-env-log = "0.2.7" | ||
log = "*" | ||
env_logger="*" | ||
|
||
[dependencies] | ||
pallet-registry = { version = "3.0.0", default-features = false, path = "../pallet-registry" } | ||
codec = {default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.0.0'} | ||
frame-benchmarking = { default-features = false, git = 'https://github.com/paritytech/substrate.git', optional = true, tag = 'monthly-2021-12', version = '4.0.0-dev'} | ||
frame-support = {default-features = false, git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-12', version = '4.0.0-dev'} | ||
frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-12', version = '4.0.0-dev'} | ||
scale-info = { default-features = false, features = ['derive'], version = '1.0'} | ||
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-12', version = '4.0.0-dev'} | ||
sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-12', version = '4.0.0-dev'} | ||
sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-12', version = '4.0.0-dev'} | ||
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-12', version = '4.0.0-dev'} | ||
|
||
[features] | ||
default = ['std'] | ||
runtime-benchmarks = ['frame-benchmarking'] | ||
std = [ | ||
'codec/std', | ||
'scale-info/std', | ||
'frame-support/std', | ||
'frame-system/std', | ||
'frame-benchmarking/std', | ||
] | ||
try-runtime = ['frame-support/try-runtime'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
License: GPL-3.0 |
24 changes: 24 additions & 0 deletions
24
crates/skw-blockchain-pallets/pallet-parentchain/src/benchmarking.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
//! Benchmarking setup for pallet-template | ||
use super::*; | ||
|
||
use frame_system::RawOrigin; | ||
use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite}; | ||
#[allow(unused)] | ||
use crate::Pallet as Secrets; | ||
|
||
benchmarks! { | ||
register_secret { | ||
let s in 0 .. 100; | ||
let caller: T::AccountId = whitelisted_caller(); | ||
}: _(RawOrigin::Signed(caller), s) | ||
verify { | ||
assert_eq!(Metadata::<T>::get(), Some(s)); | ||
} | ||
} | ||
|
||
impl_benchmark_test_suite!( | ||
Secrets, | ||
crate::mock::new_test_ext(), | ||
crate::mock::Test, | ||
); |
193 changes: 193 additions & 0 deletions
193
crates/skw-blockchain-pallets/pallet-parentchain/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
use sp_std::prelude::*; | ||
pub use pallet::*; | ||
|
||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
#[cfg(test)] | ||
mod mock; | ||
|
||
// #[cfg(feature = "runtime-benchmarks")] | ||
// mod benchmarking; | ||
|
||
pub type CallIndex = u64; | ||
pub type ShardId = u64; | ||
|
||
#[frame_support::pallet] | ||
pub mod pallet { | ||
use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; | ||
use frame_system::pallet_prelude::*; | ||
use super::*; | ||
|
||
#[pallet::config] | ||
pub trait Config: frame_system::Config + pallet_registry::Config { | ||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>; | ||
|
||
#[pallet::constant] | ||
type DeplayThreshold: Get<<Self as frame_system::Config>::BlockNumber>; | ||
|
||
#[pallet::constant] | ||
type MaxOutcomePerSubmission: Get<u64>; | ||
|
||
#[pallet::constant] | ||
type MaxSizePerOutcome: Get<u64>; | ||
} | ||
|
||
#[pallet::pallet] | ||
#[pallet::generate_store(pub(super) trait Store)] | ||
pub struct Pallet<T>(_); | ||
|
||
#[pallet::storage] | ||
#[pallet::getter(fn shard_confirmation_threshold)] | ||
pub(super) type ShardConfirmationThreshold<T: Config> = StorageMap<_, Twox64Concat, | ||
ShardId, u64>; | ||
|
||
#[pallet::storage] | ||
#[pallet::getter(fn state_root_at)] | ||
pub(super) type StateRoot<T: Config> = StorageDoubleMap<_, Twox64Concat, ShardId, | ||
Twox64Concat, T::BlockNumber, [u8; 32]>; | ||
|
||
#[pallet::storage] | ||
#[pallet::getter(fn state_file_hash_at)] | ||
pub(super) type StateFileHash<T: Config> = StorageDoubleMap<_, Twox64Concat, ShardId, | ||
Twox64Concat, T::BlockNumber, [u8; 32]>; | ||
|
||
#[pallet::storage] | ||
#[pallet::getter(fn confirmation_of)] | ||
pub(super) type Confirmation<T: Config> = StorageDoubleMap<_, Twox64Concat, ShardId, | ||
Twox64Concat, T::BlockNumber, u64>; | ||
|
||
#[pallet::storage] | ||
#[pallet::getter(fn outcome_of)] | ||
pub(super) type Outcome<T: Config> = StorageMap<_, Twox64Concat, | ||
CallIndex, Vec<u8>>; | ||
|
||
#[pallet::event] | ||
#[pallet::generate_deposit(pub(super) fn deposit_event)] | ||
pub enum Event<T: Config> { | ||
BlockSynced(T::BlockNumber), | ||
BlockConfirmed(T::BlockNumber), | ||
} | ||
|
||
#[pallet::error] | ||
pub enum Error<T> { | ||
Unauthorized, | ||
OutcomeSubmissionTooLate, | ||
InvalidShardId, | ||
InvalidOutcome, | ||
InconsistentState, | ||
Unexpected, | ||
} | ||
|
||
#[pallet::call] | ||
impl<T:Config> Pallet<T> { | ||
|
||
#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(0, 1))] | ||
pub fn set_shard_confirmation_threshold( | ||
origin: OriginFor<T>, | ||
shard_id: ShardId, | ||
threshold: u64, | ||
) -> DispatchResult { | ||
ensure_root(origin)?; | ||
<ShardConfirmationThreshold<T>>::mutate(&shard_id, |t| { | ||
* t = Some(threshold) | ||
}); | ||
Ok(()) | ||
} | ||
|
||
#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(8, 10))] | ||
pub fn submit_outcome( | ||
origin: OriginFor<T>, | ||
block_number: T::BlockNumber, | ||
shard_id: ShardId, | ||
|
||
state_root: [u8; 32], | ||
state_file_hash: [u8; 32], | ||
|
||
outcome_call_index: Vec<CallIndex>, | ||
outcome: Vec<Vec<u8>>, | ||
) -> DispatchResult { | ||
let who = ensure_signed(origin)?; | ||
|
||
ensure!(pallet_registry::Pallet::<T>::is_valid_shard_id(shard_id), Error::<T>::InvalidShardId); | ||
ensure!(pallet_registry::Pallet::<T>::is_valid_secret_keeper(&who), Error::<T>::Unauthorized); | ||
let now = frame_system::Pallet::<T>::block_number(); | ||
ensure!(now <= block_number + T::DeplayThreshold::get(), Error::<T>::OutcomeSubmissionTooLate); | ||
|
||
// by default - confirmation at 1 | ||
let threshold = Self::shard_confirmation_threshold(shard_id).unwrap_or(1); | ||
|
||
ensure!(pallet_registry::Pallet::<T>::is_beacon_turn(block_number, &who, shard_id, threshold), Error::<T>::Unauthorized); | ||
ensure!(outcome_call_index.len() == outcome.len(), Error::<T>::InvalidOutcome); | ||
ensure!(outcome_call_index.len() < T::MaxOutcomePerSubmission::get() as usize, Error::<T>::InvalidOutcome); | ||
|
||
for o in outcome.iter() { | ||
ensure!(Self::validate_outcome(&o), Error::<T>::InvalidOutcome); | ||
} | ||
|
||
let old_state_root = Self::state_root_at(shard_id, block_number); | ||
// 1. existing state_root doesnt match the current state_root | ||
if old_state_root != Some(state_root) { | ||
if Self::confirmation_of(shard_id, block_number).is_some() { | ||
// 2. Someone had written another state_root before!! | ||
// THIS IS VERY SERIOUS | ||
return Err(Error::<T>::InconsistentState.into()); | ||
} | ||
|
||
// 3. The record has never been written before | ||
// We can write it - exit the if statement | ||
} else { | ||
// 4. old state root matches the current state_root | ||
// 5. update the confirmation count | ||
<Confirmation<T>>::mutate(&shard_id, &block_number, |confirmation| { | ||
*confirmation = Some(confirmation.unwrap_or(0) + 1); | ||
}); | ||
let confirms = Self::confirmation_of(shard_id, block_number).unwrap_or(0); | ||
ensure!(confirms <= threshold, Error::<T>::Unauthorized); | ||
|
||
// 6. threshold has been met. The block is confirmed! | ||
if confirms == threshold { | ||
Self::deposit_event(Event::<T>::BlockConfirmed(block_number)); | ||
} | ||
|
||
return Ok(()); | ||
} | ||
|
||
// The record has never been written before! | ||
|
||
<Confirmation<T>>::mutate(&shard_id, &block_number, |confirmation| { | ||
*confirmation = Some(confirmation.unwrap_or(0) + 1); | ||
}); | ||
let confirms = Self::confirmation_of(shard_id, block_number).unwrap_or(0); | ||
|
||
// this should never happen as we have checked for specific secret keepers! | ||
ensure!(confirms <= threshold, Error::<T>::Unexpected); | ||
|
||
for (i, call_index) in outcome_call_index.iter().enumerate() { | ||
<Outcome<T>>::insert(&call_index, &outcome[i]); | ||
} | ||
|
||
<StateRoot<T>>::insert(&shard_id, &block_number, &state_root); | ||
<StateFileHash<T>>::insert(&shard_id, &block_number, &state_file_hash); | ||
|
||
// emit BlockSynced only at the first time! | ||
Self::deposit_event(Event::<T>::BlockSynced(block_number)); | ||
|
||
if threshold == 1 { | ||
// if this is the first time the state is syced & threshold == 1 | ||
// the block is confirmed! | ||
Self::deposit_event(Event::<T>::BlockConfirmed(block_number)); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<T: Config> Pallet<T> { | ||
pub fn validate_outcome(call: &Vec<u8>) -> bool { | ||
call.len() < T::MaxSizePerOutcome::get() as usize | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.