From 0df672b3296dc95f8997ca509459c092d49e6d98 Mon Sep 17 00:00:00 2001 From: austinabell Date: Fri, 16 Oct 2020 19:59:14 -0400 Subject: [PATCH 01/13] setup versioning and upgrade testing logic --- crypto/src/randomness.rs | 3 +- tests/conformance_tests/Cargo.toml | 1 + tests/conformance_tests/src/lib.rs | 65 ++++++--- tests/conformance_tests/src/message.rs | 7 +- tests/conformance_tests/src/rand_replay.rs | 67 +++++++++ tests/conformance_tests/src/tipset.rs | 5 +- tests/conformance_tests/test-vectors | 2 +- .../tests/conformance_runner.rs | 133 +++++++++++------- vm/interpreter/src/default_runtime.rs | 2 +- 9 files changed, 206 insertions(+), 79 deletions(-) create mode 100644 tests/conformance_tests/src/rand_replay.rs diff --git a/crypto/src/randomness.rs b/crypto/src/randomness.rs index eed5e6617963..8347ef33d6f7 100644 --- a/crypto/src/randomness.rs +++ b/crypto/src/randomness.rs @@ -1,11 +1,12 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT +use encoding::repr::*; use num_derive::FromPrimitive; use num_traits::FromPrimitive; /// Specifies a domain for randomness generation. -#[derive(PartialEq, Eq, Copy, Clone, FromPrimitive, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, FromPrimitive, Debug, Hash, Deserialize_repr)] #[repr(i64)] pub enum DomainSeparationTag { TicketProduction = 1, diff --git a/tests/conformance_tests/Cargo.toml b/tests/conformance_tests/Cargo.toml index e0df43c5ae40..2c9347671df8 100644 --- a/tests/conformance_tests/Cargo.toml +++ b/tests/conformance_tests/Cargo.toml @@ -5,6 +5,7 @@ authors = ["ChainSafe Systems "] edition = "2018" [features] +default = ["submodule_tests"] submodule_tests = [ "serde", "cid", diff --git a/tests/conformance_tests/src/lib.rs b/tests/conformance_tests/src/lib.rs index 49aecc99c376..91be5a6553ae 100644 --- a/tests/conformance_tests/src/lib.rs +++ b/tests/conformance_tests/src/lib.rs @@ -1,13 +1,15 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -#![cfg(feature = "submodule_tests")] +// #![cfg(feature = "submodule_tests")] mod message; +mod rand_replay; mod stubs; mod tipset; pub use self::message::*; +pub use self::rand_replay::*; pub use self::stubs::*; pub use self::tipset::*; use actor::CHAOS_ACTOR_CODE_ID; @@ -16,7 +18,7 @@ use blockstore::BlockStore; use cid::Cid; use clock::ChainEpoch; use crypto::{DomainSeparationTag, Signature}; -use encoding::Cbor; +use encoding::{tuple::*, Cbor}; use fil_types::{SealVerifyInfo, WindowPoStVerifyInfo}; use forest_message::{ChainMessage, Message, MessageReceipt, SignedMessage, UnsignedMessage}; use interpreter::{ApplyRet, BlockMessages, Rand, VM}; @@ -86,7 +88,7 @@ pub struct StateTreeVector { pub root_cid: Cid, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Clone)] pub struct GenerationData { #[serde(default)] pub source: String, @@ -94,7 +96,7 @@ pub struct GenerationData { pub version: String, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Clone)] pub struct MetaData { pub id: String, #[serde(default)] @@ -108,10 +110,11 @@ pub struct MetaData { #[derive(Debug, Deserialize)] pub struct PreConditions { - pub epoch: ChainEpoch, pub state_tree: StateTreeVector, #[serde(default)] pub basefee: Option, + #[serde(default)] + pub variants: Vec, } #[derive(Debug, Deserialize)] @@ -129,6 +132,43 @@ pub struct Selector { pub puppet_actor: Option, #[serde(default)] pub chaos_actor: Option, + #[serde(default)] + pub min_protocol_version: Option, +} + +#[derive(Debug, Deserialize)] +pub struct Variant { + pub id: String, + pub epoch: ChainEpoch, + pub nv: u32, +} + +/// Encoded VM randomness used to be replayed. +pub type Randomness = Vec; + +/// One randomness entry. +#[derive(Debug, Deserialize)] +pub struct RandomnessMatch { + pub on: RandomnessRule, + #[serde(with = "base64_bytes")] + pub ret: Vec, +} + +#[derive(Debug, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum RandomnessKind { + Beacon, + Chain, +} + +/// Rule for matching when randomness is returned. +#[derive(Debug, Deserialize_tuple, PartialEq)] +pub struct RandomnessRule { + pub kind: RandomnessKind, + pub dst: DomainSeparationTag, + pub epoch: ChainEpoch, + #[serde(with = "base64_bytes")] + pub entropy: Vec, } #[derive(Debug, Deserialize)] @@ -145,12 +185,9 @@ pub enum TestVector { preconditions: PreConditions, apply_messages: Vec, postconditions: PostConditions, - }, - #[serde(rename = "block")] - Block { - selector: Option, - #[serde(rename = "_meta")] - meta: Option, + + #[serde(default)] + randomness: Randomness, }, #[serde(rename = "tipset")] Tipset { @@ -164,12 +201,6 @@ pub enum TestVector { apply_tipsets: Vec, postconditions: PostConditions, }, - #[serde(rename = "chain")] - Chain { - selector: Option, - #[serde(rename = "_meta")] - meta: Option, - }, } // This might be changed to be encoded into vector, matching go runner for now diff --git a/tests/conformance_tests/src/message.rs b/tests/conformance_tests/src/message.rs index 641157e441a9..8d4191a9537b 100644 --- a/tests/conformance_tests/src/message.rs +++ b/tests/conformance_tests/src/message.rs @@ -10,23 +10,24 @@ pub struct MessageVector { #[serde(with = "base64_bytes")] pub bytes: Vec, #[serde(default)] - pub epoch: Option, + pub epoch_offset: Option, } -pub fn execute_message( +pub fn execute_message<'a>( bs: &db::MemoryDB, msg: &ChainMessage, pre_root: &Cid, epoch: ChainEpoch, basefee: TokenAmount, selector: &Option, + randomness: ReplayingRand<'a>, ) -> Result<(ApplyRet, Cid), Box> { let mut vm = VM::<_, _, _, _>::new( pre_root, bs, epoch, TestSyscalls, - &TestRand, + &randomness, basefee, get_network_version_default, )?; diff --git a/tests/conformance_tests/src/rand_replay.rs b/tests/conformance_tests/src/rand_replay.rs new file mode 100644 index 000000000000..78c1cc8891c6 --- /dev/null +++ b/tests/conformance_tests/src/rand_replay.rs @@ -0,0 +1,67 @@ +use super::*; + +pub struct ReplayingRand<'a> { + pub recorded: &'a Randomness, + pub fallback: TestRand, +} + +impl<'a> ReplayingRand<'a> { + pub fn new(recorded: &'a Randomness) -> Self { + Self { + recorded, + fallback: TestRand, + } + } + + pub fn matches(&self, requested: RandomnessRule) -> Option<[u8; 32]> { + for other in self.recorded { + if other.on == requested { + let mut randomness = [0u8; 32]; + randomness.copy_from_slice(&other.ret); + return Some(randomness); + } + } + None + } +} + +impl Rand for ReplayingRand<'_> { + fn get_chain_randomness( + &self, + db: &DB, + dst: DomainSeparationTag, + epoch: ChainEpoch, + entropy: &[u8], + ) -> Result<[u8; 32], Box> { + let rule = RandomnessRule { + kind: RandomnessKind::Chain, + dst, + epoch, + entropy: entropy.to_vec(), + }; + if let Some(bz) = self.matches(rule) { + Ok(bz) + } else { + self.fallback.get_chain_randomness(db, dst, epoch, entropy) + } + } + fn get_beacon_randomness( + &self, + db: &DB, + dst: DomainSeparationTag, + epoch: ChainEpoch, + entropy: &[u8], + ) -> Result<[u8; 32], Box> { + let rule = RandomnessRule { + kind: RandomnessKind::Beacon, + dst, + epoch, + entropy: entropy.to_vec(), + }; + if let Some(bz) = self.matches(rule) { + Ok(bz) + } else { + self.fallback.get_beacon_randomness(db, dst, epoch, entropy) + } + } +} diff --git a/tests/conformance_tests/src/tipset.rs b/tests/conformance_tests/src/tipset.rs index 4bf74478834d..dea9aa62f746 100644 --- a/tests/conformance_tests/src/tipset.rs +++ b/tests/conformance_tests/src/tipset.rs @@ -56,7 +56,7 @@ mod block_messages_json { #[derive(Debug, Deserialize)] pub struct TipsetVector { - pub epoch: ChainEpoch, + pub epoch_offset: ChainEpoch, pub basefee: f64, #[serde(with = "block_messages_json")] pub blocks: Vec, @@ -74,6 +74,7 @@ pub fn execute_tipset( pre_root: &Cid, parent_epoch: ChainEpoch, tipset: &TipsetVector, + exec_epoch: ChainEpoch, ) -> Result> { let sm = StateManager::new(bs); let mut _applied_messages = Vec::new(); @@ -82,7 +83,7 @@ pub fn execute_tipset( parent_epoch, pre_root, &tipset.blocks, - tipset.epoch, + exec_epoch, &TestRand, tipset.basefee.to_bigint().unwrap_or_default(), Some(|_, msg: &ChainMessage, ret| { diff --git a/tests/conformance_tests/test-vectors b/tests/conformance_tests/test-vectors index 75f517e3666c..d9a75a7873ae 160000 --- a/tests/conformance_tests/test-vectors +++ b/tests/conformance_tests/test-vectors @@ -1 +1 @@ -Subproject commit 75f517e3666cd6f10430de62430eb5354cb6276a +Subproject commit d9a75a7873aee0db28b87e3970d2ea16a2f37c6a diff --git a/tests/conformance_tests/tests/conformance_runner.rs b/tests/conformance_tests/tests/conformance_runner.rs index 40719fdfbb2c..23725695a16b 100644 --- a/tests/conformance_tests/tests/conformance_runner.rs +++ b/tests/conformance_tests/tests/conformance_runner.rs @@ -1,7 +1,7 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -#![cfg(feature = "submodule_tests")] +// #![cfg(feature = "submodule_tests")] #[macro_use] extern crate lazy_static; @@ -9,6 +9,7 @@ extern crate lazy_static; use address::Address; use blockstore::resolve::resolve_cids_recursive; use cid::{json::CidJson, Cid}; +use clock::ChainEpoch; use colored::*; use conformance_tests::*; use difference::{Changeset, Difference}; @@ -229,34 +230,37 @@ fn compare_state_roots(bs: &db::MemoryDB, root: &Cid, expected_root: &Cid) -> Re } fn execute_message_vector( - selector: Option, - car: Vec, - preconditions: PreConditions, - apply_messages: Vec, - postconditions: PostConditions, + selector: &Option, + car: &[u8], + root_cid: Cid, + base_fee: Option, + apply_messages: &[MessageVector], + postconditions: &PostConditions, + randomness: &Randomness, + variant: &Variant, ) -> Result<(), Box> { - let bs = load_car(car.as_slice())?; + let bs = load_car(car)?; - let mut epoch = preconditions.epoch; - let mut root = preconditions.state_tree.root_cid; + let mut base_epoch: ChainEpoch = variant.epoch; + let mut root = root_cid; for (i, m) in apply_messages.iter().enumerate() { let msg = UnsignedMessage::unmarshal_cbor(&m.bytes)?; - if let Some(ep) = m.epoch { - epoch = ep; + if let Some(ep) = m.epoch_offset { + base_epoch += ep; } let (ret, post_root) = execute_message( &bs, &to_chain_msg(msg), &root, - epoch, - preconditions - .basefee + base_epoch, + base_fee .map(|i| i.to_bigint().unwrap()) .unwrap_or(DEFAULT_BASE_FEE.clone()), &selector, + ReplayingRand::new(randomness), )?; root = post_root; @@ -270,25 +274,28 @@ fn execute_message_vector( } fn execute_tipset_vector( - _selector: Option, - car: Vec, - preconditions: PreConditions, - tipsets: Vec, - postconditions: PostConditions, + _selector: &Option, + car: &[u8], + root_cid: Cid, + tipsets: &[TipsetVector], + postconditions: &PostConditions, + variant: &Variant, ) -> Result<(), Box> { - let bs = Arc::new(load_car(car.as_slice())?); + let bs = Arc::new(load_car(car)?); - let mut prev_epoch = preconditions.epoch; - let mut root = preconditions.state_tree.root_cid; + let base_epoch = variant.epoch; + let mut root = root_cid; let mut receipt_idx = 0; + let mut prev_epoch = base_epoch; for (i, ts) in tipsets.into_iter().enumerate() { + let exec_epoch = base_epoch + ts.epoch_offset; let ExecuteTipsetResult { receipts_root, post_state_root, applied_results, .. - } = execute_tipset(Arc::clone(&bs), &root, prev_epoch, &ts)?; + } = execute_tipset(Arc::clone(&bs), &root, prev_epoch, &ts, exec_epoch)?; for (j, apply_ret) in applied_results.into_iter().enumerate() { check_msg_result( @@ -309,7 +316,7 @@ fn execute_tipset_vector( .into()); } - prev_epoch = ts.epoch; + prev_epoch = exec_epoch; root = post_state_root; } @@ -328,13 +335,7 @@ fn conformance_test_runner() { let file = File::open(entry.path()).unwrap(); let reader = BufReader::new(file); let test_name = entry.path().display(); - let vector: TestVector = match serde_json::from_reader(reader) { - Ok(v) => v, - Err(e) => { - log::warn!("Could not deserialize vector: {}", e); - continue; - } - }; + let vector: TestVector = serde_json::from_reader(reader).unwrap(); match vector { TestVector::Message { @@ -344,18 +345,32 @@ fn conformance_test_runner() { preconditions, apply_messages, postconditions, + randomness, } => { - if let Err(e) = execute_message_vector( - selector, - car, - preconditions, - apply_messages, - postconditions, - ) { - failed.push((test_name.to_string(), meta, e)); - } else { - println!("{} succeeded", test_name); - succeeded += 1; + for variant in preconditions.variants { + if variant.nv > 3 { + // Skip v2 upgrade and above + continue; + } + if let Err(e) = execute_message_vector( + &selector, + &car, + preconditions.state_tree.root_cid.clone(), + preconditions.basefee, + &apply_messages, + &postconditions, + &randomness, + &variant, + ) { + failed.push(( + format!("{} variant {}", test_name, variant.id), + meta.clone(), + e, + )); + } else { + println!("{} succeeded", test_name); + succeeded += 1; + } } } TestVector::Tipset { @@ -366,20 +381,30 @@ fn conformance_test_runner() { apply_tipsets, postconditions, } => { - if let Err(e) = execute_tipset_vector( - selector, - car, - preconditions, - apply_tipsets, - postconditions, - ) { - failed.push((test_name.to_string(), meta, e)); - } else { - println!("{} succeeded", test_name); - succeeded += 1; + for variant in preconditions.variants { + if variant.nv > 3 { + // Skip v2 upgrade and above + continue; + } + if let Err(e) = execute_tipset_vector( + &selector, + &car, + preconditions.state_tree.root_cid.clone(), + &apply_tipsets, + &postconditions, + &variant, + ) { + failed.push(( + format!("{} variant {}", test_name, variant.id), + meta.clone(), + e, + )); + } else { + println!("{} succeeded", test_name); + succeeded += 1; + } } } - _ => panic!("Unsupported test vector class"), } } diff --git a/vm/interpreter/src/default_runtime.rs b/vm/interpreter/src/default_runtime.rs index 9bbc7e7da524..e0db1511bd04 100644 --- a/vm/interpreter/src/default_runtime.rs +++ b/vm/interpreter/src/default_runtime.rs @@ -427,7 +427,7 @@ where ) -> Result { let r = self .rand - .get_chain_randomness(&self.store, personalization, rand_epoch, entropy) + .get_beacon_randomness(&self.store, personalization, rand_epoch, entropy) .map_err(|e| e.downcast_fatal("could not get randomness"))?; Ok(Randomness(r)) From 3470c1b90ca3d68d901f31ef3b01007e4ee8f0c3 Mon Sep 17 00:00:00 2001 From: austinabell Date: Fri, 16 Oct 2020 21:23:35 -0400 Subject: [PATCH 02/13] Update vectors to handle circ supply param --- Cargo.lock | 28 +------------ blockchain/state_manager/src/lib.rs | 3 ++ tests/conformance_tests/src/lib.rs | 2 + tests/conformance_tests/src/message.rs | 27 +++++++----- .../tests/conformance_runner.rs | 25 +++++++---- vm/interpreter/src/default_runtime.rs | 42 +++++++++++-------- vm/interpreter/src/vm.rs | 10 ++++- vm/interpreter/tests/transfer_test.rs | 1 + 8 files changed, 74 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 002ad66676e1..c82db78bba62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2120,7 +2120,7 @@ dependencies = [ "forest_car", "forest_cid", "forest_libp2p", - "futures 0.3.5", + "futures 0.3.6", "genesis", "hex", "ipld_blockstore", @@ -2673,32 +2673,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "graphsync" -version = "0.1.0" -dependencies = [ - "async-std", - "async-trait", - "bytes", - "fnv", - "forest_cid", - "forest_encoding", - "forest_ipld", - "futures 0.3.5", - "futures-util", - "futures_codec", - "ipld_blockstore", - "libp2p", - "log", - "multihash 0.10.1", - "protobuf", - "protoc-rust", - "rand 0.7.3", - "serde", - "smallvec", - "unsigned-varint 0.5.1", -] - [[package]] name = "groupy" version = "0.3.1" diff --git a/blockchain/state_manager/src/lib.rs b/blockchain/state_manager/src/lib.rs index 82c6d0178bc6..0b34ca47e047 100644 --- a/blockchain/state_manager/src/lib.rs +++ b/blockchain/state_manager/src/lib.rs @@ -204,6 +204,7 @@ where rand, base_fee, get_network_version_default, + None, )?; // Apply tipset messages @@ -284,6 +285,7 @@ where rand, 0.into(), get_network_version_default, + None, )?; if msg.gas_limit() == 0 { @@ -360,6 +362,7 @@ where &chain_rand, ts.blocks()[0].parent_base_fee().clone(), get_network_version_default, + None, )?; for msg in prior_messages { diff --git a/tests/conformance_tests/src/lib.rs b/tests/conformance_tests/src/lib.rs index 91be5a6553ae..a7decdfcd3c4 100644 --- a/tests/conformance_tests/src/lib.rs +++ b/tests/conformance_tests/src/lib.rs @@ -114,6 +114,8 @@ pub struct PreConditions { #[serde(default)] pub basefee: Option, #[serde(default)] + pub circ_supply: Option, + #[serde(default)] pub variants: Vec, } diff --git a/tests/conformance_tests/src/message.rs b/tests/conformance_tests/src/message.rs index 8d4191a9537b..481e53110cb0 100644 --- a/tests/conformance_tests/src/message.rs +++ b/tests/conformance_tests/src/message.rs @@ -13,23 +13,30 @@ pub struct MessageVector { pub epoch_offset: Option, } +pub struct ExecuteMessageParams<'a> { + pub pre_root: &'a Cid, + pub epoch: ChainEpoch, + pub msg: &'a ChainMessage, + pub circ_supply: TokenAmount, + pub basefee: TokenAmount, + pub randomness: ReplayingRand<'a>, +} + pub fn execute_message<'a>( bs: &db::MemoryDB, - msg: &ChainMessage, - pre_root: &Cid, - epoch: ChainEpoch, - basefee: TokenAmount, selector: &Option, - randomness: ReplayingRand<'a>, + params: ExecuteMessageParams, ) -> Result<(ApplyRet, Cid), Box> { + let circ_supply = params.circ_supply; let mut vm = VM::<_, _, _, _>::new( - pre_root, + params.pre_root, bs, - epoch, + params.epoch, TestSyscalls, - &randomness, - basefee, + ¶ms.randomness, + params.basefee, get_network_version_default, + Some(Box::new(move |_, _| Ok(circ_supply.clone()))), )?; if let Some(s) = &selector { @@ -42,7 +49,7 @@ pub fn execute_message<'a>( } } - let ret = vm.apply_message(msg)?; + let ret = vm.apply_message(params.msg)?; let root = vm.flush()?; Ok((ret, root)) diff --git a/tests/conformance_tests/tests/conformance_runner.rs b/tests/conformance_tests/tests/conformance_runner.rs index 23725695a16b..b2fdb31c8787 100644 --- a/tests/conformance_tests/tests/conformance_runner.rs +++ b/tests/conformance_tests/tests/conformance_runner.rs @@ -14,7 +14,7 @@ use colored::*; use conformance_tests::*; use difference::{Changeset, Difference}; use encoding::Cbor; -use fil_types::HAMT_BIT_WIDTH; +use fil_types::{HAMT_BIT_WIDTH, TOTAL_FILECOIN}; use flate2::read::GzDecoder; use forest_message::{MessageReceipt, UnsignedMessage}; use interpreter::ApplyRet; @@ -34,7 +34,7 @@ use vm::ActorState; use walkdir::{DirEntry, WalkDir}; lazy_static! { - static ref DEFAULT_BASE_FEE: BigInt = 100.to_bigint().unwrap(); + static ref DEFAULT_BASE_FEE: BigInt = BigInt::from(100); static ref SKIP_TESTS: Vec = vec![ Regex::new(r"test-vectors/corpus/vm_violations/x--").unwrap(), Regex::new(r"test-vectors/corpus/nested/x--").unwrap(), @@ -234,6 +234,7 @@ fn execute_message_vector( car: &[u8], root_cid: Cid, base_fee: Option, + circ_supply: Option, apply_messages: &[MessageVector], postconditions: &PostConditions, randomness: &Randomness, @@ -253,14 +254,19 @@ fn execute_message_vector( let (ret, post_root) = execute_message( &bs, - &to_chain_msg(msg), - &root, - base_epoch, - base_fee - .map(|i| i.to_bigint().unwrap()) - .unwrap_or(DEFAULT_BASE_FEE.clone()), &selector, - ReplayingRand::new(randomness), + ExecuteMessageParams { + pre_root: &root, + epoch: base_epoch, + msg: &to_chain_msg(msg), + circ_supply: circ_supply + .map(|i| i.to_bigint().unwrap()) + .unwrap_or(TOTAL_FILECOIN.clone()), + basefee: base_fee + .map(|i| i.to_bigint().unwrap()) + .unwrap_or(DEFAULT_BASE_FEE.clone()), + randomness: ReplayingRand::new(randomness), + }, )?; root = post_root; @@ -357,6 +363,7 @@ fn conformance_test_runner() { &car, preconditions.state_tree.root_cid.clone(), preconditions.basefee, + preconditions.circ_supply, &apply_messages, &postconditions, &randomness, diff --git a/vm/interpreter/src/default_runtime.rs b/vm/interpreter/src/default_runtime.rs index e0db1511bd04..44a153bdbe1c 100644 --- a/vm/interpreter/src/default_runtime.rs +++ b/vm/interpreter/src/default_runtime.rs @@ -4,6 +4,7 @@ use super::gas_block_store::GasBlockStore; use super::gas_syscalls::GasSyscalls; use super::gas_tracker::{price_list_by_epoch, GasCharge, GasTracker, PriceList}; +use super::CircSupplyCalc; use super::Rand; use actor::*; use address::{Address, Protocol}; @@ -57,11 +58,11 @@ impl MessageInfo for VMMsg { } /// Implementation of the Runtime trait. -pub struct DefaultRuntime<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P = DevnetParams> { +pub struct DefaultRuntime<'db, 'vm, BS, SYS, R, P = DevnetParams> { version: NetworkVersion, - state: &'st mut StateTree<'db, BS>, + state: &'vm mut StateTree<'db, BS>, store: GasBlockStore<'db, BS>, - syscalls: GasSyscalls<'sys, SYS>, + syscalls: GasSyscalls<'vm, SYS>, gas_tracker: Rc>, vm_msg: VMMsg, epoch: ChainEpoch, @@ -69,15 +70,15 @@ pub struct DefaultRuntime<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P = DevnetParams origin_nonce: u64, num_actors_created: u64, price_list: PriceList, - rand: &'r R, + rand: &'vm R, caller_validated: bool, allow_internal: bool, - registered_actors: &'act HashSet, + registered_actors: &'vm HashSet, + circ_supply_calc: &'vm Option>, params: PhantomData

, } -impl<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P> - DefaultRuntime<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P> +impl<'db, 'vm, BS, SYS, R, P> DefaultRuntime<'db, 'vm, BS, SYS, R, P> where BS: BlockStore, SYS: Syscalls, @@ -88,17 +89,18 @@ where #[allow(clippy::too_many_arguments)] pub fn new( version: NetworkVersion, - state: &'st mut StateTree<'db, BS>, + state: &'vm mut StateTree<'db, BS>, store: &'db BS, - syscalls: &'sys SYS, + syscalls: &'vm SYS, gas_used: i64, message: &UnsignedMessage, epoch: ChainEpoch, origin: Address, origin_nonce: u64, num_actors_created: u64, - rand: &'r R, - registered_actors: &'act HashSet, + rand: &'vm R, + registered_actors: &'vm HashSet, + circ_supply_calc: &'vm Option>, ) -> Result { let price_list = price_list_by_epoch(epoch); let gas_tracker = Rc::new(RefCell::new(GasTracker::new(message.gas_limit(), gas_used))); @@ -140,6 +142,7 @@ where price_list, rand, registered_actors, + circ_supply_calc, allow_internal: true, caller_validated: false, params: PhantomData, @@ -334,8 +337,7 @@ where } } -impl<'bs, BS, SYS, R, P> Runtime> - for DefaultRuntime<'bs, '_, '_, '_, '_, BS, SYS, R, P> +impl<'bs, BS, SYS, R, P> Runtime> for DefaultRuntime<'bs, '_, BS, SYS, R, P> where BS: BlockStore, SYS: Syscalls, @@ -599,6 +601,12 @@ where &self.syscalls } fn total_fil_circ_supply(&self) -> Result { + if let Some(circ_supply_calc) = self.circ_supply_calc.as_ref() { + // TODO all circ supply calculations should go through trait and not only override + return circ_supply_calc(self.epoch, &self.state).map_err(|e| { + actor_error!(ErrIllegalState, "failed to get total circ supply: {}", e) + }); + } let get_actor_state = |addr: &Address| -> Result { self.state .get_actor(&addr) @@ -643,8 +651,8 @@ where /// Shared logic between the DefaultRuntime and the Interpreter. /// It invokes methods on different Actors based on the Message. -pub fn vm_send<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P>( - rt: &mut DefaultRuntime<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P>, +pub fn vm_send<'db, 'vm, BS, SYS, R, P>( + rt: &mut DefaultRuntime<'db, 'vm, BS, SYS, R, P>, msg: &UnsignedMessage, gas_cost: Option, ) -> Result @@ -751,8 +759,8 @@ fn transfer( } /// Calls actor code with method and parameters. -fn invoke<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P>( - rt: &mut DefaultRuntime<'db, 'st, 'sys, 'r, 'act, BS, SYS, R, P>, +fn invoke<'db, 'vm, BS, SYS, R, P>( + rt: &mut DefaultRuntime<'db, 'vm, BS, SYS, R, P>, code: Cid, method_num: MethodNum, params: &Serialized, diff --git a/vm/interpreter/src/vm.rs b/vm/interpreter/src/vm.rs index 8946d39beb1d..df7ab6dc88d5 100644 --- a/vm/interpreter/src/vm.rs +++ b/vm/interpreter/src/vm.rs @@ -37,6 +37,10 @@ pub struct BlockMessages { pub win_count: i64, } +// TODO replace with some trait or some generic solution (needs to use context) +pub type CircSupplyCalc = + Box) -> Result>; + /// Interpreter which handles execution of state transitioning messages and returns receipts /// from the vm execution. pub struct VM<'db, 'r, DB, SYS, R, N, P = DevnetParams> { @@ -48,6 +52,7 @@ pub struct VM<'db, 'r, DB, SYS, R, N, P = DevnetParams> { base_fee: BigInt, registered_actors: HashSet, network_version_getter: N, + circ_supply_calc: Option>, params: PhantomData

, } @@ -67,6 +72,7 @@ where rand: &'r R, base_fee: BigInt, network_version_getter: N, + circ_supply_calc: Option>, ) -> Result { let state = StateTree::new_from_root(store, root).map_err(|e| e.to_string())?; let registered_actors = HashSet::new(); @@ -79,6 +85,7 @@ where rand, base_fee, registered_actors, + circ_supply_calc, params: PhantomData, }) } @@ -476,7 +483,7 @@ where gas_cost: Option, ) -> ( Serialized, - Option>, + Option>, Option, ) { let res = DefaultRuntime::new( @@ -492,6 +499,7 @@ where 0, self.rand, &self.registered_actors, + &self.circ_supply_calc, ); match res { diff --git a/vm/interpreter/tests/transfer_test.rs b/vm/interpreter/tests/transfer_test.rs index a941ee8dbff8..5f90bc92de26 100644 --- a/vm/interpreter/tests/transfer_test.rs +++ b/vm/interpreter/tests/transfer_test.rs @@ -109,6 +109,7 @@ fn transfer_test() { 0, &dummy_rand, ®istered, + &None ) .unwrap(); let _serialized = vm_send(&mut runtime, &message, None).unwrap(); From fa6d45e661f9ba9715b25ca1fc7187e60b17506f Mon Sep 17 00:00:00 2001 From: austinabell Date: Mon, 19 Oct 2020 13:00:47 -0400 Subject: [PATCH 03/13] Update test skips --- tests/conformance_tests/tests/conformance_runner.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/conformance_tests/tests/conformance_runner.rs b/tests/conformance_tests/tests/conformance_runner.rs index b2fdb31c8787..4ee84418b11c 100644 --- a/tests/conformance_tests/tests/conformance_runner.rs +++ b/tests/conformance_tests/tests/conformance_runner.rs @@ -56,9 +56,13 @@ lazy_static! { // Extracted miner faults Regex::new(r"fil_1_storageminer-DeclareFaults-Ok-3").unwrap(), Regex::new(r"fil_1_storageminer-DeclareFaults-Ok-7").unwrap(), + Regex::new(r"fil_1_storageminer-SubmitWindowedPoSt").unwrap(), - // Extracted market faults - Regex::new(r"fil_1_storagemarket-PublishStorageDeals-").unwrap(), + // Other faults (related to versioning, randomness, ) + Regex::new(r"paych--update-ok--genesis").unwrap(), + Regex::new(r"paych--collect-ok--").unwrap(), + Regex::new(r"actor_exec--msg-apply-fail-actor-execution-illegal-arg--genesis").unwrap(), + Regex::new(r"fail-insufficient-funds-for-transfer-in-inner-send--genesis").unwrap(), ]; } From eadbe61862cf0d5d3a2c06e7ecf72474225eeae8 Mon Sep 17 00:00:00 2001 From: austinabell Date: Mon, 19 Oct 2020 15:13:09 -0400 Subject: [PATCH 04/13] reset feature usage --- tests/conformance_tests/Cargo.toml | 2 +- tests/conformance_tests/src/lib.rs | 2 +- tests/conformance_tests/tests/conformance_runner.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conformance_tests/Cargo.toml b/tests/conformance_tests/Cargo.toml index 2c9347671df8..6337cf210da6 100644 --- a/tests/conformance_tests/Cargo.toml +++ b/tests/conformance_tests/Cargo.toml @@ -5,7 +5,7 @@ authors = ["ChainSafe Systems "] edition = "2018" [features] -default = ["submodule_tests"] +default = [] submodule_tests = [ "serde", "cid", diff --git a/tests/conformance_tests/src/lib.rs b/tests/conformance_tests/src/lib.rs index a7decdfcd3c4..385bb6472978 100644 --- a/tests/conformance_tests/src/lib.rs +++ b/tests/conformance_tests/src/lib.rs @@ -1,7 +1,7 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -// #![cfg(feature = "submodule_tests")] +#![cfg(feature = "submodule_tests")] mod message; mod rand_replay; diff --git a/tests/conformance_tests/tests/conformance_runner.rs b/tests/conformance_tests/tests/conformance_runner.rs index 4ee84418b11c..f098ee91af53 100644 --- a/tests/conformance_tests/tests/conformance_runner.rs +++ b/tests/conformance_tests/tests/conformance_runner.rs @@ -1,7 +1,7 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -// #![cfg(feature = "submodule_tests")] +#![cfg(feature = "submodule_tests")] #[macro_use] extern crate lazy_static; From 171c3f12d03783f0afb88802e3ea05e9836d9828 Mon Sep 17 00:00:00 2001 From: austinabell Date: Mon, 19 Oct 2020 15:18:03 -0400 Subject: [PATCH 05/13] lint --- vm/interpreter/src/vm.rs | 1 + vm/interpreter/tests/transfer_test.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/vm/interpreter/src/vm.rs b/vm/interpreter/src/vm.rs index df7ab6dc88d5..805e41047e7c 100644 --- a/vm/interpreter/src/vm.rs +++ b/vm/interpreter/src/vm.rs @@ -43,6 +43,7 @@ pub type CircSupplyCalc = /// Interpreter which handles execution of state transitioning messages and returns receipts /// from the vm execution. +#[allow(clippy::too_many_arguments)] pub struct VM<'db, 'r, DB, SYS, R, N, P = DevnetParams> { state: StateTree<'db, DB>, store: &'db DB, diff --git a/vm/interpreter/tests/transfer_test.rs b/vm/interpreter/tests/transfer_test.rs index 5f90bc92de26..16cc0fe8adb6 100644 --- a/vm/interpreter/tests/transfer_test.rs +++ b/vm/interpreter/tests/transfer_test.rs @@ -109,7 +109,7 @@ fn transfer_test() { 0, &dummy_rand, ®istered, - &None + &None, ) .unwrap(); let _serialized = vm_send(&mut runtime, &message, None).unwrap(); From a8f8a6c0e6684f54742e99081d8d496e0d03090e Mon Sep 17 00:00:00 2001 From: austinabell Date: Mon, 19 Oct 2020 15:21:28 -0400 Subject: [PATCH 06/13] header --- tests/conformance_tests/src/rand_replay.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/conformance_tests/src/rand_replay.rs b/tests/conformance_tests/src/rand_replay.rs index 78c1cc8891c6..5b111b6f68a9 100644 --- a/tests/conformance_tests/src/rand_replay.rs +++ b/tests/conformance_tests/src/rand_replay.rs @@ -1,3 +1,6 @@ +// Copyright 2020 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + use super::*; pub struct ReplayingRand<'a> { From 53033de828ffcaab17c942dd0a62f1c0f3d7d6eb Mon Sep 17 00:00:00 2001 From: austinabell Date: Mon, 19 Oct 2020 15:35:13 -0400 Subject: [PATCH 07/13] oops --- vm/interpreter/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/interpreter/src/vm.rs b/vm/interpreter/src/vm.rs index 805e41047e7c..77dbce41badd 100644 --- a/vm/interpreter/src/vm.rs +++ b/vm/interpreter/src/vm.rs @@ -43,7 +43,6 @@ pub type CircSupplyCalc = /// Interpreter which handles execution of state transitioning messages and returns receipts /// from the vm execution. -#[allow(clippy::too_many_arguments)] pub struct VM<'db, 'r, DB, SYS, R, N, P = DevnetParams> { state: StateTree<'db, DB>, store: &'db DB, @@ -65,6 +64,7 @@ where R: Rand, N: Fn(ChainEpoch) -> NetworkVersion, { + #[allow(clippy::too_many_arguments)] pub fn new( root: &Cid, store: &'db DB, From 011d7e30b0008f68369f37b64db9ad0ac88f6eb5 Mon Sep 17 00:00:00 2001 From: austinabell Date: Mon, 19 Oct 2020 16:07:37 -0400 Subject: [PATCH 08/13] lint feature --- tests/conformance_tests/src/message.rs | 2 +- tests/conformance_tests/src/rand_replay.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conformance_tests/src/message.rs b/tests/conformance_tests/src/message.rs index 481e53110cb0..34590d325d25 100644 --- a/tests/conformance_tests/src/message.rs +++ b/tests/conformance_tests/src/message.rs @@ -22,7 +22,7 @@ pub struct ExecuteMessageParams<'a> { pub randomness: ReplayingRand<'a>, } -pub fn execute_message<'a>( +pub fn execute_message( bs: &db::MemoryDB, selector: &Option, params: ExecuteMessageParams, diff --git a/tests/conformance_tests/src/rand_replay.rs b/tests/conformance_tests/src/rand_replay.rs index 5b111b6f68a9..8c7753fac723 100644 --- a/tests/conformance_tests/src/rand_replay.rs +++ b/tests/conformance_tests/src/rand_replay.rs @@ -4,12 +4,12 @@ use super::*; pub struct ReplayingRand<'a> { - pub recorded: &'a Randomness, + pub recorded: &'a [RandomnessMatch], pub fallback: TestRand, } impl<'a> ReplayingRand<'a> { - pub fn new(recorded: &'a Randomness) -> Self { + pub fn new(recorded: &'a [RandomnessMatch]) -> Self { Self { recorded, fallback: TestRand, From 25c5f055e652fee4db0dfabd3e313b4a997f0c78 Mon Sep 17 00:00:00 2001 From: austinabell Date: Mon, 19 Oct 2020 18:24:02 -0400 Subject: [PATCH 09/13] Refactor runtime, get rid of gas syscalls and default syscalls --- blockchain/state_manager/src/lib.rs | 13 +- tests/conformance_tests/src/message.rs | 5 +- .../tests/conformance_runner.rs | 5 +- vm/interpreter/src/default_runtime.rs | 265 ++++++++++++++++-- vm/interpreter/src/default_syscalls.rs | 201 ------------- vm/interpreter/src/gas_syscalls.rs | 185 ------------ vm/interpreter/src/lib.rs | 4 +- vm/interpreter/src/vm.rs | 20 +- vm/interpreter/tests/transfer_test.rs | 7 +- vm/runtime/src/lib.rs | 67 +++-- 10 files changed, 291 insertions(+), 481 deletions(-) delete mode 100644 vm/interpreter/src/default_syscalls.rs delete mode 100644 vm/interpreter/src/gas_syscalls.rs diff --git a/blockchain/state_manager/src/lib.rs b/blockchain/state_manager/src/lib.rs index 0b34ca47e047..a962796a649c 100644 --- a/blockchain/state_manager/src/lib.rs +++ b/blockchain/state_manager/src/lib.rs @@ -20,9 +20,7 @@ use flo_stream::Subscriber; use forest_blocks::{BlockHeader, Tipset, TipsetKeys}; use futures::channel::oneshot; use futures::stream::{FuturesUnordered, StreamExt}; -use interpreter::{ - resolve_to_key_addr, ApplyRet, BlockMessages, ChainRand, DefaultSyscalls, Rand, VM, -}; +use interpreter::{resolve_to_key_addr, ApplyRet, BlockMessages, ChainRand, Rand, VM}; use ipld_amt::Amt; use log::{trace, warn}; use message::{message_receipt, unsigned_message}; @@ -196,11 +194,10 @@ where { let mut buf_store = BufferedBlockStore::new(self.bs.as_ref()); // TODO change from statically using devnet params when needed - let mut vm = VM::<_, _, _, _>::new( + let mut vm = VM::<_, _, _, V>::new( p_state, &buf_store, epoch, - DefaultSyscalls::<_, V>::new(&buf_store), rand, base_fee, get_network_version_default, @@ -277,11 +274,10 @@ where span!("state_call_raw", { let block_store = self.blockstore(); let buf_store = BufferedBlockStore::new(block_store); - let mut vm = VM::<_, _, _, _>::new( + let mut vm = VM::<_, _, _, V>::new( bstate, &buf_store, *bheight, - DefaultSyscalls::<_, V>::new(&buf_store), rand, 0.into(), get_network_version_default, @@ -354,11 +350,10 @@ where .map_err(|_| Error::Other("Could not load tipset state".to_string()))?; let chain_rand = ChainRand::new(ts.key().to_owned()); - let mut vm = VM::<_, _, _, _>::new( + let mut vm = VM::<_, _, _, V>::new( &st, self.bs.as_ref(), ts.epoch() + 1, - DefaultSyscalls::<_, V>::new(self.bs.as_ref()), &chain_rand, ts.blocks()[0].parent_base_fee().clone(), get_network_version_default, diff --git a/tests/conformance_tests/src/message.rs b/tests/conformance_tests/src/message.rs index 34590d325d25..73819f33730a 100644 --- a/tests/conformance_tests/src/message.rs +++ b/tests/conformance_tests/src/message.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::*; -use fil_types::get_network_version_default; +use fil_types::{get_network_version_default, verifier::MockVerifier}; use vm::TokenAmount; #[derive(Debug, Deserialize)] @@ -28,11 +28,10 @@ pub fn execute_message( params: ExecuteMessageParams, ) -> Result<(ApplyRet, Cid), Box> { let circ_supply = params.circ_supply; - let mut vm = VM::<_, _, _, _>::new( + let mut vm = VM::<_, _, _, MockVerifier>::new( params.pre_root, bs, params.epoch, - TestSyscalls, ¶ms.randomness, params.basefee, get_network_version_default, diff --git a/tests/conformance_tests/tests/conformance_runner.rs b/tests/conformance_tests/tests/conformance_runner.rs index f098ee91af53..1ae74d72e3af 100644 --- a/tests/conformance_tests/tests/conformance_runner.rs +++ b/tests/conformance_tests/tests/conformance_runner.rs @@ -58,10 +58,7 @@ lazy_static! { Regex::new(r"fil_1_storageminer-DeclareFaults-Ok-7").unwrap(), Regex::new(r"fil_1_storageminer-SubmitWindowedPoSt").unwrap(), - // Other faults (related to versioning, randomness, ) - Regex::new(r"paych--update-ok--genesis").unwrap(), - Regex::new(r"paych--collect-ok--").unwrap(), - Regex::new(r"actor_exec--msg-apply-fail-actor-execution-illegal-arg--genesis").unwrap(), + // Other fault Regex::new(r"fail-insufficient-funds-for-transfer-in-inner-send--genesis").unwrap(), ]; } diff --git a/vm/interpreter/src/default_runtime.rs b/vm/interpreter/src/default_runtime.rs index 44a153bdbe1c..f9661c9cb8b8 100644 --- a/vm/interpreter/src/default_runtime.rs +++ b/vm/interpreter/src/default_runtime.rs @@ -2,28 +2,32 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::gas_block_store::GasBlockStore; -use super::gas_syscalls::GasSyscalls; use super::gas_tracker::{price_list_by_epoch, GasCharge, GasTracker, PriceList}; -use super::CircSupplyCalc; -use super::Rand; +use super::{CircSupplyCalc, Rand}; use actor::*; use address::{Address, Protocol}; +use blocks::BlockHeader; use byteorder::{BigEndian, WriteBytesExt}; use cid::{multihash::Blake2b256, Cid}; use clock::ChainEpoch; -use crypto::DomainSeparationTag; -use fil_types::{DevnetParams, NetworkParams, NetworkVersion, Randomness}; -use forest_encoding::to_vec; -use forest_encoding::Cbor; +use crypto::{DomainSeparationTag, Signature}; +use fil_types::{verifier::ProofVerifier, DevnetParams, NetworkParams, NetworkVersion, Randomness}; +use fil_types::{PieceInfo, RegisteredSealProof, SealVerifyInfo, WindowPoStVerifyInfo}; +use forest_encoding::{blake2b_256, to_vec, Cbor}; use ipld_blockstore::BlockStore; use log::warn; use message::{Message, UnsignedMessage}; use num_bigint::BigInt; use num_traits::Zero; -use runtime::{ActorCode, MessageInfo, Runtime, Syscalls}; +use rayon::prelude::*; +use runtime::{ + compute_unsealed_sector_cid, ActorCode, ConsensusFault, ConsensusFaultType, MessageInfo, + Runtime, Syscalls, +}; use state_tree::StateTree; use std::cell::RefCell; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; +use std::error::Error as StdError; use std::marker::PhantomData; use std::rc::Rc; use vm::{ @@ -58,11 +62,10 @@ impl MessageInfo for VMMsg { } /// Implementation of the Runtime trait. -pub struct DefaultRuntime<'db, 'vm, BS, SYS, R, P = DevnetParams> { +pub struct DefaultRuntime<'db, 'vm, BS, R, V, P = DevnetParams> { version: NetworkVersion, state: &'vm mut StateTree<'db, BS>, store: GasBlockStore<'db, BS>, - syscalls: GasSyscalls<'vm, SYS>, gas_tracker: Rc>, vm_msg: VMMsg, epoch: ChainEpoch, @@ -75,13 +78,14 @@ pub struct DefaultRuntime<'db, 'vm, BS, SYS, R, P = DevnetParams> { allow_internal: bool, registered_actors: &'vm HashSet, circ_supply_calc: &'vm Option>, + verifier: PhantomData, params: PhantomData

, } -impl<'db, 'vm, BS, SYS, R, P> DefaultRuntime<'db, 'vm, BS, SYS, R, P> +impl<'db, 'vm, BS, R, V, P> DefaultRuntime<'db, 'vm, BS, R, V, P> where BS: BlockStore, - SYS: Syscalls, + V: ProofVerifier, P: NetworkParams, R: Rand, { @@ -91,7 +95,6 @@ where version: NetworkVersion, state: &'vm mut StateTree<'db, BS>, store: &'db BS, - syscalls: &'vm SYS, gas_used: i64, message: &UnsignedMessage, epoch: ChainEpoch, @@ -109,11 +112,11 @@ where gas: Rc::clone(&gas_tracker), store, }; - let gas_syscalls = GasSyscalls { - price_list: price_list.clone(), - gas: Rc::clone(&gas_tracker), - syscalls, - }; + // let gas_syscalls = GasSyscalls { + // price_list: price_list.clone(), + // gas: Rc::clone(&gas_tracker), + // syscalls, + // }; let caller_id = state .lookup_id(&message.from()) @@ -132,7 +135,6 @@ where version, state, store: gas_block_store, - syscalls: gas_syscalls, gas_tracker, vm_msg, epoch, @@ -146,6 +148,7 @@ where allow_internal: true, caller_validated: false, params: PhantomData, + verifier: PhantomData, }) } @@ -276,7 +279,7 @@ where }; self.caller_validated = false; - let send_res = vm_send::(self, &msg, None); + let send_res = vm_send::(self, &msg, None); // Reset values back to their values before the call self.vm_msg = prev_msg; @@ -335,12 +338,29 @@ where Ok(act) } + + fn verify_block_signature(&self, bh: &BlockHeader) -> Result<(), Box> { + let actor = self + .state + .get_actor(bh.miner_address())? + .ok_or_else(|| format!("actor not found {:?}", bh.miner_address()))?; + + let ms: miner::State = self + .store + .get(&actor.state)? + .ok_or_else(|| format!("actor state not found {:?}", actor.state.to_string()))?; + + let info = ms.get_info(&self.store)?; + let work_address = resolve_to_key_addr(&self.state, &self.store, &info.worker)?; + bh.check_block_signature(&work_address)?; + Ok(()) + } } -impl<'bs, BS, SYS, R, P> Runtime> for DefaultRuntime<'bs, '_, BS, SYS, R, P> +impl<'bs, BS, R, V, P> Runtime> for DefaultRuntime<'bs, '_, BS, R, V, P> where BS: BlockStore, - SYS: Syscalls, + V: ProofVerifier, P: NetworkParams, R: Rand, { @@ -598,7 +618,7 @@ where .map_err(|e| e.downcast_fatal("failed to delete actor")) } fn syscalls(&self) -> &dyn Syscalls { - &self.syscalls + self } fn total_fil_circ_supply(&self) -> Result { if let Some(circ_supply_calc) = self.circ_supply_calc.as_ref() { @@ -649,16 +669,201 @@ where } } +impl<'bs, BS, R, V, P> Syscalls for DefaultRuntime<'bs, '_, BS, R, V, P> +where + BS: BlockStore, + V: ProofVerifier, + P: NetworkParams, + R: Rand, +{ + fn verify_signature( + &self, + signature: &Signature, + signer: &Address, + plaintext: &[u8], + ) -> Result<(), Box> { + self.gas_tracker.borrow_mut().charge_gas( + self.price_list + .on_verify_signature(signature.signature_type()), + )?; + + // Resolve to key address before verifying signature. + let signing_addr = resolve_to_key_addr(self.state, &self.store, signer)?; + Ok(signature.verify(plaintext, &signing_addr)?) + } + fn hash_blake2b(&self, data: &[u8]) -> Result<[u8; 32], Box> { + self.gas_tracker + .borrow_mut() + .charge_gas(self.price_list.on_hashing(data.len()))?; + + Ok(blake2b_256(data)) + } + fn compute_unsealed_sector_cid( + &self, + reg: RegisteredSealProof, + pieces: &[PieceInfo], + ) -> Result> { + self.gas_tracker + .borrow_mut() + .charge_gas(self.price_list.on_compute_unsealed_sector_cid(reg, pieces))?; + + compute_unsealed_sector_cid(reg, pieces) + } + fn verify_seal(&self, vi: &SealVerifyInfo) -> Result<(), Box> { + self.gas_tracker + .borrow_mut() + .charge_gas(self.price_list.on_verify_seal(vi))?; + + V::verify_seal(vi) + } + fn verify_post(&self, vi: &WindowPoStVerifyInfo) -> Result<(), Box> { + self.gas_tracker + .borrow_mut() + .charge_gas(self.price_list.on_verify_post(vi))?; + + V::verify_window_post(vi.randomness, &vi.proofs, &vi.challenged_sectors, vi.prover) + } + fn verify_consensus_fault( + &self, + h1: &[u8], + h2: &[u8], + extra: &[u8], + ) -> Result, Box> { + self.gas_tracker + .borrow_mut() + .charge_gas(self.price_list.on_verify_consensus_fault())?; + + // Note that block syntax is not validated. Any validly signed block will be accepted pursuant to the below conditions. + // Whether or not it could ever have been accepted in a chain is not checked/does not matter here. + // for that reason when checking block parent relationships, rather than instantiating a Tipset to do so + // (which runs a syntactic check), we do it directly on the CIDs. + + // (0) cheap preliminary checks + + if h1 == h2 { + return Err(format!( + "no consensus fault: submitted blocks are the same: {:?}, {:?}", + h1, h2 + ) + .into()); + }; + let bh_1 = BlockHeader::unmarshal_cbor(h1)?; + let bh_2 = BlockHeader::unmarshal_cbor(h2)?; + + // (1) check conditions necessary to any consensus fault + + if bh_1.miner_address() != bh_2.miner_address() { + return Err(format!( + "no consensus fault: blocks not mined by same miner: {:?}, {:?}", + bh_1.miner_address(), + bh_2.miner_address() + ) + .into()); + }; + // block a must be earlier or equal to block b, epoch wise (ie at least as early in the chain). + if bh_1.epoch() < bh_2.epoch() { + return Err(format!( + "first block must not be of higher height than second: {:?}, {:?}", + bh_1.epoch(), + bh_2.epoch() + ) + .into()); + }; + let mut cf: Option = None; + // (a) double-fork mining fault + if bh_1.epoch() == bh_2.epoch() { + cf = Some(ConsensusFault { + target: *bh_1.miner_address(), + epoch: bh_2.epoch(), + fault_type: ConsensusFaultType::DoubleForkMining, + }) + }; + // (b) time-offset mining fault + // strictly speaking no need to compare heights based on double fork mining check above, + // but at same height this would be a different fault. + if bh_1.parents() != bh_2.parents() && bh_1.epoch() != bh_2.epoch() { + cf = Some(ConsensusFault { + target: *bh_1.miner_address(), + epoch: bh_2.epoch(), + fault_type: ConsensusFaultType::TimeOffsetMining, + }) + }; + // (c) parent-grinding fault + // Here extra is the "witness", a third block that shows the connection between A and B as + // A's sibling and B's parent. + // Specifically, since A is of lower height, it must be that B was mined omitting A from its tipset + if !extra.is_empty() { + let bh_3 = BlockHeader::unmarshal_cbor(extra)?; + if bh_1.parents() != bh_3.parents() + && bh_1.epoch() != bh_3.epoch() + && bh_2.parents().cids().contains(bh_3.cid()) + && !bh_2.parents().cids().contains(bh_1.cid()) + { + cf = Some(ConsensusFault { + target: *bh_1.miner_address(), + epoch: bh_2.epoch(), + fault_type: ConsensusFaultType::ParentGrinding, + }) + } + }; + + // (3) return if no consensus fault by now + if cf.is_none() { + Ok(cf) + } else { + // (4) expensive final checks + + // check blocks are properly signed by their respective miner + // note we do not need to check extra's: it is a parent to block b + // which itself is signed, so it was willingly included by the miner + self.verify_block_signature(&bh_1)?; + self.verify_block_signature(&bh_2)?; + + Ok(cf) + } + } + + fn batch_verify_seals( + &self, + vis: &[(Address, &Vec)], + ) -> Result>, Box> { + // Gas charged for batch verify in actor + + // TODO ideal to not use rayon https://github.com/ChainSafe/forest/issues/676 + let out = vis + .par_iter() + .map(|(addr, seals)| { + let results = seals + .par_iter() + .map(|s| { + if let Err(err) = V::verify_seal(s) { + warn!( + "seal verify in batch failed (miner: {}) (err: {})", + addr, err + ); + false + } else { + true + } + }) + .collect(); + (*addr, results) + }) + .collect(); + Ok(out) + } +} + /// Shared logic between the DefaultRuntime and the Interpreter. /// It invokes methods on different Actors based on the Message. -pub fn vm_send<'db, 'vm, BS, SYS, R, P>( - rt: &mut DefaultRuntime<'db, 'vm, BS, SYS, R, P>, +pub fn vm_send<'db, 'vm, BS, R, V, P>( + rt: &mut DefaultRuntime<'db, 'vm, BS, R, V, P>, msg: &UnsignedMessage, gas_cost: Option, ) -> Result where BS: BlockStore, - SYS: Syscalls, + V: ProofVerifier, P: NetworkParams, R: Rand, { @@ -759,8 +964,8 @@ fn transfer( } /// Calls actor code with method and parameters. -fn invoke<'db, 'vm, BS, SYS, R, P>( - rt: &mut DefaultRuntime<'db, 'vm, BS, SYS, R, P>, +fn invoke<'db, 'vm, BS, R, V, P>( + rt: &mut DefaultRuntime<'db, 'vm, BS, R, V, P>, code: Cid, method_num: MethodNum, params: &Serialized, @@ -768,7 +973,7 @@ fn invoke<'db, 'vm, BS, SYS, R, P>( ) -> Result where BS: BlockStore, - SYS: Syscalls, + V: ProofVerifier, P: NetworkParams, R: Rand, { diff --git a/vm/interpreter/src/default_syscalls.rs b/vm/interpreter/src/default_syscalls.rs deleted file mode 100644 index 5b38dacc01b4..000000000000 --- a/vm/interpreter/src/default_syscalls.rs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2020 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use crate::resolve_to_key_addr; -use actor::miner; -use address::Address; -use blocks::BlockHeader; -use fil_types::{verifier::ProofVerifier, SealVerifyInfo, WindowPoStVerifyInfo}; -use forest_encoding::from_slice; -use ipld_blockstore::BlockStore; -use log::warn; -use rayon::prelude::*; -use runtime::{ConsensusFault, ConsensusFaultType, Syscalls}; -use state_tree::StateTree; -use std::marker::PhantomData; -use std::{collections::HashMap, error::Error as StdError}; - -/// Default syscalls information -pub struct DefaultSyscalls<'bs, BS, V> { - store: &'bs BS, - verifier: PhantomData, -} - -impl<'bs, BS, V> DefaultSyscalls<'bs, BS, V> { - pub fn new(store: &'bs BS) -> Self { - Self { - store, - verifier: Default::default(), - } - } -} - -impl<'bs, BS, V> Syscalls for DefaultSyscalls<'bs, BS, V> -where - BS: BlockStore, - V: ProofVerifier, -{ - fn verify_consensus_fault( - &self, - h1: &[u8], - h2: &[u8], - extra: &[u8], - ) -> Result, Box> { - // Note that block syntax is not validated. Any validly signed block will be accepted pursuant to the below conditions. - // Whether or not it could ever have been accepted in a chain is not checked/does not matter here. - // for that reason when checking block parent relationships, rather than instantiating a Tipset to do so - // (which runs a syntactic check), we do it directly on the CIDs. - - // (0) cheap preliminary checks - - if h1 == h2 { - return Err(format!( - "no consensus fault: submitted blocks are the same: {:?}, {:?}", - h1, h2 - ) - .into()); - }; - let bh_1: BlockHeader = from_slice(h1)?; - let bh_2: BlockHeader = from_slice(h2)?; - - // (1) check conditions necessary to any consensus fault - - if bh_1.miner_address() != bh_2.miner_address() { - return Err(format!( - "no consensus fault: blocks not mined by same miner: {:?}, {:?}", - bh_1.miner_address(), - bh_2.miner_address() - ) - .into()); - }; - // block a must be earlier or equal to block b, epoch wise (ie at least as early in the chain). - if bh_1.epoch() < bh_2.epoch() { - return Err(format!( - "first block must not be of higher height than second: {:?}, {:?}", - bh_1.epoch(), - bh_2.epoch() - ) - .into()); - }; - let mut cf: Option = None; - // (a) double-fork mining fault - if bh_1.epoch() == bh_2.epoch() { - cf = Some(ConsensusFault { - target: *bh_1.miner_address(), - epoch: bh_2.epoch(), - fault_type: ConsensusFaultType::DoubleForkMining, - }) - }; - // (b) time-offset mining fault - // strictly speaking no need to compare heights based on double fork mining check above, - // but at same height this would be a different fault. - if bh_1.parents() != bh_2.parents() && bh_1.epoch() != bh_2.epoch() { - cf = Some(ConsensusFault { - target: *bh_1.miner_address(), - epoch: bh_2.epoch(), - fault_type: ConsensusFaultType::TimeOffsetMining, - }) - }; - // (c) parent-grinding fault - // Here extra is the "witness", a third block that shows the connection between A and B as - // A's sibling and B's parent. - // Specifically, since A is of lower height, it must be that B was mined omitting A from its tipset - if !extra.is_empty() { - let bh_3: BlockHeader = from_slice(extra)?; - if bh_1.parents() != bh_3.parents() - && bh_1.epoch() != bh_3.epoch() - && bh_2.parents().cids().contains(bh_3.cid()) - && !bh_2.parents().cids().contains(bh_1.cid()) - { - cf = Some(ConsensusFault { - target: *bh_1.miner_address(), - epoch: bh_2.epoch(), - fault_type: ConsensusFaultType::ParentGrinding, - }) - } - }; - - // (3) return if no consensus fault by now - if cf.is_none() { - Ok(cf) - } else { - // (4) expensive final checks - - // check blocks are properly signed by their respective miner - // note we do not need to check extra's: it is a parent to block b - // which itself is signed, so it was willingly included by the miner - self.verify_block_signature(&bh_1)?; - self.verify_block_signature(&bh_2)?; - - Ok(cf) - } - } - - fn verify_seal(&self, vi: &SealVerifyInfo) -> Result<(), Box> { - V::verify_seal(vi) - } - - fn verify_post( - &self, - WindowPoStVerifyInfo { - randomness, - proofs, - challenged_sectors, - prover, - }: &WindowPoStVerifyInfo, - ) -> Result<(), Box> { - V::verify_window_post(*randomness, &proofs, challenged_sectors, *prover) - } - - fn batch_verify_seals( - &self, - vis: &[(Address, &Vec)], - ) -> Result>, Box> { - // TODO ideal to not use rayon https://github.com/ChainSafe/forest/issues/676 - let out = vis - .par_iter() - .map(|(addr, seals)| { - let results = seals - .par_iter() - .map(|s| { - if let Err(err) = V::verify_seal(s) { - warn!( - "seal verify in batch failed (miner: {}) (err: {})", - addr, err - ); - false - } else { - true - } - }) - .collect(); - (*addr, results) - }) - .collect(); - Ok(out) - } -} - -impl<'bs, BS, V> DefaultSyscalls<'bs, BS, V> -where - BS: BlockStore, -{ - fn verify_block_signature(&self, bh: &BlockHeader) -> Result<(), Box> { - // TODO look into attaching StateTree to DefaultSyscalls - let state = StateTree::new_from_root(self.store, bh.state_root())?; - - let actor = state - .get_actor(bh.miner_address())? - .ok_or_else(|| format!("actor not found {:?}", bh.miner_address()))?; - - let ms: miner::State = self - .store - .get(&actor.state)? - .ok_or_else(|| format!("actor state not found {:?}", actor.state.to_string()))?; - - let info = ms.get_info(self.store)?; - let work_address = resolve_to_key_addr(&state, self.store, &info.worker)?; - bh.check_block_signature(&work_address)?; - Ok(()) - } -} diff --git a/vm/interpreter/src/gas_syscalls.rs b/vm/interpreter/src/gas_syscalls.rs deleted file mode 100644 index cb4fbdd379a9..000000000000 --- a/vm/interpreter/src/gas_syscalls.rs +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2020 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use super::gas_tracker::{GasTracker, PriceList}; -use address::Address; -use cid::Cid; -use crypto::Signature; -use fil_types::{PieceInfo, RegisteredSealProof, SealVerifyInfo, WindowPoStVerifyInfo}; -use runtime::{ConsensusFault, Syscalls}; -use std::cell::RefCell; -use std::collections::HashMap; -use std::error::Error as StdError; -use std::rc::Rc; - -/// Syscall wrapper to charge gas on syscalls -pub(crate) struct GasSyscalls<'sys, S> { - pub price_list: PriceList, - pub gas: Rc>, - pub syscalls: &'sys S, -} - -impl<'sys, S> Syscalls for GasSyscalls<'sys, S> -where - S: Syscalls, -{ - fn verify_signature( - &self, - signature: &Signature, - signer: &Address, - plaintext: &[u8], - ) -> Result<(), Box> { - self.gas.borrow_mut().charge_gas( - self.price_list - .on_verify_signature(signature.signature_type()), - )?; - self.syscalls.verify_signature(signature, signer, plaintext) - } - fn hash_blake2b(&self, data: &[u8]) -> Result<[u8; 32], Box> { - self.gas - .borrow_mut() - .charge_gas(self.price_list.on_hashing(data.len()))?; - self.syscalls.hash_blake2b(data) - } - fn compute_unsealed_sector_cid( - &self, - reg: RegisteredSealProof, - pieces: &[PieceInfo], - ) -> Result> { - self.gas - .borrow_mut() - .charge_gas(self.price_list.on_compute_unsealed_sector_cid(reg, pieces))?; - self.syscalls.compute_unsealed_sector_cid(reg, pieces) - } - fn verify_seal(&self, vi: &SealVerifyInfo) -> Result<(), Box> { - self.gas - .borrow_mut() - .charge_gas(self.price_list.on_verify_seal(vi))?; - self.syscalls.verify_seal(vi) - } - fn verify_post(&self, vi: &WindowPoStVerifyInfo) -> Result<(), Box> { - self.gas - .borrow_mut() - .charge_gas(self.price_list.on_verify_post(vi))?; - self.syscalls.verify_post(vi) - } - fn verify_consensus_fault( - &self, - h1: &[u8], - h2: &[u8], - extra: &[u8], - ) -> Result, Box> { - self.gas - .borrow_mut() - .charge_gas(self.price_list.on_verify_consensus_fault())?; - self.syscalls.verify_consensus_fault(h1, h2, extra) - } - - fn batch_verify_seals( - &self, - vis: &[(Address, &Vec)], - ) -> Result>, Box> { - // Gas charged for batch verify in actor - self.syscalls.batch_verify_seals(vis) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use runtime::{ConsensusFault, ConsensusFaultType, Syscalls}; - - #[derive(Copy, Debug, Clone)] - struct TestSyscalls; - impl Syscalls for TestSyscalls { - fn verify_signature( - &self, - _signature: &Signature, - _signer: &Address, - _plaintext: &[u8], - ) -> Result<(), Box> { - Ok(()) - } - fn hash_blake2b(&self, _data: &[u8]) -> Result<[u8; 32], Box> { - Ok([0u8; 32]) - } - fn compute_unsealed_sector_cid( - &self, - _reg: RegisteredSealProof, - _pieces: &[PieceInfo], - ) -> Result> { - Ok(Default::default()) - } - fn verify_seal(&self, _vi: &SealVerifyInfo) -> Result<(), Box> { - Ok(Default::default()) - } - fn verify_post(&self, _vi: &WindowPoStVerifyInfo) -> Result<(), Box> { - Ok(Default::default()) - } - fn verify_consensus_fault( - &self, - _h1: &[u8], - _h2: &[u8], - _extra: &[u8], - ) -> Result, Box> { - Ok(Some(ConsensusFault { - target: Address::new_id(0), - epoch: 0, - fault_type: ConsensusFaultType::DoubleForkMining, - })) - } - fn batch_verify_seals( - &self, - _vis: &[(Address, &Vec)], - ) -> Result>, Box> { - Ok(Default::default()) - } - } - - #[test] - fn gas_syscalls() { - let gsys = GasSyscalls { - price_list: PriceList { - on_chain_message_compute_base: 1, - on_chain_message_storage_per_byte: 1, - on_chain_return_value_per_byte: 1, - hashing_base: 2, - compute_unsealed_sector_cid_base: 1, - bls_sig_cost: 5, - verify_seal_base: 1, - verify_consensus_fault: 1, - ..Default::default() - }, - gas: Rc::new(RefCell::new(GasTracker::new(20, 0))), - syscalls: &TestSyscalls, - }; - - assert_eq!(gsys.gas.borrow().gas_used(), 0); - gsys.verify_signature(&Default::default(), &Address::new_id(0), &[0u8]) - .unwrap(); - assert_eq!(gsys.gas.borrow().gas_used(), 5); - - gsys.hash_blake2b(&[0u8]).unwrap(); - assert_eq!(gsys.gas.borrow().gas_used(), 7); - - gsys.compute_unsealed_sector_cid(RegisteredSealProof::from(0), &[]) - .unwrap(); - assert_eq!(gsys.gas.borrow().gas_used(), 8); - - gsys.verify_seal(&SealVerifyInfo { - registered_proof: RegisteredSealProof::from(1), - sector_id: Default::default(), - deal_ids: Vec::new(), - randomness: Default::default(), - interactive_randomness: Default::default(), - proof: Default::default(), - sealed_cid: Default::default(), - unsealed_cid: Default::default(), - }) - .unwrap(); - assert_eq!(gsys.gas.borrow().gas_used(), 9); - - gsys.verify_consensus_fault(&[], &[], &[]).unwrap(); - assert_eq!(gsys.gas.borrow().gas_used(), 10); - } -} diff --git a/vm/interpreter/src/lib.rs b/vm/interpreter/src/lib.rs index 8cf81536b987..57b86c0fc04a 100644 --- a/vm/interpreter/src/lib.rs +++ b/vm/interpreter/src/lib.rs @@ -5,14 +5,12 @@ extern crate lazy_static; mod default_runtime; -mod default_syscalls; mod gas_block_store; -mod gas_syscalls; mod gas_tracker; mod rand; mod vm; + pub use self::default_runtime::*; -pub use self::default_syscalls::DefaultSyscalls; pub use self::gas_tracker::*; pub use self::rand::*; pub use self::vm::*; diff --git a/vm/interpreter/src/vm.rs b/vm/interpreter/src/vm.rs index 77dbce41badd..0db7b8d2ccae 100644 --- a/vm/interpreter/src/vm.rs +++ b/vm/interpreter/src/vm.rs @@ -12,14 +12,16 @@ use actor::{ use address::Address; use cid::Cid; use clock::ChainEpoch; -use fil_types::{DevnetParams, NetworkParams, NetworkVersion}; +use fil_types::{ + verifier::{FullVerifier, ProofVerifier}, + DevnetParams, NetworkParams, NetworkVersion, +}; use forest_encoding::Cbor; use ipld_blockstore::BlockStore; use log::warn; use message::{ChainMessage, Message, MessageReceipt, UnsignedMessage}; use num_bigint::{BigInt, Sign}; use num_traits::Zero; -use runtime::Syscalls; use state_tree::StateTree; use std::collections::HashSet; use std::convert::TryFrom; @@ -43,23 +45,23 @@ pub type CircSupplyCalc = /// Interpreter which handles execution of state transitioning messages and returns receipts /// from the vm execution. -pub struct VM<'db, 'r, DB, SYS, R, N, P = DevnetParams> { +pub struct VM<'db, 'r, DB, R, N, V = FullVerifier, P = DevnetParams> { state: StateTree<'db, DB>, store: &'db DB, epoch: ChainEpoch, - syscalls: SYS, rand: &'r R, base_fee: BigInt, registered_actors: HashSet, network_version_getter: N, circ_supply_calc: Option>, + verifier: PhantomData, params: PhantomData

, } -impl<'db, 'r, DB, SYS, R, N, P> VM<'db, 'r, DB, SYS, R, N, P> +impl<'db, 'r, DB, R, N, V, P> VM<'db, 'r, DB, R, N, V, P> where DB: BlockStore, - SYS: Syscalls, + V: ProofVerifier, P: NetworkParams, R: Rand, N: Fn(ChainEpoch) -> NetworkVersion, @@ -69,7 +71,6 @@ where root: &Cid, store: &'db DB, epoch: ChainEpoch, - syscalls: SYS, rand: &'r R, base_fee: BigInt, network_version_getter: N, @@ -82,11 +83,11 @@ where state, store, epoch, - syscalls, rand, base_fee, registered_actors, circ_supply_calc, + verifier: PhantomData, params: PhantomData, }) } @@ -484,14 +485,13 @@ where gas_cost: Option, ) -> ( Serialized, - Option>, + Option>, Option, ) { let res = DefaultRuntime::new( (self.network_version_getter)(self.epoch), &mut self.state, self.store, - &self.syscalls, 0, &msg, self.epoch, diff --git a/vm/interpreter/tests/transfer_test.rs b/vm/interpreter/tests/transfer_test.rs index 16cc0fe8adb6..a40bf3530075 100644 --- a/vm/interpreter/tests/transfer_test.rs +++ b/vm/interpreter/tests/transfer_test.rs @@ -7,7 +7,7 @@ use blocks::TipsetKeys; use cid::multihash::{Blake2b256, Identity}; use db::MemoryDB; use fil_types::{verifier::MockVerifier, NetworkVersion}; -use interpreter::{vm_send, ChainRand, DefaultRuntime, DefaultSyscalls}; +use interpreter::{vm_send, ChainRand, DefaultRuntime}; use ipld_blockstore::BlockStore; use ipld_hamt::Hamt; use message::UnsignedMessage; @@ -92,15 +92,12 @@ fn transfer_test() { .build() .unwrap(); - let default_syscalls = DefaultSyscalls::<_, MockVerifier>::new(&store); - let dummy_rand = ChainRand::new(TipsetKeys::new(vec![])); let registered = HashSet::new(); - let mut runtime = DefaultRuntime::<_, _, _>::new( + let mut runtime = DefaultRuntime::<_, _, MockVerifier>::new( NetworkVersion::V0, &mut state, &store, - &default_syscalls, 0, &message, 0, diff --git a/vm/runtime/src/lib.rs b/vm/runtime/src/lib.rs index a9d619763469..7f6f196221b2 100644 --- a/vm/runtime/src/lib.rs +++ b/vm/runtime/src/lib.rs @@ -167,9 +167,7 @@ pub trait Syscalls { signature: &Signature, signer: &Address, plaintext: &[u8], - ) -> Result<(), Box> { - Ok(signature.verify(plaintext, signer)?) - } + ) -> Result<(), Box>; /// Hashes input data using blake2b with 256 bit output. fn hash_blake2b(&self, data: &[u8]) -> Result<[u8; 32], Box> { Ok(blake2b_256(data)) @@ -180,34 +178,7 @@ pub trait Syscalls { proof_type: RegisteredSealProof, pieces: &[PieceInfo], ) -> Result> { - let sum: u64 = pieces.iter().map(|p| p.size.0).sum(); - - let ssize = proof_type.sector_size()? as u64; - - let mut fcp_pieces: Vec = pieces - .iter() - .map(proofs::PieceInfo::try_from) - .collect::>()?; - - // pad remaining space with 0 piece commitments - { - let mut to_fill = ssize - sum; - let n = to_fill.count_ones(); - for _ in 0..n { - let next = to_fill.trailing_zeros(); - let p_size = 1 << next; - to_fill ^= p_size; - let padded = PaddedPieceSize(p_size); - fcp_pieces.push(filecoin_proofs_api::PieceInfo { - commitment: zero_piece_commitment(padded), - size: padded.unpadded().into(), - }); - } - } - - let comm_d = compute_comm_d(proof_type.try_into()?, &fcp_pieces)?; - - Ok(data_commitment_v1_to_cid(&comm_d)?) + compute_unsealed_sector_cid(proof_type, pieces) } /// Verifies a sector seal proof. fn verify_seal(&self, vi: &SealVerifyInfo) -> Result<(), Box>; @@ -263,3 +234,37 @@ pub enum ConsensusFaultType { ParentGrinding = 2, TimeOffsetMining = 3, } + +pub fn compute_unsealed_sector_cid( + proof_type: RegisteredSealProof, + pieces: &[PieceInfo], +) -> Result> { + let sum: u64 = pieces.iter().map(|p| p.size.0).sum(); + + let ssize = proof_type.sector_size()? as u64; + + let mut fcp_pieces: Vec = pieces + .iter() + .map(proofs::PieceInfo::try_from) + .collect::>()?; + + // pad remaining space with 0 piece commitments + { + let mut to_fill = ssize - sum; + let n = to_fill.count_ones(); + for _ in 0..n { + let next = to_fill.trailing_zeros(); + let p_size = 1 << next; + to_fill ^= p_size; + let padded = PaddedPieceSize(p_size); + fcp_pieces.push(filecoin_proofs_api::PieceInfo { + commitment: zero_piece_commitment(padded), + size: padded.unpadded().into(), + }); + } + } + + let comm_d = compute_comm_d(proof_type.try_into()?, &fcp_pieces)?; + + Ok(data_commitment_v1_to_cid(&comm_d)?) +} From a47aa56292cbb5455d4e6162ce1e7cc5aa70869c Mon Sep 17 00:00:00 2001 From: austinabell Date: Tue, 20 Oct 2020 13:09:54 -0400 Subject: [PATCH 10/13] Remove commented out code --- vm/interpreter/src/default_runtime.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/vm/interpreter/src/default_runtime.rs b/vm/interpreter/src/default_runtime.rs index f9661c9cb8b8..6f17b2f1415b 100644 --- a/vm/interpreter/src/default_runtime.rs +++ b/vm/interpreter/src/default_runtime.rs @@ -112,11 +112,6 @@ where gas: Rc::clone(&gas_tracker), store, }; - // let gas_syscalls = GasSyscalls { - // price_list: price_list.clone(), - // gas: Rc::clone(&gas_tracker), - // syscalls, - // }; let caller_id = state .lookup_id(&message.from()) From 99b1d0fbde61c4c08c79570b76f00672e502acc3 Mon Sep 17 00:00:00 2001 From: austinabell Date: Tue, 20 Oct 2020 15:57:54 -0400 Subject: [PATCH 11/13] Switch to full verifier and fetch params by default --- Cargo.lock | 23 +++++++++++++++---- forest/Cargo.toml | 5 +--- forest/src/cli/fetch_params_cmd.rs | 2 +- forest/src/daemon.rs | 2 +- forest/src/main.rs | 1 - tests/conformance_tests/Cargo.toml | 2 ++ tests/conformance_tests/src/message.rs | 4 ++-- tests/conformance_tests/src/tipset.rs | 4 ++-- .../tests/conformance_runner.rs | 5 ++++ utils/paramfetch/Cargo.toml | 17 ++++++++++++++ .../mod.rs => utils/paramfetch/src/lib.rs | 0 .../paramfetch/src}/parameters.json | 0 vm/actor/src/builtin/miner/state.rs | 2 +- 13 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 utils/paramfetch/Cargo.toml rename forest/src/paramfetch/mod.rs => utils/paramfetch/src/lib.rs (100%) rename {forest/src/paramfetch => utils/paramfetch/src}/parameters.json (100%) diff --git a/Cargo.lock b/Cargo.lock index f324d537a432..853c0976f34e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1125,6 +1125,7 @@ name = "conformance_tests" version = "0.1.0" dependencies = [ "actor", + "async-std", "base64 0.12.3", "clock", "colored", @@ -1146,6 +1147,7 @@ dependencies = [ "ipld_hamt", "lazy_static", "log", + "paramfetch", "pretty_env_logger", "regex", "runtime", @@ -2106,7 +2108,6 @@ dependencies = [ "async-std", "auth", "beacon", - "blake2b_simd", "chain", "chain_sync", "ctrlc", @@ -2128,8 +2129,7 @@ dependencies = [ "libp2p", "log", "message_pool", - "pbr", - "pin-project-lite", + "paramfetch", "pretty_env_logger", "rpc", "rpc-client", @@ -2137,7 +2137,6 @@ dependencies = [ "serde_json", "state_manager", "structopt", - "surf", "utils", "uuid", ] @@ -4305,6 +4304,22 @@ dependencies = [ "serde", ] +[[package]] +name = "paramfetch" +version = "0.1.0" +dependencies = [ + "async-std", + "blake2b_simd", + "fil_types", + "futures 0.3.6", + "log", + "pbr", + "pin-project-lite", + "serde", + "serde_json", + "surf", +] + [[package]] name = "parity-multiaddr" version = "0.9.2" diff --git a/forest/Cargo.toml b/forest/Cargo.toml index 29ca89bea16f..23da5e80bff3 100644 --- a/forest/Cargo.toml +++ b/forest/Cargo.toml @@ -33,10 +33,6 @@ rpc = { path = "../node/rpc" } rpc_client = { package = "rpc-client", path = "../node/rpc-client" } fil_types = { path = "../types" } serde_json = "1.0" -blake2b_simd = "0.5.9" -surf = "2.0" -pbr = "1.0.3" -pin-project-lite = "0.1" message_pool = { package = "message_pool", path = "../blockchain/message_pool" } wallet = { package = "key_management", path = "../key_management" } jsonrpc-v2 = { version = "0.5.2", git = "https://github.com/ChainSafe/jsonrpc-v2", features = ["easy-errors", "macros"], default-features = false } @@ -44,3 +40,4 @@ uuid = { version = "0.8.1", features = ["v4"] } auth = { path = "../utils/auth"} actor = { path = "../vm/actor/" } genesis = { path = "../utils/genesis" } +paramfetch = { path = "../utils/paramfetch" } diff --git a/forest/src/cli/fetch_params_cmd.rs b/forest/src/cli/fetch_params_cmd.rs index 15464e404684..2408d8feb52d 100644 --- a/forest/src/cli/fetch_params_cmd.rs +++ b/forest/src/cli/fetch_params_cmd.rs @@ -1,8 +1,8 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use crate::paramfetch::{get_params_default, SectorSizeOpt}; use fil_types::SectorSize; +use paramfetch::{get_params_default, SectorSizeOpt}; use structopt::StructOpt; #[allow(missing_docs)] diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index f187c318f6e4..85f9ffcef402 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::cli::{block_until_sigint, Config}; -use super::paramfetch::{get_params_default, SectorSizeOpt}; use actor::EPOCH_DURATION_SECONDS; use async_std::sync::RwLock; use async_std::task; @@ -18,6 +17,7 @@ use genesis::initialize_genesis; use libp2p::identity::{ed25519, Keypair}; use log::{debug, info, trace}; use message_pool::{MessagePool, MpoolConfig, MpoolRpcProvider}; +use paramfetch::{get_params_default, SectorSizeOpt}; use rpc::{start_rpc, RpcState}; use state_manager::StateManager; use std::sync::Arc; diff --git a/forest/src/main.rs b/forest/src/main.rs index e0db1d7d4ff8..c813ebbec3af 100644 --- a/forest/src/main.rs +++ b/forest/src/main.rs @@ -4,7 +4,6 @@ mod cli; mod daemon; mod logger; -pub(crate) mod paramfetch; mod subcommand; use cli::CLI; diff --git a/tests/conformance_tests/Cargo.toml b/tests/conformance_tests/Cargo.toml index 6337cf210da6..caa7dffeacec 100644 --- a/tests/conformance_tests/Cargo.toml +++ b/tests/conformance_tests/Cargo.toml @@ -63,3 +63,5 @@ colored = "2.0" ipld = { package = "forest_ipld", path = "../../ipld", features = ["json"] } ipld_hamt = { path = "../../ipld/hamt", features = ["ignore-dead-links"] } log = "0.4" +paramfetch = { path = "../../utils/paramfetch" } +async-std = "1.6" \ No newline at end of file diff --git a/tests/conformance_tests/src/message.rs b/tests/conformance_tests/src/message.rs index 73819f33730a..0df79f6157b3 100644 --- a/tests/conformance_tests/src/message.rs +++ b/tests/conformance_tests/src/message.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::*; -use fil_types::{get_network_version_default, verifier::MockVerifier}; +use fil_types::get_network_version_default; use vm::TokenAmount; #[derive(Debug, Deserialize)] @@ -28,7 +28,7 @@ pub fn execute_message( params: ExecuteMessageParams, ) -> Result<(ApplyRet, Cid), Box> { let circ_supply = params.circ_supply; - let mut vm = VM::<_, _, _, MockVerifier>::new( + let mut vm = VM::<_, _, _>::new( params.pre_root, bs, params.epoch, diff --git a/tests/conformance_tests/src/tipset.rs b/tests/conformance_tests/src/tipset.rs index dea9aa62f746..ed930a5e4034 100644 --- a/tests/conformance_tests/src/tipset.rs +++ b/tests/conformance_tests/src/tipset.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::*; -use fil_types::verifier::MockVerifier; +use fil_types::verifier::FullVerifier; use num_bigint::ToBigInt; use state_manager::StateManager; use std::sync::Arc; @@ -79,7 +79,7 @@ pub fn execute_tipset( let sm = StateManager::new(bs); let mut _applied_messages = Vec::new(); let mut applied_results = Vec::new(); - let (post_state_root, receipts_root) = sm.apply_blocks::<_, MockVerifier, _>( + let (post_state_root, receipts_root) = sm.apply_blocks::<_, FullVerifier, _>( parent_epoch, pre_root, &tipset.blocks, diff --git a/tests/conformance_tests/tests/conformance_runner.rs b/tests/conformance_tests/tests/conformance_runner.rs index 1ae74d72e3af..da62fbabe276 100644 --- a/tests/conformance_tests/tests/conformance_runner.rs +++ b/tests/conformance_tests/tests/conformance_runner.rs @@ -22,6 +22,7 @@ use ipld::json::{IpldJson, IpldJsonRef}; use ipld::Ipld; use ipld_hamt::{BytesKey, Hamt}; use num_bigint::{BigInt, ToBigInt}; +use paramfetch::{get_params_default, SectorSizeOpt}; use regex::Regex; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -335,6 +336,10 @@ fn execute_tipset_vector( #[test] fn conformance_test_runner() { pretty_env_logger::init(); + + // Retrieve verification params + async_std::task::block_on(get_params_default(SectorSizeOpt::Keys, false)).unwrap(); + let walker = WalkDir::new("test-vectors/corpus").into_iter(); let mut failed = Vec::new(); let mut succeeded = 0; diff --git a/utils/paramfetch/Cargo.toml b/utils/paramfetch/Cargo.toml new file mode 100644 index 000000000000..50bdf6305bf5 --- /dev/null +++ b/utils/paramfetch/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "paramfetch" +version = "0.1.0" +authors = ["ChainSafe Systems "] +edition = "2018" + +[dependencies] +surf = "2.0" +async-std = { version = "1.6.3", features = ["attributes"] } +pbr = "1.0.3" +futures = "0.3.5" +pin-project-lite = "0.1" +fil_types = { path = "../../types" } +log = "0.4.8" +blake2b_simd = "0.5.9" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/forest/src/paramfetch/mod.rs b/utils/paramfetch/src/lib.rs similarity index 100% rename from forest/src/paramfetch/mod.rs rename to utils/paramfetch/src/lib.rs diff --git a/forest/src/paramfetch/parameters.json b/utils/paramfetch/src/parameters.json similarity index 100% rename from forest/src/paramfetch/parameters.json rename to utils/paramfetch/src/parameters.json diff --git a/vm/actor/src/builtin/miner/state.rs b/vm/actor/src/builtin/miner/state.rs index 87bf13a4ae92..1fe425f1fdc0 100644 --- a/vm/actor/src/builtin/miner/state.rs +++ b/vm/actor/src/builtin/miner/state.rs @@ -603,7 +603,7 @@ impl State { proven_sectors: &BitField, expected_faults: &BitField, ) -> Result, Box> { - let non_faults = expected_faults - proven_sectors; + let non_faults = proven_sectors - expected_faults; if non_faults.is_empty() { return Ok(Vec::new()); From 5627851a7d9962de08a05b897c26f8674a7c5a7f Mon Sep 17 00:00:00 2001 From: austinabell Date: Tue, 20 Oct 2020 15:59:27 -0400 Subject: [PATCH 12/13] lock update --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 853c0976f34e..20876be19e94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5245,8 +5245,7 @@ dependencies = [ [[package]] name = "serde_cbor" version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +source = "git+https://github.com/ChainSafe/cbor?rev=3e7bf81f57e9010762dbc12292bd6f927fdfe83a#3e7bf81f57e9010762dbc12292bd6f927fdfe83a" dependencies = [ "half", "serde", @@ -5255,7 +5254,8 @@ dependencies = [ [[package]] name = "serde_cbor" version = "0.11.1" -source = "git+https://github.com/ChainSafe/cbor?rev=3e7bf81f57e9010762dbc12292bd6f927fdfe83a#3e7bf81f57e9010762dbc12292bd6f927fdfe83a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" dependencies = [ "half", "serde", From 3ae9f832319442f9bd7cc07f4a749a7863bc13fc Mon Sep 17 00:00:00 2001 From: austinabell Date: Tue, 20 Oct 2020 16:00:25 -0400 Subject: [PATCH 13/13] nvm that was nightly --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20876be19e94..853c0976f34e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5245,7 +5245,8 @@ dependencies = [ [[package]] name = "serde_cbor" version = "0.11.1" -source = "git+https://github.com/ChainSafe/cbor?rev=3e7bf81f57e9010762dbc12292bd6f927fdfe83a#3e7bf81f57e9010762dbc12292bd6f927fdfe83a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" dependencies = [ "half", "serde", @@ -5254,8 +5255,7 @@ dependencies = [ [[package]] name = "serde_cbor" version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +source = "git+https://github.com/ChainSafe/cbor?rev=3e7bf81f57e9010762dbc12292bd6f927fdfe83a#3e7bf81f57e9010762dbc12292bd6f927fdfe83a" dependencies = [ "half", "serde",