Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 3 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
2,731 changes: 1,382 additions & 1,349 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = [ "consensus" ]
members = [ "consensus", "runtime" ]
18 changes: 9 additions & 9 deletions consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@
name = "cumulus-consensus"
description = "Proxy Polkadot's consensus as a consensus engine for Substrate"
version = "0.1.0"
authors = ["Parity Technologies"]
authors = ["Parity Technologies <[email protected]>"]
edition = "2018"

[dependencies]
# substrate deps
substrate-client = { git = "https://github.com/paritytech/substrate" }
substrate-consensus-common = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" }
sr-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }
substrate-consensus-common = { git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }
sr-primitives = { git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }

# polkadot deps
polkadot-service = { git = "https://github.com/paritytech/polkadot" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot" }
polkadot-runtime = { git = "https://github.com/paritytech/polkadot" }
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-validate_block" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-validate_block" }
polkadot-runtime = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-validate_block" }

# other deps
futures = "0.1.21"
tokio = "0.1.8"
parity-codec = "3.0"
parity-codec = "3.1"
log = "0.4"
16 changes: 8 additions & 8 deletions consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub enum Error<P> {
/// A parachain head update.
pub struct HeadUpdate {
/// The relay-chain's block hash where the parachain head updated.
pub relay_hash: PHash,
pub relay_hash: PHash,
/// The parachain head-data.
pub head_data: Vec<u8>,
}
Expand All @@ -80,9 +80,9 @@ pub trait PolkadotClient: Clone {
}

/// Spawns a future that follows the Polkadot relay chain for the given parachain.
pub fn follow_polkadot<'a, L: 'a, P: 'a>(para_id: ParaId, local: Arc<L>, polkadot: P)
pub fn follow_polkadot<'a, L: 'a, P: 'a>(para_id: ParaId, local: Arc<L>, polkadot: P)
-> impl Future<Item=(),Error=()> + Send + 'a
where
where
L: LocalClient + Send + Sync,
P: PolkadotClient + Send + Sync,
{
Expand Down Expand Up @@ -169,23 +169,23 @@ impl<B, E, RA> PolkadotClient for Arc<Client<B, E, PBlock, RA>> where
{
type Error = ClientError;

type HeadUpdates = Box<Stream<Item=HeadUpdate,Error=Self::Error> + Send>;
type Finalized = Box<Stream<Item=Vec<u8>,Error=Self::Error> + Send>;
type HeadUpdates = Box<Stream<Item=HeadUpdate, Error=Self::Error> + Send>;
type Finalized = Box<Stream<Item=Vec<u8>, Error=Self::Error> + Send>;

fn head_updates(&self, para_id: ParaId) -> Self::HeadUpdates {
let parachain_key = parachain_key(para_id);
let stream = stream::once(self.storage_changes_notification_stream(Some(&[parachain_key.clone()])))
.map(|s| s.map_err(|()| panic!("unbounded receivers never yield errors; qed")))
.flatten();

let s = stream.filter_map(move |(hash, changes)| {
let head_data = changes.iter()
.filter_map(|(k, v)| if k == &parachain_key { Some(v) } else { None })
.next();

match head_data {
Some(Some(head_data)) => Some(HeadUpdate {
relay_hash: hash,
Some(Some(head_data)) => Some(HeadUpdate {
relay_hash: hash,
head_data: head_data.0.clone(),
}),
Some(None) | None => None,
Expand Down
28 changes: 28 additions & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "cumulus-runtime"
version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2018"

[dependencies]
codec = { package = "parity-codec", version = "3.1", default-features = false, features = [ "derive" ] }
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-validate_block" }
runtime-primitives = { package = "sr-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-validate_block" }
rio = { package = "sr-io", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-validate_block" }
executive = { package = "srml-executive", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-validate_block" }

[dev-dependencies]
keyring = { package = "substrate-keyring", git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }
executor = { package = "substrate-executor", git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }
test-runtime = { package = "substrate-test-runtime", git = "https://github.com/paritytech/substrate", branch = "bkchr-validate_block" }

[features]
default = ["std"]
std = [
"codec/std",
"rstd/std",
"rio/std",
"runtime-primitives/std",
"executive/std",
]
57 changes: 57 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.

// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]

use rstd::{vec::Vec, collections::btree_map::BTreeMap};
use codec::{Encode, Decode};
use runtime_primitives::traits::Block as BlockT;

#[cfg(not(feature = "std"))]
#[doc(hidden)]
pub use rstd::slice;

#[macro_use]
pub mod validate_block;

type WitnessData = BTreeMap<Vec<u8>, Vec<u8>>;

/// The parachain block that is created on a collator and validated by a validator.
#[derive(Encode, Decode)]
struct ParachainBlock<B: BlockT> {
extrinsics: Vec<<B as BlockT>::Extrinsic>,
/// The data that is required to emulate the storage accesses executed by all extrinsics.
witness_data: WitnessData,
}

impl<B: BlockT> ParachainBlock<B> {
#[cfg(test)]
fn new(extrinsics: Vec<<B as BlockT>::Extrinsic>, witness_data: WitnessData) -> Self {
Self {
extrinsics,
witness_data,
}
}
}

impl<B: BlockT> Default for ParachainBlock<B> {
fn default() -> Self {
Self {
extrinsics: Vec::default(),
witness_data: BTreeMap::default(),
}
}
}
106 changes: 106 additions & 0 deletions runtime/src/validate_block/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.

// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

//! A module that enables a runtime to work as parachain.

#[cfg(not(feature = "std"))]
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, One};
#[cfg(not(feature = "std"))]
use executive::ExecuteBlock;

#[cfg(not(feature = "std"))]
#[doc(hidden)]
pub mod storage_functions;
#[cfg(test)]
mod tests;

/// Register the `validate_block` function that is used by parachains to validate blocks on a validator.
///
/// Does *nothing* when `std` feature is enabled.
///
/// Expects as parameters the block and the block executor.
///
/// # Example
///
/// ```
/// struct Block;
/// struct BlockExecutor;
///
/// cumulus_runtime::register_validate_block!(Block, BlockExecutor);
///
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! register_validate_block {
($block:ty, $block_executor:ty) => {
$crate::register_validate_block_impl!($block, $block_executor);
};
}

/// The actual implementation of `register_validate_block` for `no_std`.
#[cfg(not(feature = "std"))]
#[doc(hidden)]
#[macro_export]
macro_rules! register_validate_block_impl {
($block:ty, $block_executor:ty) => {
#[doc(hidden)]
mod parachain_validate_block {
use super::*;

#[no_mangle]
unsafe fn validate_block(block: *const u8, block_len: u64, prev_head: *const u8, prev_head_len: u64) {
let block = $crate::slice::from_raw_parts(block, block_len as usize);
let prev_head = $crate::slice::from_raw_parts(prev_head, prev_head_len as usize);

$crate::validate_block::validate_block::<$block, $block_executor>(block, prev_head);
}
}
};
}

/// The actual implementation of `register_validate_block` for `std`.
#[cfg(feature = "std")]
#[doc(hidden)]
#[macro_export]
macro_rules! register_validate_block_impl {
($block:ty, $block_executor:ty) => {};
}

/// Validate a given parachain block on a validator.
#[cfg(not(feature = "std"))]
#[doc(hidden)]
pub fn validate_block<Block: BlockT, E: ExecuteBlock<Block>>(mut block: &[u8], mut prev_head: &[u8]) {
use codec::Decode;

let block = crate::ParachainBlock::<Block>::decode(&mut block).expect("Could not decode parachain block.");
let parent_header = <<Block as BlockT>::Header as Decode>::decode(&mut prev_head).expect("Could not decode parent header.");

let _guard = unsafe {
use storage_functions as storage;
storage::STORAGE = Some(block.witness_data);
(
// Replace storage calls with our own implementations
rio::ext_get_allocated_storage.replace_implementation(storage::ext_get_allocated_storage),
rio::ext_get_storage_into.replace_implementation(storage::ext_get_storage_into),
rio::ext_set_storage.replace_implementation(storage::ext_set_storage),
rio::ext_exists_storage.replace_implementation(storage::ext_exists_storage),
rio::ext_clear_storage.replace_implementation(storage::ext_clear_storage),
)
};

let block_number = *parent_header.number() + One::one();
E::execute_extrinsics_without_checks(block_number, block.extrinsics);
}
79 changes: 79 additions & 0 deletions runtime/src/validate_block/storage_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.

// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

//! All storage functions that are replaced by `validate_block` in the Substrate runtime.

use crate::WitnessData;
use rstd::{slice, ptr, cmp};

pub static mut STORAGE: Option<WitnessData> = None;
const STORAGE_SET_EXPECT: &str = "`STORAGE` needs to be set before calling this function.";

pub unsafe fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 {
let key = slice::from_raw_parts(key_data, key_len as usize);
match STORAGE.as_mut().expect(STORAGE_SET_EXPECT).get_mut(key) {
Some(value) => {
*written_out = value.len() as u32;
value.as_mut_ptr()
},
None => {
*written_out = u32::max_value();
ptr::null_mut()
}
}
}

pub unsafe fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32) {
let key = slice::from_raw_parts(key_data, key_len as usize);
let value = slice::from_raw_parts(value_data, value_len as usize);

STORAGE.as_mut().map(|s| {
s.insert(key.to_vec(), value.to_vec());
});
}

pub unsafe fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32 {
let key = slice::from_raw_parts(key_data, key_len as usize);
let out_value = slice::from_raw_parts_mut(value_data, value_len as usize);

match STORAGE.as_mut().expect(STORAGE_SET_EXPECT).get_mut(key) {
Some(value) => {
let value = &value[value_offset as usize..];
let len = cmp::min(value_len as usize, value.len());
out_value[..len].copy_from_slice(&value[..len]);
len as u32
},
None => {
u32::max_value()
}
}
}

pub unsafe fn ext_exists_storage(key_data: *const u8, key_len: u32) -> u32 {
let key = slice::from_raw_parts(key_data, key_len as usize);

if STORAGE.as_mut().expect(STORAGE_SET_EXPECT).contains_key(key) {
1
} else {
0
}
}

pub unsafe fn ext_clear_storage(key_data: *const u8, key_len: u32) {
let key = slice::from_raw_parts(key_data, key_len as usize);

STORAGE.as_mut().expect(STORAGE_SET_EXPECT).remove(key);
}
Loading