diff --git a/clippy.toml b/clippy.toml index 1bd6147d8..15906305c 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1 @@ -too-many-arguments-threshold = 15 +too-many-arguments-threshold = 10 diff --git a/common/crypto/Cargo.toml b/common/crypto/Cargo.toml index 2054e146e..c70bd5bea 100644 --- a/common/crypto/Cargo.toml +++ b/common/crypto/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ophelia-bls12381 = { git = "https://github.com/zeroqn/ophelia.git", features = [ "generate" ] } ophelia-secp256k1 = { git = "https://github.com/zeroqn/ophelia.git" } ophelia = { git = "https://github.com/zeroqn/ophelia.git" } diff --git a/common/crypto/src/lib.rs b/common/crypto/src/lib.rs index 3c8699873..a120151f5 100644 --- a/common/crypto/src/lib.rs +++ b/common/crypto/src/lib.rs @@ -1,4 +1,7 @@ pub use ophelia::{Crypto, CryptoError, PrivateKey, PublicKey, Signature}; +pub use ophelia_bls12381::{ + BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature, BLS12381Threshold, BLS12381, +}; pub use ophelia_secp256k1::{ Secp256k1, Secp256k1PrivateKey, Secp256k1PublicKey, Secp256k1Signature, }; diff --git a/core/consensus/Cargo.toml b/core/consensus/Cargo.toml index 7f42e026f..948dbf07f 100644 --- a/core/consensus/Cargo.toml +++ b/core/consensus/Cargo.toml @@ -21,4 +21,9 @@ common-crypto = { path = "../../common/crypto"} core-mempool = { path = "../../core/mempool"} core-storage = { path = "../../core/storage"} core-network = { path = "../../core/network"} -protocol = { path = "../../protocol" } \ No newline at end of file +protocol = { path = "../../protocol" } + +[dev-dependencies] +futures-preview = "0.3.0-alpha.18" +num-traits = "0.2" +rand = "0.7" diff --git a/core/consensus/src/adapter.rs b/core/consensus/src/adapter.rs index 1ac7f9ceb..afe1189d5 100644 --- a/core/consensus/src/adapter.rs +++ b/core/consensus/src/adapter.rs @@ -1,15 +1,13 @@ -use std::collections::HashSet; use std::marker::PhantomData; use std::sync::Arc; use async_trait::async_trait; -use bytes::Bytes; use protocol::traits::{ ConsensusAdapter, Context, Gossip, MemPool, MemPoolAdapter, MessageTarget, MixedTxHashes, Priority, Storage, StorageAdapter, }; -use protocol::types::{Epoch, Hash, Proof, Receipt, SignedTransaction, UserAddress, Validator}; +use protocol::types::{Epoch, Hash, Proof, Receipt, SignedTransaction, Validator}; use protocol::ProtocolResult; // use crate::ConsensusError; @@ -21,11 +19,6 @@ pub struct OverlordConsensusAdapter< MA: MemPoolAdapter, SA: StorageAdapter, > { - address: UserAddress, - proof: Option, - cycle_limit: u64, - exemption_hash: HashSet, - network: Arc, mempool: Arc, storage: Arc, @@ -97,6 +90,10 @@ where self.storage.insert_receipts(receipts).await } + async fn save_proof(&self, _ctx: Context, proof: Proof) -> ProtocolResult<()> { + self.storage.update_latest_proof(proof).await + } + async fn save_signed_txs( &self, _ctx: Context, @@ -123,19 +120,8 @@ where MA: MemPoolAdapter + 'static, SA: StorageAdapter + 'static, { - pub fn new( - address: UserAddress, - cycle_limit: u64, - network: Arc, - mempool: Arc, - storage: Arc, - ) -> Self { + pub fn new(network: Arc, mempool: Arc, storage: Arc) -> Self { OverlordConsensusAdapter { - address, - proof: None, - cycle_limit, - exemption_hash: HashSet::new(), - mempool_adapter: PhantomData, storage_adapter: PhantomData, network, @@ -143,16 +129,4 @@ where storage, } } - - pub fn is_hold_proof(&self) -> bool { - self.proof.is_some() - } - - pub fn get_proof(&self) -> Option { - self.proof.clone() - } - - pub fn update_proof(&mut self, proof: Proof) { - self.proof = Some(proof); - } } diff --git a/core/consensus/src/consensus.rs b/core/consensus/src/consensus.rs index 10a19b34a..a64bbf928 100644 --- a/core/consensus/src/consensus.rs +++ b/core/consensus/src/consensus.rs @@ -3,62 +3,54 @@ use std::sync::Arc; use async_trait::async_trait; use creep::Context; -use overlord::types::{AggregatedVote, OverlordMsg, SignedProposal, SignedVote}; -use overlord::{Codec, Consensus as OverlordConsensus, Crypto, Overlord, OverlordHandler}; +use overlord::types::{AggregatedVote, Node, OverlordMsg, SignedProposal, SignedVote, Status}; +use overlord::{Overlord, OverlordHandler}; use rlp::decode; -use protocol::traits::{ - Consensus, ConsensusAdapter, Gossip, MemPool, MemPoolAdapter, Storage, StorageAdapter, -}; -use protocol::types::{Epoch, Proof, SignedTransaction, UserAddress}; +use common_crypto::{Secp256k1PrivateKey, Secp256k1PublicKey}; + +use protocol::traits::{Consensus, Gossip, MemPool, MemPoolAdapter, Storage, StorageAdapter}; +use protocol::types::{Epoch, Hash, Proof, SignedTransaction, UserAddress, Validator}; use protocol::ProtocolResult; use crate::adapter::OverlordConsensusAdapter; +use crate::engine::ConsensusEngine; +use crate::fixed_types::{FixedPill, FixedSignedTxs}; +use crate::util::OverlordCrypto; use crate::{ConsensusError, MsgType}; +pub type OverlordRuntime = + Overlord, OverlordCrypto>; + /// Provide consensus pub struct ConsensusProvider< - CA: ConsensusAdapter, - MA: MemPoolAdapter, - SA: StorageAdapter, - G: Gossip, + MA: MemPoolAdapter + 'static, + SA: StorageAdapter + 'static, + G: Gossip + Send + Sync, M: MemPool, S: Storage, - C: Codec, - E: Codec, - F: OverlordConsensus, - T: Crypto, > { /// Overlord consensus protocol instance. - overlord: Option>, + overlord: Option>, /// An overlord consensus protocol handler. - handler: OverlordHandler, - /// Supply necessary functions from other modules. - adapter: CA, - /// **TODO** to be changed into `Engine` - overlord_adapter: OverlordConsensusAdapter, + handler: OverlordHandler, mempool_adapter: PhantomData, storage_adapter: PhantomData, } #[async_trait] -impl Consensus - for ConsensusProvider +impl Consensus> + for ConsensusProvider where - CA: ConsensusAdapter + 'static, MA: MemPoolAdapter + 'static, SA: StorageAdapter + 'static, G: Gossip + Send + Sync, M: MemPool + 'static, S: Storage + 'static, - C: Codec + Send + Sync + 'static, - E: Codec + Send + Sync + 'static, - F: OverlordConsensus + 'static, - T: Crypto + Send + Sync + 'static, { async fn set_proposal(&self, ctx: Context, proposal: Vec) -> ProtocolResult<()> { - let signed_proposal: SignedProposal = + let signed_proposal: SignedProposal = decode(&proposal).map_err(|_| ConsensusError::DecodeErr(MsgType::SignedProposal))?; self.handler .send_msg(ctx, OverlordMsg::SignedProposal(signed_proposal)) @@ -95,51 +87,75 @@ where } } -impl ConsensusProvider +impl ConsensusProvider where - CA: ConsensusAdapter + 'static, MA: MemPoolAdapter + 'static, SA: StorageAdapter + 'static, - G: Gossip + Send + Sync, + G: Gossip + Send + Sync + 'static, M: MemPool + 'static, S: Storage + 'static, - C: Codec + Send + Sync + 'static, - E: Codec + Send + Sync + 'static, - F: OverlordConsensus + 'static, - T: Crypto + Send + Sync + 'static, { pub fn new( + init_epoch_id: u64, + chain_id: Hash, address: UserAddress, cycle_limit: u64, - overlord_adapter: F, - crypto: T, - consensus_adapter: CA, + validators: Vec, + pub_key: Secp256k1PublicKey, + priv_key: Secp256k1PrivateKey, gossip_network: Arc, menpool_adapter: Arc, storage_adapter: Arc, ) -> Self { - let mut overlord = Overlord::new(address.as_bytes(), overlord_adapter, crypto); + let engine = ConsensusEngine::new( + chain_id, + address.clone(), + cycle_limit, + validators.clone(), + gossip_network, + menpool_adapter, + storage_adapter, + ); + + let crypto = OverlordCrypto::new(pub_key, priv_key); + + let mut overlord = Overlord::new(address.as_bytes(), engine, crypto); let overlord_handler = overlord.take_handler(); + overlord_handler + .send_msg( + Context::new(), + OverlordMsg::RichStatus(handle_genesis(init_epoch_id, validators)), + ) + .unwrap(); ConsensusProvider { - overlord: Some(overlord), - handler: overlord_handler, - adapter: consensus_adapter, - overlord_adapter: OverlordConsensusAdapter::new( - address, - cycle_limit, - gossip_network, - menpool_adapter, - storage_adapter, - ), - + overlord: Some(overlord), + handler: overlord_handler, mempool_adapter: PhantomData, storage_adapter: PhantomData, } } - pub fn take_overlord(&mut self) -> Overlord { + pub fn take_overlord(&mut self) -> OverlordRuntime { assert!(self.overlord.is_some()); self.overlord.take().unwrap() } } + +fn handle_genesis(epoch_id: u64, validators: Vec) -> Status { + let mut authority_list = validators + .into_iter() + .map(|v| Node { + address: v.address.as_bytes(), + propose_weight: v.propose_weight, + vote_weight: v.vote_weight, + }) + .collect::>(); + + authority_list.sort(); + Status { + epoch_id, + interval: None, + authority_list, + } +} diff --git a/core/consensus/src/engine.rs b/core/consensus/src/engine.rs index bf11d249f..5673455f0 100644 --- a/core/consensus/src/engine.rs +++ b/core/consensus/src/engine.rs @@ -1,6 +1,6 @@ -use std::collections::{HashMap, HashSet}; -use std::error::Error; +use std::collections::HashSet; use std::time::{SystemTime, UNIX_EPOCH}; +use std::{error::Error, sync::Arc}; use async_trait::async_trait; use bincode::serialize; @@ -10,12 +10,14 @@ use overlord::Consensus as Overlord; use parking_lot::RwLock; use rlp::Encodable; +use protocol::codec::ProtocolCodec; use protocol::traits::{ ConsensusAdapter, Context, Gossip, MemPool, MemPoolAdapter, MessageTarget, Storage, StorageAdapter, }; use protocol::types::{ - Bloom, Epoch, EpochHeader, Hash, MerkleRoot, Pill, Proof, Receipt, UserAddress, + Bloom, Epoch, EpochHeader, Fee, Hash, MerkleRoot, Pill, Proof, UserAddress, Validator, + GENESIS_EPOCH_ID, }; use protocol::ProtocolError; @@ -27,6 +29,10 @@ use crate::message::{ }; use crate::ConsensusError; +const INIT_ROUND: u64 = 0; + +/// validator is for create new epoch, and authority is for build overlord +/// status. pub struct ConsensusEngine< G: Gossip, M: MemPool, @@ -38,9 +44,9 @@ pub struct ConsensusEngine< address: UserAddress, cycle_limit: u64, exemption_hash: RwLock>, - state_root: MerkleRoot, - order_root: MerkleRoot, - header_cache: HashMap, + latest_header: RwLock, + validators: Vec, + authority: Vec, adapter: OverlordConsensusAdapter, } @@ -65,31 +71,33 @@ where .await? .clap(); - let proposal_proof = self - .adapter - .get_proof() - .ok_or_else(|| ProtocolError::from(ConsensusError::MissingProof(epoch_id)))?; + let cache = { + let header = self.latest_header.read(); - let cache = self - .header_cache - .get(&epoch_id) - .ok_or_else(|| ProtocolError::from(ConsensusError::MissingEpochHeader(epoch_id)))?; + if header.epoch_id == epoch_id { + header.clone() + } else { + return Err( + ProtocolError::from(ConsensusError::MissingEpochHeader(epoch_id)).into(), + ); + } + }; let header = EpochHeader { chain_id: self.chain_id.clone(), - pre_hash: Hash::from_empty(), + pre_hash: cache.prev_hash, epoch_id: tmp, timestamp: time_now(), logs_bloom: cache.logs_bloom, - order_root: MerkleRoot::from_empty(), - confirm_root: Vec::new(), - state_root: cache.state_root.clone(), - receipt_root: Vec::new(), - cycles_used: 0u64, + order_root: cache.order_root, + confirm_root: cache.confirm_root, + state_root: cache.state_root, + receipt_root: cache.receipt_root, + cycles_used: cache.cycles_used, proposer: self.address.clone(), - proof: proposal_proof, + proof: cache.proof, validator_version: 0u64, - validators: Vec::new(), + validators: self.validators.clone(), }; let epoch = Epoch { header, @@ -144,9 +152,11 @@ where epoch_id: u64, commit: Commit, ) -> Result> { - let pill = commit.content; + let pill = commit.content.inner; let tmp = commit.proof; - let _proof = Proof { + + // Sorage save the lastest proof. + let proof = Proof { epoch_id: tmp.epoch_id, round: tmp.round, epoch_hash: Hash::from_bytes(tmp.epoch_hash)?, @@ -154,21 +164,35 @@ where bitmap: tmp.signature.address_bitmap, }; + self.adapter.save_proof(ctx.clone(), proof).await?; + + // Get full transactions from mempool temporarily. + // Storage save the signed transactions. let full_txs = self .adapter - .get_full_txs(ctx.clone(), pill.inner.epoch.ordered_tx_hashes) + .get_full_txs(ctx.clone(), pill.epoch.ordered_tx_hashes.clone()) .await?; self.adapter .save_signed_txs(ctx.clone(), full_txs.clone()) .await?; + // Storage save the epoch. + let mut epoch = pill.epoch; + self.adapter.save_epoch(ctx.clone(), epoch.clone()).await?; + + self.adapter + .flush_mempool(ctx.clone(), epoch.ordered_tx_hashes.clone()) + .await?; + + let _prev_hash = Hash::digest(epoch.encode().await?); + // TODO: update header cache. let status = Status { epoch_id: epoch_id + 1, interval: None, - authority_list: vec![], + authority_list: self.authority.clone(), }; Ok(status) } @@ -191,6 +215,7 @@ where } _ => unreachable!(), }; + self.adapter .transmit(ctx, msg, end, MessageTarget::Broadcast) .await?; @@ -210,6 +235,7 @@ where } _ => unreachable!(), }; + self.adapter .transmit( ctx, @@ -251,35 +277,75 @@ where MA: MemPoolAdapter + 'static, SA: StorageAdapter + 'static, { - fn new( + pub fn new( chain_id: Hash, address: UserAddress, cycle_limit: u64, - adapter: OverlordConsensusAdapter, + validators: Vec, + network: Arc, + mempool: Arc, + storage: Arc, ) -> Self { + let adapter = OverlordConsensusAdapter::new(network, mempool, storage); + let mut authority = validators + .clone() + .into_iter() + .map(|v| Node { + address: v.address.as_bytes(), + propose_weight: v.propose_weight, + vote_weight: v.vote_weight, + }) + .collect::>(); + + authority.sort(); + ConsensusEngine { chain_id, address, cycle_limit, exemption_hash: RwLock::new(HashSet::new()), - state_root: Hash::from_empty(), - order_root: Hash::from_empty(), - header_cache: HashMap::new(), + latest_header: RwLock::new(HeaderCache::default()), + validators, + authority, adapter, } } } +#[derive(Clone, Debug, Hash)] struct HeaderCache { - receipts: Vec, - all_cycle_used: u64, - logs_bloom: Bloom, - state_root: MerkleRoot, + pub epoch_id: u64, + pub prev_hash: Hash, + pub logs_bloom: Bloom, + pub order_root: MerkleRoot, + pub confirm_root: Vec, + pub state_root: MerkleRoot, + pub receipt_root: Vec, + pub cycles_used: Vec, + pub proof: Proof, } -impl HeaderCache { - fn get_all_cycle_used(&self) -> u64 { - self.all_cycle_used +impl Default for HeaderCache { + fn default() -> Self { + let genesis_proof = Proof { + epoch_id: GENESIS_EPOCH_ID, + round: INIT_ROUND, + epoch_hash: Hash::from_empty(), + signature: Bytes::default(), + bitmap: Bytes::default(), + }; + + HeaderCache { + epoch_id: GENESIS_EPOCH_ID, + prev_hash: Hash::from_empty(), + logs_bloom: Bloom::zero(), + order_root: MerkleRoot::from_empty(), + confirm_root: Vec::new(), + state_root: MerkleRoot::from_empty(), + receipt_root: Vec::new(), + cycles_used: Vec::new(), + proof: genesis_proof, + } } } diff --git a/core/consensus/src/fixed_types.rs b/core/consensus/src/fixed_types.rs index 2cd56af3a..b6f85226c 100644 --- a/core/consensus/src/fixed_types.rs +++ b/core/consensus/src/fixed_types.rs @@ -8,7 +8,7 @@ use rlp::{Encodable, RlpStream}; use protocol::codec::{Deserialize, ProtocolCodecSync, Serialize}; use protocol::types::{Hash, Pill, Proof, SignedTransaction, Validator}; -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct FixedSignedTxs { #[serde(with = "core_network::serde_multi")] pub inner: Vec, @@ -44,12 +44,17 @@ impl Encodable for FixedPill { let confirm_root = header .confirm_root .iter() - .map(|mkr| mkr.as_hex()) + .map(|root| root.as_hex()) .collect::>(); let receipt_root = header .receipt_root .iter() - .map(|mkr| mkr.as_hex()) + .map(|root| root.as_hex()) + .collect::>(); + let cycles_used = header + .cycles_used + .iter() + .map(|fee| fee.encode_sync().unwrap().as_ref().to_vec()) .collect::>(); let validators = header .validators @@ -67,7 +72,7 @@ impl Encodable for FixedPill { .append_list::(&confirm_root) .append(&header.state_root.as_hex()) .append_list::(&receipt_root) - .append(&header.cycles_used) + .append_list::, Vec>(&cycles_used) .append(&header.proposer.as_hex()) .append(&FixedProof::from(header.proof.clone())) .append(&header.validator_version) @@ -137,3 +142,73 @@ impl Encodable for FixedProof { .append(&inner.signature.as_ref()); } } + +#[cfg(test)] +mod test { + use std::convert::From; + + use bytes::Bytes; + use futures::executor; + use num_traits::FromPrimitive; + use overlord::Codec; + use rand::random; + + use protocol::codec::ProtocolCodec; + use protocol::types::{ + Fee, Hash, RawTransaction, SignedTransaction, TransactionAction, UserAddress, + }; + + use super::FixedSignedTxs; + + fn gen_random_bytes(len: usize) -> Vec { + (0..len).map(|_| random::()).collect::>() + } + + fn gen_user_address() -> UserAddress { + let inner = "0x107899EE7319601cbC2684709e0eC3A4807bb0Fd74"; + UserAddress::from_hex(inner).unwrap() + } + + fn gen_signed_tx() -> SignedTransaction { + let address = gen_user_address(); + let nonce = Hash::digest(Bytes::from(gen_random_bytes(10))); + let fee = Fee { + asset_id: nonce.clone(), + cycle: random::(), + }; + let action = TransactionAction::Transfer { + receiver: address.clone(), + asset_id: nonce.clone(), + amount: FromPrimitive::from_i32(42).unwrap(), + }; + let mut raw = RawTransaction { + chain_id: nonce.clone(), + nonce, + timeout: random::(), + fee, + action, + }; + + let raw_bytes = executor::block_on(async { raw.encode().await.unwrap() }); + let tx_hash = Hash::digest(raw_bytes); + + SignedTransaction { + raw, + tx_hash, + pubkey: Bytes::from(gen_random_bytes(32)), + signature: Bytes::from(gen_random_bytes(64)), + } + } + + #[test] + fn test_codec() { + for _ in 0..10 { + let fixed_txs = FixedSignedTxs { + inner: (0..1000).map(|_| gen_signed_tx()).collect::>(), + }; + + let bytes = fixed_txs.encode().unwrap(); + assert_eq!(fixed_txs, FixedSignedTxs::decode(bytes).unwrap()); + } + } +} diff --git a/core/consensus/src/lib.rs b/core/consensus/src/lib.rs index 6e8160ce1..6bec840c3 100644 --- a/core/consensus/src/lib.rs +++ b/core/consensus/src/lib.rs @@ -1,15 +1,16 @@ -#![allow(dead_code)] - -pub mod adapter; +mod adapter; pub mod consensus; mod engine; mod fixed_types; pub mod message; +mod util; use std::error::Error; use derive_more::{Display, From}; +use common_crypto::CryptoError; + use protocol::types::Hash; use protocol::{ProtocolError, ProtocolErrorKind}; @@ -54,7 +55,7 @@ pub enum ConsensusError { /// This boxed error should be a `CryptoError`. #[display(fmt = "Crypto error {:?}", _0)] - CryptoErr(Box), + CryptoErr(Box), /// Other error used for very few errors. #[display(fmt = "{:?}", _0)] diff --git a/core/consensus/src/util.rs b/core/consensus/src/util.rs new file mode 100644 index 000000000..0bfc69f04 --- /dev/null +++ b/core/consensus/src/util.rs @@ -0,0 +1,75 @@ +use std::error::Error; + +use bytes::Bytes; +use overlord::{types::AggregatedSignature, Crypto}; + +use protocol::types::{Hash, UserAddress}; +use protocol::ProtocolError; + +use common_crypto::{ + Crypto as Secp256k1Crypto, PrivateKey, PublicKey, Secp256k1, Secp256k1PrivateKey, + Secp256k1PublicKey, Signature, +}; + +use crate::ConsensusError; + +#[derive(Clone, Debug)] +pub struct OverlordCrypto { + public_key: Secp256k1PublicKey, + private_key: Secp256k1PrivateKey, +} + +impl Crypto for OverlordCrypto { + fn hash(&self, msg: Bytes) -> Bytes { + Hash::digest(msg).as_bytes() + } + + fn sign(&self, hash: Bytes) -> Result> { + let signature = Secp256k1::sign_message(&hash, &self.private_key.to_bytes()) + .map_err(|e| ProtocolError::from(ConsensusError::CryptoErr(Box::new(e))))? + .to_bytes(); + + let mut res = self.public_key.to_bytes(); + res.extend_from_slice(&signature); + Ok(res) + } + + fn verify_signature( + &self, + mut signature: Bytes, + hash: Bytes, + ) -> Result> { + let tmp = signature.split_off(32); + let pub_key = signature; + let signature = tmp; + + Secp256k1::verify_signature(&hash, &signature, &pub_key) + .map_err(|e| ProtocolError::from(ConsensusError::CryptoErr(Box::new(e))))?; + let address = UserAddress::from_pubkey_bytes(pub_key)?; + Ok(address.as_bytes()) + } + + fn aggregate_signatures( + &self, + _signatures: Vec, + _voters: Vec, + ) -> Result> { + Ok(Bytes::new()) + } + + fn verify_aggregated_signature( + &self, + _aggregated_signature: AggregatedSignature, + ) -> Result<(), Box> { + Ok(()) + } +} + +impl OverlordCrypto { + pub fn new(public_key: Secp256k1PublicKey, private_key: Secp256k1PrivateKey) -> Self { + OverlordCrypto { + public_key, + private_key, + } + } +} diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 04ac81167..779004479 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -9,24 +9,24 @@ edition = "2018" [dependencies] protocol = { path = "../../protocol" } -tentacle = { version = "0.2", features = [ "flatc" ] } -futures-preview = { version = "0.3.0-alpha.18", features = [ "compat" ] } -log = "0.4" +async-trait = "0.1" +bincode = "1.1" +bytes = { version = "0.4", features = ["serde"] } derive_more = "0.15" -tentacle-ping = "0.3" +futures-timer = "0.3" +futures-preview = { version = "0.3.0-alpha.18", features = [ "compat" ] } generic-channel = { version = "0.2", features = [ "all" ] } -tentacle-discovery = "0.2" +log = "0.4" parking_lot = "0.9" +prost = "0.5" rand = "0.7" -futures-timer = "0.3" runtime = "0.3.0-alpha.7" -snap = "0.2" -async-trait = "0.1" -prost = "0.5" -bytes = { version = "0.4", features = ["serde"] } serde = "1.0" serde_derive = "1.0" -bincode = "1.1" +snap = "0.2" +tentacle = { version = "0.2", features = [ "flatc" ] } +tentacle-ping = { version = "0.3", features = [ "flatc" ] } +tentacle-discovery = { version = "0.2", features = [ "flatc" ] } [dev-dependencies] env_logger = "0.6" diff --git a/core/storage/src/tests/mod.rs b/core/storage/src/tests/mod.rs index f5ddd07e2..dc12b97a5 100644 --- a/core/storage/src/tests/mod.rs +++ b/core/storage/src/tests/mod.rs @@ -82,7 +82,7 @@ fn mock_epoch(epoch_id: u64, epoch_hash: Hash) -> Epoch { confirm_root: Vec::new(), state_root: nonce.clone(), receipt_root: Vec::new(), - cycles_used: 100, + cycles_used: Vec::new(), proposer: UserAddress::from_hex(addr_str).unwrap(), proof: mock_proof(epoch_hash), validator_version: 1, diff --git a/protocol/src/codec/epoch.rs b/protocol/src/codec/epoch.rs index 86df6bb3d..50ec62ff1 100644 --- a/protocol/src/codec/epoch.rs +++ b/protocol/src/codec/epoch.rs @@ -5,7 +5,7 @@ use prost::Message; use crate::{ codec::{ - primitive::{Hash, UserAddress}, + primitive::{Fee, Hash, UserAddress}, CodecError, ProtocolCodecSync, }, field, impl_default_bytes_codec_for, @@ -56,8 +56,8 @@ pub struct EpochHeader { #[prost(message, repeated, tag = "9")] pub receipt_root: Vec, - #[prost(uint64, tag = "10")] - pub cycles_used: u64, + #[prost(message, repeated, tag = "10")] + pub cycles_used: Vec, #[prost(message, tag = "11")] pub proposer: Option, @@ -180,6 +180,11 @@ impl From for EpochHeader { .into_iter() .map(Hash::from) .collect::>(); + let cycles_used = epoch_header + .cycles_used + .into_iter() + .map(Fee::from) + .collect::>(); let validators = epoch_header .validators .into_iter() @@ -196,7 +201,7 @@ impl From for EpochHeader { confirm_root, state_root, receipt_root, - cycles_used: epoch_header.cycles_used, + cycles_used, proposer, proof, validator_version: epoch_header.validator_version, @@ -226,6 +231,11 @@ impl TryFrom for epoch::EpochHeader { receipt_root.push(protocol_primitive::Hash::try_from(root)?); } + let mut cycles_used = Vec::new(); + for fee in epoch_header.cycles_used { + cycles_used.push(protocol_primitive::Fee::try_from(fee)?); + } + let mut validators = Vec::new(); for validator in epoch_header.validators { validators.push(epoch::Validator::try_from(validator)?); @@ -241,7 +251,7 @@ impl TryFrom for epoch::EpochHeader { confirm_root, state_root: protocol_primitive::Hash::try_from(state_root)?, receipt_root, - cycles_used: epoch_header.cycles_used, + cycles_used, proposer: protocol_primitive::UserAddress::try_from(proposer)?, proof: epoch::Proof::try_from(proof)?, validator_version: epoch_header.validator_version, diff --git a/protocol/src/codec/tests/mod.rs b/protocol/src/codec/tests/mod.rs index bc2c95b78..d2c9e91a5 100644 --- a/protocol/src/codec/tests/mod.rs +++ b/protocol/src/codec/tests/mod.rs @@ -204,7 +204,7 @@ fn mock_epoch_header() -> EpochHeader { confirm_root: vec![mock_hash(), mock_hash()], state_root: mock_merkle_root(), receipt_root: vec![mock_hash(), mock_hash()], - cycles_used: 10, + cycles_used: Vec::new(), proposer: mock_account_address(), proof: mock_proof(), validator_version: 1, diff --git a/protocol/src/traits/consensus.rs b/protocol/src/traits/consensus.rs index 9a5c54de1..4d9bfc50e 100644 --- a/protocol/src/traits/consensus.rs +++ b/protocol/src/traits/consensus.rs @@ -79,6 +79,9 @@ pub trait ConsensusAdapter: Send + Sync { /// Save some receipts to the database. async fn save_receipts(&self, ctx: Context, receipts: Vec) -> ProtocolResult<()>; + /// + async fn save_proof(&self, ctx: Context, proof: Proof) -> ProtocolResult<()>; + /// Save some signed transactions to the database. async fn save_signed_txs( &self, diff --git a/protocol/src/types/epoch.rs b/protocol/src/types/epoch.rs index 5af6b5d49..b62209e00 100644 --- a/protocol/src/types/epoch.rs +++ b/protocol/src/types/epoch.rs @@ -1,6 +1,6 @@ use bytes::Bytes; -use crate::types::{Bloom, Hash, MerkleRoot, UserAddress}; +use crate::types::{Bloom, Fee, Hash, MerkleRoot, UserAddress}; #[derive(Clone, Debug)] pub struct Epoch { @@ -19,14 +19,14 @@ pub struct EpochHeader { pub confirm_root: Vec, pub state_root: MerkleRoot, pub receipt_root: Vec, - pub cycles_used: u64, + pub cycles_used: Vec, pub proposer: UserAddress, pub proof: Proof, pub validator_version: u64, pub validators: Vec, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Hash)] pub struct Proof { pub epoch_id: u64, pub round: u64, diff --git a/protocol/src/types/primitive.rs b/protocol/src/types/primitive.rs index 056ac000b..daabe7b9b 100644 --- a/protocol/src/types/primitive.rs +++ b/protocol/src/types/primitive.rs @@ -281,7 +281,7 @@ pub struct Asset { pub storage_root: MerkleRoot, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Fee { pub asset_id: AssetID, pub cycle: u64, diff --git a/protocol/src/types/transaction.rs b/protocol/src/types/transaction.rs index 070ca0909..bdbc8f5b1 100644 --- a/protocol/src/types/transaction.rs +++ b/protocol/src/types/transaction.rs @@ -4,7 +4,7 @@ use crate::types::primitive::{ AssetID, Balance, ContractAddress, ContractType, Fee, Hash, UserAddress, }; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct RawTransaction { pub chain_id: Hash, pub nonce: Hash, @@ -13,7 +13,7 @@ pub struct RawTransaction { pub action: TransactionAction, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum TransactionAction { Transfer { receiver: UserAddress, @@ -38,7 +38,7 @@ pub enum TransactionAction { }, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct SignedTransaction { pub raw: RawTransaction, pub tx_hash: Hash,