diff --git a/Cargo.lock b/Cargo.lock index e834500a94e..d3c465b998c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1149,6 +1149,7 @@ version = "0.1.0" dependencies = [ "bn 0.4.4 (git+https://github.com/paritytech/bn)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "common-types 0.1.0", "eip-152 0.1.0", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", diff --git a/ethcore/builtin/Cargo.toml b/ethcore/builtin/Cargo.toml index 906d17a5837..441e68a954e 100644 --- a/ethcore/builtin/Cargo.toml +++ b/ethcore/builtin/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] bn = { git = "https://github.com/paritytech/bn", default-features = false } +common-types = { path = "../types" } ethereum-types = "0.8.0" ethjson = { path = "../../json" } ethkey = { path = "../../accounts/ethkey" } diff --git a/ethcore/builtin/src/lib.rs b/ethcore/builtin/src/lib.rs index a3c50c3c381..795bf6f4796 100644 --- a/ethcore/builtin/src/lib.rs +++ b/ethcore/builtin/src/lib.rs @@ -18,12 +18,14 @@ use std::{ cmp::{max, min}, + convert::TryFrom, io::{self, Read, Cursor}, mem::size_of, }; use bn; use byteorder::{BigEndian, LittleEndian, ReadBytesExt}; +use common_types::errors::EthcoreError; use ethereum_types::{H256, U256}; use ethjson; use ethkey::{Signature, recover as ec_recover}; @@ -215,8 +217,10 @@ impl Builtin { } } -impl From for Builtin { - fn from(b: ethjson::spec::Builtin) -> Self { +impl TryFrom for Builtin { + type Error = EthcoreError; + + fn try_from(b: ethjson::spec::Builtin) -> Result { let pricer: Box = match b.pricing { ethjson::spec::Pricing::Blake2F { gas_per_round } => { Box::new(gas_per_round) @@ -259,17 +263,18 @@ impl From for Builtin { } }; - Builtin { + let native = ethereum_builtin(&b.name)?; + Ok(Builtin { pricer, - native: ethereum_builtin(&b.name), + native, activate_at: b.activate_at.map_or(0, Into::into), - } + }) } } /// Ethereum built-in factory. -fn ethereum_builtin(name: &str) -> Box { - match name { +fn ethereum_builtin(name: &str) -> Result, EthcoreError> { + let implementation = match name { "identity" => Box::new(Identity) as Box, "ecrecover" => Box::new(EcRecover) as Box, "sha256" => Box::new(Sha256) as Box, @@ -279,8 +284,9 @@ fn ethereum_builtin(name: &str) -> Box { "alt_bn128_mul" => Box::new(Bn128Mul) as Box, "alt_bn128_pairing" => Box::new(Bn128Pairing) as Box, "blake2_f" => Box::new(Blake2F) as Box, - _ => panic!("invalid builtin name: {}", name), - } + _ => return Err(EthcoreError::Msg(format!("invalid builtin name: {}", name))), + }; + Ok(implementation) } // Ethereum builtins: @@ -679,6 +685,7 @@ impl Bn128Pairing { #[cfg(test)] mod tests { + use std::convert::TryFrom; use ethereum_types::U256; use ethjson::uint::Uint; use num::{BigUint, Zero, One}; @@ -690,7 +697,7 @@ mod tests { fn blake2f_cost() { let f = Builtin { pricer: Box::new(123), - native: ethereum_builtin("blake2_f"), + native: ethereum_builtin("blake2_f").expect("known builtin"), activate_at: 0, }; // 5 rounds @@ -703,7 +710,7 @@ mod tests { #[test] fn blake2_f_is_err_on_invalid_length() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 1 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-1 let input = hex!("00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let mut out = [0u8; 64]; @@ -715,7 +722,7 @@ mod tests { #[test] fn blake2_f_is_err_on_invalid_length_2() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 2 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-2 let input = hex!("000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let mut out = [0u8; 64]; @@ -727,7 +734,7 @@ mod tests { #[test] fn blake2_f_is_err_on_bad_finalization_flag() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 3 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-3 let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002"); let mut out = [0u8; 64]; @@ -739,7 +746,7 @@ mod tests { #[test] fn blake2_f_zero_rounds_is_ok_test_vector_4() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 4 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-4 let input = hex!("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let expected = hex!("08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b"); @@ -750,7 +757,7 @@ mod tests { #[test] fn blake2_f_test_vector_5() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 5 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-5 let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let expected = hex!("ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"); @@ -761,7 +768,7 @@ mod tests { #[test] fn blake2_f_test_vector_6() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 6 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-6 let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000"); let expected = hex!("75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735"); @@ -772,7 +779,7 @@ mod tests { #[test] fn blake2_f_test_vector_7() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 7 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-7 let input = hex!("0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let expected = hex!("b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421"); @@ -784,7 +791,7 @@ mod tests { #[ignore] #[test] fn blake2_f_test_vector_8() { - let blake2 = ethereum_builtin("blake2_f"); + let blake2 = ethereum_builtin("blake2_f").expect("known builtin"); // Test vector 8 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-8 // Note this test is slow, 4294967295/0xffffffff rounds take a while. let input = hex!("ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); @@ -829,7 +836,7 @@ mod tests { #[test] fn identity() { - let f = ethereum_builtin("identity"); + let f = ethereum_builtin("identity").expect("known builtin"); let i = [0u8, 1, 2, 3]; @@ -849,7 +856,7 @@ mod tests { #[test] fn sha256() { - let f = ethereum_builtin("sha256"); + let f = ethereum_builtin("sha256").expect("known builtin"); let i = [0u8; 0]; @@ -872,7 +879,7 @@ mod tests { #[test] fn ripemd160() { - let f = ethereum_builtin("ripemd160"); + let f = ethereum_builtin("ripemd160").expect("known builtin"); let i = [0u8; 0]; @@ -891,7 +898,7 @@ mod tests { #[test] fn ecrecover() { - let f = ethereum_builtin("ecrecover"); + let f = ethereum_builtin("ecrecover").expect("known builtin"); let i = hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03"); @@ -944,7 +951,7 @@ mod tests { let f = Builtin { pricer: Box::new(ModexpPricer { divisor: 20 }), - native: ethereum_builtin("modexp"), + native: ethereum_builtin("modexp").expect("known builtin"), activate_at: 0, }; @@ -1055,7 +1062,7 @@ mod tests { let f = Builtin { pricer: Box::new(Linear { base: 0, word: 0 }), - native: ethereum_builtin("alt_bn128_add"), + native: ethereum_builtin("alt_bn128_add").expect("known builtin"), activate_at: 0, }; @@ -1114,7 +1121,7 @@ mod tests { let f = Builtin { pricer: Box::new(Linear { base: 0, word: 0 }), - native: ethereum_builtin("alt_bn128_mul"), + native: ethereum_builtin("alt_bn128_mul").expect("known builtin"), activate_at: 0, }; @@ -1154,7 +1161,7 @@ mod tests { fn builtin_pairing() -> Builtin { Builtin { pricer: Box::new(Linear { base: 0, word: 0 }), - native: ethereum_builtin("alt_bn128_pairing"), + native: ethereum_builtin("alt_bn128_pairing").expect("known builtin"), activate_at: 0, } } @@ -1226,7 +1233,7 @@ mod tests { #[test] #[should_panic] fn from_unknown_linear() { - let _ = ethereum_builtin("foo"); + let _ = ethereum_builtin("foo").unwrap(); } #[test] @@ -1234,7 +1241,7 @@ mod tests { let pricer = Box::new(Linear { base: 10, word: 20} ); let b = Builtin { pricer: pricer as Box, - native: ethereum_builtin("identity"), + native: ethereum_builtin("identity").expect("known builtin"), activate_at: 100_000, }; @@ -1248,7 +1255,7 @@ mod tests { let pricer = Box::new(Linear { base: 10, word: 20 }); let b = Builtin { pricer: pricer as Box, - native: ethereum_builtin("identity"), + native: ethereum_builtin("identity").expect("known builtin"), activate_at: 1, }; @@ -1265,7 +1272,7 @@ mod tests { #[test] fn from_json() { - let b = Builtin::from(ethjson::spec::Builtin { + let b = Builtin::try_from(ethjson::spec::Builtin { name: "identity".to_owned(), pricing: ethjson::spec::Pricing::Linear(ethjson::spec::Linear { base: 10, @@ -1273,7 +1280,7 @@ mod tests { }), activate_at: None, eip1108_transition: None, - }); + }).expect("known builtin"); assert_eq!(b.cost(&[0; 0], 0), U256::from(10)); assert_eq!(b.cost(&[0; 1], 0), U256::from(30)); @@ -1288,7 +1295,7 @@ mod tests { #[test] fn bn128_pairing_eip1108_transition() { - let b = Builtin::from(ethjson::spec::Builtin { + let b = Builtin::try_from(ethjson::spec::Builtin { name: "alt_bn128_pairing".to_owned(), pricing: ethjson::spec::Pricing::AltBn128Pairing(ethjson::spec::builtin::AltBn128Pairing { base: 100_000, @@ -1298,7 +1305,7 @@ mod tests { }), activate_at: Some(Uint(U256::from(10))), eip1108_transition: Some(Uint(U256::from(20))), - }); + }).expect("known builtin"); assert_eq!(b.cost(&[0; 192 * 3], 10), U256::from(340_000), "80 000 * 3 + 100 000 == 340 000"); assert_eq!(b.cost(&[0; 192 * 7], 20), U256::from(283_000), "34 000 * 7 + 45 000 == 283 000"); @@ -1306,7 +1313,7 @@ mod tests { #[test] fn bn128_add_eip1108_transition() { - let b = Builtin::from(ethjson::spec::Builtin { + let b = Builtin::try_from(ethjson::spec::Builtin { name: "alt_bn128_add".to_owned(), pricing: ethjson::spec::Pricing::AltBn128ConstOperations(ethjson::spec::builtin::AltBn128ConstOperations { price: 500, @@ -1314,7 +1321,7 @@ mod tests { }), activate_at: Some(Uint(U256::from(10))), eip1108_transition: Some(Uint(U256::from(20))), - }); + }).expect("known builtin"); assert_eq!(b.cost(&[0; 192], 10), U256::from(500)); assert_eq!(b.cost(&[0; 10], 20), U256::from(150), "after istanbul hardfork gas cost for add should be 150"); @@ -1322,7 +1329,7 @@ mod tests { #[test] fn bn128_mul_eip1108_transition() { - let b = Builtin::from(ethjson::spec::Builtin { + let b = Builtin::try_from(ethjson::spec::Builtin { name: "alt_bn128_mul".to_owned(), pricing: ethjson::spec::Pricing::AltBn128ConstOperations(ethjson::spec::builtin::AltBn128ConstOperations { price: 40_000, @@ -1330,7 +1337,7 @@ mod tests { }), activate_at: Some(Uint(U256::from(10))), eip1108_transition: Some(Uint(U256::from(20))), - }); + }).expect("known builtin"); assert_eq!(b.cost(&[0; 192], 10), U256::from(40_000)); assert_eq!(b.cost(&[0; 10], 20), U256::from(6_000), "after istanbul hardfork gas cost for mul should be 6 000"); diff --git a/ethcore/engine/src/engine.rs b/ethcore/engine/src/engine.rs index 815c14b3896..357a184c7af 100644 --- a/ethcore/engine/src/engine.rs +++ b/ethcore/engine/src/engine.rs @@ -293,7 +293,7 @@ pub trait Engine: Sync + Send { fn handle_message(&self, _message: &[u8]) -> Result<(), EngineError> { Err(EngineError::UnexpectedMessage) } /// Register a component which signs consensus messages. - fn set_signer(&self, _signer: Box) {} + fn set_signer(&self, _signer: Option>) {} /// Sign using the EngineSigner, to be used for consensus tx signing. fn sign(&self, _hash: H256) -> Result { unimplemented!() } diff --git a/ethcore/engines/authority-round/src/lib.rs b/ethcore/engines/authority-round/src/lib.rs index 202b4dbc6c4..99ee36b7826 100644 --- a/ethcore/engines/authority-round/src/lib.rs +++ b/ethcore/engines/authority-round/src/lib.rs @@ -1622,8 +1622,8 @@ impl Engine for AuthorityRound { self.validators.register_client(client); } - fn set_signer(&self, signer: Box) { - *self.signer.write() = Some(signer); + fn set_signer(&self, signer: Option>) { + *self.signer.write() = signer; } fn sign(&self, hash: H256) -> Result { @@ -1751,31 +1751,72 @@ mod tests { fn generates_seal_and_does_not_double_propose() { let tap = Arc::new(AccountProvider::transient_provider()); let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap(); - let addr2 = tap.insert_account(keccak("2").into(), &"2".into()).unwrap(); - let spec = spec::new_test_round(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); - let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b1 = b1.close_and_lock().unwrap(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); - let b2 = b2.close_and_lock().unwrap(); - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); if let Seal::Regular(seal) = engine.generate_seal(&b1, &genesis_header) { assert!(b1.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None); + } else { + panic!("block 1 not sealed"); } + } - engine.set_signer(Box::new((tap, addr2, "2".into()))); - if let Seal::Regular(seal) = engine.generate_seal(&b2, &genesis_header) { + #[test] + fn generates_seal_iff_sealer_is_set() { + let tap = Arc::new(AccountProvider::transient_provider()); + let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap(); + let spec = spec::new_test_round(); + let engine = &*spec.engine; + let genesis_header = spec.genesis_header(); + let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); + let last_hashes = Arc::new(vec![genesis_header.hash()]); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, + last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), + vec![], false) + .unwrap().close_and_lock().unwrap(); + // Not a signer. A seal cannot be generated. + assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None); + // Become a signer. + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); + if let Seal::Regular(seal) = engine.generate_seal(&b1, &genesis_header) { + assert!(b1.clone().try_seal(engine, seal).is_ok()); + // Second proposal is forbidden. + assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None); + } else { + panic!("block 1 not sealed"); + } + // Stop being a signer. + engine.set_signer(None); + // Make a step first and then create a new block in that new step. + engine.step(); + let addr2 = tap.insert_account(keccak("0").into(), &"0".into()).unwrap(); + let mut header2 = genesis_header.clone(); + header2.set_number(2); + header2.set_author(addr2); + header2.set_parent_hash(header2.hash()); + let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &header2, + last_hashes, addr2, (3141562.into(), 31415620.into()), + vec![], false) + .unwrap().close_and_lock().unwrap(); + // Not a signer. A seal cannot be generated. + assert!(engine.generate_seal(&b2, &header2) == Seal::None); + // Become a signer once more. + engine.set_signer(Some(Box::new((tap, addr2, "0".into())))); + if let Seal::Regular(seal) = engine.generate_seal(&b2, &header2) { assert!(b2.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. - assert!(engine.generate_seal(&b2, &genesis_header) == Seal::None); + assert!(engine.generate_seal(&b2, &header2) == Seal::None); + } else { + panic!("block 2 not sealed"); } } @@ -1798,13 +1839,13 @@ mod tests { let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b2 = b2.close_and_lock().unwrap(); - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); match engine.generate_seal(&b1, &genesis_header) { Seal::None => panic!("wrong seal"), Seal::Regular(_) => { engine.step(); - engine.set_signer(Box::new((tap.clone(), addr2, "0".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into())))); match engine.generate_seal(&b2, &genesis_header) { Seal::Regular(_) => panic!("sealed despite wrong difficulty"), Seal::None => {} @@ -1922,11 +1963,11 @@ mod tests { assert!(aura.verify_block_family(&header, &parent_header).is_ok()); assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0); - aura.set_signer(Box::new(( + aura.set_signer(Some(Box::new(( Arc::new(AccountProvider::transient_provider()), validator2, "".into(), - ))); + )))); // Do not report on steps skipped between genesis and first block. header.set_number(1); @@ -2041,7 +2082,7 @@ mod tests { client.add_notify(notify.clone()); engine.register_client(Arc::downgrade(&client) as _); - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b1 = b1.close_and_lock().unwrap(); @@ -2085,7 +2126,7 @@ mod tests { let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None); engine.step(); @@ -2102,9 +2143,9 @@ mod tests { let b2 = b2.close_and_lock().unwrap(); // we will now seal a block with 1tx and include the accumulated empty step message - engine.set_signer(Box::new((tap.clone(), addr2, "0".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into())))); if let Seal::Regular(seal) = engine.generate_seal(&b2, &genesis_header) { - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash()); let empty_steps = ::rlp::encode_list(&vec![empty_step2]); @@ -2138,14 +2179,14 @@ mod tests { let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None); engine.step(); // step 3 let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b2 = b2.close_and_lock().unwrap(); - engine.set_signer(Box::new((tap.clone(), addr2, "0".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into())))); assert_eq!(engine.generate_seal(&b2, &genesis_header), Seal::None); engine.step(); @@ -2154,10 +2195,10 @@ mod tests { let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b3 = b3.close_and_lock().unwrap(); - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); if let Seal::Regular(seal) = engine.generate_seal(&b3, &genesis_header) { let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash()); - engine.set_signer(Box::new((tap.clone(), addr2, "0".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into())))); let empty_step3 = sealed_empty_step(engine, 3, &genesis_header.hash()); let empty_steps = ::rlp::encode_list(&vec![empty_step2, empty_step3]); @@ -2188,7 +2229,7 @@ mod tests { let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None); engine.step(); @@ -2242,7 +2283,7 @@ mod tests { ); // empty step with valid signature from incorrect proposer for step - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); let empty_steps = vec![sealed_empty_step(engine, 1, &parent_header.hash())]; set_empty_steps_seal(&mut header, 2, &signature, &empty_steps); @@ -2252,9 +2293,9 @@ mod tests { ); // valid empty steps - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); let empty_step2 = sealed_empty_step(engine, 2, &parent_header.hash()); - engine.set_signer(Box::new((tap.clone(), addr2, "0".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into())))); let empty_step3 = sealed_empty_step(engine, 3, &parent_header.hash()); let empty_steps = vec![empty_step2, empty_step3]; @@ -2298,7 +2339,7 @@ mod tests { let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None); engine.step(); @@ -2335,7 +2376,7 @@ mod tests { let engine = &*spec.engine; let addr1 = accounts[0]; - engine.set_signer(Box::new((tap.clone(), addr1, "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into())))); let mut header: Header = Header::default(); let empty_step = empty_step(engine, 1, &header.parent_hash()); @@ -2416,7 +2457,7 @@ mod tests { header.set_author(accounts[0]); // when - engine.set_signer(Box::new((tap.clone(), accounts[1], "0".into()))); + engine.set_signer(Some(Box::new((tap.clone(), accounts[1], "0".into())))); let empty_steps = vec![ sealed_empty_step(&*engine, 1, &parent.hash()), sealed_empty_step(&*engine, 1, &parent.hash()), @@ -2453,9 +2494,9 @@ mod tests { header.set_author(accounts[0]); // when - engine.set_signer(Box::new((tap.clone(), accounts[1], "0".into()))); + engine.set_signer(Some(Box::new((tap.clone(), accounts[1], "0".into())))); let es1 = sealed_empty_step(&*engine, 1, &parent.hash()); - engine.set_signer(Box::new((tap.clone(), accounts[0], "1".into()))); + engine.set_signer(Some(Box::new((tap.clone(), accounts[0], "1".into())))); let es2 = sealed_empty_step(&*engine, 2, &parent.hash()); let mut empty_steps = vec![es2, es1]; diff --git a/ethcore/engines/basic-authority/src/lib.rs b/ethcore/engines/basic-authority/src/lib.rs index b18283fb214..bae548781b4 100644 --- a/ethcore/engines/basic-authority/src/lib.rs +++ b/ethcore/engines/basic-authority/src/lib.rs @@ -194,8 +194,8 @@ impl Engine for BasicAuthority { } } - fn set_signer(&self, signer: Box) { - *self.signer.write() = Some(signer); + fn set_signer(&self, signer: Option>) { + *self.signer.write() = signer; } fn sign(&self, hash: H256) -> Result { @@ -269,7 +269,7 @@ mod tests { let spec = new_test_authority(); let engine = &*spec.engine; - engine.set_signer(Box::new((Arc::new(tap), addr, "".into()))); + engine.set_signer(Some(Box::new((Arc::new(tap), addr, "".into())))); let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); @@ -287,7 +287,9 @@ mod tests { let engine = new_test_authority().engine; assert_eq!(SealingState::NotReady, engine.sealing_state()); - engine.set_signer(Box::new((Arc::new(tap), authority, "".into()))); + engine.set_signer(Some(Box::new((Arc::new(tap), authority, "".into())))); assert_eq!(SealingState::Ready, engine.sealing_state()); + engine.set_signer(None); + assert_eq!(SealingState::NotReady, engine.sealing_state()); } } diff --git a/ethcore/engines/clique/src/lib.rs b/ethcore/engines/clique/src/lib.rs index 05cb5d2621c..ac8ed4b86d2 100644 --- a/ethcore/engines/clique/src/lib.rs +++ b/ethcore/engines/clique/src/lib.rs @@ -762,9 +762,14 @@ impl Engine for Clique { } } - fn set_signer(&self, signer: Box) { - trace!(target: "engine", "set_signer: {}", signer.address()); - *self.signer.write() = Some(signer); + fn set_signer(&self, signer: Option>) { + let mut current_signer = self.signer.write(); + if let Some(signer) = signer.as_ref() { + trace!(target: "engine", "set_signer: {:?}", signer.address()); + } else if let Some(signer) = &*current_signer { + trace!(target: "engine", "set_signer: cleared; previous signer: {:?})", signer.address()); + } + *current_signer = signer; } fn register_client(&self, client: Weak) { diff --git a/ethcore/machine/src/test_helpers.rs b/ethcore/machine/src/test_helpers.rs index a9d7eae4deb..aac33b9a92d 100644 --- a/ethcore/machine/src/test_helpers.rs +++ b/ethcore/machine/src/test_helpers.rs @@ -16,14 +16,16 @@ //! Provide facilities to create `Machine` instances for testing various networks. +use std::convert::TryFrom; use common_types::engines::params::CommonParams; +use ethcore_builtin::Builtin; use ethjson; use crate::Machine; pub fn load_machine(reader: &[u8]) -> Machine { let spec = ethjson::spec::Spec::load(reader).expect("chain spec is invalid"); - let builtins = spec.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect(); + let builtins = spec.accounts.builtins().into_iter().map(|p| (p.0.into(), Builtin::try_from(p.1).expect("chain spec is invalid"))).collect(); let params = CommonParams::from(spec.params); if let ethjson::spec::Engine::Ethash(ref ethash) = spec.engine { diff --git a/ethcore/spec/src/spec.rs b/ethcore/spec/src/spec.rs index afd111b96a3..79f1bdd41b8 100644 --- a/ethcore/spec/src/spec.rs +++ b/ethcore/spec/src/spec.rs @@ -18,6 +18,7 @@ use std::{ collections::BTreeMap, + convert::TryFrom, fmt, io::Read, path::Path, @@ -256,13 +257,22 @@ impl fmt::Display for SpecHardcodedSync { } } +fn convert_json_to_spec( + pair: (ethjson::hash::Address, ethjson::spec::Builtin), +) -> Result<(Address, Builtin), Error> { + let builtin = Builtin::try_from(pair.1)?; + Ok((pair.0.into(), builtin)) +} + /// Load from JSON object. fn load_from(spec_params: SpecParams, s: ethjson::spec::Spec) -> Result { - let builtins = s.accounts + let builtins: Result, _> = s + .accounts .builtins() .into_iter() - .map(|p| (p.0.into(), From::from(p.1))) + .map(convert_json_to_spec) .collect(); + let builtins = builtins?; let g = Genesis::from(s.genesis); let GenericSeal(seal_rlp) = g.seal.into(); let params = CommonParams::from(s.params); @@ -472,10 +482,16 @@ impl Spec { pub fn load_machine(reader: R) -> Result { ethjson::spec::Spec::load(reader) .map_err(|e| Error::Msg(e.to_string())) - .map(|s| { - let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect(); + .and_then(|s| { + let builtins: Result, _> = s + .accounts + .builtins() + .into_iter() + .map(convert_json_to_spec) + .collect(); + let builtins = builtins?; let params = CommonParams::from(s.params); - Spec::machine(&s.engine, params, builtins) + Ok(Spec::machine(&s.engine, params, builtins)) }) } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index b6a70d231e7..d97b1170266 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -893,21 +893,38 @@ impl miner::MinerService for Miner { self.params.write().extra_data = extra_data; } - fn set_author(&self, author: Author) { - self.params.write().author = author.address(); - - if let Author::Sealer(signer) = author { - if self.engine.sealing_state() != SealingState::External { - // Enable sealing - self.sealing.lock().enabled = true; - // -------------------------------------------------------------------------- - // | NOTE Code below may require author and sealing locks | - // | (some `Engine`s call `EngineClient.update_sealing()`) | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - self.engine.set_signer(signer); - } else { - warn!("Setting an EngineSigner while Engine does not require one."); + fn set_author>>(&self, author: T) { + let author_opt = author.into(); + self.params.write().author = author_opt.as_ref().map(Author::address).unwrap_or_default(); + + match author_opt { + Some(Author::Sealer(signer)) => { + if self.engine.sealing_state() != SealingState::External { + // Enable sealing + self.sealing.lock().enabled = true; + // -------------------------------------------------------------------------- + // | NOTE Code below may require author and sealing locks | + // | (some `Engine`s call `EngineClient.update_sealing()`) | + // | Make sure to release the locks before calling that method. | + // -------------------------------------------------------------------------- + self.engine.set_signer(Some(signer)); + } else { + warn!("Setting an EngineSigner while Engine does not require one."); + } + } + Some(Author::External(_address)) => (), + None => { + // Clear the author. + if self.engine.sealing_state() != SealingState::External { + // Disable sealing. + self.sealing.lock().enabled = false; + // -------------------------------------------------------------------------- + // | NOTE Code below may require author and sealing locks | + // | (some `Engine`s call `EngineClient.update_sealing()`) | + // | Make sure to release the locks before calling that method. | + // -------------------------------------------------------------------------- + self.engine.set_signer(None); + } } } } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 3b68359ac96..9961f12af80 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -132,7 +132,7 @@ pub trait MinerService : Send + Sync { /// Set info necessary to sign consensus messages and block authoring. /// /// On chains where sealing is done externally (e.g. PoW) we provide only reward beneficiary. - fn set_author(&self, author: Author); + fn set_author>>(&self, author: T); // Transaction Pool diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index 8195e4ddaf3..bb2ca0aee26 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -75,6 +75,10 @@ impl ParitySet for ParitySetClient { Err(errors::light_unimplemented(None)) } + fn clear_engine_signer(&self) -> Result { + Err(errors::light_unimplemented(None)) + } + fn set_transactions_limit(&self, _limit: usize) -> Result { Err(errors::light_unimplemented(None)) } diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 7d7b46847af..0db3c99ca27 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -166,6 +166,11 @@ impl ParitySet for ParitySetClient where Ok(true) } + fn clear_engine_signer(&self) -> Result { + self.miner.set_author(None); + Ok(true) + } + fn add_reserved_peer(&self, peer: String) -> Result { match self.net.add_reserved_peer(peer) { Ok(()) => Ok(true), diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index df7102e15be..0af99e1227c 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -127,10 +127,13 @@ impl MinerService for TestMinerService { self.authoring_params.read().clone() } - fn set_author(&self, author: miner::Author) { - self.authoring_params.write().author = author.address(); - if let miner::Author::Sealer(signer) = author { - *self.signer.write() = Some(signer); + fn set_author>>(&self, author: T) { + let author_opt = author.into(); + self.authoring_params.write().author = author_opt.as_ref().map(miner::Author::address).unwrap_or_default(); + match author_opt { + Some(miner::Author::Sealer(signer)) => *self.signer.write() = Some(signer), + Some(miner::Author::External(_addr)) => (), + None => *self.signer.write() = None, } } diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index 0c328b6b313..94fe9fa386f 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -57,6 +57,10 @@ pub trait ParitySet { #[rpc(name = "parity_setEngineSignerSecret")] fn set_engine_signer_secret(&self, H256) -> Result; + /// Unsets the engine signer account address. + #[rpc(name = "parity_clearEngineSigner")] + fn clear_engine_signer(&self) -> Result; + /// Sets the limits for transaction queue. #[rpc(name = "parity_setTransactionsLimit")] fn set_transactions_limit(&self, usize) -> Result; diff --git a/secret-store/src/key_server_cluster/cluster_connections_net.rs b/secret-store/src/key_server_cluster/cluster_connections_net.rs index 75c0a36fa9d..155c0604d23 100644 --- a/secret-store/src/key_server_cluster/cluster_connections_net.rs +++ b/secret-store/src/key_server_cluster/cluster_connections_net.rs @@ -467,10 +467,13 @@ fn net_maintain(data: Arc) { /// Send keep alive messages to remote nodes. fn net_keep_alive(data: Arc) { - let now = Instant::now(); let active_connections = data.active_connections(); for connection in active_connections { - let last_message_diff = now - connection.last_message_time(); + // the last_message_time could change after active_connections() call + // => we always need to call Instant::now() after getting last_message_time + let last_message_time = connection.last_message_time(); + let now = Instant::now(); + let last_message_diff = now - last_message_time; if last_message_diff > KEEP_ALIVE_DISCONNECT_INTERVAL { warn!(target: "secretstore_net", "{}: keep alive timeout for node {}", data.self_key_pair.public(), connection.node_id());