Skip to content

Commit

Permalink
base
Browse files Browse the repository at this point in the history
  • Loading branch information
guoxbin committed May 11, 2020
1 parent ffd7cf0 commit f671269
Show file tree
Hide file tree
Showing 20 changed files with 2,821 additions and 372 deletions.
447 changes: 85 additions & 362 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -2,5 +2,5 @@
members = [
"bin/yee/node",
"bin/yee/runtime",
"client/consensus/pow",
# "client/consensus/pow",
]
4 changes: 2 additions & 2 deletions bin/yee/node/Cargo.toml
Expand Up @@ -34,9 +34,9 @@ sp-finality-grandpa = { version = "2.0.0-dev", git = "https://github.com/yeeco/s
sc-client-api = { version = "2.0.0-dev", git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sp-runtime = { version = "2.0.0-dev", git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sc-basic-authorship = { version = "0.8.0-dev", git = "https://github.com/yeeco/substrate.git", branch = "yee" }
yc-consensus-pow = { path = "../../../client/consensus/pow" }
#yc-consensus-pow = { path = "../../../client/consensus/pow" }

yee-runtime = { version = "2.0.0-dev", path = "../runtime" }
node-runtime = { version = "2.0.0-dev", path = "../runtime" }

[build-dependencies]
substrate-build-script-utils = { version = "2.0.0-dev", git = "https://github.com/yeeco/substrate.git", branch = "yee" }
2 changes: 1 addition & 1 deletion bin/yee/runtime/Cargo.toml
@@ -1,5 +1,5 @@
[package]
name = "yee-runtime"
name = "node-runtime"
version = "2.0.0-dev"
authors = ["Anonymous"]
edition = "2018"
Expand Down
46 changes: 46 additions & 0 deletions client/consensus/pow/Cargo.toml
@@ -0,0 +1,46 @@
[package]
name = "yc-consensus-pow"
version = "0.1.0"
authors = ["YeeCo <contact@yeefoundation.com>"]
edition = "2018"

[dependencies]
log = "0.4"
codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false, features = ["derive"] }
parking_lot = "0.7.1"
hash-db = "0.12"
ansi_term = "0.11"
futures = { version = "0.3.1", features = ["compat"] }
futures-timer = "3.0.1"
serde = { version = "1.0", optional = true, features = ["derive"] }
merkle_light = { git = "https://github.com/yeeco/merkle_light.git", branch = "yee2" }

sc-consensus = { git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sp-blockchain = { git = "https://github.com/yeeco/substrate.git", branch = "yee"}
sp-inherents = { git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sp-core = { git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sp-runtime = { git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sp-api = { git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sp-consensus = { git = "https://github.com/yeeco/substrate.git", branch = "yee" }
sp-arithmetic = { git = "https://github.com/yeeco/substrate.git", default_features = false, branch = "yee" }

pallet-pow = { path = "../../../frame/pow" }
yee-runtime = { package = "yee-runtime", path = "../../../bin/yee/runtime" }
yc-sharding = { path = "../../sharding" }
yc-util-merkle = { path = "../../util/merkle" }
yc-util = { path = "../../util" }
yp-consensus-pow = { path = "../../../primitives/consensus/pow" }
yp-sharding = { path = "../../../primitives/sharding" }
yp-context = { path = "../../../primitives/context" }

#foreign_chain = { package = "yee-foreign-chain", path = "../../../foreign/chain" }

[dev-dependencies]
hex-literal = "0.2"
hex = "0.3.1"

[features]
default = ["std"]
std = [
"serde",
]
54 changes: 54 additions & 0 deletions client/consensus/pow/src/digest.rs
@@ -0,0 +1,54 @@
// Copyright (C) 2019 Yee Foundation.
//
// This file is part of YeeChain.
//
// YeeChain 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.
//
// YeeChain 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 YeeChain. If not, see <https://www.gnu.org/licenses/>.

//! POW chain digests
//!
//! Implements POW signature wrapped in block header DigestItem.

use sp_runtime::{
codec::{
Decode, Encode,
},
generic::{DigestItem, OpaqueDigestItemId},
traits::Block,
};

use yp_consensus_pow::YEE_POW_ENGINE_ID;

use super::PowSeal;

/// Digest item acts as a valid POW consensus digest.
pub trait CompatibleDigestItem<B: Block, AuthorityId: Decode + Encode + Clone>: Sized {
/// construct digest item with work proof
fn pow_seal(seal: PowSeal<B, AuthorityId>) -> Self;

/// get work proof if digest item is pow item
fn as_pow_seal(&self) -> Option<PowSeal<B, AuthorityId>>;
}

impl<B, Hash, AuthorityId> CompatibleDigestItem<B, AuthorityId> for DigestItem<Hash> where
B: Block,
AuthorityId: Decode + Encode + Clone,
{
fn pow_seal(seal: PowSeal<B, AuthorityId>) -> Self {
DigestItem::Consensus(YEE_POW_ENGINE_ID, seal.encode())
}

fn as_pow_seal(&self) -> Option<PowSeal<B, AuthorityId>> {
self.try_to(OpaqueDigestItemId::Seal(&YEE_POW_ENGINE_ID))
}
}
257 changes: 257 additions & 0 deletions client/consensus/pow/src/job.rs
@@ -0,0 +1,257 @@
// Copyright (C) 2019 Yee Foundation.
//
// This file is part of YeeChain.
//
// YeeChain 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.
//
// YeeChain 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 YeeChain. If not, see <https://www.gnu.org/licenses/>.

use std::time::Duration;

use ansi_term::Colour;
use codec::{Decode, Encode};
use log::info;
use sp_core::H256;

use {
futures::{
Future, future,
},
log::warn,
std::{
fmt::Debug,
marker::PhantomData,
sync::Arc,
time::{
SystemTime, UNIX_EPOCH,
},
},
};
use {
sp_api::ProvideRuntimeApi,
sp_blockchain::HeaderBackend,
sp_consensus::{
BlockImport, BlockImportParams, BlockOrigin, Environment, ForkChoiceStrategy, Proposer,
},
sp_inherents::InherentDataProviders,
sp_runtime::{
traits::{Block, DigestItemFor, NumberFor, Header},
},
};
use {
super::{
worker::to_common_error,
},
};
use yc_sharding::{ScaleOutPhaseDigestItem, ShardingDigestItem};
use yp_consensus_pow::YeePOWApi;
use yp_context::Context;

use crate::{CompatibleDigestItem, PowSeal, ShardExtra, WorkProof};
use crate::pow::{calc_pow_target, check_work_proof, gen_extrinsic_proof};
use crate::verifier::check_scale;
use parking_lot::Mutex;
use sp_consensus::{SelectChain, RecordProof};
use sp_runtime::Digest;

#[derive(Clone)]
pub struct DefaultJob<B: Block, AuthorityId: Decode + Encode + Clone> {
/// Hash for header with consensus post-digests (unknown WorkProof) applied
/// The hash has 2 uses:
/// 1. distinguish different job
/// 2. build merkle tree of ProofMulti
pub hash: B::Hash,
/// The header, without consensus post-digests applied
pub header: B::Header,
/// Block's body
pub body: Vec<B::Extrinsic>,
/// Digest item
pub digest_item: PowSeal<B, AuthorityId>,
/// extrinsic proof
pub xts_proof: Vec<u8>,
}

impl<B: Block, AuthorityId: Decode + Encode + Clone> Job for DefaultJob<B, AuthorityId> {
type Hash = B::Hash;
}

pub trait Job {
type Hash;
}

pub trait JobManager: Send + Sync
{
type Job: Job;

/// get job with unknown proof
fn get_job(&mut self) -> Box<dyn Future<Output=Result<Self::Job, sp_consensus::Error>> + Send>;

/// submit job
fn submit_job(&self, job: Self::Job) -> Box<dyn Future<Output=Result<<Self::Job as Job>::Hash, sp_consensus::Error>> + Send>;
}

pub struct DefaultJobManager<B, C, SC, E, AccountId, AuthorityId, I> where
B: Block,
{
client: Arc<C>,
select_chain: SC,
env: E,
inherent_data_providers: InherentDataProviders,
authority_id: AuthorityId,
block_import: Arc<Mutex<I>>,
shard_extra: ShardExtra<AccountId>,
context: Context<B>,
phantom: PhantomData<B>,
}

impl<B, C, SC, E, AccountId, AuthorityId, I> DefaultJobManager<B, C, SC, E, AccountId, AuthorityId, I> where
B: Block,
E: Environment<B> + 'static,
<E as Environment<B>>::Proposer: Proposer<B>,
<E as Environment<B>>::Error: Debug,
AuthorityId: Decode + Encode + Clone,
I: BlockImport<B, Error=sp_consensus::Error> + Send + Sync + 'static,
{
pub fn new(
client: Arc<C>,
select_chain: SC,
env: E,
inherent_data_providers: InherentDataProviders,
authority_id: AuthorityId,
block_import: Arc<Mutex<I>>,
shard_extra: ShardExtra<AccountId>,
context: Context<B>,
) -> Self {
Self {
client,
select_chain,
env,
inherent_data_providers,
authority_id,
block_import,
shard_extra,
context,
phantom: PhantomData,
}
}
}

impl<B, C, SC, E, AccountId, AuthorityId, I> JobManager for DefaultJobManager<B, C, SC, E, AccountId, AuthorityId, I>
where B: Block,
DigestItemFor<B>: super::CompatibleDigestItem<B, AuthorityId> + ShardingDigestItem<u16> + ScaleOutPhaseDigestItem<NumberFor<B>, u16>,
C: HeaderBackend<B> + ProvideRuntimeApi<B>,
C::Api: YeePOWApi<B>,
SC: SelectChain<B> + Send + Sync,
E: Environment<B> + Send + Sync + 'static,
E::Proposer: Proposer<B, Transaction=sp_api::TransactionFor<C, B>>,
E::Error: Debug,
AuthorityId: Decode + Encode + Clone + Send + Sync + 'static,
AccountId: Decode + Encode + Clone + Send + Sync + 'static,
I: BlockImport<B, Error=sp_consensus::Error> + Send + Sync + 'static,
B::Hash: From<H256> + Ord,
{
type Job = DefaultJob<B, AuthorityId>;

fn get_job(&mut self) -> Box<dyn Future<Output=Result<Self::Job, sp_consensus::Error>> + Send> {
let chain_head = match self.select_chain.best_chain()
.map_err(to_common_error) {
Ok(chain_head) => chain_head,
Err(e) => return Box::new(future::err(e)),
};

let inherent_data = match self.inherent_data_providers.create_inherent_data()
.map_err(to_common_error) {
Ok(inherent_data) => inherent_data,
Err(e) => return Box::new(future::err(e)),
};

let awaiting_proposer = self.env.init(&chain_head);

let client = self.client.clone();
let authority_id = self.authority_id.clone();
let context = self.context.clone();

let build_job = move |block: B| {
let (header, body) = block.deconstruct();
let header_num = header.number().clone();
let header_pre_hash = header.hash();
let timestamp = timestamp_now()?;
let pow_target = calc_pow_target(client, &header, timestamp, &context)?;
let authority_id = authority_id;
let work_proof = WorkProof::Unknown;
// generate proof
let (relay_proof, proof) = gen_extrinsic_proof::<B>(&header, &body);

let pow_seal = PowSeal {
authority_id,
pow_target,
timestamp,
work_proof,
relay_proof,
};
let mut header_with_pow_seal = header.clone();
let item = <DigestItemFor<B> as CompatibleDigestItem<B, AuthorityId>>::pow_seal(pow_seal.clone());
header_with_pow_seal.digest_mut().push(item);

let hash = header_with_pow_seal.hash();

info!("job {} @ {:?}, pow target: {:#x}", header_num, header_pre_hash, pow_target);

Ok(DefaultJob {
hash,
header,
body,
digest_item: pow_seal,
xts_proof: proof,
})
};

awaiting_proposer.and_then(move |mut proposer| proposer.propose(
inherent_data,
Digest::default(),
Duration::from_secs(10),
RecordProof::No,
)).and_then(build_job)


// Box::new(awaiting_proposer.and_then(inherent_data, Duration::from_secs(10)).into_future()
// .map_err(to_common_error).and_then(build_job))
}

fn submit_job(&self, job: Self::Job) -> Box<dyn Future<Output=Result<<Self::Job as Job>::Hash, sp_consensus::Error>> + Send> {
let mut block_import = self.block_import.clone();

let check_job = move |job: Self::Job| -> Result<<Self::Job as Job>::Hash, sp_consensus::Error>{
let number = &job.header.number().clone();
let (post_digest, hash) = check_work_proof(&job.header, &job.digest_item)?;

check_scale::<B, AccountId>(&job.header, self.shard_extra.clone())?;

let mut import_block = BlockImportParams::new(BlockOrigin::Own, job.header);
import_block.post_digests.push(post_digest);
import_block.body = Some(job.body);
import_block.storage_changes = None;//TODO Some(storage_changes);
import_block.fork_choice = Some(ForkChoiceStrategy::LongestChain);

block_import.import_block(import_block, Default::default())?;
info!("{} @ {} {:?}", Colour::Green.bold().paint("Block mined"), number, hash);
Ok(hash)
};

Box::new(check_job(job).into_future())
}
}

fn timestamp_now() -> Result<u64, sp_consensus::Error> {
Ok(SystemTime::now().duration_since(UNIX_EPOCH)
.map_err(to_common_error)?.as_millis() as u64)
}

0 comments on commit f671269

Please sign in to comment.