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
18 changes: 13 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

105 changes: 55 additions & 50 deletions demo/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,56 +82,61 @@ pub fn run<I, T>(args: I) -> error::Result<()> where

// Create client
let executor = demo_executor::Executor::new();
let mut storage = Default::default();
let god_key = hex!["3d866ec8a9190c8343c2fc593d21d8a6d0c5c4763aaab2349de3a6111d64d124"];

let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig {
code: vec![], // TODO
authorities: vec![god_key.clone()],
}),
system: None,
// block_time: 5, // 5 second block time.
session: Some(SessionConfig {
validators: vec![god_key.clone()],
session_length: 720, // that's 1 hour per session.
}),
staking: Some(StakingConfig {
current_era: 0,
intentions: vec![],
transaction_fee: 100,
balances: vec![(god_key.clone(), 1u64 << 63)].into_iter().collect(),
validator_count: 12,
sessions_per_era: 24, // 24 hours per era.
bonding_duration: 90, // 90 days per bond.
}),
democracy: Some(DemocracyConfig {
launch_period: 120 * 24 * 14, // 2 weeks per public referendum
voting_period: 120 * 24 * 28, // 4 weeks to discuss & vote on an active referendum
minimum_deposit: 1000, // 1000 as the minimum deposit for a referendum
}),
council: Some(CouncilConfig {
active_council: vec![],
candidacy_bond: 1000, // 1000 to become a council candidate
voter_bond: 100, // 100 down to vote for a candidate
present_slash_per_voter: 1, // slash by 1 per voter for an invalid presentation.
carry_count: 24, // carry over the 24 runners-up to the next council election
presentation_duration: 120 * 24, // one day for presenting winners.
approval_voting_period: 7 * 120 * 24, // one week period between possible council elections.
term_duration: 180 * 120 * 24, // 180 day term duration for the council.
desired_seats: 0, // start with no council: we'll raise this once the stake has been dispersed a bit.
inactive_grace_period: 1, // one addition vote should go by before an inactive voter can be reaped.

cooloff_period: 90 * 120 * 24, // 90 day cooling off period if council member vetoes a proposal.
voting_period: 7 * 120 * 24, // 7 day voting period for council members.
}),
};
let prepare_genesis = || {
storage = genesis_config.build_externalities();
let block = genesis::construct_genesis_block(&storage);
(primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
};
let client = Arc::new(client::new_in_mem(executor, prepare_genesis)?);

struct GenesisBuilder;

impl client::GenesisBuilder for GenesisBuilder {
fn build(self) -> (primitives::Header, Vec<(Vec<u8>, Vec<u8>)>) {
let god_key = hex!["3d866ec8a9190c8343c2fc593d21d8a6d0c5c4763aaab2349de3a6111d64d124"];
let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig {
code: vec![], // TODO
authorities: vec![god_key.clone()],
}),
system: None,
// block_time: 5, // 5 second block time.
session: Some(SessionConfig {
validators: vec![god_key.clone()],
session_length: 720, // that's 1 hour per session.
}),
staking: Some(StakingConfig {
current_era: 0,
intentions: vec![],
transaction_fee: 100,
balances: vec![(god_key.clone(), 1u64 << 63)].into_iter().collect(),
validator_count: 12,
sessions_per_era: 24, // 24 hours per era.
bonding_duration: 90, // 90 days per bond.
}),
democracy: Some(DemocracyConfig {
launch_period: 120 * 24 * 14, // 2 weeks per public referendum
voting_period: 120 * 24 * 28, // 4 weeks to discuss & vote on an active referendum
minimum_deposit: 1000, // 1000 as the minimum deposit for a referendum
}),
council: Some(CouncilConfig {
active_council: vec![],
candidacy_bond: 1000, // 1000 to become a council candidate
voter_bond: 100, // 100 down to vote for a candidate
present_slash_per_voter: 1, // slash by 1 per voter for an invalid presentation.
carry_count: 24, // carry over the 24 runners-up to the next council election
presentation_duration: 120 * 24, // one day for presenting winners.
approval_voting_period: 7 * 120 * 24, // one week period between possible council elections.
term_duration: 180 * 120 * 24, // 180 day term duration for the council.
desired_seats: 0, // start with no council: we'll raise this once the stake has been dispersed a bit.
inactive_grace_period: 1, // one addition vote should go by before an inactive voter can be reaped.

cooloff_period: 90 * 120 * 24, // 90 day cooling off period if council member vetoes a proposal.
voting_period: 7 * 120 * 24, // 7 day voting period for council members.
}),
};

let storage = genesis_config.build_externalities();
let block = genesis::construct_genesis_block(&storage);
(primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
}
}

let client = Arc::new(client::new_in_mem(executor, GenesisBuilder)?);
let mut core = ::tokio_core::reactor::Core::new().expect("Unable to spawn event loop.");

let _rpc_servers = {
Expand Down
64 changes: 41 additions & 23 deletions polkadot/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ extern crate error_chain;
#[cfg(test)]
extern crate substrate_keyring as keyring;

use client::backend::Backend;
use client::Client;
pub mod light;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: since light clients are meant to be first-class we should also put the full client implementation in a submodule

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, will do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to do this, but actually full client could be backed by db backend (which is already in the separate crate, named db, not the full) and in-memory backend (which I guess could be renamed to TestBackend). So there's actually nothing to move to the full submodule right now, except for db crate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

impl<B: LocalBackend> PolkadotApi for Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>> looks like it could go in a full module.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right. missed that you're talking about Api, not about the client


use client::backend::{Backend, LocalBackend};
use client::{Client, LocalCallExecutor};
use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::{NativeExecutionDispatch, NativeExecutor};
use state_machine::OverlayedChanges;
Expand Down Expand Up @@ -143,6 +145,12 @@ pub trait PolkadotApi {
fn build_block(&self, parent: &Self::CheckedBlockId, timestamp: u64) -> Result<Self::BlockBuilder>;
}

/// Mark for all Polkadot API implementations, that are making use of state data, stored locally.
pub trait LocalPolkadotApi: PolkadotApi {}

/// Mark for all Polkadot API implementations, that are fetching required state data from remote nodes.
pub trait RemotePolkadotApi: PolkadotApi {}

/// A checked block ID used for the substrate-client implementation of CheckedBlockId;
#[derive(Debug, Clone, Copy)]
pub struct CheckedId(BlockId);
Expand Down Expand Up @@ -178,7 +186,7 @@ macro_rules! with_runtime {
}}
}

impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
impl<B: LocalBackend> PolkadotApi for Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>>
where ::client::error::Error: From<<<B as Backend>::State as state_machine::backend::Backend>::Error>
{
type CheckedBlockId = CheckedId;
Expand Down Expand Up @@ -261,6 +269,10 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
}
}

impl<B: LocalBackend> LocalPolkadotApi for Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>>
where ::client::error::Error: From<<<B as Backend>::State as state_machine::backend::Backend>::Error>
{}

/// A polkadot block builder.
#[derive(Debug, Clone)]
pub struct ClientBlockBuilder<S> {
Expand Down Expand Up @@ -356,8 +368,10 @@ mod tests {
use super::*;
use keyring::Keyring;
use codec::Slicable;
use client::{self, LocalCallExecutor};
use client::in_mem::Backend as InMemory;
use substrate_executor::NativeExecutionDispatch;
use substrate_primitives::Header;
use runtime::{GenesisConfig, ConsensusConfig, SessionConfig, BuildExternalities};

fn validators() -> Vec<AccountId> {
Expand All @@ -367,30 +381,34 @@ mod tests {
]
}

fn client() -> Client<InMemory, NativeExecutor<LocalDispatch>> {
let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig {
code: LocalDispatch::native_equivalent().to_vec(),
authorities: validators(),
}),
system: None,
session: Some(SessionConfig {
validators: validators(),
session_length: 100,
}),
council: Some(Default::default()),
democracy: Some(Default::default()),
parachains: Some(Default::default()),
staking: Some(Default::default()),
};
::client::new_in_mem(
LocalDispatch::new(),
|| {
fn client() -> Client<InMemory, LocalCallExecutor<InMemory, NativeExecutor<LocalDispatch>>> {
struct GenesisBuilder;

impl client::GenesisBuilder for GenesisBuilder {
fn build(self) -> (Header, Vec<(Vec<u8>, Vec<u8>)>) {
let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig {
code: LocalDispatch::native_equivalent().to_vec(),
authorities: validators(),
}),
system: None,
session: Some(SessionConfig {
validators: validators(),
session_length: 100,
}),
council: Some(Default::default()),
democracy: Some(Default::default()),
parachains: Some(Default::default()),
staking: Some(Default::default()),
};

let storage = genesis_config.build_externalities();
let block = ::client::genesis::construct_genesis_block(&storage);
(substrate_primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
}
).unwrap()
}

::client::new_in_mem(LocalDispatch::new(), GenesisBuilder).unwrap()
}

#[test]
Expand Down
93 changes: 93 additions & 0 deletions polkadot/api/src/light.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot 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.

// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Strongly typed API for light Polkadot client.

use std::sync::Arc;
use client::backend::{Backend, RemoteBackend};
use client::{Client, CallExecutor};
use codec::Slicable;
use state_machine;
use primitives::{AccountId, BlockId, Hash, Index, SessionKey, Timestamp};
use primitives::parachain::DutyRoster;
use runtime::{Block, UncheckedExtrinsic};
use {PolkadotApi, RemotePolkadotApi, BlockBuilder, CheckedBlockId, CheckedId, Result, ErrorKind};

/// Remote polkadot API implementation.
pub struct RemotePolkadotApiWrapper<B: Backend, E: CallExecutor>(pub Arc<Client<B, E>>);

/// Block builder for light client.
pub struct LightBlockBuilder;

impl<B: Backend, E: CallExecutor> PolkadotApi for RemotePolkadotApiWrapper<B, E>
where ::client::error::Error: From<<<B as Backend>::State as state_machine::backend::Backend>::Error>
{
type CheckedBlockId = CheckedId;
type BlockBuilder = LightBlockBuilder;

fn check_id(&self, id: BlockId) -> Result<CheckedId> {
Ok(CheckedId(id))
}

fn session_keys(&self, at: &CheckedId) -> Result<Vec<SessionKey>> {
self.0.executor().call(at.block_id(), "authorities", &[])
.and_then(|r| Vec::<SessionKey>::decode(&mut &r.return_data[..])
.ok_or("error decoding session keys".into()))
.map_err(Into::into)
}

fn validators(&self, _at: &CheckedId) -> Result<Vec<AccountId>> {
Err(ErrorKind::UnknownRuntime.into())
}

fn random_seed(&self, _at: &Self::CheckedBlockId) -> Result<Hash> {
Err(ErrorKind::UnknownRuntime.into())
}

fn duty_roster(&self, _at: &CheckedId) -> Result<DutyRoster> {
Err(ErrorKind::UnknownRuntime.into())
}

fn timestamp(&self, _at: &CheckedId) -> Result<Timestamp> {
Err(ErrorKind::UnknownRuntime.into())
}

fn evaluate_block(&self, _at: &CheckedId, _block: Block) -> Result<()> {
Err(ErrorKind::UnknownRuntime.into())
}

fn index(&self, _at: &CheckedId, _account: AccountId) -> Result<Index> {
Err(ErrorKind::UnknownRuntime.into())
}

fn build_block(&self, _parent: &CheckedId, _timestamp: Timestamp) -> Result<Self::BlockBuilder> {
Err(ErrorKind::UnknownRuntime.into())
}
}

impl<B: RemoteBackend, E: CallExecutor> RemotePolkadotApi for RemotePolkadotApiWrapper<B, E>
where ::client::error::Error: From<<<B as Backend>::State as state_machine::backend::Backend>::Error>
{}

impl BlockBuilder for LightBlockBuilder {
fn push_extrinsic(&mut self, _extrinsic: UncheckedExtrinsic) -> Result<()> {
Err(ErrorKind::UnknownRuntime.into())
}

fn bake(self) -> Block {
unimplemented!()
}
}
Loading