diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 454fa9984..f3a8a3f0c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,12 +8,10 @@ variables: CARGOFLAGS: "" CI_SERVER_NAME: "GitLab CI" LIBSSL: "libssl1.0.0 (>=1.0.0)" - CARGO_HOME: $CI_PROJECT_DIR/cargo cache: key: "$CI_BUILD_STAGE-$CI_BUILD_REF_NAME" paths: - target/ - - cargo/ untracked: true linux-stable: stage: build @@ -132,7 +130,7 @@ linux-aarch64: name: "aarch64-unknown-linux-gnu_parity" linux-snap: stage: build - image: snapcore/snapcraft:stable + image: parity/snapcraft:gitlab-ci only: - stable - beta diff --git a/ethcore/res/ethereum/mcip6_byz.json b/ethcore/res/ethereum/mcip6_byz.json new file mode 100644 index 000000000..da40d6882 --- /dev/null +++ b/ethcore/res/ethereum/mcip6_byz.json @@ -0,0 +1,160 @@ +{ + "name":"Musicoin Byzantium Test", + "dataDir":"mcip6test", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x020000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "homesteadTransition":"0x17", + "eip100bTransition":"0x2a", + "eip150Transition":"0x2a", + "eip160Transition":"0x7fffffffffffff", + "eip161abcTransition":"0x7fffffffffffff", + "eip161dTransition":"0x7fffffffffffff", + "eip649Transition":"0x2a", + "blockReward":"0x1105a0185b50a80000", + "mcip3Transition":"0x17", + "mcip3MinerReward":"0xd8d726b7177a80000", + "mcip3UbiReward":"0x2b5e3af16b1880000", + "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", + "mcip3DevReward":"0xc249fdd327780000", + "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" + } + } + }, + "params":{ + "gasLimitBoundDivisor":"0x0400", + "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", + "accountStartNonce":"0x00", + "maximumExtraDataSize":"0x20", + "minGasLimit":"0x1388", + "networkID":"0x76740c", + "forkBlock":"0x2b", + "forkCanonHash":"0x23c3171e864a5d513a3ef85e4cf86dac4cc36b89e5b8e63bf0ebcca68b9e43c9", + "eip86Transition":"0x7fffffffffffff", + "eip98Transition":"0x7fffffffffffff", + "eip140Transition":"0x2a", + "eip155Transition":"0x2a", + "eip211Transition":"0x2a", + "eip214Transition":"0x2a", + "eip658Transition":"0x2a", + "maxCodeSize":"0x6000" + }, + "genesis":{ + "seal":{ + "ethereum":{ + "nonce":"0x000000000000002a", + "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty":"0x3d0900", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x00", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"", + "gasLimit":"0x7a1200" + }, + "nodes":[ + "enode://5ddc110733f6d34101973cdef3f9b43484159acf6f816d3b1ee92bc3c98ea453e857bb1207edf0ec0242008ab3a0f9f05eeaee99d47bd414c08a5bdf4847de13@176.9.3.148:30303", + "enode://38f074f4db8e64dfbaf87984bf290eef67772a901a7113d1b62f36216be152b8450c393d6fc562a5e38f04f99bc8f439a99010a230b1d92dc1df43bf0bd00615@176.9.3.148:30403" + ], + "accounts":{ + "0000000000000000000000000000000000000001":{ + "balance":"1", + "builtin":{ + "name":"ecrecover", + "pricing":{ + "linear":{ + "base":3000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000002":{ + "balance":"1", + "builtin":{ + "name":"sha256", + "pricing":{ + "linear":{ + "base":60, + "word":12 + } + } + } + }, + "0000000000000000000000000000000000000003":{ + "balance":"1", + "builtin":{ + "name":"ripemd160", + "pricing":{ + "linear":{ + "base":600, + "word":120 + } + } + } + }, + "0000000000000000000000000000000000000004":{ + "balance":"1", + "builtin":{ + "name":"identity", + "pricing":{ + "linear":{ + "base":15, + "word":3 + } + } + } + }, + "0000000000000000000000000000000000000005":{ + "builtin":{ + "name":"modexp", + "activate_at":"0x2a", + "pricing":{ + "modexp":{ + "divisor":20 + } + } + } + }, + "0000000000000000000000000000000000000006":{ + "builtin":{ + "name":"alt_bn128_add", + "activate_at":"0x2a", + "pricing":{ + "linear":{ + "base":500, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000007":{ + "builtin":{ + "name":"alt_bn128_mul", + "activate_at":"0x2a", + "pricing":{ + "linear":{ + "base":40000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000008":{ + "builtin":{ + "name":"alt_bn128_pairing", + "activate_at":"0x2a", + "pricing":{ + "alt_bn128_pairing":{ + "base":100000, + "pair":80000 + } + } + } + } + } +} diff --git a/ethcore/res/ethereum/musicoin.json b/ethcore/res/ethereum/musicoin.json index cf4d4ffba..2dcdb6d8f 100644 --- a/ethcore/res/ethereum/musicoin.json +++ b/ethcore/res/ethereum/musicoin.json @@ -8,12 +8,12 @@ "difficultyBoundDivisor":"0x0800", "durationLimit":"0x0d", "homesteadTransition":"0x118c30", - "eip100bTransition":"0x7fffffffffffff", - "eip150Transition":"0x7fffffffffffff", + "eip100bTransition":"0x21e88e", + "eip150Transition":"0x21e88e", "eip160Transition":"0x7fffffffffffff", "eip161abcTransition":"0x7fffffffffffff", "eip161dTransition":"0x7fffffffffffff", - "eip649Transition":"0x7fffffffffffff", + "eip649Transition":"0x21e88e", "blockReward":"0x1105a0185b50a80000", "mcip3Transition":"0x124f81", "mcip3MinerReward":"0xd8d726b7177a80000", @@ -31,15 +31,15 @@ "maximumExtraDataSize":"0x20", "minGasLimit":"0x1388", "networkID":"0x76740f", - "forkBlock":"0x5b6", - "forkCanonHash":"0xa5e88ad9e34d113e264e307bc27e8471452c8fc13780324bb3abb96fd0558343", + "forkBlock":"0x1d8015", + "forkCanonHash":"0x380602acf82b629a0be6b5adb2b4a801e960a07dc8261bf196d21befdbb8f2f9", "eip86Transition":"0x7fffffffffffff", "eip98Transition":"0x7fffffffffffff", - "eip140Transition":"0x7fffffffffffff", - "eip155Transition":"0x7fffffffffffff", - "eip211Transition":"0x7fffffffffffff", - "eip214Transition":"0x7fffffffffffff", - "eip658Transition":"0x7fffffffffffff", + "eip140Transition":"0x21e88e", + "eip155Transition":"0x21e88e", + "eip211Transition":"0x21e88e", + "eip214Transition":"0x21e88e", + "eip658Transition":"0x21e88e", "maxCodeSize":"0x6000" }, "genesis":{ @@ -57,12 +57,9 @@ "gasLimit":"0x7a1200" }, "nodes":[ - "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", - "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", - "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", - "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", - "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", - "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303", + "enode://09fcd36d553044c8b499b9b9e13a228ffd99572c513f77073d41f009717c464cd4399c0e665d6aff1590324254ee4e698b2b2533b1998dd04d896b9d6aff7895@35.185.67.35:30303", + "enode://89e51a34770a0badf8ea18c4c4d2c361cde707abd60031d99b1ab3010363e1898230a516ddb37d974af8d8db1b322779d7fe0caae0617bed4924d1b4968cf92b@35.231.48.142:30303", + "enode://b58c0c71f08864c0cf7fa9dea2c4cbefae5ae7a36cc30d286603b24982d25f3ccc056b589119324c51768fc2054b8c529ecf682e06e1e9980170b93ff194ed7a@132.148.132.9:30303", "enode://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" @@ -119,7 +116,7 @@ "0000000000000000000000000000000000000005":{ "builtin":{ "name":"modexp", - "activate_at":"0x7fffffffffffff", + "activate_at":"0x21e88e", "pricing":{ "modexp":{ "divisor":20 @@ -130,7 +127,7 @@ "0000000000000000000000000000000000000006":{ "builtin":{ "name":"alt_bn128_add", - "activate_at":"0x7fffffffffffff", + "activate_at":"0x21e88e", "pricing":{ "linear":{ "base":500, @@ -142,7 +139,7 @@ "0000000000000000000000000000000000000007":{ "builtin":{ "name":"alt_bn128_mul", - "activate_at":"0x7fffffffffffff", + "activate_at":"0x21e88e", "pricing":{ "linear":{ "base":40000, @@ -154,7 +151,7 @@ "0000000000000000000000000000000000000008":{ "builtin":{ "name":"alt_bn128_pairing", - "activate_at":"0x7fffffffffffff", + "activate_at":"0x21e88e", "pricing":{ "alt_bn128_pairing":{ "base":100000, diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index a9ee79f30..79755749f 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -27,7 +27,7 @@ use error::{BlockError, Error}; use header::{Header, BlockNumber}; use engines::{self, Engine}; use ethjson; -use rlp::{self, UntrustedRlp}; +use rlp::UntrustedRlp; use machine::EthereumMachine; /// Number of blocks in an ethash snapshot. @@ -38,6 +38,38 @@ const MAX_SNAPSHOT_BLOCKS: u64 = 30000; const DEFAULT_EIP649_DELAY: u64 = 3_000_000; +/// Ethash specific seal +#[derive(Debug, PartialEq)] +pub struct Seal { + /// Ethash seal mix_hash + pub mix_hash: H256, + /// Ethash seal nonce + pub nonce: H64, +} + +impl Seal { + /// Tries to parse rlp as ethash seal. + pub fn parse_seal>(seal: &[T]) -> Result { + if seal.len() != 2 { + return Err(BlockError::InvalidSealArity( + Mismatch { + expected: 2, + found: seal.len() + } + ).into()); + } + + let mix_hash = UntrustedRlp::new(seal[0].as_ref()).as_val::()?; + let nonce = UntrustedRlp::new(seal[1].as_ref()).as_val::()?; + let seal = Seal { + mix_hash, + nonce, + }; + + Ok(seal) + } +} + /// Ethash params. #[derive(Debug, PartialEq)] pub struct EthashParams { @@ -173,13 +205,12 @@ impl Engine for Arc { /// Additional engine-specific information for the user/developer concerning `header`. fn extra_info(&self, header: &Header) -> BTreeMap { - if header.seal().len() == self.seal_fields(header) { - map![ - "nonce".to_owned() => format!("0x{:x}", header.nonce()), - "mixHash".to_owned() => format!("0x{:x}", header.mix_hash()) - ] - } else { - BTreeMap::default() + match Seal::parse_seal(header.seal()) { + Ok(seal) => map![ + "nonce".to_owned() => format!("0x{:x}", seal.nonce), + "mixHash".to_owned() => format!("0x{:x}", seal.mix_hash) + ], + _ => BTreeMap::default() } } @@ -265,14 +296,7 @@ impl Engine for Arc { fn verify_block_basic(&self, header: &Header) -> Result<(), Error> { // check the seal fields. - let expected_seal_fields = self.seal_fields(header); - if header.seal().len() != expected_seal_fields { - return Err(From::from(BlockError::InvalidSealArity( - Mismatch { expected: expected_seal_fields, found: header.seal().len() } - ))); - } - UntrustedRlp::new(&header.seal()[0]).as_val::()?; - UntrustedRlp::new(&header.seal()[1]).as_val::()?; + let seal = Seal::parse_seal(header.seal())?; // TODO: consider removing these lines. let min_difficulty = self.ethash_params.minimum_difficulty; @@ -282,9 +306,10 @@ impl Engine for Arc { let difficulty = Ethash::boundary_to_difficulty(&H256(quick_get_difficulty( &header.bare_hash().0, - header.nonce().low_u64(), - &header.mix_hash().0 + seal.nonce.low_u64(), + &seal.mix_hash.0 ))); + if &difficulty < header.difficulty() { return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty().clone()), max: None, found: difficulty }))); } @@ -297,18 +322,20 @@ impl Engine for Arc { } fn verify_block_unordered(&self, header: &Header) -> Result<(), Error> { - let expected_seal_fields = self.seal_fields(header); - if header.seal().len() != expected_seal_fields { - return Err(From::from(BlockError::InvalidSealArity( - Mismatch { expected: expected_seal_fields, found: header.seal().len() } - ))); - } - let result = self.pow.compute_light(header.number() as u64, &header.bare_hash().0, header.nonce().low_u64()); + let seal = Seal::parse_seal(header.seal())?; + + let result = self.pow.compute_light(header.number() as u64, &header.bare_hash().0, seal.nonce.low_u64()); let mix = H256(result.mix_hash); let difficulty = Ethash::boundary_to_difficulty(&H256(result.value)); - trace!(target: "miner", "num: {}, seed: {}, h: {}, non: {}, mix: {}, res: {}" , header.number() as u64, H256(slow_hash_block_number(header.number() as u64)), header.bare_hash(), header.nonce().low_u64(), H256(result.mix_hash), H256(result.value)); - if mix != header.mix_hash() { - return Err(From::from(BlockError::MismatchedH256SealElement(Mismatch { expected: mix, found: header.mix_hash() }))); + trace!(target: "miner", "num: {num}, seed: {seed}, h: {h}, non: {non}, mix: {mix}, res: {res}", + num = header.number() as u64, + seed = H256(slow_hash_block_number(header.number() as u64)), + h = header.bare_hash(), + non = seal.nonce.low_u64(), + mix = H256(result.mix_hash), + res = H256(result.value)); + if mix != seal.mix_hash { + return Err(From::from(BlockError::MismatchedH256SealElement(Mismatch { expected: mix, found: seal.mix_hash }))); } if &difficulty < header.difficulty() { return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty().clone()), max: None, found: difficulty }))); @@ -439,18 +466,6 @@ impl Ethash { } } -impl Header { - /// Get the nonce field of the header. - pub fn nonce(&self) -> H64 { - rlp::decode(&self.seal()[1]) - } - - /// Get the mix hash field of the header. - pub fn mix_hash(&self) -> H256 { - rlp::decode(&self.seal()[0]) - } -} - fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u64) -> (u64, U256) { let eras = if block_number != 0 && block_number % era_rounds == 0 { block_number / era_rounds - 1 @@ -633,7 +648,7 @@ mod tests { #[test] fn can_do_seal_unordered_verification_fail() { let engine = test_spec().engine; - let header: Header = Header::default(); + let header = Header::default(); let verify_result = engine.verify_block_unordered(&header); @@ -644,6 +659,17 @@ mod tests { } } + #[test] + fn can_do_seal_unordered_verification_fail2() { + let engine = test_spec().engine; + let mut header = Header::default(); + header.set_seal(vec![vec![], vec![]]); + + let verify_result = engine.verify_block_unordered(&header); + // rlp error, shouldn't panic + assert!(verify_result.is_err()); + } + #[test] fn can_do_seal256_verification_fail() { let engine = test_spec().engine; diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 5b09c201f..ab1d11fd1 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -37,7 +37,7 @@ use client::BlockChainClient; use engines::EthEngine; use error::{BlockError, Error}; use header::{BlockNumber, Header}; -use transaction::SignedTransaction; +use transaction::{SignedTransaction, UnverifiedTransaction}; use views::BlockView; /// Preprocessed block data gathered in `verify_block_unordered` call @@ -68,11 +68,9 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &EthEngine) -> verify_header_params(&u, engine, false)?; engine.verify_block_basic(&u)?; } - // Verify transactions. - // TODO: either use transaction views or cache the decoded transactions. - let v = BlockView::new(bytes); - for t in v.transactions() { - engine.verify_transaction_basic(&t, &header)?; + + for t in UntrustedRlp::new(bytes).at(1)?.iter().map(|rlp| rlp.as_val::()) { + engine.verify_transaction_basic(&t?, &header)?; } Ok(()) } @@ -348,6 +346,8 @@ mod tests { use time::get_time; use transaction::{SignedTransaction, Transaction, UnverifiedTransaction, Action}; use types::log_entry::{LogEntry, LocalizedLogEntry}; + use rlp; + use triehash::ordered_trie_root; fn check_ok(result: Result<(), Error>) { result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e)); @@ -501,6 +501,27 @@ mod tests { Ok(()) } + #[test] + fn test_verify_block_basic_with_invalid_transactions() { + let spec = Spec::new_test(); + let engine = &*spec.engine; + + let block = { + let mut rlp = rlp::RlpStream::new_list(3); + let mut header = Header::default(); + // that's an invalid transaction list rlp + let invalid_transactions = vec![vec![0u8]]; + header.set_transactions_root(ordered_trie_root(&invalid_transactions)); + header.set_gas_limit(engine.params().min_gas_limit); + rlp.append(&header); + rlp.append_list::, _>(&invalid_transactions); + rlp.append_raw(&rlp::EMPTY_LIST_RLP, 1); + rlp.out() + }; + + assert!(basic_test(&block, engine).is_err()); + } + #[test] fn test_verify_block() { use rlp::RlpStream; diff --git a/ethstore/cli/src/main.rs b/ethstore/cli/src/main.rs index e9cd4975a..45f9f6920 100644 --- a/ethstore/cli/src/main.rs +++ b/ethstore/cli/src/main.rs @@ -266,7 +266,7 @@ fn execute(command: I) -> Result where I: IntoIterator sign.cmd } build () { + if [[ "windows" = $IDENT ]] + then + # This is a nasty hack till we figure out the proper cargo caching strategy + echo "Remove index" + rm -rf cargo/registry/index/*. + fi echo "Build parity:" cargo build --target $PLATFORM --features final --release echo "Build evmbin:"