From 234e582c6a370b9c9fbb742e216587e4571851b7 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Fri, 13 Apr 2018 16:01:10 +0300 Subject: [PATCH 001/147] Tx permission contract improvement --- ethcore/res/contracts/tx_acl.json | 2 +- ethcore/src/tx_filter.rs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ethcore/res/contracts/tx_acl.json b/ethcore/res/contracts/tx_acl.json index cc924cafb81..47ce7f36974 100644 --- a/ethcore/res/contracts/tx_acl.json +++ b/ethcore/res/contracts/tx_acl.json @@ -1 +1 @@ -[{"constant":true,"inputs":[{"name":"sender","type":"address"}],"name":"allowedTxTypes","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] +[{"constant":true,"inputs":[{"name":"sender","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"allowedTxTypes","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index a4fa8a0874f..55c4bed3526 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -60,17 +60,21 @@ impl TransactionFilter { /// Check if transaction is allowed at given block. pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool { let mut cache = self.permission_cache.lock(); - + let mut to: Address = Address::new(); let tx_type = match transaction.action { Action::Create => tx_permissions::CREATE, - Action::Call(address) => if client.code_hash(&address, BlockId::Hash(*parent_hash)).map_or(false, |c| c != KECCAK_EMPTY) { - tx_permissions::CALL - } else { - tx_permissions::BASIC + Action::Call(address) => { + to = address; + if client.code_hash(&address, BlockId::Hash(*parent_hash)).map_or(false, |c| c != KECCAK_EMPTY) { + tx_permissions::CALL + } else { + tx_permissions::BASIC + } } }; let sender = transaction.sender(); + let value = transaction.value; let key = (*parent_hash, sender); if let Some(permissions) = cache.get_mut(&key) { @@ -80,7 +84,7 @@ impl TransactionFilter { let contract_address = self.contract_address; let permissions = self.contract.functions() .allowed_tx_types() - .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .call(sender, to, value, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) .map(|p| p.low_u32()) .unwrap_or_else(|e| { debug!("Error callling tx permissions contract: {:?}", e); From 1b393c0786d3c9ee7b9311a8d545f59d61645629 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Tue, 17 Apr 2018 01:42:47 +0300 Subject: [PATCH 002/147] Use tuple for to address --- ethcore/src/tx_filter.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index 55c4bed3526..600e84a95b9 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -60,17 +60,13 @@ impl TransactionFilter { /// Check if transaction is allowed at given block. pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool { let mut cache = self.permission_cache.lock(); - let mut to: Address = Address::new(); - let tx_type = match transaction.action { - Action::Create => tx_permissions::CREATE, - Action::Call(address) => { - to = address; - if client.code_hash(&address, BlockId::Hash(*parent_hash)).map_or(false, |c| c != KECCAK_EMPTY) { - tx_permissions::CALL + let (tx_type, to) = match transaction.action { + Action::Create => (tx_permissions::CREATE, Address::new()), + Action::Call(address) => if client.code_hash(&address, BlockId::Hash(*parent_hash)).map_or(false, |c| c != KECCAK_EMPTY) { + (tx_permissions::CALL, address) } else { - tx_permissions::BASIC + (tx_permissions::BASIC, address) } - } }; let sender = transaction.sender(); From 5927a72621e40978c83e0b92e68fe222dd6e1447 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Wed, 18 Apr 2018 16:58:54 +0300 Subject: [PATCH 003/147] Introduced ABI for deprecated tx permission contract --- ethcore/res/contracts/tx_acl_deprecated.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 ethcore/res/contracts/tx_acl_deprecated.json diff --git a/ethcore/res/contracts/tx_acl_deprecated.json b/ethcore/res/contracts/tx_acl_deprecated.json new file mode 100644 index 00000000000..cc924cafb81 --- /dev/null +++ b/ethcore/res/contracts/tx_acl_deprecated.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[{"name":"sender","type":"address"}],"name":"allowedTxTypes","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] From 985937a4dee417948231aa96fb5c1adae40847e8 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Wed, 18 Apr 2018 16:59:54 +0300 Subject: [PATCH 004/147] Improved ABI for tx permission contract with contract name, name hash and version --- ethcore/res/contracts/tx_acl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/res/contracts/tx_acl.json b/ethcore/res/contracts/tx_acl.json index 47ce7f36974..ac6be2d5233 100644 --- a/ethcore/res/contracts/tx_acl.json +++ b/ethcore/res/contracts/tx_acl.json @@ -1 +1 @@ -[{"constant":true,"inputs":[{"name":"sender","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"allowedTxTypes","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] +[ { "constant": true, "inputs": [], "name": "contractNameHash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractName", "outputs": [ { "name": "", "type": "string" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractVersion", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "sender", "type": "address" }, { "name": "to", "type": "address" }, { "name": "value", "type": "uint256" } ], "name": "allowedTxTypes", "outputs": [ { "name": "", "type": "uint32" } ], "payable": false, "stateMutability": "view", "type": "function" } ] From 555fba0700227cb687ada8b4dc81888a8706adc4 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Wed, 18 Apr 2018 17:03:20 +0300 Subject: [PATCH 005/147] Introduced support for deprecated tx permission contract + fixed cache for the new version + introduced `target` for tx filter loging --- ethcore/src/tx_filter.rs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index 600e84a95b9..ec2a55f1a73 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -16,7 +16,7 @@ //! Smart contract based transaction filter. -use ethereum_types::{H256, Address}; +use ethereum_types::{H256, U256, Address}; use lru_cache::LruCache; use client::{BlockInfo, CallContract, BlockId}; @@ -25,6 +25,7 @@ use spec::CommonParams; use transaction::{Action, SignedTransaction}; use hash::KECCAK_EMPTY; +use_contract!(transact_acl_deprecated, "TransactAclDeprecated", "res/contracts/tx_acl_deprecated.json"); use_contract!(transact_acl, "TransactAcl", "res/contracts/tx_acl.json"); const MAX_CACHE_SIZE: usize = 4096; @@ -40,9 +41,10 @@ mod tx_permissions { /// Connection filter that uses a contract to manage permissions. pub struct TransactionFilter { + contract_deprecated: transact_acl_deprecated::TransactAclDeprecated, contract: transact_acl::TransactAcl, contract_address: Address, - permission_cache: Mutex>, + permission_cache: Mutex>, } impl TransactionFilter { @@ -50,6 +52,7 @@ impl TransactionFilter { pub fn from_params(params: &CommonParams) -> Option { params.transaction_permission_contract.map(|address| TransactionFilter { + contract_deprecated: transact_acl_deprecated::TransactAclDeprecated::default(), contract: transact_acl::TransactAcl::default(), contract_address: address, permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)), @@ -71,25 +74,37 @@ impl TransactionFilter { let sender = transaction.sender(); let value = transaction.value; - let key = (*parent_hash, sender); + let key = (*parent_hash, sender, to, value); if let Some(permissions) = cache.get_mut(&key) { return *permissions & tx_type != 0; } let contract_address = self.contract_address; + + // Check permissions in smart contracts let permissions = self.contract.functions() .allowed_tx_types() .call(sender, to, value, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) .map(|p| p.low_u32()) - .unwrap_or_else(|e| { - debug!("Error callling tx permissions contract: {:?}", e); - tx_permissions::NONE + .unwrap_or_else(|_e| { + // If failed, first check deprecated contract + trace!(target: "tx_filter", "Fallback to the deprecated version of tx permission contract"); + self.contract_deprecated.functions() + .allowed_tx_types() + .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .map(|p| p.low_u32()) + .unwrap_or_else(|e| { + error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e); + tx_permissions::NONE + }) }); - cache.insert((*parent_hash, sender), permissions); - - trace!("Permissions required: {}, got: {}", tx_type, permissions); + cache.insert((*parent_hash, sender, to, value), permissions); + trace!(target: "tx_filter", + "Given transaction data: sender: {:?} to: {:?} value: {}. Permissions required: {:X}, got: {:X}", + sender, to, value, tx_type, permissions + ); permissions & tx_type != 0 } } From caf8b89a8402824c58e1bc287e04eba0e95cefe2 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Wed, 18 Apr 2018 17:08:42 +0300 Subject: [PATCH 006/147] Introduced test for the new tx permission contract version + old test renamed as deprecated --- ethcore/src/tx_filter.rs | 126 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 2 deletions(-) diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index ec2a55f1a73..ab01a895c2f 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -115,16 +115,138 @@ mod test { use spec::Spec; use client::{BlockChainClient, Client, ClientConfig, BlockId}; use miner::Miner; - use ethereum_types::Address; + use ethereum_types::{U256, Address}; use io::IoChannel; use ethkey::{Secret, KeyPair}; use super::TransactionFilter; use transaction::{Transaction, Action}; use tempdir::TempDir; - /// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a + /// Contract code: https://gist.github.com/VladLupashevskyi/a157d8162db85de67de522eeb7c8ee85 #[test] fn transaction_filter() { + let spec_data = r#" + { + "name": "TestNodeFilterContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "contract": "0x0000000000000000000000000000000000000000" + } + } + } + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "gasLimitBoundDivisor": "0x0400", + "transactionPermissionContract": "0x0000000000000000000000000000000000000005" + }, + "genesis": { + "seal": { + "generic": "0xc180" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" + }, + "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": { + "balance": "1", + "constructor": "608060405234801561001057600080fd5b506104c3806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc1461009a578063a0a8e4601461012a578063d4b03ee014610155575b600080fd5b34801561007357600080fd5b5061007c6101e2565b60405180826000191660001916815260200191505060405180910390f35b3480156100a657600080fd5b506100af610253565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ef5780820151818401526020810190506100d4565b50505050905090810190601f16801561011c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013657600080fd5b5061013f610290565b6040518082815260200191505060405180910390f35b34801561016157600080fd5b506101c0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610299565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b60006101ec610253565b6040518082805190602001908083835b60208310151561022157805182526020820191506020810190506020830392506101fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b60606040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006002905090565b6000737e5f4552091a69125d5dfcb7b8c2659029395bdf8473ffffffffffffffffffffffffffffffffffffffff1614156102d95763ffffffff9050610490565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8473ffffffffffffffffffffffffffffffffffffffff1614156103175760026001179050610490565b736813eb9362372eef6200f3b1dbc3f819671cba698473ffffffffffffffffffffffffffffffffffffffff1614156103525760019050610490565b73e1ab8145f7e55dc933d51a18c793f901a3a0b2768473ffffffffffffffffffffffffffffffffffffffff1614801561038b5750600082145b1561039c5763ffffffff9050610490565b73e57bfe9f44b819898f47bf37e5af72a0783e11418473ffffffffffffffffffffffffffffffffffffffff161480156103fe575073d41c057fd1c78805aac12b0a94a405c0461a6fbb8373ffffffffffffffffffffffffffffffffffffffff16145b1561040c5760019050610490565b73d41c057fd1c78805aac12b0a94a405c0461a6fbb8473ffffffffffffffffffffffffffffffffffffffff1614801561046e575073e57bfe9f44b819898f47bf37e5af72a0783e11418373ffffffffffffffffffffffffffffffffffffffff16145b801561047a5750600082145b1561048b5763ffffffff9050610490565b600090505b93925050505600a165627a7a72305820ea35352692061875f689bdefc5e0d0ec86be33cdcf729bb0908f76b1da038b560029" + } + } + } + "#; + + let tempdir = TempDir::new("").unwrap(); + let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap(); + let client_db = Arc::new(::kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))); + + let client = Client::new( + ClientConfig::default(), + &spec, + client_db, + Arc::new(Miner::with_spec(&spec)), + IoChannel::disconnected(), + ).unwrap(); + let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000001")).unwrap(); + let key2 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000002")).unwrap(); + let key3 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000003")).unwrap(); + let key4 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000004")).unwrap(); + let key5 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000005")).unwrap(); + let key6 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000006")).unwrap(); + let key7 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000007")).unwrap(); + + let filter = TransactionFilter::from_params(spec.params()).unwrap(); + let mut basic_tx = Transaction::default(); + basic_tx.action = Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb")); + let create_tx = Transaction::default(); + let mut call_tx = Transaction::default(); + call_tx.action = Action::Call(Address::from("0000000000000000000000000000000000000005")); + + let mut basic_tx_with_ether_and_to_key7 = Transaction::default(); + basic_tx_with_ether_and_to_key7.action = Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb")); + basic_tx_with_ether_and_to_key7.value = U256::from(123123); + let mut call_tx_with_ether = Transaction::default(); + call_tx_with_ether.action = Action::Call(Address::from("0000000000000000000000000000000000000005")); + call_tx_with_ether.value = U256::from(123123); + + + let mut basic_tx_to_key6 = Transaction::default(); + basic_tx_to_key6.action = Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141")); + let mut basic_tx_with_ether_and_to_key6 = Transaction::default(); + basic_tx_with_ether_and_to_key6.action = Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141")); + basic_tx_with_ether_and_to_key6.value = U256::from(123123); + + let genesis = client.block_hash(BlockId::Latest).unwrap(); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &create_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key1.secret(), None), &*client)); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key2.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key2.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key2.secret(), None), &*client)); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key3.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key3.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key3.secret(), None), &*client)); + + assert!(!filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key4.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key4.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key4.secret(), None), &*client)); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &create_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key1.secret(), None), &*client)); + + assert!(!filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key7.clone().sign(key5.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &call_tx_with_ether.clone().sign(key5.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key6.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key7.clone().sign(key6.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &basic_tx_to_key6.clone().sign(key7.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key6.clone().sign(key7.secret(), None), &*client)); + + + + } + + /// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a + #[test] + fn transaction_filter_deprecated() { let spec_data = r#" { "name": "TestNodeFilterContract", From f47cab5e6ffe9779d74f15173336f4a2b3b947d7 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Wed, 18 Apr 2018 17:12:28 +0300 Subject: [PATCH 007/147] Removed empty lines --- ethcore/src/tx_filter.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index ab01a895c2f..6aa73e9286a 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -239,9 +239,6 @@ mod test { assert!(filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key7.clone().sign(key6.secret(), None), &*client)); assert!(filter.transaction_allowed(&genesis, &basic_tx_to_key6.clone().sign(key7.secret(), None), &*client)); assert!(!filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key6.clone().sign(key7.secret(), None), &*client)); - - - } /// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a From e0d5b42aa82edc6738f299f3c9eb0824a632bc7e Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Thu, 26 Apr 2018 11:57:52 +0300 Subject: [PATCH 008/147] Introduced filter_only_sender return value in allowedTxTypes fn + improved caching --- ethcore/res/contracts/tx_acl.json | 2 +- ethcore/src/tx_filter.rs | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/ethcore/res/contracts/tx_acl.json b/ethcore/res/contracts/tx_acl.json index ac6be2d5233..e110797d96f 100644 --- a/ethcore/res/contracts/tx_acl.json +++ b/ethcore/res/contracts/tx_acl.json @@ -1 +1 @@ -[ { "constant": true, "inputs": [], "name": "contractNameHash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractName", "outputs": [ { "name": "", "type": "string" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractVersion", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "sender", "type": "address" }, { "name": "to", "type": "address" }, { "name": "value", "type": "uint256" } ], "name": "allowedTxTypes", "outputs": [ { "name": "", "type": "uint32" } ], "payable": false, "stateMutability": "view", "type": "function" } ] +[ { "constant": true, "inputs": [], "name": "contractNameHash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractName", "outputs": [ { "name": "", "type": "string" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractVersion", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "sender", "type": "address" }, { "name": "to", "type": "address" }, { "name": "value", "type": "uint256" } ], "name": "allowedTxTypes", "outputs": [ { "name": "", "type": "uint32" }, { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ] diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index 6aa73e9286a..5c32854638e 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -16,7 +16,7 @@ //! Smart contract based transaction filter. -use ethereum_types::{H256, U256, Address}; +use ethereum_types::{H256, Address}; use lru_cache::LruCache; use client::{BlockInfo, CallContract, BlockId}; @@ -44,7 +44,7 @@ pub struct TransactionFilter { contract_deprecated: transact_acl_deprecated::TransactAclDeprecated, contract: transact_acl::TransactAcl, contract_address: Address, - permission_cache: Mutex>, + permission_cache: Mutex>, } impl TransactionFilter { @@ -74,7 +74,7 @@ impl TransactionFilter { let sender = transaction.sender(); let value = transaction.value; - let key = (*parent_hash, sender, to, value); + let key = (*parent_hash, sender); if let Some(permissions) = cache.get_mut(&key) { return *permissions & tx_type != 0; @@ -83,24 +83,26 @@ impl TransactionFilter { let contract_address = self.contract_address; // Check permissions in smart contracts - let permissions = self.contract.functions() + let (permissions, filter_only_sender) = self.contract.functions() .allowed_tx_types() .call(sender, to, value, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) - .map(|p| p.low_u32()) + .map(|(p, f)| (p.low_u32(), f)) .unwrap_or_else(|_e| { // If failed, first check deprecated contract trace!(target: "tx_filter", "Fallback to the deprecated version of tx permission contract"); - self.contract_deprecated.functions() + (self.contract_deprecated.functions() .allowed_tx_types() .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) .map(|p| p.low_u32()) .unwrap_or_else(|e| { error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e); tx_permissions::NONE - }) + }), true) }); - - cache.insert((*parent_hash, sender, to, value), permissions); + println!("{:?}, {:?}", permissions, filter_only_sender); + if filter_only_sender { + cache.insert((*parent_hash, sender), permissions); + } trace!(target: "tx_filter", "Given transaction data: sender: {:?} to: {:?} value: {}. Permissions required: {:X}, got: {:X}", sender, to, value, tx_type, permissions @@ -122,7 +124,7 @@ mod test { use transaction::{Transaction, Action}; use tempdir::TempDir; - /// Contract code: https://gist.github.com/VladLupashevskyi/a157d8162db85de67de522eeb7c8ee85 + /// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f #[test] fn transaction_filter() { let spec_data = r#" @@ -165,7 +167,7 @@ mod test { "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "0000000000000000000000000000000000000005": { "balance": "1", - "constructor": "608060405234801561001057600080fd5b506104c3806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc1461009a578063a0a8e4601461012a578063d4b03ee014610155575b600080fd5b34801561007357600080fd5b5061007c6101e2565b60405180826000191660001916815260200191505060405180910390f35b3480156100a657600080fd5b506100af610253565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ef5780820151818401526020810190506100d4565b50505050905090810190601f16801561011c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013657600080fd5b5061013f610290565b6040518082815260200191505060405180910390f35b34801561016157600080fd5b506101c0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610299565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b60006101ec610253565b6040518082805190602001908083835b60208310151561022157805182526020820191506020810190506020830392506101fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b60606040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006002905090565b6000737e5f4552091a69125d5dfcb7b8c2659029395bdf8473ffffffffffffffffffffffffffffffffffffffff1614156102d95763ffffffff9050610490565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8473ffffffffffffffffffffffffffffffffffffffff1614156103175760026001179050610490565b736813eb9362372eef6200f3b1dbc3f819671cba698473ffffffffffffffffffffffffffffffffffffffff1614156103525760019050610490565b73e1ab8145f7e55dc933d51a18c793f901a3a0b2768473ffffffffffffffffffffffffffffffffffffffff1614801561038b5750600082145b1561039c5763ffffffff9050610490565b73e57bfe9f44b819898f47bf37e5af72a0783e11418473ffffffffffffffffffffffffffffffffffffffff161480156103fe575073d41c057fd1c78805aac12b0a94a405c0461a6fbb8373ffffffffffffffffffffffffffffffffffffffff16145b1561040c5760019050610490565b73d41c057fd1c78805aac12b0a94a405c0461a6fbb8473ffffffffffffffffffffffffffffffffffffffff1614801561046e575073e57bfe9f44b819898f47bf37e5af72a0783e11418373ffffffffffffffffffffffffffffffffffffffff16145b801561047a5750600082145b1561048b5763ffffffff9050610490565b600090505b93925050505600a165627a7a72305820ea35352692061875f689bdefc5e0d0ec86be33cdcf729bb0908f76b1da038b560029" + "constructor": "608060405234801561001057600080fd5b506104eb806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc1461009a578063a0a8e4601461012a578063d4b03ee014610155575b600080fd5b34801561007357600080fd5b5061007c6101ed565b60405180826000191660001916815260200191505060405180910390f35b3480156100a657600080fd5b506100af61025e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ef5780820151818401526020810190506100d4565b50505050905090810190601f16801561011c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013657600080fd5b5061013f61029b565b6040518082815260200191505060405180910390f35b34801561016157600080fd5b506101c0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506102a4565b604051808363ffffffff1663ffffffff168152602001821515151581526020019250505060405180910390f35b60006101f761025e565b6040518082805190602001908083835b60208310151561022c5780518252602082019150602081019050602083039250610207565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b60606040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006002905090565b600080737e5f4552091a69125d5dfcb7b8c2659029395bdf8573ffffffffffffffffffffffffffffffffffffffff1614156102e95763ffffffff6001915091506104b7565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8573ffffffffffffffffffffffffffffffffffffffff16141561032b5760026001176001915091506104b7565b736813eb9362372eef6200f3b1dbc3f819671cba698573ffffffffffffffffffffffffffffffffffffffff16141561036957600180915091506104b7565b73e1ab8145f7e55dc933d51a18c793f901a3a0b2768573ffffffffffffffffffffffffffffffffffffffff161480156103a25750600083145b156103b75763ffffffff6000915091506104b7565b73e57bfe9f44b819898f47bf37e5af72a0783e11418573ffffffffffffffffffffffffffffffffffffffff16148015610419575073d41c057fd1c78805aac12b0a94a405c0461a6fbb8473ffffffffffffffffffffffffffffffffffffffff16145b1561042b5760016000915091506104b7565b73d41c057fd1c78805aac12b0a94a405c0461a6fbb8573ffffffffffffffffffffffffffffffffffffffff1614801561048d575073e57bfe9f44b819898f47bf37e5af72a0783e11418473ffffffffffffffffffffffffffffffffffffffff16145b80156104995750600083145b156104ae5763ffffffff6000915091506104b7565b60006001915091505b9350939150505600a165627a7a723058204982adea2aa10a7b8328ec3829472ee17c62a86957ef6737f2eb729b2c3faf910029" } } } From 2759b9a5bf0fd2b7f26b551258df3b1278b0e147 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Mon, 21 May 2018 18:24:32 +0300 Subject: [PATCH 009/147] Introduced version checking for tx permission contract --- ethcore/src/tx_filter.rs | 69 +++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index 5c32854638e..cc99a2986d2 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -16,7 +16,7 @@ //! Smart contract based transaction filter. -use ethereum_types::{H256, Address}; +use ethereum_types::{H256, U256, Address}; use lru_cache::LruCache; use client::{BlockInfo, CallContract, BlockId}; @@ -45,6 +45,7 @@ pub struct TransactionFilter { contract: transact_acl::TransactAcl, contract_address: Address, permission_cache: Mutex>, + contract_version_cache: Mutex>> } impl TransactionFilter { @@ -56,13 +57,16 @@ impl TransactionFilter { contract: transact_acl::TransactAcl::default(), contract_address: address, permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)), + contract_version_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)), } ) } /// Check if transaction is allowed at given block. pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool { - let mut cache = self.permission_cache.lock(); + let mut permission_cache = self.permission_cache.lock(); + let mut contract_version_cache = self.contract_version_cache.lock(); + let (tx_type, to) = match transaction.action { Action::Create => (tx_permissions::CREATE, Address::new()), Action::Call(address) => if client.code_hash(&address, BlockId::Hash(*parent_hash)).map_or(false, |c| c != KECCAK_EMPTY) { @@ -76,32 +80,54 @@ impl TransactionFilter { let value = transaction.value; let key = (*parent_hash, sender); - if let Some(permissions) = cache.get_mut(&key) { + if let Some(permissions) = permission_cache.get_mut(&key) { return *permissions & tx_type != 0; } let contract_address = self.contract_address; - - // Check permissions in smart contracts - let (permissions, filter_only_sender) = self.contract.functions() - .allowed_tx_types() - .call(sender, to, value, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) - .map(|(p, f)| (p.low_u32(), f)) - .unwrap_or_else(|_e| { - // If failed, first check deprecated contract + let contract_version = contract_version_cache.get_mut(parent_hash).and_then(|v| *v).or_else(|| { + self.contract.functions() + .contract_version() + .call(&|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .ok() + }); + contract_version_cache.insert(*parent_hash, contract_version); + + // Check permissions in smart contract based on its version + let (permissions, filter_only_sender) = match contract_version { + Some(version) => { + let version_u64 = version.low_u64(); + trace!(target: "tx_filter", "Version of tx permission contract: {}", version); + match version_u64 { + 2 => self.contract.functions() + .allowed_tx_types() + .call(sender, to, value, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .map(|(p, f)| (p.low_u32(), f)) + .unwrap_or_else(|e| { + error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e); + (tx_permissions::NONE, true) + }), + _ => { + error!(target: "tx_filter", "Unknown version of tx permissions contract is used"); + (tx_permissions::NONE, true) + } + } + }, + None => { trace!(target: "tx_filter", "Fallback to the deprecated version of tx permission contract"); (self.contract_deprecated.functions() - .allowed_tx_types() - .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) - .map(|p| p.low_u32()) - .unwrap_or_else(|e| { - error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e); - tx_permissions::NONE - }), true) - }); - println!("{:?}, {:?}", permissions, filter_only_sender); + .allowed_tx_types() + .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .map(|p| p.low_u32()) + .unwrap_or_else(|e| { + error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e); + tx_permissions::NONE + }), true) + } + }; + if filter_only_sender { - cache.insert((*parent_hash, sender), permissions); + permission_cache.insert((*parent_hash, sender), permissions); } trace!(target: "tx_filter", "Given transaction data: sender: {:?} to: {:?} value: {}. Permissions required: {:X}, got: {:X}", @@ -206,7 +232,6 @@ mod test { call_tx_with_ether.action = Action::Call(Address::from("0000000000000000000000000000000000000005")); call_tx_with_ether.value = U256::from(123123); - let mut basic_tx_to_key6 = Transaction::default(); basic_tx_to_key6.action = Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141")); let mut basic_tx_with_ether_and_to_key6 = Transaction::default(); From 22aa033f3440c07002097fac72472ac379dc00af Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Mon, 21 May 2018 18:33:30 +0300 Subject: [PATCH 010/147] Moved tx permission contract test genesis specs to separate files --- .../contract_ver_2_genesis.json | 43 +++++++++ .../deprecated_contract_genesis.json | 43 +++++++++ ethcore/src/tx_filter.rs | 92 +------------------ 3 files changed, 88 insertions(+), 90 deletions(-) create mode 100644 ethcore/res/tx_permission_tests/contract_ver_2_genesis.json create mode 100644 ethcore/res/tx_permission_tests/deprecated_contract_genesis.json diff --git a/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json b/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json new file mode 100644 index 00000000000..b165625a165 --- /dev/null +++ b/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json @@ -0,0 +1,43 @@ +{ + "name": "TestNodeFilterContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "contract": "0x0000000000000000000000000000000000000000" + } + } + } + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "gasLimitBoundDivisor": "0x0400", + "transactionPermissionContract": "0x0000000000000000000000000000000000000005" + }, + "genesis": { + "seal": { + "generic": "0xc180" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" + }, + "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": { + "balance": "1", + "constructor": "608060405234801561001057600080fd5b506104eb806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc1461009a578063a0a8e4601461012a578063d4b03ee014610155575b600080fd5b34801561007357600080fd5b5061007c6101ed565b60405180826000191660001916815260200191505060405180910390f35b3480156100a657600080fd5b506100af61025e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ef5780820151818401526020810190506100d4565b50505050905090810190601f16801561011c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013657600080fd5b5061013f61029b565b6040518082815260200191505060405180910390f35b34801561016157600080fd5b506101c0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506102a4565b604051808363ffffffff1663ffffffff168152602001821515151581526020019250505060405180910390f35b60006101f761025e565b6040518082805190602001908083835b60208310151561022c5780518252602082019150602081019050602083039250610207565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b60606040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006002905090565b600080737e5f4552091a69125d5dfcb7b8c2659029395bdf8573ffffffffffffffffffffffffffffffffffffffff1614156102e95763ffffffff6001915091506104b7565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8573ffffffffffffffffffffffffffffffffffffffff16141561032b5760026001176001915091506104b7565b736813eb9362372eef6200f3b1dbc3f819671cba698573ffffffffffffffffffffffffffffffffffffffff16141561036957600180915091506104b7565b73e1ab8145f7e55dc933d51a18c793f901a3a0b2768573ffffffffffffffffffffffffffffffffffffffff161480156103a25750600083145b156103b75763ffffffff6000915091506104b7565b73e57bfe9f44b819898f47bf37e5af72a0783e11418573ffffffffffffffffffffffffffffffffffffffff16148015610419575073d41c057fd1c78805aac12b0a94a405c0461a6fbb8473ffffffffffffffffffffffffffffffffffffffff16145b1561042b5760016000915091506104b7565b73d41c057fd1c78805aac12b0a94a405c0461a6fbb8573ffffffffffffffffffffffffffffffffffffffff1614801561048d575073e57bfe9f44b819898f47bf37e5af72a0783e11418473ffffffffffffffffffffffffffffffffffffffff16145b80156104995750600083145b156104ae5763ffffffff6000915091506104b7565b60006001915091505b9350939150505600a165627a7a723058204982adea2aa10a7b8328ec3829472ee17c62a86957ef6737f2eb729b2c3faf910029" + } + } +} diff --git a/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json b/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json new file mode 100644 index 00000000000..92fde908089 --- /dev/null +++ b/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json @@ -0,0 +1,43 @@ +{ + "name": "TestNodeFilterContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "contract": "0x0000000000000000000000000000000000000000" + } + } + } + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "gasLimitBoundDivisor": "0x0400", + "transactionPermissionContract": "0x0000000000000000000000000000000000000005" + }, + "genesis": { + "seal": { + "generic": "0xc180" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" + }, + "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": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b5b6101868061001f6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e17512211461003e575b600080fd5b341561004957600080fd5b610075600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610097565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b6000737e5f4552091a69125d5dfcb7b8c2659029395bdf8273ffffffffffffffffffffffffffffffffffffffff1614156100d75763ffffffff9050610155565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8273ffffffffffffffffffffffffffffffffffffffff1614156101155760026001179050610155565b736813eb9362372eef6200f3b1dbc3f819671cba698273ffffffffffffffffffffffffffffffffffffffff1614156101505760019050610155565b600090505b9190505600a165627a7a72305820f1f21cb978925a8a92c6e30c8c81adf598adff6d1ef941cf5ed6c0ec7ad1ae3d0029" + } + } +} diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index cc99a2986d2..f4af2df9a82 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -153,51 +153,7 @@ mod test { /// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f #[test] fn transaction_filter() { - let spec_data = r#" - { - "name": "TestNodeFilterContract", - "engine": { - "authorityRound": { - "params": { - "stepDuration": 1, - "startStep": 2, - "validators": { - "contract": "0x0000000000000000000000000000000000000000" - } - } - } - }, - "params": { - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID" : "0x69", - "gasLimitBoundDivisor": "0x0400", - "transactionPermissionContract": "0x0000000000000000000000000000000000000005" - }, - "genesis": { - "seal": { - "generic": "0xc180" - }, - "difficulty": "0x20000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x222222" - }, - "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": { - "balance": "1", - "constructor": "608060405234801561001057600080fd5b506104eb806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc1461009a578063a0a8e4601461012a578063d4b03ee014610155575b600080fd5b34801561007357600080fd5b5061007c6101ed565b60405180826000191660001916815260200191505060405180910390f35b3480156100a657600080fd5b506100af61025e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ef5780820151818401526020810190506100d4565b50505050905090810190601f16801561011c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013657600080fd5b5061013f61029b565b6040518082815260200191505060405180910390f35b34801561016157600080fd5b506101c0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506102a4565b604051808363ffffffff1663ffffffff168152602001821515151581526020019250505060405180910390f35b60006101f761025e565b6040518082805190602001908083835b60208310151561022c5780518252602082019150602081019050602083039250610207565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b60606040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006002905090565b600080737e5f4552091a69125d5dfcb7b8c2659029395bdf8573ffffffffffffffffffffffffffffffffffffffff1614156102e95763ffffffff6001915091506104b7565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8573ffffffffffffffffffffffffffffffffffffffff16141561032b5760026001176001915091506104b7565b736813eb9362372eef6200f3b1dbc3f819671cba698573ffffffffffffffffffffffffffffffffffffffff16141561036957600180915091506104b7565b73e1ab8145f7e55dc933d51a18c793f901a3a0b2768573ffffffffffffffffffffffffffffffffffffffff161480156103a25750600083145b156103b75763ffffffff6000915091506104b7565b73e57bfe9f44b819898f47bf37e5af72a0783e11418573ffffffffffffffffffffffffffffffffffffffff16148015610419575073d41c057fd1c78805aac12b0a94a405c0461a6fbb8473ffffffffffffffffffffffffffffffffffffffff16145b1561042b5760016000915091506104b7565b73d41c057fd1c78805aac12b0a94a405c0461a6fbb8573ffffffffffffffffffffffffffffffffffffffff1614801561048d575073e57bfe9f44b819898f47bf37e5af72a0783e11418473ffffffffffffffffffffffffffffffffffffffff16145b80156104995750600083145b156104ae5763ffffffff6000915091506104b7565b60006001915091505b9350939150505600a165627a7a723058204982adea2aa10a7b8328ec3829472ee17c62a86957ef6737f2eb729b2c3faf910029" - } - } - } - "#; + let spec_data = include_str!("../res/tx_permission_tests/contract_ver_2_genesis.json"); let tempdir = TempDir::new("").unwrap(); let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap(); @@ -271,51 +227,7 @@ mod test { /// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a #[test] fn transaction_filter_deprecated() { - let spec_data = r#" - { - "name": "TestNodeFilterContract", - "engine": { - "authorityRound": { - "params": { - "stepDuration": 1, - "startStep": 2, - "validators": { - "contract": "0x0000000000000000000000000000000000000000" - } - } - } - }, - "params": { - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID" : "0x69", - "gasLimitBoundDivisor": "0x0400", - "transactionPermissionContract": "0x0000000000000000000000000000000000000005" - }, - "genesis": { - "seal": { - "generic": "0xc180" - }, - "difficulty": "0x20000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x222222" - }, - "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": { - "balance": "1", - "constructor": "6060604052341561000f57600080fd5b5b6101868061001f6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e17512211461003e575b600080fd5b341561004957600080fd5b610075600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610097565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b6000737e5f4552091a69125d5dfcb7b8c2659029395bdf8273ffffffffffffffffffffffffffffffffffffffff1614156100d75763ffffffff9050610155565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8273ffffffffffffffffffffffffffffffffffffffff1614156101155760026001179050610155565b736813eb9362372eef6200f3b1dbc3f819671cba698273ffffffffffffffffffffffffffffffffffffffff1614156101505760019050610155565b600090505b9190505600a165627a7a72305820f1f21cb978925a8a92c6e30c8c81adf598adff6d1ef941cf5ed6c0ec7ad1ae3d0029" - } - } - } - "#; + let spec_data = include_str!("../res/tx_permission_tests/deprecated_contract_genesis.json"); let tempdir = TempDir::new("").unwrap(); let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap(); From b9bfff2f88a5545ba76f04d45b4c7bb0280e3f4a Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 13 Apr 2018 14:06:22 +0200 Subject: [PATCH 011/147] handle queue import errors a bit more gracefully (#8385) --- ethcore/sync/src/light_sync/mod.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index ef1bd8742f3..df76d25ccca 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -427,6 +427,8 @@ impl LightSync { // handles request dispatch, block import, state machine transitions, and timeouts. fn maintain_sync(&self, ctx: &BasicContext) { + use ethcore::error::{BlockImportError, ImportError}; + const DRAIN_AMOUNT: usize = 128; let client = self.client.as_light_client(); @@ -453,11 +455,20 @@ impl LightSync { trace!(target: "sync", "Drained {} headers to import", sink.len()); for header in sink.drain(..) { - if let Err(e) = client.queue_header(header) { - debug!(target: "sync", "Found bad header ({:?}). Reset to search state.", e); + match client.queue_header(header) { + Ok(_) => {} + Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + trace!(target: "sync", "Block already in chain. Continuing."); + }, + Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + trace!(target: "sync", "Block already queued. Continuing."); + }, + Err(e) => { + debug!(target: "sync", "Found bad header ({:?}). Reset to search state.", e); - self.begin_search(&mut state); - break 'a; + self.begin_search(&mut state); + break 'a; + } } } } From 94e2ea59fcacf36351bb04e71f59e2680d4dc467 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 13 Apr 2018 14:21:15 +0200 Subject: [PATCH 012/147] Some tweaks to main.rs for parity as a library (#8370) * Some tweaks to main.rs for parity as a library * Remove pub from PostExecutionAction --- parity/configuration.rs | 33 ++++++++++++++------------------- parity/main.rs | 32 +++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/parity/configuration.rs b/parity/configuration.rs index 96f819cba2c..d921c9377b4 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -95,16 +95,14 @@ pub struct Execute { #[derive(Debug, PartialEq)] pub struct Configuration { pub args: Args, - pub spec_name_override: Option, } impl Configuration { - pub fn parse>(command: &[S], spec_name_override: Option) -> Result { + pub fn parse>(command: &[S]) -> Result { let args = Args::parse(command)?; let config = Configuration { args: args, - spec_name_override: spec_name_override, }; Ok(config) @@ -462,9 +460,7 @@ impl Configuration { } fn chain(&self) -> Result { - let name = if let Some(ref s) = self.spec_name_override { - s.clone() - } else if self.args.flag_testnet { + let name = if self.args.flag_testnet { "testnet".to_owned() } else { self.args.arg_chain.clone() @@ -1264,7 +1260,6 @@ mod tests { fn parse(args: &[&str]) -> Configuration { Configuration { args: Args::parse_without_config(args).unwrap(), - spec_name_override: None, } } @@ -1844,7 +1839,7 @@ mod tests { let filename = tempdir.path().join("peers"); File::create(&filename).unwrap().write_all(b" \n\t\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); assert!(conf.init_reserved_nodes().is_ok()); } @@ -1854,7 +1849,7 @@ mod tests { let filename = tempdir.path().join("peers_comments"); File::create(&filename).unwrap().write_all(b"# Sample comment\nenode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@172.0.0.1:30303\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); let reserved_nodes = conf.init_reserved_nodes(); assert!(reserved_nodes.is_ok()); assert_eq!(reserved_nodes.unwrap().len(), 1); @@ -1863,7 +1858,7 @@ mod tests { #[test] fn test_dev_preset() { let args = vec!["parity", "--config", "dev"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1877,7 +1872,7 @@ mod tests { #[test] fn test_mining_preset() { let args = vec!["parity", "--config", "mining"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 50); @@ -1899,7 +1894,7 @@ mod tests { #[test] fn test_non_standard_ports_preset() { let args = vec!["parity", "--config", "non-standard-ports"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.network_port, 30305); @@ -1912,7 +1907,7 @@ mod tests { #[test] fn test_insecure_preset() { let args = vec!["parity", "--config", "insecure"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.update_policy.require_consensus, false); @@ -1932,7 +1927,7 @@ mod tests { #[test] fn test_dev_insecure_preset() { let args = vec!["parity", "--config", "dev-insecure"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1955,7 +1950,7 @@ mod tests { #[test] fn test_override_preset() { let args = vec!["parity", "--config", "mining", "--min-peers=99"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 99); @@ -2078,7 +2073,7 @@ mod tests { #[test] fn should_respect_only_max_peers_and_default() { let args = vec!["parity", "--max-peers=50"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 25); @@ -2091,7 +2086,7 @@ mod tests { #[test] fn should_respect_only_max_peers_less_than_default() { let args = vec!["parity", "--max-peers=5"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2104,7 +2099,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_default() { let args = vec!["parity", "--min-peers=5"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2117,7 +2112,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_greater_than_default() { let args = vec!["parity", "--min-peers=500"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 500); diff --git a/parity/main.rs b/parity/main.rs index 0b7c31d954d..d7d5b137e32 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -180,9 +180,10 @@ fn execute(command: Execute, can_restart: bool) -> Result Result { - let args: Vec = env::args().collect(); - let conf = Configuration::parse(&args, take_spec_name_override()).unwrap_or_else(|e| e.exit()); +fn start(mut args: Vec) -> Result { + args.insert(0, "parity".to_owned()); + let conf = Configuration::parse(&args).unwrap_or_else(|e| e.exit()); + let can_restart = conf.args.flag_can_restart; let deprecated = find_deprecated(&conf.args); for d in deprecated { @@ -276,7 +277,7 @@ const PLEASE_RESTART_EXIT_CODE: i32 = 69; // Run our version of parity. // Returns the exit error code. -fn main_direct(can_restart: bool) -> i32 { +fn main_direct(force_can_restart: bool) -> i32 { global_init(); let mut alt_mains = HashMap::new(); sync_main(&mut alt_mains); @@ -285,7 +286,25 @@ fn main_direct(can_restart: bool) -> i32 { f(); 0 } else { - match start(can_restart) { + let mut args = std::env::args().skip(1).collect::>(); + if force_can_restart && !args.iter().any(|arg| arg == "--can-restart") { + args.push("--can-restart".to_owned()); + } + + if let Some(spec_override) = take_spec_name_override() { + args.retain(|f| f != "--testnet"); + args.retain(|f| !f.starts_with("--chain=")); + while let Some(pos) = args.iter().position(|a| a == "--chain") { + if args.len() > pos + 1 { + args.remove(pos + 1); + } + args.remove(pos); + } + args.push("--chain".to_owned()); + args.push(spec_override); + } + + match start(args) { Ok(result) => match result { PostExecutionAction::Print(s) => { println!("{}", s); 0 }, PostExecutionAction::Restart(spec_name_override) => { @@ -365,7 +384,6 @@ fn main() { } else { trace_main!("Running direct"); // Otherwise, we're presumably running the version we want. Just run and fall-through. - let can_restart = std::env::args().any(|arg| arg == "--can-restart"); - process::exit(main_direct(can_restart)); + process::exit(main_direct(false)); } } From 77727efb96cc357069cfdfb271503eaa7d165700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 13 Apr 2018 17:34:27 +0200 Subject: [PATCH 013/147] New Transaction Queue implementation (#8074) * Implementation of Verifier, Scoring and Ready. * Queue in progress. * TransactionPool. * Prepare for txpool release. * Miner refactor [WiP] * WiP reworking miner. * Make it compile. * Add some docs. * Split blockchain access to a separate file. * Work on miner API. * Fix ethcore tests. * Refactor miner interface for sealing/work packages. * Implement next nonce. * RPC compiles. * Implement couple of missing methdods for RPC. * Add transaction queue listeners. * Compiles! * Clean-up and parallelize. * Get rid of RefCell in header. * Revert "Get rid of RefCell in header." This reverts commit 0f2424c9b7319a786e1565ea2a8a6d801a21b4fb. * Override Sync requirement. * Fix status display. * Unify logging. * Extract some cheap checks. * Measurements and optimizations. * Fix scoring bug, heap size of bug and add cache * Disable tx queueing and parallel verification. * Make ethcore and ethcore-miner compile again. * Make RPC compile again. * Bunch of txpool tests. * Migrate transaction queue tests. * Nonce Cap * Nonce cap cache and tests. * Remove stale future transactions from the queue. * Optimize scoring and write some tests. * Simple penalization. * Clean up and support for different scoring algorithms. * Add CLI parameters for the new queue. * Remove banning queue. * Disable debug build. * Change per_sender limit to be 1% instead of 5% * Avoid cloning when propagating transactions. * Remove old todo. * Post-review fixes. * Fix miner options default. * Implement back ready transactions for light client. * Get rid of from_pending_block * Pass rejection reason. * Add more details to drop. * Rollback heap size of. * Avoid cloning hashes when propagating and include more details on rejection. * Fix tests. * Introduce nonces cache. * Remove uneccessary hashes allocation. * Lower the mem limit. * Re-enable parallel verification. * Add miner log. Don't check the type if not below min_gas_price. * Add more traces, fix disabling miner. * Fix creating pending blocks twice on AuRa authorities. * Fix tests. * re-use pending blocks in AuRa * Use reseal_min_period to prevent too frequent update_sealing. * Fix log to contain hash not sender. * Optimize local transactions. * Fix aura tests. * Update locks comments. * Get rid of unsafe Sync impl. * Review fixes. * Remove excessive matches. * Fix compilation errors. * Use new pool in private transactions. * Fix private-tx test. * Fix secret store tests. * Actually use gas_floor_target * Fix config tests. * Fix pool tests. * Address grumbles. --- Cargo.lock | 23 +- ethcore/Cargo.toml | 15 +- ethcore/light/src/provider.rs | 3 + ethcore/light/src/transaction_queue.rs | 24 +- ethcore/node_filter/src/lib.rs | 2 +- ethcore/private-tx/src/lib.rs | 97 +- .../private-tx/src/private_transactions.rs | 105 +- ethcore/private-tx/tests/private_contract.rs | 11 +- ethcore/service/src/service.rs | 15 +- ethcore/src/account_provider/mod.rs | 3 - ethcore/src/block.rs | 81 +- ethcore/src/blockchain/best_block.rs | 1 + ethcore/src/client/chain_notify.rs | 5 +- ethcore/src/client/client.rs | 95 +- ethcore/src/client/mod.rs | 2 +- ethcore/src/client/test_client.rs | 39 +- ethcore/src/client/traits.rs | 20 +- ethcore/src/engines/authority_round/mod.rs | 17 +- ethcore/src/engines/basic_authority.rs | 6 +- ethcore/src/engines/mod.rs | 26 +- ethcore/src/engines/tendermint/mod.rs | 14 +- ethcore/src/engines/validator_set/contract.rs | 4 +- ethcore/src/engines/validator_set/multi.rs | 8 +- .../engines/validator_set/safe_contract.rs | 6 +- ethcore/src/json_tests/chain.rs | 2 +- ethcore/src/lib.rs | 19 +- ethcore/src/machine.rs | 10 +- ethcore/src/miner/miner.rs | 1618 ++++----- ethcore/src/miner/mod.rs | 248 +- ethcore/src/miner/pool_client.rs | 216 ++ .../src/miner/service_transaction_checker.rs | 19 +- ethcore/src/miner/stratum.rs | 25 +- .../src/snapshot/tests/proof_of_authority.rs | 6 +- ethcore/src/snapshot/tests/service.rs | 2 +- ethcore/src/test_helpers.rs | 4 +- ethcore/src/tests/client.rs | 16 +- ethcore/src/tests/trace.rs | 2 +- ethcore/src/tx_filter.rs | 2 +- ethcore/sync/src/api.rs | 5 +- ethcore/sync/src/chain.rs | 44 +- ethcore/sync/src/tests/consensus.rs | 38 +- ethcore/sync/src/tests/helpers.rs | 12 +- ethcore/transaction/src/lib.rs | 11 - ethcore/transaction/src/transaction.rs | 2 +- miner/Cargo.toml | 29 +- miner/src/banning_queue.rs | 321 -- miner/src/gas_pricer.rs | 97 + miner/src/lib.rs | 24 +- miner/src/local_transactions.rs | 220 -- miner/src/pool/client.rs | 71 + miner/src/pool/listener.rs | 161 + miner/src/pool/local_transactions.rs | 273 ++ miner/src/pool/mod.rs | 135 + miner/src/pool/queue.rs | 445 +++ miner/src/pool/ready.rs | 212 ++ miner/src/pool/scoring.rs | 171 + miner/src/pool/tests/client.rs | 125 + miner/src/pool/tests/mod.rs | 757 +++++ miner/src/pool/tests/tx.rs | 185 ++ miner/src/pool/verifier.rs | 288 ++ miner/src/transaction_queue.rs | 2944 ----------------- parity/blockchain.rs | 12 +- parity/cli/mod.rs | 32 +- parity/cli/presets/config.mining.toml | 9 +- parity/configuration.rs | 96 +- parity/helpers.rs | 23 +- parity/params.rs | 36 +- parity/run.rs | 48 +- parity/snapshot.rs | 6 +- price-info/src/lib.rs | 2 +- rpc/Cargo.toml | 7 +- rpc/src/lib.rs | 2 + rpc/src/v1/helpers/dispatch.rs | 13 +- rpc/src/v1/helpers/errors.rs | 4 +- rpc/src/v1/impls/eth.rs | 121 +- rpc/src/v1/impls/eth_filter.rs | 29 +- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 15 + rpc/src/v1/impls/parity.rs | 46 +- rpc/src/v1/impls/parity_set.rs | 50 +- rpc/src/v1/impls/traces.rs | 4 +- rpc/src/v1/tests/eth.rs | 31 +- rpc/src/v1/tests/helpers/miner_service.rs | 238 +- rpc/src/v1/tests/mocked/eth.rs | 20 +- rpc/src/v1/tests/mocked/parity.rs | 25 +- rpc/src/v1/tests/mocked/parity_set.rs | 14 +- rpc/src/v1/tests/mocked/personal.rs | 2 +- rpc/src/v1/tests/mocked/signing.rs | 2 +- rpc/src/v1/traits/parity.rs | 8 +- rpc/src/v1/types/transaction.rs | 31 +- secret_store/src/trusted_client.rs | 2 +- transaction-pool/Cargo.toml | 1 + transaction-pool/src/error.rs | 10 +- transaction-pool/src/lib.rs | 3 + transaction-pool/src/listener.rs | 46 +- transaction-pool/src/options.rs | 2 +- transaction-pool/src/pool.rs | 93 +- transaction-pool/src/scoring.rs | 16 +- transaction-pool/src/status.rs | 4 +- transaction-pool/src/tests/helpers.rs | 17 +- transaction-pool/src/tests/mod.rs | 94 +- transaction-pool/src/transactions.rs | 19 +- util/table/Cargo.toml | 6 - util/table/src/lib.rs | 261 -- util/using_queue/src/lib.rs | 4 +- 105 files changed, 5144 insertions(+), 5743 deletions(-) create mode 100644 ethcore/src/miner/pool_client.rs delete mode 100644 miner/src/banning_queue.rs create mode 100644 miner/src/gas_pricer.rs delete mode 100644 miner/src/local_transactions.rs create mode 100644 miner/src/pool/client.rs create mode 100644 miner/src/pool/listener.rs create mode 100644 miner/src/pool/local_transactions.rs create mode 100644 miner/src/pool/mod.rs create mode 100644 miner/src/pool/queue.rs create mode 100644 miner/src/pool/ready.rs create mode 100644 miner/src/pool/scoring.rs create mode 100644 miner/src/pool/tests/client.rs create mode 100644 miner/src/pool/tests/mod.rs create mode 100644 miner/src/pool/tests/tx.rs create mode 100644 miner/src/pool/verifier.rs delete mode 100644 miner/src/transaction_queue.rs delete mode 100644 util/table/Cargo.toml delete mode 100644 util/table/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fb1d9ce5575..70f7a026617 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -511,7 +511,6 @@ dependencies = [ "ethstore 0.2.0", "evm 0.1.0", "fetch 0.1.0", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hardware-wallet 1.11.0", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -532,7 +531,6 @@ dependencies = [ "parity-machine 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", - "price-info 1.11.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -543,7 +541,6 @@ dependencies = [ "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", "stats 0.1.0", "stop-guard 0.1.0", - "table 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", "trie-standardmap 0.1.0", @@ -655,16 +652,16 @@ dependencies = [ name = "ethcore-miner" version = "1.11.0" dependencies = [ - "common-types 0.1.0", - "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -672,9 +669,11 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "price-info 1.11.0", + "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "table 0.1.0", - "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", + "transaction-pool 1.11.0", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2191,6 +2190,7 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "transaction-pool 1.11.0", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -3076,10 +3076,6 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "table" -version = "0.1.0" - [[package]] name = "take" version = "0.1.0" @@ -3403,6 +3399,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", ] [[package]] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 0ffb7034a35..b8035f07124 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -34,7 +34,6 @@ ethjson = { path = "../json" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } evm = { path = "evm" } -futures-cpupool = "0.1" hardware-wallet = { path = "../hw" } heapsize = "0.4" itertools = "0.5" @@ -45,7 +44,6 @@ num = { version = "0.1", default-features = false, features = ["bigint"] } num_cpus = "1.2" parity-machine = { path = "../machine" } parking_lot = "0.5" -price-info = { path = "../price-info" } rayon = "1.0" rand = "0.4" rlp = { path = "../util/rlp" } @@ -63,7 +61,6 @@ rustc-hex = "1.0" stats = { path = "../util/stats" } trace-time = { path = "../util/trace-time" } using_queue = { path = "../util/using_queue" } -table = { path = "../util/table" } vm = { path = "vm" } wasm = { path = "wasm" } keccak-hash = { path = "../util/hash" } @@ -76,10 +73,18 @@ tempdir = "0.3" trie-standardmap = { path = "../util/trie-standardmap" } [features] +# Display EVM debug traces. evm-debug = ["slow-blocks"] +# Display EVM debug traces when running tests. evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"] -slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms +# Measure time of transaction execution. +# Whenever the transaction execution time (in millis) exceeds the value of +# SLOW_TX_DURATION env variable (provided compile time!) +# EVM debug traces are printed. +slow-blocks = [] +# Run JSON consensus tests. json-tests = ["ethcore-transaction/json-tests"] +# Run memory/cpu heavy tests. test-heavy = [] -default = [] +# Compile benches benches = [] diff --git a/ethcore/light/src/provider.rs b/ethcore/light/src/provider.rs index 1d9af0ac19b..aaa6f5858ae 100644 --- a/ethcore/light/src/provider.rs +++ b/ethcore/light/src/provider.rs @@ -282,6 +282,9 @@ impl Provider for T { fn ready_transactions(&self) -> Vec { BlockChainClient::ready_transactions(self) + .into_iter() + .map(|tx| tx.pending().clone()) + .collect() } fn epoch_signal(&self, req: request::CompleteSignalRequest) -> Option { diff --git a/ethcore/light/src/transaction_queue.rs b/ethcore/light/src/transaction_queue.rs index 156152253dd..ae3dc269156 100644 --- a/ethcore/light/src/transaction_queue.rs +++ b/ethcore/light/src/transaction_queue.rs @@ -120,6 +120,18 @@ impl AccountTransactions { } } +/// Transaction import result. +pub enum ImportDestination { + /// Transaction has been imported to the current queue. + /// + /// It's going to be propagated to peers. + Current, + /// Transaction has been imported to future queue. + /// + /// It means it won't be propagated until the gap is filled. + Future, +} + type Listener = Box; /// Light transaction queue. See module docs for more details. @@ -142,7 +154,7 @@ impl fmt::Debug for TransactionQueue { impl TransactionQueue { /// Import a pending transaction to be queued. - pub fn import(&mut self, tx: PendingTransaction) -> Result { + pub fn import(&mut self, tx: PendingTransaction) -> Result { let sender = tx.sender(); let hash = tx.hash(); let nonce = tx.nonce; @@ -158,7 +170,7 @@ impl TransactionQueue { future: BTreeMap::new(), }); - (transaction::ImportResult::Current, vec![hash]) + (ImportDestination::Current, vec![hash]) } Entry::Occupied(mut entry) => { let acct_txs = entry.get_mut(); @@ -180,7 +192,7 @@ impl TransactionQueue { let old = ::std::mem::replace(&mut acct_txs.current[idx], tx_info); self.by_hash.remove(&old.hash); - (transaction::ImportResult::Current, vec![hash]) + (ImportDestination::Current, vec![hash]) } Err(idx) => { let cur_len = acct_txs.current.len(); @@ -202,13 +214,13 @@ impl TransactionQueue { acct_txs.future.insert(future_nonce, future); } - (transaction::ImportResult::Current, vec![hash]) + (ImportDestination::Current, vec![hash]) } else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) { trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce); let future_nonce = nonce; acct_txs.future.insert(future_nonce, tx_info); - (transaction::ImportResult::Future, vec![]) + (ImportDestination::Future, vec![]) } else { trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce); @@ -217,7 +229,7 @@ impl TransactionQueue { let mut promoted = acct_txs.adjust_future(); promoted.insert(0, hash); - (transaction::ImportResult::Current, promoted) + (ImportDestination::Current, promoted) } } } diff --git a/ethcore/node_filter/src/lib.rs b/ethcore/node_filter/src/lib.rs index cbf5f4e5d46..715b7ae3e98 100644 --- a/ethcore/node_filter/src/lib.rs +++ b/ethcore/node_filter/src/lib.rs @@ -132,7 +132,7 @@ mod test { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let filter = NodeFilter::new(Arc::downgrade(&client) as Weak, contract_addr); diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index ef97c6e2e6d..e28dd7c3314 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -78,12 +78,10 @@ use ethcore::executed::{Executed}; use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction}; use ethcore::{contract_address as ethcore_contract_address}; use ethcore::client::{ - Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, - MiningBlockChainClient, ChainInfo, Nonce, CallContract + Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, CallContract }; use ethcore::account_provider::AccountProvider; -use ethcore_miner::transaction_queue::{TransactionDetailsProvider as TransactionQueueDetailsProvider, AccountDetails}; -use ethcore::miner::MinerService; +use ethcore::miner::{self, Miner, MinerService}; use ethcore::trace::{Tracer, VMTracer}; use rustc_hex::FromHex; @@ -95,35 +93,6 @@ use_contract!(private, "PrivateContract", "res/private.json"); /// Initialization vector length. const INIT_VEC_LEN: usize = 16; -struct TransactionDetailsProvider<'a> { - client: &'a MiningBlockChainClient, -} - -impl<'a> TransactionDetailsProvider<'a> { - pub fn new(client: &'a MiningBlockChainClient) -> Self { - TransactionDetailsProvider { - client: client, - } - } -} - -impl<'a> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a> { - fn fetch_account(&self, address: &Address) -> AccountDetails { - AccountDetails { - nonce: self.client.latest_nonce(address), - balance: self.client.latest_balance(address), - } - } - - fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256 { - tx.gas_required(&self.client.latest_schedule()).into() - } - - fn is_service_transaction_acceptable(&self, _tx: &SignedTransaction) -> Result { - Ok(false) - } -} - /// Configurtion for private transaction provider #[derive(Default, PartialEq, Debug, Clone)] pub struct ProviderConfig { @@ -154,8 +123,10 @@ pub struct Provider { passwords: Vec, notify: RwLock>>, transactions_for_signing: Mutex, + // TODO [ToDr] Move the Mutex/RwLock inside `VerificationStore` after refactored to `drain`. transactions_for_verification: Mutex, client: Arc, + miner: Arc, accounts: Arc, channel: IoChannel, } @@ -172,6 +143,7 @@ impl Provider where { /// Create a new provider. pub fn new( client: Arc, + miner: Arc, accounts: Arc, encryptor: Box, config: ProviderConfig, @@ -186,6 +158,7 @@ impl Provider where { transactions_for_signing: Mutex::default(), transactions_for_verification: Mutex::default(), client, + miner, accounts, channel, }) @@ -282,6 +255,9 @@ impl Provider where { match validation_account { None => { + // TODO [ToDr] This still seems a bit invalid, imho we should still import the transaction to the pool. + // Importing to pool verifies correctness and nonce; here we are just blindly forwarding. + // // Not for verification, broadcast further to peers self.broadcast_private_transaction(rlp.into()); return Ok(()); @@ -291,29 +267,59 @@ impl Provider where { trace!("Private transaction taken for verification"); let original_tx = self.extract_original_transaction(private_tx, &contract)?; trace!("Validating transaction: {:?}", original_tx); - let details_provider = TransactionDetailsProvider::new(&*self.client as &MiningBlockChainClient); - let insertion_time = self.client.chain_info().best_block_number; // Verify with the first account available trace!("The following account will be used for verification: {:?}", validation_account); - self.transactions_for_verification.lock() - .add_transaction(original_tx, contract, validation_account, hash, &details_provider, insertion_time)?; + let nonce_cache = Default::default(); + self.transactions_for_verification.lock().add_transaction( + original_tx, + contract, + validation_account, + hash, + self.pool_client(&nonce_cache), + )?; + // NOTE This will just fire `on_private_transaction_queued` but from a client thread. + // It seems that a lot of heavy work (verification) is done in this thread anyway + // it might actually make sense to decouple it from clientService and just use dedicated thread + // for both verification and execution. self.channel.send(ClientIoMessage::NewPrivateTransaction).map_err(|_| ErrorKind::ClientIsMalformed.into()) } } } + fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { + let engine = self.client.engine(); + let refuse_service_transactions = true; + miner::pool_client::PoolClient::new( + &*self.client, + nonce_cache, + engine, + Some(&*self.accounts), + refuse_service_transactions, + ) + } + /// Private transaction for validation added into queue pub fn on_private_transaction_queued(&self) -> Result<(), Error> { self.process_queue() } /// Retrieve and verify the first available private transaction for every sender + /// + /// TODO [ToDr] It seems that: + /// 1. This method will fail on any error without removing invalid transaction. + /// 2. It means that the transaction will be stuck there forever and we will never be able to make any progress. + /// + /// It might be more sensible to `drain()` transactions from the queue instead and process all of them, + /// possibly printing some errors in case of failures. + /// The 3 methods `ready_transaction,get_descriptor,remove` are always used in conjuction so most likely + /// can be replaced with a single `drain()` method instead. + /// Thanks to this we also don't really need to lock the entire verification for the time of execution. fn process_queue(&self) -> Result<(), Error> { + let nonce_cache = Default::default(); let mut verification_queue = self.transactions_for_verification.lock(); - let ready_transactions = verification_queue.ready_transactions(); - let fetch_nonce = |a: &Address| self.client.latest_nonce(a); + let ready_transactions = verification_queue.ready_transactions(self.pool_client(&nonce_cache)); for transaction in ready_transactions { - let transaction_hash = transaction.hash(); + let transaction_hash = transaction.signed().hash(); match verification_queue.private_transaction_descriptor(&transaction_hash) { Ok(desc) => { if !self.validator_accounts.contains(&desc.validator_account) { @@ -321,9 +327,10 @@ impl Provider where { bail!(ErrorKind::ValidatorAccountNotSet); } let account = desc.validator_account; - if let Action::Call(contract) = transaction.action { + if let Action::Call(contract) = transaction.signed().action { + // TODO [ToDr] Usage of BlockId::Latest let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest)?; - let private_state = self.execute_private_transaction(BlockId::Latest, &transaction)?; + let private_state = self.execute_private_transaction(BlockId::Latest, transaction.signed())?; let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce); trace!("Hashed effective private state for validator: {:?}", private_state_hash); let password = find_account_password(&self.passwords, &*self.accounts, &account); @@ -341,7 +348,7 @@ impl Provider where { bail!(e); } } - verification_queue.remove_private_transaction(&transaction_hash, &fetch_nonce); + verification_queue.remove_private_transaction(&transaction_hash); } Ok(()) } @@ -354,6 +361,8 @@ impl Provider where { let private_hash = tx.private_transaction_hash(); let desc = match self.transactions_for_signing.lock().get(&private_hash) { None => { + // TODO [ToDr] Verification (we can't just blindly forward every transaction) + // Not our transaction, broadcast further to peers self.broadcast_signed_private_transaction(rlp.into()); return Ok(()); @@ -383,7 +392,7 @@ impl Provider where { let password = find_account_password(&self.passwords, &*self.accounts, &signer_account); let signature = self.accounts.sign(signer_account, password, hash)?; let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?; - match self.client.miner().import_own_transaction(&*self.client, signed.into()) { + match self.miner.import_own_transaction(&*self.client, signed.into()) { Ok(_) => trace!("Public transaction added to queue"), Err(err) => { trace!("Failed to add transaction to queue, error: {:?}", err); diff --git a/ethcore/private-tx/src/private_transactions.rs b/ethcore/private-tx/src/private_transactions.rs index 502694294ec..1a018d927ad 100644 --- a/ethcore/private-tx/src/private_transactions.rs +++ b/ethcore/private-tx/src/private_transactions.rs @@ -14,15 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::Signature; +use std::sync::Arc; +use std::collections::{HashMap, HashSet}; + use bytes::Bytes; -use std::collections::HashMap; +use ethcore_miner::pool; use ethereum_types::{H256, U256, Address}; +use ethkey::Signature; use transaction::{UnverifiedTransaction, SignedTransaction}; -use ethcore_miner::transaction_queue::{TransactionQueue, RemovalReason, - TransactionDetailsProvider as TransactionQueueDetailsProvider, TransactionOrigin}; + use error::{Error, ErrorKind}; -use ethcore::header::BlockNumber; /// Maximum length for private transactions queues. const MAX_QUEUE_LEN: usize = 8312; @@ -39,56 +40,92 @@ pub struct PrivateTransactionDesc { } /// Storage for private transactions for verification -#[derive(Default)] pub struct VerificationStore { /// Descriptors for private transactions in queue for verification with key - hash of the original transaction descriptors: HashMap, /// Queue with transactions for verification - transactions: TransactionQueue, + /// + /// TODO [ToDr] Might actually be better to use `txpool` directly and: + /// 1. Store descriptors inside `VerifiedTransaction` + /// 2. Use custom `ready` implementation to only fetch one transaction per sender. + /// 3. Get rid of passing dummy `block_number` and `timestamp` + transactions: pool::TransactionQueue, +} + +impl Default for VerificationStore { + fn default() -> Self { + VerificationStore { + descriptors: Default::default(), + transactions: pool::TransactionQueue::new( + pool::Options { + max_count: MAX_QUEUE_LEN, + max_per_sender: MAX_QUEUE_LEN / 10, + max_mem_usage: 8 * 1024 * 1024, + }, + pool::verifier::Options { + // TODO [ToDr] This should probably be based on some real values? + minimal_gas_price: 0.into(), + block_gas_limit: 8_000_000.into(), + tx_gas_limit: U256::max_value(), + }, + pool::PrioritizationStrategy::GasPriceOnly, + ) + } + } } impl VerificationStore { /// Adds private transaction for verification into the store - pub fn add_transaction( + pub fn add_transaction( &mut self, transaction: UnverifiedTransaction, contract: Address, validator_account: Address, private_hash: H256, - details_provider: &TransactionQueueDetailsProvider, - insertion_time: BlockNumber, + client: C, ) -> Result<(), Error> { if self.descriptors.len() > MAX_QUEUE_LEN { bail!(ErrorKind::QueueIsFull); } - if self.descriptors.get(&transaction.hash()).is_some() { + let transaction_hash = transaction.hash(); + if self.descriptors.get(&transaction_hash).is_some() { bail!(ErrorKind::PrivateTransactionAlreadyImported); } - let transaction_hash = transaction.hash(); - let signed_transaction = SignedTransaction::new(transaction)?; - self.transactions - .add(signed_transaction, TransactionOrigin::External, insertion_time, None, details_provider) - .and_then(|_| { - self.descriptors.insert(transaction_hash, PrivateTransactionDesc{ - private_hash, - contract, - validator_account, - }); - Ok(()) - }) - .map_err(Into::into) + + let results = self.transactions.import( + client, + vec![pool::verifier::Transaction::Unverified(transaction)], + ); + + // Verify that transaction was imported + results.into_iter() + .next() + .expect("One transaction inserted; one result returned; qed")?; + + self.descriptors.insert(transaction_hash, PrivateTransactionDesc { + private_hash, + contract, + validator_account, + }); + + Ok(()) } /// Returns transactions ready for verification /// Returns only one transaction per sender because several cannot be verified in a row without verification from other peers - pub fn ready_transactions(&self) -> Vec { - // TODO [ToDr] Performance killer, re-work with new transaction queue. - let mut transactions = self.transactions.top_transactions(); - // TODO [ToDr] Potential issue (create low address to have your transactions processed first) - transactions.sort_by(|a, b| a.sender().cmp(&b.sender())); - transactions.dedup_by(|a, b| a.sender().eq(&b.sender())); - transactions + pub fn ready_transactions(&self, client: C) -> Vec> { + // We never store PendingTransactions and we don't use internal cache, + // so we don't need to provide real block number of timestamp here + let block_number = 0; + let timestamp = 0; + let nonce_cap = None; + + self.transactions.collect_pending(client, block_number, timestamp, nonce_cap, |transactions| { + // take only one transaction per sender + let mut senders = HashSet::with_capacity(self.descriptors.len()); + transactions.filter(move |tx| senders.insert(tx.signed().sender())).collect() + }) } /// Returns descriptor of the corresponding private transaction @@ -97,11 +134,9 @@ impl VerificationStore { } /// Remove transaction from the queue for verification - pub fn remove_private_transaction(&mut self, transaction_hash: &H256, fetch_nonce: &F) - where F: Fn(&Address) -> U256 { - + pub fn remove_private_transaction(&mut self, transaction_hash: &H256) { self.descriptors.remove(transaction_hash); - self.transactions.remove(transaction_hash, fetch_nonce, RemovalReason::Invalid); + self.transactions.remove(&[*transaction_hash], true); } } diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs index ba918c96361..e53ad5e5f68 100644 --- a/ethcore/private-tx/tests/private_contract.rs +++ b/ethcore/private-tx/tests/private_contract.rs @@ -36,6 +36,7 @@ use ethcore::account_provider::AccountProvider; use ethcore::client::BlockChainClient; use ethcore::client::BlockId; use ethcore::executive::{contract_address}; +use ethcore::miner::Miner; use ethcore::test_helpers::{generate_dummy_client, push_block_with_transactions}; use ethcore_transaction::{Transaction, Action}; use ethkey::{Secret, KeyPair, Signature}; @@ -65,7 +66,15 @@ fn private_contract() { }; let io = ethcore_io::IoChannel::disconnected(); - let pm = Arc::new(Provider::new(client.clone(), ap.clone(), Box::new(NoopEncryptor::default()), config, io).unwrap()); + let miner = Arc::new(Miner::new_for_tests(&::ethcore::spec::Spec::new_test(), None)); + let pm = Arc::new(Provider::new( + client.clone(), + miner, + ap.clone(), + Box::new(NoopEncryptor::default()), + config, + io, + ).unwrap()); let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]); diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 8fab545574c..b57d613e3ba 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -92,7 +92,7 @@ impl ClientService { info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name())); let pruning = config.pruning; - let client = Client::new(config, &spec, client_db.clone(), miner, io_service.channel())?; + let client = Client::new(config, &spec, client_db.clone(), miner.clone(), io_service.channel())?; let snapshot_params = SnapServiceParams { engine: spec.engine.clone(), @@ -105,7 +105,14 @@ impl ClientService { }; let snapshot = Arc::new(SnapshotService::new(snapshot_params)?); - let provider = Arc::new(ethcore_private_tx::Provider::new(client.clone(), account_provider, encryptor, private_tx_conf, io_service.channel())?); + let provider = Arc::new(ethcore_private_tx::Provider::new( + client.clone(), + miner, + account_provider, + encryptor, + private_tx_conf, + io_service.channel())?, + ); let private_tx = Arc::new(PrivateTxService::new(provider)); let client_io = Arc::new(ClientIoHandler { @@ -292,10 +299,10 @@ mod tests { &snapshot_path, restoration_db_handler, tempdir.path(), - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ); assert!(service.is_ok()); drop(service.unwrap()); diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 74d24e7f50e..2edb42be1e9 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -66,8 +66,6 @@ pub enum SignError { Hardware(HardwareError), /// Low-level error from store SStore(SSError), - /// Inappropriate chain - InappropriateChain, } impl fmt::Display for SignError { @@ -77,7 +75,6 @@ impl fmt::Display for SignError { SignError::NotFound => write!(f, "Account does not exist"), SignError::Hardware(ref e) => write!(f, "{}", e), SignError::SStore(ref e) => write!(f, "{}", e), - SignError::InappropriateChain => write!(f, "Inappropriate chain"), } } } diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 8e1fac1792e..4cbc0bac9f8 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -337,8 +337,33 @@ impl<'x> OpenBlock<'x> { } /// Push transactions onto the block. - pub fn push_transactions(&mut self, transactions: &[SignedTransaction]) -> Result<(), Error> { - push_transactions(self, transactions) + #[cfg(not(feature = "slow-blocks"))] + fn push_transactions(&mut self, transactions: Vec) -> Result<(), Error> { + for t in transactions { + self.push_transaction(t, None)?; + } + Ok(()) + } + + /// Push transactions onto the block. + #[cfg(feature = "slow-blocks")] + fn push_transactions(&mut self, transactions: Vec) -> Result<(), Error> { + use std::time; + + let slow_tx = option_env!("SLOW_TX_DURATION").and_then(|v| v.parse().ok()).unwrap_or(100); + for t in transactions { + let hash = t.hash(); + let start = time::Instant::now(); + self.push_transaction(t, None)?; + let took = start.elapsed(); + let took_ms = took.as_secs() * 1000 + took.subsec_nanos() as u64 / 1000000; + if took > time::Duration::from_millis(slow_tx) { + warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, block.header().number(), hash); + } + debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms); + } + + Ok(()) } /// Populate self from a header. @@ -534,10 +559,10 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact( - header: &Header, - transactions: &[SignedTransaction], - uncles: &[Header], +fn enact( + header: Header, + transactions: Vec, + uncles: Vec
, engine: &EthEngine, tracing: bool, db: StateDB, @@ -568,11 +593,11 @@ pub fn enact( is_epoch_begin, )?; - b.populate_from(header); + b.populate_from(&header); b.push_transactions(transactions)?; for u in uncles { - b.push_uncle(u.clone())?; + b.push_uncle(u)?; } if strip_receipts { @@ -584,38 +609,9 @@ pub fn enact( Ok(b.close_and_lock()) } -#[inline] -#[cfg(not(feature = "slow-blocks"))] -fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> { - for t in transactions { - block.push_transaction(t.clone(), None)?; - } - Ok(()) -} - -#[cfg(feature = "slow-blocks")] -fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> { - use std::time; - - let slow_tx = option_env!("SLOW_TX_DURATION").and_then(|v| v.parse().ok()).unwrap_or(100); - for t in transactions { - let hash = t.hash(); - let start = time::Instant::now(); - block.push_transaction(t.clone(), None)?; - let took = start.elapsed(); - let took_ms = took.as_secs() * 1000 + took.subsec_nanos() as u64 / 1000000; - if took > time::Duration::from_millis(slow_tx) { - warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, block.header().number(), hash); - } - debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms); - } - Ok(()) -} - -// TODO [ToDr] Pass `PreverifiedBlock` by move, this will avoid unecessary allocation /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header pub fn enact_verified( - block: &PreverifiedBlock, + block: PreverifiedBlock, engine: &EthEngine, tracing: bool, db: StateDB, @@ -629,9 +625,9 @@ pub fn enact_verified( let view = BlockView::new(&block.bytes); enact( - &block.header, - &block.transactions, - &view.uncles(), + block.header, + block.transactions, + view.uncles(), engine, tracing, db, @@ -700,7 +696,7 @@ mod tests { )?; b.populate_from(&header); - b.push_transactions(&transactions)?; + b.push_transactions(transactions)?; for u in &block.uncles() { b.push_uncle(u.clone())?; @@ -793,3 +789,4 @@ mod tests { assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); } } + diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index d5a6ce91a4e..017c4f86ea0 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use ethereum_types::{H256, U256}; + use encoded; use header::{Header, BlockNumber}; diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index bdd8d00278c..ccfb2558d61 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -14,8 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; use bytes::Bytes; +use ethereum_types::H256; +use transaction::UnverifiedTransaction; /// Messages to broadcast via chain pub enum ChainMessageType { @@ -59,7 +60,7 @@ pub trait ChainNotify : Send + Sync { /// fires when new transactions are received from a peer fn transactions_received(&self, - _hashes: Vec, + _txs: &[UnverifiedTransaction], _peer_id: usize, ) { // does nothing by default diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a8ce3f65c3c..fb3f07e41e1 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -44,7 +44,7 @@ use client::{ }; use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, - MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, + TraceFilter, CallAnalytics, BlockImportError, Mode, ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType }; use encoded; @@ -58,6 +58,7 @@ use header::{BlockNumber, Header}; use io::IoChannel; use log_entry::LocalizedLogEntry; use miner::{Miner, MinerService}; +use ethcore_miner::pool::VerifiedTransaction; use parking_lot::{Mutex, RwLock}; use rand::OsRng; use receipt::{Receipt, LocalizedReceipt}; @@ -68,7 +69,7 @@ use state_db::StateDB; use state::{self, State}; use trace; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; -use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, PendingTransaction, Action}; +use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, Action}; use types::filter::Filter; use types::mode::Mode as IpcMode; use verification; @@ -103,10 +104,10 @@ pub struct ClientReport { impl ClientReport { /// Alter internal reporting to reflect the additional `block` has been processed. - pub fn accrue_block(&mut self, block: &PreverifiedBlock) { + pub fn accrue_block(&mut self, header: &Header, transactions: usize) { self.blocks_imported += 1; - self.transactions_applied += block.transactions.len(); - self.gas_processed = self.gas_processed + block.header.gas_used().clone(); + self.transactions_applied += transactions; + self.gas_processed = self.gas_processed + *header.gas_used(); } } @@ -295,23 +296,29 @@ impl Importer { let start = Instant::now(); for block in blocks { - let header = &block.header; + let header = block.header.clone(); + let bytes = block.bytes.clone(); + let hash = header.hash(); + let is_invalid = invalid_blocks.contains(header.parent_hash()); if is_invalid { - invalid_blocks.insert(header.hash()); + invalid_blocks.insert(hash); continue; } - if let Ok(closed_block) = self.check_and_close_block(&block, client) { - if self.engine.is_proposal(&block.header) { - self.block_queue.mark_as_good(&[header.hash()]); - proposed_blocks.push(block.bytes); + + if let Ok(closed_block) = self.check_and_close_block(block, client) { + if self.engine.is_proposal(&header) { + self.block_queue.mark_as_good(&[hash]); + proposed_blocks.push(bytes); } else { - imported_blocks.push(header.hash()); + imported_blocks.push(hash); + + let transactions_len = closed_block.transactions().len(); - let route = self.commit_block(closed_block, &header, &block.bytes, client); + let route = self.commit_block(closed_block, &header, &bytes, client); import_results.push(route); - client.report.write().accrue_block(&block); + client.report.write().accrue_block(&header, transactions_len); } } else { invalid_blocks.insert(header.hash()); @@ -337,7 +344,7 @@ impl Importer { let (enacted, retracted) = self.calculate_enacted_retracted(&import_results); if is_empty { - self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, &enacted, &retracted); + self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, &enacted, &retracted, false); } client.notify(|notify| { @@ -358,9 +365,9 @@ impl Importer { imported } - fn check_and_close_block(&self, block: &PreverifiedBlock, client: &Client) -> Result { + fn check_and_close_block(&self, block: PreverifiedBlock, client: &Client) -> Result { let engine = &*self.engine; - let header = &block.header; + let header = block.header.clone(); // Check the block isn't so old we won't be able to enact it. let best_block_number = client.chain.read().best_block_number(); @@ -381,7 +388,7 @@ impl Importer { let chain = client.chain.read(); // Verify Block Family let verify_family_result = self.verifier.verify_block_family( - header, + &header, &parent, engine, Some(verification::FullFamilyParams { @@ -397,7 +404,7 @@ impl Importer { return Err(()); }; - let verify_external_result = self.verifier.verify_block_external(header, engine); + let verify_external_result = self.verifier.verify_block_external(&header, engine); if let Err(e) = verify_external_result { warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); @@ -409,7 +416,8 @@ impl Importer { let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some(); let strip_receipts = header.number() < engine.params().validate_receipts_transition; - let enact_result = enact_verified(block, + let enact_result = enact_verified( + block, engine, client.tracedb.read().tracing_enabled(), db, @@ -425,7 +433,7 @@ impl Importer { })?; // Final Verification - if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) { + if let Err(e) = self.verifier.verify_block_final(&header, locked_block.block().header()) { warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); } @@ -975,19 +983,24 @@ impl Client { /// Import transactions from the IO queue pub fn import_queued_transactions(&self, transactions: &[Bytes], peer_id: usize) -> usize { - trace!(target: "external_tx", "Importing queued"); trace_time!("import_queued_transactions"); self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst); - let txs: Vec = transactions.iter().filter_map(|bytes| UntrustedRlp::new(bytes).as_val().ok()).collect(); - let hashes: Vec<_> = txs.iter().map(|tx| tx.hash()).collect(); + + let txs: Vec = transactions + .iter() + .filter_map(|bytes| UntrustedRlp::new(bytes).as_val().ok()) + .collect(); + self.notify(|notify| { - notify.transactions_received(hashes.clone(), peer_id); + notify.transactions_received(&txs, peer_id); }); + let results = self.importer.miner.import_external_transactions(self, txs); results.len() } /// Get shared miner reference. + #[cfg(test)] pub fn miner(&self) -> Arc { self.importer.miner.clone() } @@ -1915,12 +1928,8 @@ impl BlockChainClient for Client { } } - fn ready_transactions(&self) -> Vec { - let (number, timestamp) = { - let chain = self.chain.read(); - (chain.best_block_number(), chain.best_block_timestamp()) - }; - self.importer.miner.ready_transactions(number, timestamp) + fn ready_transactions(&self) -> Vec> { + self.importer.miner.ready_transactions(self) } fn queue_consensus_message(&self, message: Bytes) { @@ -1951,17 +1960,19 @@ impl BlockChainClient for Client { } } - fn transact_contract(&self, address: Address, data: Bytes) -> Result { + fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> { + let authoring_params = self.importer.miner.authoring_params(); let transaction = Transaction { - nonce: self.latest_nonce(&self.importer.miner.author()), + nonce: self.latest_nonce(&authoring_params.author), action: Action::Call(address), - gas: self.importer.miner.gas_floor_target(), + gas: self.importer.miner.sensible_gas_limit(), gas_price: self.importer.miner.sensible_gas_price(), value: U256::zero(), data: data, }; let chain_id = self.engine.signing_chain_id(&self.latest_env_info()); - let signature = self.engine.sign(transaction.hash(chain_id))?; + let signature = self.engine.sign(transaction.hash(chain_id)) + .map_err(|e| transaction::Error::InvalidSignature(e.to_string()))?; let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?; self.importer.miner.import_own_transaction(self, signed.into()) } @@ -2070,7 +2081,7 @@ impl ImportSealedBlock for Client { route }; let (enacted, retracted) = self.importer.calculate_enacted_retracted(&[route]); - self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted); + self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted, true); self.notify(|notify| { notify.new_blocks( vec![h.clone()], @@ -2108,11 +2119,8 @@ impl BroadcastProposalBlock for Client { impl SealedBlockImporter for Client {} -impl MiningBlockChainClient for Client { - fn vm_factory(&self) -> &VmFactory { - &self.factories.vm - } -} +impl ::miner::TransactionVerifierClient for Client {} +impl ::miner::BlockChainClient for Client {} impl super::traits::EngineClient for Client { fn update_sealing(&self) { @@ -2120,8 +2128,9 @@ impl super::traits::EngineClient for Client { } fn submit_seal(&self, block_hash: H256, seal: Vec) { - if self.importer.miner.submit_seal(self, block_hash, seal).is_err() { - warn!(target: "poa", "Wrong internal seal submission!") + let import = self.importer.miner.submit_seal(block_hash, seal).and_then(|block| self.import_sealed_block(block)); + if let Err(err) = import { + warn!(target: "poa", "Wrong internal seal submission! {:?}", err); } } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 2ae3436aa98..8f6b624a5ed 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -38,7 +38,7 @@ pub use self::traits::{ }; //pub use self::private_notify::PrivateNotify; pub use state::StateInfo; -pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient, ProvingBlockChainClient}; +pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient}; pub use types::ids::*; pub use types::trace_filter::Filter as TraceFilter; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 6d61035af29..02067afd002 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -31,11 +31,12 @@ use kvdb_memorydb; use bytes::Bytes; use rlp::{UntrustedRlp, RlpStream}; use ethkey::{Generator, Random}; -use transaction::{self, Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action}; +use ethcore_miner::pool::VerifiedTransaction; +use transaction::{self, Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::{TreeRoute, BlockReceipts}; use client::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, CallContract, TransactionInfo, RegistryInfo, - PrepareOpenBlock, BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId, + PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter @@ -45,9 +46,7 @@ use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; use receipt::{Receipt, LocalizedReceipt, TransactionOutcome}; -use error::{ImportResult, Error as EthcoreError}; -use evm::VMType; -use factory::VmFactory; +use error::ImportResult; use vm::Schedule; use miner::{Miner, MinerService}; use spec::Spec; @@ -102,8 +101,6 @@ pub struct TestBlockChainClient { pub miner: Arc, /// Spec pub spec: Spec, - /// VM Factory - pub vm_factory: VmFactory, /// Timestamp assigned to latest sealed block pub latest_block_timestamp: RwLock, /// Ancient block info. @@ -174,9 +171,8 @@ impl TestBlockChainClient { receipts: RwLock::new(HashMap::new()), logs: RwLock::new(Vec::new()), queue_size: AtomicUsize::new(0), - miner: Arc::new(Miner::with_spec(&spec)), + miner: Arc::new(Miner::new_for_tests(&spec, None)), spec: spec, - vm_factory: VmFactory::new(VMType::Interpreter, 1024 * 1024), latest_block_timestamp: RwLock::new(10_000_000), ancient_block: RwLock::new(None), first_block: RwLock::new(None), @@ -345,8 +341,8 @@ impl TestBlockChainClient { self.set_balance(signed_tx.sender(), 10_000_000_000_000_000_000u64.into()); let hash = signed_tx.hash(); let res = self.miner.import_external_transactions(self, vec![signed_tx.into()]); - let res = res.into_iter().next().unwrap().expect("Successful import"); - assert_eq!(res, transaction::ImportResult::Current); + let res = res.into_iter().next().unwrap(); + assert!(res.is_ok()); hash } @@ -423,11 +419,8 @@ impl BroadcastProposalBlock for TestBlockChainClient { impl SealedBlockImporter for TestBlockChainClient {} -impl MiningBlockChainClient for TestBlockChainClient { - fn vm_factory(&self) -> &VmFactory { - &self.vm_factory - } -} +impl ::miner::TransactionVerifierClient for TestBlockChainClient {} +impl ::miner::BlockChainClient for TestBlockChainClient {} impl Nonce for TestBlockChainClient { fn nonce(&self, address: &Address, id: BlockId) -> Option { @@ -826,9 +819,8 @@ impl BlockChainClient for TestBlockChainClient { self.spec.engine.handle_message(&message).unwrap(); } - fn ready_transactions(&self) -> Vec { - let info = self.chain_info(); - self.miner.ready_transactions(info.best_block_number, info.best_block_timestamp) + fn ready_transactions(&self) -> Vec> { + self.miner.ready_transactions(self) } fn signing_chain_id(&self) -> Option { None } @@ -851,9 +843,9 @@ impl BlockChainClient for TestBlockChainClient { } } - fn transact_contract(&self, address: Address, data: Bytes) -> Result { + fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> { let transaction = Transaction { - nonce: self.latest_nonce(&self.miner.author()), + nonce: self.latest_nonce(&self.miner.authoring_params().author), action: Action::Call(address), gas: self.spec.gas_limit, gas_price: U256::zero(), @@ -895,8 +887,9 @@ impl super::traits::EngineClient for TestBlockChainClient { } fn submit_seal(&self, block_hash: H256, seal: Vec) { - if self.miner.submit_seal(self, block_hash, seal).is_err() { - warn!(target: "poa", "Wrong internal seal submission!") + let import = self.miner.submit_seal(block_hash, seal).and_then(|block| self.import_sealed_block(block)); + if let Err(err) = import { + warn!(target: "poa", "Wrong internal seal submission! {:?}", err); } } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 901ba30db30..7d4d5846c69 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -15,28 +15,30 @@ // along with Parity. If not, see . use std::collections::BTreeMap; +use std::sync::Arc; + use itertools::Itertools; use block::{OpenBlock, SealedBlock, ClosedBlock}; use blockchain::TreeRoute; use encoded; use vm::LastHashes; -use error::{ImportResult, CallError, Error as EthcoreError, BlockImportError}; +use error::{ImportResult, CallError, BlockImportError}; use evm::Schedule; -use factory::VmFactory; use executive::Executed; use filter::Filter; use header::{BlockNumber}; use log_entry::LocalizedLogEntry; use receipt::LocalizedReceipt; use trace::LocalizedTrace; -use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction, ImportResult as TransactionImportResult}; +use transaction::{self, LocalizedTransaction, SignedTransaction}; use verification::queue::QueueInfo as BlockQueueInfo; use state::StateInfo; use header::Header; use engines::EthEngine; use ethereum_types::{H256, U256, Address}; +use ethcore_miner::pool::VerifiedTransaction; use bytes::Bytes; use hashdb::DBValue; @@ -315,7 +317,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn queue_consensus_message(&self, message: Bytes); /// List all transactions that are allowed into the next block. - fn ready_transactions(&self) -> Vec; + fn ready_transactions(&self) -> Vec>; /// Sorted list of transaction gas prices from at least last sample_size blocks. fn gas_price_corpus(&self, sample_size: usize) -> ::stats::Corpus { @@ -366,8 +368,8 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Returns information about pruning/data availability. fn pruning_info(&self) -> PruningInfo; - /// Import a transaction: used for misbehaviour reporting. - fn transact_contract(&self, address: Address, data: Bytes) -> Result; + /// Schedule state-altering transaction to be executed on the next pending block. + fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error>; /// Get the address of the registry itself. fn registrar_address(&self) -> Option
; @@ -416,12 +418,6 @@ pub trait BroadcastProposalBlock { /// Provides methods to import sealed block and broadcast a block proposal pub trait SealedBlockImporter: ImportSealedBlock + BroadcastProposalBlock {} -/// Extended client interface used for mining -pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + ScheduleInfo + SealedBlockImporter { - /// Returns EvmFactory. - fn vm_factory(&self) -> &VmFactory; -} - /// Client facilities used by internally sealing Engines. pub trait EngineClient: Sync + Send + ChainInfo { /// Make a new block and seal it. diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 8282e5738a8..e3acc5eed9d 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -38,7 +38,7 @@ use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; use self::finality::RollingFinality; -use ethkey::{public_to_address, recover, verify_address, Signature}; +use ethkey::{self, Signature}; use io::{IoContext, IoHandler, TimerToken, IoService}; use itertools::{self, Itertools}; use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; @@ -292,14 +292,14 @@ impl EmptyStep { let message = keccak(empty_step_rlp(self.step, &self.parent_hash)); let correct_proposer = step_proposer(validators, &self.parent_hash, self.step); - verify_address(&correct_proposer, &self.signature.into(), &message) + ethkey::verify_address(&correct_proposer, &self.signature.into(), &message) .map_err(|e| e.into()) } fn author(&self) -> Result { let message = keccak(empty_step_rlp(self.step, &self.parent_hash)); - let public = recover(&self.signature.into(), &message)?; - Ok(public_to_address(&public)) + let public = ethkey::recover(&self.signature.into(), &message)?; + Ok(ethkey::public_to_address(&public)) } fn sealed(&self) -> SealedEmptyStep { @@ -555,7 +555,7 @@ fn verify_external(header: &Header, validators: &ValidatorSet, empty_steps_trans }; let header_seal_hash = header_seal_hash(header, empty_steps_rlp); - !verify_address(&correct_proposer, &proposer_signature, &header_seal_hash)? + !ethkey::verify_address(&correct_proposer, &proposer_signature, &header_seal_hash)? }; if is_invalid_proposer { @@ -824,7 +824,10 @@ impl Engine for AuthorityRound { fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal { // first check to avoid generating signature most of the time // (but there's still a race to the `compare_and_swap`) - if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; } + if !self.can_propose.load(AtomicOrdering::SeqCst) { + trace!(target: "engine", "Aborting seal generation. Can't propose."); + return Seal::None; + } let header = block.header(); let parent_step: U256 = header_step(parent, self.empty_steps_transition) @@ -1305,7 +1308,7 @@ impl Engine for AuthorityRound { } fn sign(&self, hash: H256) -> Result { - self.signer.read().sign(hash).map_err(Into::into) + Ok(self.signer.read().sign(hash)?) } fn snapshot_components(&self) -> Option> { diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index c4eafd851c6..768cde3d5ee 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -19,7 +19,7 @@ use std::sync::{Weak, Arc}; use ethereum_types::{H256, H520, Address}; use parking_lot::RwLock; -use ethkey::{recover, public_to_address, Signature}; +use ethkey::{self, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, ConstructedVerifier, EngineError}; @@ -61,7 +61,7 @@ fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Err // Check if the signature belongs to a validator, can depend on parent state. let sig = UntrustedRlp::new(&header.seal()[0]).as_val::()?; - let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?); + let signer = ethkey::public_to_address(ðkey::recover(&sig.into(), &header.bare_hash())?); if *header.author() != signer { return Err(EngineError::NotAuthorized(*header.author()).into()) @@ -185,7 +185,7 @@ impl Engine for BasicAuthority { } fn sign(&self, hash: H256) -> Result { - self.signer.read().sign(hash).map_err(Into::into) + Ok(self.signer.read().sign(hash)?) } fn snapshot_components(&self) -> Option> { diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 65fa13b54e8..4d22bd1f76a 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -48,7 +48,7 @@ use error::Error; use header::{Header, BlockNumber}; use snapshot::SnapshotComponents; use spec::CommonParams; -use transaction::{UnverifiedTransaction, SignedTransaction}; +use transaction::{self, UnverifiedTransaction, SignedTransaction}; use ethkey::Signature; use parity_machine::{Machine, LocalizedMachine as Localized}; @@ -387,14 +387,28 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> { } /// Verify a particular transaction is valid. - fn verify_transaction_unordered(&self, t: UnverifiedTransaction, header: &Header) -> Result { + /// + /// Unordered verification doesn't rely on the transaction execution order, + /// i.e. it should only verify stuff that doesn't assume any previous transactions + /// has already been verified and executed. + /// + /// NOTE This function consumes an `UnverifiedTransaction` and produces `SignedTransaction` + /// which implies that a heavy check of the signature is performed here. + fn verify_transaction_unordered(&self, t: UnverifiedTransaction, header: &Header) -> Result { self.machine().verify_transaction_unordered(t, header) } - /// Additional verification for transactions in blocks. - // TODO: Add flags for which bits of the transaction to check. - // TODO: consider including State in the params. - fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> { + /// Perform basic/cheap transaction verification. + /// + /// This should include all cheap checks that can be done before + /// actually checking the signature, like chain-replay protection. + /// + /// NOTE This is done before the signature is recovered so avoid + /// doing any state-touching checks that might be expensive. + /// + /// TODO: Add flags for which bits of the transaction to check. + /// TODO: consider including State in the params. + fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), transaction::Error> { self.machine().verify_transaction_basic(t, header) } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 011e3f8d425..c9312e90435 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -37,7 +37,7 @@ use bytes::Bytes; use error::{Error, BlockError}; use header::{Header, BlockNumber}; use rlp::UntrustedRlp; -use ethkey::{Message, public_to_address, recover, Signature}; +use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; @@ -518,8 +518,8 @@ impl Engine for Tendermint { let message: ConsensusMessage = rlp.as_val().map_err(fmt_err)?; if !self.votes.is_old_or_known(&message) { let msg_hash = keccak(rlp.at(1).map_err(fmt_err)?.as_raw()); - let sender = public_to_address( - &recover(&message.signature.into(), &msg_hash).map_err(fmt_err)? + let sender = ethkey::public_to_address( + ðkey::recover(&message.signature.into(), &msg_hash).map_err(fmt_err)? ); if !self.is_authority(&sender) { @@ -614,7 +614,7 @@ impl Engine for Tendermint { }; let address = match self.votes.get(&precommit) { Some(a) => a, - None => public_to_address(&recover(&precommit.signature.into(), &precommit_hash)?), + None => ethkey::public_to_address(ðkey::recover(&precommit.signature.into(), &precommit_hash)?), }; if !self.validators.contains(header.parent_hash(), &address) { return Err(EngineError::NotAuthorized(address.to_owned()).into()); @@ -669,7 +669,7 @@ impl Engine for Tendermint { let verifier = Box::new(EpochVerifier { subchain_validators: list, recover: |signature: &Signature, message: &Message| { - Ok(public_to_address(&::ethkey::recover(&signature, &message)?)) + Ok(ethkey::public_to_address(ðkey::recover(&signature, &message)?)) }, }); @@ -690,7 +690,7 @@ impl Engine for Tendermint { } fn sign(&self, hash: H256) -> Result { - self.signer.read().sign(hash).map_err(Into::into) + Ok(self.signer.read().sign(hash)?) } fn snapshot_components(&self) -> Option> { @@ -1026,7 +1026,7 @@ mod tests { let client = generate_dummy_client_with_spec_and_accounts(Spec::new_test_tendermint, Some(tap.clone())); let engine = client.engine(); - client.miner().set_engine_signer(v1.clone(), "1".into()).unwrap(); + client.miner().set_author(v1.clone(), Some("1".into())).unwrap(); let notify = Arc::new(TestNotify::default()); client.add_notify(notify.clone()); diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index fb9fccf3e22..00f74fd2eb4 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -169,8 +169,8 @@ mod tests { let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); // Make sure reporting can be done. - client.miner().set_gas_floor_target(1_000_000.into()); - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_gas_range_target((1_000_000.into(), 1_000_000.into())); + client.miner().set_author(v1, Some("".into())).unwrap(); // Check a block that is a bit in future, reject it but don't report the validator. let mut header = Header::default(); diff --git a/ethcore/src/engines/validator_set/multi.rs b/ethcore/src/engines/validator_set/multi.rs index 9c287f9a371..89a33abc74a 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -171,22 +171,22 @@ mod tests { client.engine().register_client(Arc::downgrade(&client) as _); // Make sure txs go through. - client.miner().set_gas_floor_target(1_000_000.into()); + client.miner().set_gas_range_target((1_000_000.into(), 1_000_000.into())); // Wrong signer for the first block. - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); client.transact_contract(Default::default(), Default::default()).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 0); // Right signer for the first block. - client.miner().set_engine_signer(v0, "".into()).unwrap(); + client.miner().set_author(v0, Some("".into())).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); // This time v0 is wrong. client.transact_contract(Default::default(), Default::default()).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 2); // v1 is still good. diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 82befdadff2..5c73cb28d14 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -484,7 +484,7 @@ mod tests { client.engine().register_client(Arc::downgrade(&client) as _); let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); // Remove "1" validator. let tx = Transaction { nonce: 0.into(), @@ -512,11 +512,11 @@ mod tests { assert_eq!(client.chain_info().best_block_number, 1); // Switch to the validator that is still there. - client.miner().set_engine_signer(v0, "".into()).unwrap(); + client.miner().set_author(v0, Some("".into())).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 2); // Switch back to the added validator, since the state is updated. - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); let tx = Transaction { nonce: 2.into(), gas_price: 0.into(), diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 64414450bd5..89b8df4a261 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -64,7 +64,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { config, &spec, db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); for b in &blockchain.blocks_rlp() { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index c71a266f740..abb680c952b 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -71,7 +71,6 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethjson; extern crate ethkey; -extern crate futures_cpupool; extern crate hardware_wallet; extern crate hashdb; extern crate itertools; @@ -80,7 +79,6 @@ extern crate num_cpus; extern crate num; extern crate parity_machine; extern crate parking_lot; -extern crate price_info; extern crate rand; extern crate rayon; extern crate rlp; @@ -99,18 +97,10 @@ extern crate util_error; extern crate snappy; extern crate ethabi; -#[macro_use] -extern crate ethabi_derive; -#[macro_use] -extern crate ethabi_contract; - -#[macro_use] -extern crate rlp_derive; extern crate rustc_hex; extern crate stats; extern crate stop_guard; extern crate using_queue; -extern crate table; extern crate vm; extern crate wasm; extern crate memory_cache; @@ -119,13 +109,20 @@ extern crate journaldb; extern crate tempdir; #[macro_use] -extern crate macros; +extern crate ethabi_derive; +#[macro_use] +extern crate ethabi_contract; #[macro_use] extern crate log; #[macro_use] extern crate lazy_static; #[macro_use] +extern crate macros; +#[macro_use] +extern crate rlp_derive; +#[macro_use] extern crate trace_time; + #[cfg_attr(test, macro_use)] extern crate evm; diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index fa6a62454e1..7d488e0d0c9 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -334,12 +334,12 @@ impl EthereumMachine { } /// Verify a particular transaction is valid, regardless of order. - pub fn verify_transaction_unordered(&self, t: UnverifiedTransaction, _header: &Header) -> Result { + pub fn verify_transaction_unordered(&self, t: UnverifiedTransaction, _header: &Header) -> Result { Ok(SignedTransaction::new(t)?) } /// Does basic verification of the transaction. - pub fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> { + pub fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), transaction::Error> { let check_low_s = match self.ethash_extensions { Some(ref ext) => header.number() >= ext.homestead_transition, None => true, @@ -358,9 +358,9 @@ impl EthereumMachine { } /// Does verification of the transaction against the parent state. - // TODO: refine the bound here to be a "state provider" or similar as opposed - // to full client functionality. - pub fn verify_transaction(&self, t: &SignedTransaction, header: &Header, client: &C) -> Result<(), Error> { + pub fn verify_transaction(&self, t: &SignedTransaction, header: &Header, client: &C) + -> Result<(), transaction::Error> + { if let Some(ref filter) = self.tx_filter.as_ref() { if !filter.transaction_allowed(header.parent_hash(), t, client) { return Err(transaction::Error::NotAllowed.into()) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 755294637b8..e344ee6b12c 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -15,49 +15,38 @@ // along with Parity. If not, see . use std::time::{Instant, Duration}; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, HashMap}; use std::sync::Arc; -use account_provider::{AccountProvider, SignError as AccountError}; use ansi_term::Colour; -use ethereum_types::{H256, U256, Address}; -use parking_lot::{Mutex, RwLock}; use bytes::Bytes; use engines::{EthEngine, Seal}; -use error::{ExecutionError, Error}; -use ethcore_miner::banning_queue::{BanningTransactionQueue, Threshold}; -use ethcore_miner::local_transactions::{Status as LocalTransactionStatus}; -use ethcore_miner::transaction_queue::{ - TransactionQueue, - RemovalReason, - TransactionDetailsProvider as TransactionQueueDetailsProvider, - PrioritizationStrategy, - AccountDetails, - TransactionOrigin, -}; -use futures_cpupool::CpuPool; +use error::{Error, ExecutionError}; +use ethcore_miner::gas_pricer::GasPricer; +use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy}; use ethcore_miner::work_notify::NotifyWork; -use miner::service_transaction_checker::ServiceTransactionChecker; -use miner::{MinerService, MinerStatus}; -use price_info::fetch::Client as FetchClient; -use price_info::{Client as PriceInfoClient, PriceInfo}; +use ethereum_types::{H256, U256, Address}; +use parking_lot::{Mutex, RwLock}; +use rayon::prelude::*; use transaction::{ + self, Action, UnverifiedTransaction, - PendingTransaction, SignedTransaction, - Condition as TransactionCondition, - ImportResult as TransactionImportResult, - Error as TransactionError, + PendingTransaction, }; use using_queue::{UsingQueue, GetAction}; -use block::{ClosedBlock, IsBlock, Block}; + +use account_provider::{AccountProvider, SignError as AccountError}; +use block::{ClosedBlock, IsBlock, Block, SealedBlock}; use client::{ - AccountData, BlockChain, RegistryInfo, ScheduleInfo, CallContract, BlockProducer, SealedBlockImporter + BlockChain, ChainInfo, CallContract, BlockProducer, SealedBlockImporter, Nonce }; -use client::{BlockId, TransactionId, MiningBlockChainClient}; +use client::BlockId; use executive::contract_address; use header::{Header, BlockNumber}; +use miner; +use miner::pool_client::{PoolClient, CachedNonceClient}; use receipt::{Receipt, RichReceipt}; use spec::Spec; use state::State; @@ -68,39 +57,44 @@ pub enum PendingSet { /// Always just the transactions in the queue. These have had only cheap checks. AlwaysQueue, /// Always just the transactions in the sealing block. These have had full checks but - /// may be empty if the node is not actively mining or has force_sealing enabled. + /// may be empty if the node is not actively mining or has no force_sealing enabled. AlwaysSealing, - /// Try the sealing block, but if it is not currently sealing, fallback to the queue. + /// Takes from sealing if mining, from queue otherwise. SealingOrElseQueue, } -/// Type of the gas limit to apply to the transaction queue. -#[derive(Debug, PartialEq)] -pub enum GasLimit { - /// Depends on the block gas limit and is updated with every block. - Auto, - /// No limit. - None, - /// Set to a fixed gas value. - Fixed(U256), -} - -/// Transaction queue banning settings. +/// Transaction queue penalization settings. +/// +/// Senders of long-running transactions (above defined threshold) +/// will get lower priority. #[derive(Debug, PartialEq, Clone)] -pub enum Banning { - /// Banning in transaction queue is disabled +pub enum Penalization { + /// Penalization in transaction queue is disabled Disabled, - /// Banning in transaction queue is enabled + /// Penalization in transaction queue is enabled Enabled { - /// Upper limit of transaction processing time before banning. + /// Upper limit of transaction processing time before penalizing. offend_threshold: Duration, - /// Number of similar offending transactions before banning. - min_offends: u16, - /// Number of seconds the offender is banned for. - ban_duration: Duration, }, } +/// Initial minimal gas price. +/// +/// Gas price should be later overwritten externally +/// for instance by a dynamic gas price mechanism or CLI parameter. +/// This constant controls the initial value. +const DEFAULT_MINIMAL_GAS_PRICE: u64 = 20_000_000_000; + +/// Allowed number of skipped transactions when constructing pending block. +/// +/// When we push transactions to pending block, some of the transactions might +/// get skipped because of block gas limit being reached. +/// This constant controls how many transactions we can skip because of that +/// before stopping attempts to push more transactions to the block. +/// This is an optimization that prevents traversing the entire pool +/// in case we have only a fraction of available block gas limit left. +const MAX_SKIPPED_TRANSACTIONS: usize = 8; + /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] pub struct MinerOptions { @@ -116,30 +110,28 @@ pub struct MinerOptions { pub reseal_min_period: Duration, /// Maximum period between blocks (enables force sealing after that). pub reseal_max_period: Duration, - /// Maximum amount of gas to bother considering for block insertion. - pub tx_gas_limit: U256, - /// Maximum size of the transaction queue. - pub tx_queue_size: usize, - /// Maximum memory usage of transactions in the queue (current / future). - pub tx_queue_memory_limit: Option, - /// Strategy to use for prioritizing transactions in the queue. - pub tx_queue_strategy: PrioritizationStrategy, /// Whether we should fallback to providing all the queue's transactions or just pending. pub pending_set: PendingSet, /// How many historical work packages can we store before running out? pub work_queue_size: usize, /// Can we submit two different solutions for the same block and expect both to result in an import? pub enable_resubmission: bool, - /// Global gas limit for all transaction in the queue except for local and retracted. - pub tx_queue_gas_limit: GasLimit, - /// Banning settings. - pub tx_queue_banning: Banning, - /// Do we refuse to accept service transactions even if sender is certified. - pub refuse_service_transactions: bool, /// Create a pending block with maximal possible gas limit. /// NOTE: Such block will contain all pending transactions but /// will be invalid if mined. pub infinite_pending_block: bool, + + + /// Strategy to use for prioritizing transactions in the queue. + pub tx_queue_strategy: PrioritizationStrategy, + /// Simple senders penalization. + pub tx_queue_penalization: Penalization, + /// Do we refuse to accept service transactions even if sender is certified. + pub refuse_service_transactions: bool, + /// Transaction pool limits. + pub pool_limits: pool::Options, + /// Initial transaction verification options. + pub pool_verification_options: pool::verifier::Options, } impl Default for MinerOptions { @@ -149,249 +141,185 @@ impl Default for MinerOptions { reseal_on_external_tx: false, reseal_on_own_tx: true, reseal_on_uncle: false, - tx_gas_limit: !U256::zero(), - tx_queue_size: 8192, - tx_queue_memory_limit: Some(2 * 1024 * 1024), - tx_queue_gas_limit: GasLimit::None, - tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, - pending_set: PendingSet::AlwaysQueue, reseal_min_period: Duration::from_secs(2), reseal_max_period: Duration::from_secs(120), + pending_set: PendingSet::AlwaysQueue, work_queue_size: 20, enable_resubmission: true, - tx_queue_banning: Banning::Disabled, - refuse_service_transactions: false, infinite_pending_block: false, + tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, + tx_queue_penalization: Penalization::Disabled, + refuse_service_transactions: false, + pool_limits: pool::Options { + max_count: 8_192, + max_per_sender: 81, + max_mem_usage: 4 * 1024 * 1024, + }, + pool_verification_options: pool::verifier::Options { + minimal_gas_price: DEFAULT_MINIMAL_GAS_PRICE.into(), + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + }, } } } -/// Options for the dynamic gas price recalibrator. -#[derive(Debug, PartialEq)] -pub struct GasPriceCalibratorOptions { - /// Base transaction price to match against. - pub usd_per_tx: f32, - /// How frequently we should recalibrate. - pub recalibration_period: Duration, -} - -/// The gas price validator variant for a `GasPricer`. -#[derive(Debug, PartialEq)] -pub struct GasPriceCalibrator { - options: GasPriceCalibratorOptions, - next_calibration: Instant, - price_info: PriceInfoClient, -} - -impl GasPriceCalibrator { - fn recalibrate(&mut self, set_price: F) { - trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration); - if Instant::now() >= self.next_calibration { - let usd_per_tx = self.options.usd_per_tx; - trace!(target: "miner", "Getting price info"); - - self.price_info.get(move |price: PriceInfo| { - trace!(target: "miner", "Price info arrived: {:?}", price); - let usd_per_eth = price.ethusd; - let wei_per_usd: f32 = 1.0e18 / usd_per_eth; - let gas_per_tx: f32 = 21000.0; - let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; - info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas))); - set_price(U256::from(wei_per_gas as u64)); - }); - - self.next_calibration = Instant::now() + self.options.recalibration_period; - } - } -} - -/// Struct to look after updating the acceptable gas price of a miner. -#[derive(Debug, PartialEq)] -pub enum GasPricer { - /// A fixed gas price in terms of Wei - always the argument given. - Fixed(U256), - /// Gas price is calibrated according to a fixed amount of USD. - Calibrated(GasPriceCalibrator), -} - -impl GasPricer { - /// Create a new Calibrated `GasPricer`. - pub fn new_calibrated(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPricer { - GasPricer::Calibrated(GasPriceCalibrator { - options: options, - next_calibration: Instant::now(), - price_info: PriceInfoClient::new(fetch, p), - }) - } - - /// Create a new Fixed `GasPricer`. - pub fn new_fixed(gas_price: U256) -> GasPricer { - GasPricer::Fixed(gas_price) - } - - fn recalibrate(&mut self, set_price: F) { - match *self { - GasPricer::Fixed(ref max) => set_price(max.clone()), - GasPricer::Calibrated(ref mut cal) => cal.recalibrate(set_price), - } - } +/// Configurable parameters of block authoring. +#[derive(Debug, Default, Clone)] +pub struct AuthoringParams { + /// Lower and upper bound of block gas limit that we are targeting + pub gas_range_target: (U256, U256), + /// Block author + pub author: Address, + /// Block extra data + pub extra_data: Bytes, } struct SealingWork { queue: UsingQueue, enabled: bool, + next_allowed_reseal: Instant, + next_mandatory_reseal: Instant, + // block number when sealing work was last requested + last_request: u64, +} + +impl SealingWork { + /// Are we allowed to do a non-mandatory reseal? + fn reseal_allowed(&self) -> bool { + Instant::now() > self.next_allowed_reseal + } } /// Keeps track of transactions using priority queue and holds currently mined block. /// Handles preparing work for "work sealing" or seals "internally" if Engine does not require work. pub struct Miner { // NOTE [ToDr] When locking always lock in this order! - transaction_queue: Arc>, - transaction_listener: RwLock>>, - sealing_work: Mutex, - next_allowed_reseal: Mutex, - next_mandatory_reseal: RwLock, - sealing_block_last_request: Mutex, - // for sealing... + sealing: Mutex, + params: RwLock, + listeners: RwLock>>, + nonce_cache: RwLock>, + gas_pricer: Mutex, options: MinerOptions, - - gas_range_target: RwLock<(U256, U256)>, - author: RwLock
, - extra_data: RwLock, + // TODO [ToDr] Arc is only required because of price updater + transaction_queue: Arc, engine: Arc, - accounts: Option>, - notifiers: RwLock>>, - gas_pricer: Mutex, - service_transaction_action: ServiceTransactionAction, } impl Miner { - /// Push notifier that will handle new jobs - pub fn push_notifier(&self, notifier: Box) { - self.notifiers.write().push(notifier); - self.sealing_work.lock().enabled = true; + /// Push listener that will handle new jobs + pub fn add_work_listener(&self, notifier: Box) { + self.listeners.write().push(notifier); + self.sealing.lock().enabled = true; } - /// Creates new instance of miner Arc. - pub fn new(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option>) -> Arc { - Arc::new(Miner::new_raw(options, gas_pricer, spec, accounts)) + /// Set a callback to be notified about imported transactions' hashes. + pub fn add_transactions_listener(&self, f: Box) { + self.transaction_queue.add_listener(f); } - /// Creates new instance of miner. - fn new_raw(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option>) -> Miner { - let gas_limit = match options.tx_queue_gas_limit { - GasLimit::Fixed(ref limit) => *limit, - _ => !U256::zero(), - }; - let mem_limit = options.tx_queue_memory_limit.unwrap_or_else(usize::max_value); - - let txq = TransactionQueue::with_limits( - options.tx_queue_strategy, - options.tx_queue_size, - mem_limit, - gas_limit, - options.tx_gas_limit - ); - let txq = match options.tx_queue_banning { - Banning::Disabled => BanningTransactionQueue::new(txq, Threshold::NeverBan, Duration::from_secs(180)), - Banning::Enabled { ban_duration, min_offends, .. } => BanningTransactionQueue::new( - txq, - Threshold::BanAfter(min_offends), - ban_duration, - ), - }; - - let notifiers: Vec> = Vec::new(); - - let service_transaction_action = match options.refuse_service_transactions { - true => ServiceTransactionAction::Refuse, - false => ServiceTransactionAction::Check(ServiceTransactionChecker::default()), - }; + /// Creates new instance of miner Arc. + pub fn new(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option>) -> Self { + let limits = options.pool_limits.clone(); + let verifier_options = options.pool_verification_options.clone(); + let tx_queue_strategy = options.tx_queue_strategy; Miner { - transaction_queue: Arc::new(RwLock::new(txq)), - transaction_listener: RwLock::new(vec![]), - next_allowed_reseal: Mutex::new(Instant::now()), - next_mandatory_reseal: RwLock::new(Instant::now() + options.reseal_max_period), - sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(SealingWork{ + sealing: Mutex::new(SealingWork { queue: UsingQueue::new(options.work_queue_size), enabled: options.force_sealing - || spec.engine.seals_internally().is_some() + || spec.engine.seals_internally().is_some(), + next_allowed_reseal: Instant::now(), + next_mandatory_reseal: Instant::now() + options.reseal_max_period, + last_request: 0, }), - gas_range_target: RwLock::new((U256::zero(), U256::zero())), - author: RwLock::new(Address::default()), - extra_data: RwLock::new(Vec::new()), - options: options, - accounts: accounts, - engine: spec.engine.clone(), - notifiers: RwLock::new(notifiers), + params: RwLock::new(AuthoringParams::default()), + listeners: RwLock::new(vec![]), gas_pricer: Mutex::new(gas_pricer), - service_transaction_action: service_transaction_action, + nonce_cache: RwLock::new(HashMap::with_capacity(1024)), + options, + transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)), + accounts, + engine: spec.engine.clone(), } } - /// Creates new instance of miner with accounts and with given spec. - pub fn with_spec_and_accounts(spec: &Spec, accounts: Option>) -> Miner { - Miner::new_raw(Default::default(), GasPricer::new_fixed(20_000_000_000u64.into()), spec, accounts) - } - - /// Creates new instance of miner without accounts, but with given spec. - pub fn with_spec(spec: &Spec) -> Miner { - Miner::new_raw(Default::default(), GasPricer::new_fixed(20_000_000_000u64.into()), spec, None) - } - - fn forced_sealing(&self) -> bool { - self.options.force_sealing || !self.notifiers.read().is_empty() + /// Creates new instance of miner with given spec and accounts. + /// + /// NOTE This should be only used for tests. + pub fn new_for_tests(spec: &Spec, accounts: Option>) -> Miner { + let minimal_gas_price = 0.into(); + Miner::new(MinerOptions { + pool_verification_options: pool::verifier::Options { + minimal_gas_price, + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + }, + reseal_min_period: Duration::from_secs(0), + ..Default::default() + }, GasPricer::new_fixed(minimal_gas_price), spec, accounts) } /// Clear all pending block states pub fn clear(&self) { - self.sealing_work.lock().queue.reset(); + self.sealing.lock().queue.reset(); } - /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. - pub fn pending_state(&self, latest_block_number: BlockNumber) -> Option> { - self.map_pending_block(|b| b.state().clone(), latest_block_number) - } - - /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. - pub fn pending_block(&self, latest_block_number: BlockNumber) -> Option { - self.map_pending_block(|b| b.to_base(), latest_block_number) - } - - /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. - pub fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
{ - self.map_pending_block(|b| b.header().clone(), latest_block_number) + /// Updates transaction queue verification limits. + /// + /// Limits consist of current block gas limit and minimal gas price. + pub fn update_transaction_queue_limits(&self, block_gas_limit: U256) { + trace!(target: "miner", "minimal_gas_price: recalibrating..."); + let txq = self.transaction_queue.clone(); + let mut options = self.options.pool_verification_options.clone(); + self.gas_pricer.lock().recalibrate(move |gas_price| { + debug!(target: "miner", "minimal_gas_price: Got gas price! {}", gas_price); + options.minimal_gas_price = gas_price; + options.block_gas_limit = block_gas_limit; + txq.set_verifier_options(options); + }); } - /// Set a callback to be notified about imported transactions' hashes. - pub fn add_transactions_listener(&self, f: Box) { - self.transaction_listener.write().push(f); + /// Retrieves an existing pending block iff it's not older than given block number. + /// + /// NOTE: This will not prepare a new pending block if it's not existing. + /// See `map_pending_block` for alternative behaviour. + fn map_existing_pending_block(&self, f: F, latest_block_number: BlockNumber) -> Option where + F: FnOnce(&ClosedBlock) -> T, + { + self.sealing.lock().queue + .peek_last_ref() + .and_then(|b| if b.block().header().number() > latest_block_number { + Some(f(b)) + } else { + None + }) } - fn map_pending_block(&self, f: F, latest_block_number: BlockNumber) -> Option where - F: FnOnce(&ClosedBlock) -> T, + fn pool_client<'a, C: 'a>(&'a self, chain: &'a C) -> PoolClient<'a, C> where + C: BlockChain + CallContract, { - self.from_pending_block( - latest_block_number, - || None, - |block| Some(f(block)), + PoolClient::new( + chain, + &self.nonce_cache, + &*self.engine, + self.accounts.as_ref().map(|x| &**x), + self.options.refuse_service_transactions, ) } /// Prepares new block for sealing including top transactions from queue. - fn prepare_block(&self, chain: &C) -> (ClosedBlock, Option) { + fn prepare_block(&self, chain: &C) -> (ClosedBlock, Option) where + C: BlockChain + CallContract + BlockProducer + Nonce + Sync, + { trace_time!("prepare_block"); let chain_info = chain.chain_info(); - let (transactions, mut open_block, original_work_hash) = { - let nonce_cap = if chain_info.best_block_number + 1 >= self.engine.params().dust_protection_transition { - Some((self.engine.params().nonce_cap_increment * (chain_info.best_block_number + 1)).into()) - } else { None }; - let transactions = {self.transaction_queue.read().top_transactions_at(chain_info.best_block_number, chain_info.best_block_timestamp, nonce_cap)}; - let mut sealing_work = self.sealing_work.lock(); - let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().header().hash()); + + // Open block + let (mut open_block, original_work_hash) = { + let mut sealing = self.sealing.lock(); + let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.block().header().hash()); let best_hash = chain_info.best_block_hash; // check to see if last ClosedBlock in would_seals is actually same parent block. @@ -400,7 +328,7 @@ impl Miner { // if at least one was pushed successfully, close and enqueue new ClosedBlock; // otherwise, leave everything alone. // otherwise, author a fresh block. - let mut open_block = match sealing_work.queue.pop_if(|b| b.block().header().parent_hash() == &best_hash) { + let mut open_block = match sealing.queue.pop_if(|b| b.block().header().parent_hash() == &best_hash) { Some(old_block) => { trace!(target: "miner", "prepare_block: Already have previous work; updating and returning"); // add transactions to old_block @@ -409,10 +337,11 @@ impl Miner { None => { // block not found - create it. trace!(target: "miner", "prepare_block: No existing work - making new block"); + let params = self.params.read().clone(); chain.prepare_open_block( - self.author(), - (self.gas_floor_target(), self.gas_ceil_target()), - self.extra_data() + params.author, + params.gas_range_target, + params.extra_data, ) } }; @@ -421,58 +350,87 @@ impl Miner { open_block.remove_gas_limit(); } - (transactions, open_block, last_work_hash) + (open_block, last_work_hash) }; let mut invalid_transactions = HashSet::new(); - let mut non_allowed_transactions = HashSet::new(); - let mut transactions_to_penalize = HashSet::new(); + let mut not_allowed_transactions = HashSet::new(); + let mut senders_to_penalize = HashSet::new(); let block_number = open_block.block().header().number(); - let mut tx_count: usize = 0; - let tx_total = transactions.len(); - for tx in transactions { - let hash = tx.hash(); + let mut tx_count = 0usize; + let mut skipped_transactions = 0usize; + + let client = self.pool_client(chain); + let engine_params = self.engine.params(); + let min_tx_gas = self.engine.schedule(chain_info.best_block_number).tx_gas.into(); + let nonce_cap: Option = if chain_info.best_block_number + 1 >= engine_params.dust_protection_transition { + Some((engine_params.nonce_cap_increment * (chain_info.best_block_number + 1)).into()) + } else { + None + }; + + let pending: Vec> = self.transaction_queue.pending( + client.clone(), + chain_info.best_block_number, + chain_info.best_block_timestamp, + nonce_cap, + ); + + let took_ms = |elapsed: &Duration| { + elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000 + }; + + let block_start = Instant::now(); + debug!(target: "miner", "Attempting to push {} transactions.", pending.len()); + + for tx in pending { let start = Instant::now(); - // Check whether transaction type is allowed for sender - let result = match self.engine.machine().verify_transaction(&tx, open_block.header(), chain) { - Err(Error::Transaction(TransactionError::NotAllowed)) => { - Err(TransactionError::NotAllowed.into()) - } - _ => { - open_block.push_transaction(tx, None) - } - }; + + let transaction = tx.signed().clone(); + let hash = transaction.hash(); + let sender = transaction.sender(); + + // Re-verify transaction again vs current state. + let result = client.verify_signed(&transaction) + .map_err(Error::Transaction) + .and_then(|_| { + open_block.push_transaction(transaction, None) + }); + let took = start.elapsed(); // Check for heavy transactions - match self.options.tx_queue_banning { - Banning::Enabled { ref offend_threshold, .. } if &took > offend_threshold => { - match self.transaction_queue.write().ban_transaction(&hash) { - true => { - warn!(target: "miner", "Detected heavy transaction. Banning the sender and recipient/code."); - }, - false => { - transactions_to_penalize.insert(hash); - debug!(target: "miner", "Detected heavy transaction. Penalizing sender.") - } - } + match self.options.tx_queue_penalization { + Penalization::Enabled { ref offend_threshold } if &took > offend_threshold => { + senders_to_penalize.insert(sender); + debug!(target: "miner", "Detected heavy transaction ({} ms). Penalizing sender.", took_ms(&took)); }, _ => {}, } - trace!(target: "miner", "Adding tx {:?} took {:?}", hash, took); + + debug!(target: "miner", "Adding tx {:?} took {} ms", hash, took_ms(&took)); match result { Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) => { debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?})", hash, gas_limit, gas_used, gas); // Penalize transaction if it's above current gas limit if gas > gas_limit { - transactions_to_penalize.insert(hash); + debug!(target: "txqueue", "[{:?}] Transaction above block gas limit.", hash); + invalid_transactions.insert(hash); } // Exit early if gas left is smaller then min_tx_gas - let min_tx_gas: U256 = 21000.into(); // TODO: figure this out properly. - if gas_limit - gas_used < min_tx_gas { + let gas_left = gas_limit - gas_used; + if gas_left < min_tx_gas { + debug!(target: "miner", "Remaining gas is lower than minimal gas for a transaction. Block is full."); + break; + } + + // Avoid iterating over the entire queue in case block is almost full. + skipped_transactions += 1; + if skipped_transactions > MAX_SKIPPED_TRANSACTIONS { + debug!(target: "miner", "Reached skipped transactions threshold. Assuming block is full."); break; } }, @@ -482,338 +440,281 @@ impl Miner { debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got); }, // already have transaction - ignore - Err(Error::Transaction(TransactionError::AlreadyImported)) => {}, - Err(Error::Transaction(TransactionError::NotAllowed)) => { - non_allowed_transactions.insert(hash); - debug!(target: "miner", - "Skipping non-allowed transaction for sender {:?}", - hash); + Err(Error::Transaction(transaction::Error::AlreadyImported)) => {}, + Err(Error::Transaction(transaction::Error::NotAllowed)) => { + not_allowed_transactions.insert(hash); + debug!(target: "miner", "Skipping non-allowed transaction for sender {:?}", hash); }, Err(e) => { + debug!(target: "txqueue", "[{:?}] Marking as invalid: {:?}.", hash, e); + debug!( + target: "miner", "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", block_number, hash, e + ); invalid_transactions.insert(hash); - debug!(target: "miner", - "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", - block_number, hash, e); }, - _ => { - tx_count += 1; - } // imported ok + // imported ok + _ => tx_count += 1, } } - trace!(target: "miner", "Pushed {}/{} transactions", tx_count, tx_total); + let elapsed = block_start.elapsed(); + debug!(target: "miner", "Pushed {} transactions in {} ms", tx_count, took_ms(&elapsed)); let block = open_block.close(); - let fetch_nonce = |a: &Address| chain.latest_nonce(a); - { - let mut queue = self.transaction_queue.write(); - for hash in invalid_transactions { - queue.remove(&hash, &fetch_nonce, RemovalReason::Invalid); - } - for hash in non_allowed_transactions { - queue.remove(&hash, &fetch_nonce, RemovalReason::NotAllowed); - } - for hash in transactions_to_penalize { - queue.penalize(&hash); - } + self.transaction_queue.remove(invalid_transactions.iter(), true); + self.transaction_queue.remove(not_allowed_transactions.iter(), false); + self.transaction_queue.penalize(senders_to_penalize.iter()); } + (block, original_work_hash) } - /// Asynchronously updates minimal gas price for transaction queue - pub fn recalibrate_minimal_gas_price(&self) { - debug!(target: "miner", "minimal_gas_price: recalibrating..."); - let txq = self.transaction_queue.clone(); - self.gas_pricer.lock().recalibrate(move |price| { - debug!(target: "miner", "minimal_gas_price: Got gas price! {}", price); - txq.write().set_minimal_gas_price(price); - }); + /// Returns `true` if we should create pending block even if some other conditions are not met. + /// + /// In general we always seal iff: + /// 1. --force-sealing CLI parameter is provided + /// 2. There are listeners awaiting new work packages (e.g. remote work notifications or stratum). + fn forced_sealing(&self) -> bool { + self.options.force_sealing || !self.listeners.read().is_empty() } /// Check is reseal is allowed and necessary. fn requires_reseal(&self, best_block: BlockNumber) -> bool { - let has_local_transactions = self.transaction_queue.read().has_local_pending_transactions(); - let mut sealing_work = self.sealing_work.lock(); - if sealing_work.enabled { - trace!(target: "miner", "requires_reseal: sealing enabled"); - let last_request = *self.sealing_block_last_request.lock(); - let should_disable_sealing = !self.forced_sealing() - && !has_local_transactions - && self.engine.seals_internally().is_none() - && best_block > last_request - && best_block - last_request > SEALING_TIMEOUT_IN_BLOCKS; - - trace!(target: "miner", "requires_reseal: should_disable_sealing={}; best_block={}, last_request={}", should_disable_sealing, best_block, last_request); - - if should_disable_sealing { - trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, last_request); - sealing_work.enabled = false; - sealing_work.queue.reset(); - false - } else { - // sealing enabled and we don't want to sleep. - *self.next_allowed_reseal.lock() = Instant::now() + self.options.reseal_min_period; - true - } - } else { + let mut sealing = self.sealing.lock(); + if !sealing.enabled { trace!(target: "miner", "requires_reseal: sealing is disabled"); + return false + } + + if !sealing.reseal_allowed() { + trace!(target: "miner", "requires_reseal: reseal too early"); + return false + } + + trace!(target: "miner", "requires_reseal: sealing enabled"); + + // Disable sealing if there were no requests for SEALING_TIMEOUT_IN_BLOCKS + let had_requests = best_block > sealing.last_request + && best_block - sealing.last_request <= SEALING_TIMEOUT_IN_BLOCKS; + + // keep sealing enabled if any of the conditions is met + let sealing_enabled = self.forced_sealing() + || self.transaction_queue.has_local_pending_transactions() + || self.engine.seals_internally() == Some(true) + || had_requests; + + + let should_disable_sealing = !sealing_enabled; + + trace!(target: "miner", "requires_reseal: should_disable_sealing={}; forced={:?}, has_local={:?}, internal={:?}, had_requests={:?}", + should_disable_sealing, + self.forced_sealing(), + self.transaction_queue.has_local_pending_transactions(), + self.engine.seals_internally(), + had_requests, + ); + + if should_disable_sealing { + trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, sealing.last_request); + sealing.enabled = false; + sealing.queue.reset(); false + } else { + // sealing enabled and we don't want to sleep. + sealing.next_allowed_reseal = Instant::now() + self.options.reseal_min_period; + true } } /// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal. - fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool - where C: BlockChain + SealedBlockImporter + fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool where + C: BlockChain + SealedBlockImporter, { - if !block.transactions().is_empty() || self.forced_sealing() || Instant::now() > *self.next_mandatory_reseal.read() { - trace!(target: "miner", "seal_block_internally: attempting internal seal."); + { + let sealing = self.sealing.lock(); + if block.transactions().is_empty() + && !self.forced_sealing() + && Instant::now() <= sealing.next_mandatory_reseal + { + return false + } + } - let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) { - Some(hdr) => hdr.decode(), - None => return false, - }; + trace!(target: "miner", "seal_block_internally: attempting internal seal."); - match self.engine.generate_seal(block.block(), &parent_header) { - // Save proposal for later seal submission and broadcast it. - Seal::Proposal(seal) => { - trace!(target: "miner", "Received a Proposal seal."); - *self.next_mandatory_reseal.write() = Instant::now() + self.options.reseal_max_period; - { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.queue.push(block.clone()); - sealing_work.queue.use_last_ref(); - } - block - .lock() - .seal(&*self.engine, seal) - .map(|sealed| { chain.broadcast_proposal_block(sealed); true }) - .unwrap_or_else(|e| { - warn!("ERROR: seal failed when given internally generated seal: {}", e); - false - }) - }, - // Directly import a regular sealed block. - Seal::Regular(seal) => { - *self.next_mandatory_reseal.write() = Instant::now() + self.options.reseal_max_period; - block - .lock() - .seal(&*self.engine, seal) - .map(|sealed| chain.import_sealed_block(sealed).is_ok()) - .unwrap_or_else(|e| { - warn!("ERROR: seal failed when given internally generated seal: {}", e); - false - }) - }, - Seal::None => false, - } - } else { - false + let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) { + Some(hdr) => hdr.decode(), + None => return false, + }; + + match self.engine.generate_seal(block.block(), &parent_header) { + // Save proposal for later seal submission and broadcast it. + Seal::Proposal(seal) => { + trace!(target: "miner", "Received a Proposal seal."); + { + let mut sealing = self.sealing.lock(); + sealing.next_mandatory_reseal = Instant::now() + self.options.reseal_max_period; + sealing.queue.push(block.clone()); + sealing.queue.use_last_ref(); + } + + block + .lock() + .seal(&*self.engine, seal) + .map(|sealed| { + chain.broadcast_proposal_block(sealed); + true + }) + .unwrap_or_else(|e| { + warn!("ERROR: seal failed when given internally generated seal: {}", e); + false + }) + }, + // Directly import a regular sealed block. + Seal::Regular(seal) => { + trace!(target: "miner", "Received a Regular seal."); + { + let mut sealing = self.sealing.lock(); + sealing.next_mandatory_reseal = Instant::now() + self.options.reseal_max_period; + } + + block + .lock() + .seal(&*self.engine, seal) + .map(|sealed| { + chain.import_sealed_block(sealed).is_ok() + }) + .unwrap_or_else(|e| { + warn!("ERROR: seal failed when given internally generated seal: {}", e); + false + }) + }, + Seal::None => false, } } /// Prepares work which has to be done to seal. fn prepare_work(&self, block: ClosedBlock, original_work_hash: Option) { let (work, is_new) = { - let mut sealing_work = self.sealing_work.lock(); - let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().header().hash()); - trace!(target: "miner", "prepare_work: Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", original_work_hash, last_work_hash, block.block().header().hash()); - let (work, is_new) = if last_work_hash.map_or(true, |h| h != block.block().header().hash()) { - trace!(target: "miner", "prepare_work: Pushing a new, refreshed or borrowed pending {}...", block.block().header().hash()); - let pow_hash = block.block().header().hash(); - let number = block.block().header().number(); - let difficulty = *block.block().header().difficulty(); - let is_new = original_work_hash.map_or(true, |h| block.block().header().hash() != h); - sealing_work.queue.push(block); + let block_header = block.block().header().clone(); + let block_hash = block_header.hash(); + + let mut sealing = self.sealing.lock(); + let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.block().header().hash()); + + trace!( + target: "miner", + "prepare_work: Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", + original_work_hash, last_work_hash, block_hash + ); + + let (work, is_new) = if last_work_hash.map_or(true, |h| h != block_hash) { + trace!( + target: "miner", + "prepare_work: Pushing a new, refreshed or borrowed pending {}...", + block_hash + ); + let is_new = original_work_hash.map_or(true, |h| h != block_hash); + + sealing.queue.push(block); // If push notifications are enabled we assume all work items are used. - if !self.notifiers.read().is_empty() && is_new { - sealing_work.queue.use_last_ref(); + if is_new && !self.listeners.read().is_empty() { + sealing.queue.use_last_ref(); } - (Some((pow_hash, difficulty, number)), is_new) + + (Some((block_hash, *block_header.difficulty(), block_header.number())), is_new) } else { (None, false) }; - trace!(target: "miner", "prepare_work: leaving (last={:?})", sealing_work.queue.peek_last_ref().map(|b| b.block().header().hash())); + trace!( + target: "miner", + "prepare_work: leaving (last={:?})", + sealing.queue.peek_last_ref().map(|b| b.block().header().hash()) + ); (work, is_new) }; if is_new { work.map(|(pow_hash, difficulty, number)| { - for notifier in self.notifiers.read().iter() { + for notifier in self.listeners.read().iter() { notifier.notify(pow_hash, difficulty, number) } }); } } - fn update_gas_limit(&self, client: &C) { - let gas_limit = *client.best_block_header().gas_limit(); - let mut queue = self.transaction_queue.write(); - queue.set_gas_limit(gas_limit); - if let GasLimit::Auto = self.options.tx_queue_gas_limit { - // Set total tx queue gas limit to be 20x the block gas limit. - queue.set_total_gas_limit(gas_limit * 20u32); - } - } - /// Returns true if we had to prepare new pending block. - fn prepare_work_sealing(&self, client: &C) -> bool { - trace!(target: "miner", "prepare_work_sealing: entering"); + fn prepare_pending_block(&self, client: &C) -> bool where + C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, + { + trace!(target: "miner", "prepare_pending_block: entering"); let prepare_new = { - let mut sealing_work = self.sealing_work.lock(); - let have_work = sealing_work.queue.peek_last_ref().is_some(); - trace!(target: "miner", "prepare_work_sealing: have_work={}", have_work); + let mut sealing = self.sealing.lock(); + let have_work = sealing.queue.peek_last_ref().is_some(); + trace!(target: "miner", "prepare_pending_block: have_work={}", have_work); if !have_work { - sealing_work.enabled = true; + sealing.enabled = true; true } else { false } }; + if prepare_new { // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | + // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- let (block, original_work_hash) = self.prepare_block(client); self.prepare_work(block, original_work_hash); } - let mut sealing_block_last_request = self.sealing_block_last_request.lock(); + let best_number = client.chain_info().best_block_number; - if *sealing_block_last_request != best_number { - trace!(target: "miner", "prepare_work_sealing: Miner received request (was {}, now {}) - waking up.", *sealing_block_last_request, best_number); - *sealing_block_last_request = best_number; + let mut sealing = self.sealing.lock(); + if sealing.last_request != best_number { + trace!( + target: "miner", + "prepare_pending_block: Miner received request (was {}, now {}) - waking up.", + sealing.last_request, best_number + ); + sealing.last_request = best_number; } // Return if we restarted prepare_new } - - fn add_transactions_to_queue( - &self, - client: &C, - transactions: Vec, - default_origin: TransactionOrigin, - condition: Option, - transaction_queue: &mut BanningTransactionQueue, - ) -> Vec> { - let best_block_header = client.best_block_header(); - let insertion_time = client.chain_info().best_block_number; - let mut inserted = Vec::with_capacity(transactions.len()); - - let results = transactions.into_iter() - .map(|tx| { - let hash = tx.hash(); - if client.transaction_block(TransactionId::Hash(hash)).is_some() { - debug!(target: "miner", "Rejected tx {:?}: already in the blockchain", hash); - return Err(Error::Transaction(TransactionError::AlreadyImported)); - } - match self.engine.verify_transaction_basic(&tx, &best_block_header) - .and_then(|_| self.engine.verify_transaction_unordered(tx, &best_block_header)) - { - Err(e) => { - debug!(target: "miner", "Rejected tx {:?} with invalid signature: {:?}", hash, e); - Err(e) - }, - Ok(transaction) => { - // This check goes here because verify_transaction takes SignedTransaction parameter - self.engine.machine().verify_transaction(&transaction, &best_block_header, client)?; - - let origin = self.accounts.as_ref().and_then(|accounts| { - match accounts.has_account(transaction.sender()).unwrap_or(false) { - true => Some(TransactionOrigin::Local), - false => None, - } - }).unwrap_or(default_origin); - - let details_provider = TransactionDetailsProvider::new(client, &self.service_transaction_action); - let hash = transaction.hash(); - let result = match origin { - TransactionOrigin::Local | TransactionOrigin::RetractedBlock => { - transaction_queue.add(transaction, origin, insertion_time, condition.clone(), &details_provider)? - }, - TransactionOrigin::External => { - transaction_queue.add_with_banlist(transaction, insertion_time, &details_provider)? - }, - }; - - inserted.push(hash); - Ok(result) - }, - } - }) - .collect(); - - for listener in &*self.transaction_listener.read() { - listener(&inserted); - } - - results - } - - /// Are we allowed to do a non-mandatory reseal? - fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock() } - - fn from_pending_block(&self, latest_block_number: BlockNumber, from_chain: F, map_block: G) -> H - where F: Fn() -> H, G: FnOnce(&ClosedBlock) -> H { - let sealing_work = self.sealing_work.lock(); - sealing_work.queue.peek_last_ref().map_or_else( - || from_chain(), - |b| { - if b.block().header().number() > latest_block_number { - map_block(b) - } else { - from_chain() - } - } - ) - } } const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; -impl MinerService for Miner { +impl miner::MinerService for Miner { type State = State<::state_db::StateDB>; - fn clear_and_reset(&self, chain: &C) { - self.transaction_queue.write().clear(); - // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - self.update_sealing(chain); + fn authoring_params(&self) -> AuthoringParams { + self.params.read().clone() } - fn status(&self) -> MinerStatus { - let status = self.transaction_queue.read().status(); - let sealing_work = self.sealing_work.lock(); - MinerStatus { - transactions_in_pending_queue: status.pending, - transactions_in_future_queue: status.future, - transactions_in_pending_block: sealing_work.queue.peek_last_ref().map_or(0, |b| b.transactions().len()), - } + fn set_gas_range_target(&self, gas_range_target: (U256, U256)) { + self.params.write().gas_range_target = gas_range_target; } - fn set_author(&self, author: Address) { - if self.engine.seals_internally().is_some() { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.enabled = true; - } - *self.author.write() = author; + fn set_extra_data(&self, extra_data: Bytes) { + self.params.write().extra_data = extra_data; } - fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> { - if self.engine.seals_internally().is_some() { + fn set_author(&self, address: Address, password: Option) -> Result<(), AccountError> { + self.params.write().author = address; + + if self.engine.seals_internally().is_some() && password.is_some() { if let Some(ref ap) = self.accounts { + let password = password.unwrap_or_default(); + // Sign test message ap.sign(address.clone(), Some(password.clone()), Default::default())?; - // Limit the scope of the locks. - { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.enabled = true; - *self.author.write() = address; - } + // Enable sealing + self.sealing.lock().enabled = true; // -------------------------------------------------------------------------- - // | NOTE Code below may require author and sealing_work locks | - // | (some `Engine`s call `EngineClient.update_sealing()`) |. + // | 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(ap.clone(), address, password); @@ -823,132 +724,64 @@ impl MinerService for Miner { Err(AccountError::NotFound) } } else { - warn!(target: "miner", "Cannot set engine signer on a PoW chain."); - Err(AccountError::InappropriateChain) + Ok(()) } } - fn set_extra_data(&self, extra_data: Bytes) { - *self.extra_data.write() = extra_data; - } - - /// Set the gas limit we wish to target when sealing a new block. - fn set_gas_floor_target(&self, target: U256) { - self.gas_range_target.write().0 = target; - } - - fn set_gas_ceil_target(&self, target: U256) { - self.gas_range_target.write().1 = target; - } - - fn set_minimal_gas_price(&self, min_gas_price: U256) { - self.transaction_queue.write().set_minimal_gas_price(min_gas_price); - } - - fn minimal_gas_price(&self) -> U256 { - *self.transaction_queue.read().minimal_gas_price() - } - fn sensible_gas_price(&self) -> U256 { // 10% above our minimum. - *self.transaction_queue.read().minimal_gas_price() * 110u32 / 100.into() + self.transaction_queue.current_worst_gas_price() * 110u32 / 100.into() } fn sensible_gas_limit(&self) -> U256 { - self.gas_range_target.read().0 / 5.into() - } - - fn transactions_limit(&self) -> usize { - self.transaction_queue.read().limit() - } - - fn set_transactions_limit(&self, limit: usize) { - self.transaction_queue.write().set_limit(limit) - } - - fn set_tx_gas_limit(&self, limit: U256) { - self.transaction_queue.write().set_tx_gas_limit(limit) - } - - /// Get the author that we will seal blocks as. - fn author(&self) -> Address { - *self.author.read() - } - - /// Get the extra_data that we will seal blocks with. - fn extra_data(&self) -> Bytes { - self.extra_data.read().clone() - } - - /// Get the gas limit we wish to target when sealing a new block. - fn gas_floor_target(&self) -> U256 { - self.gas_range_target.read().0 - } - - /// Get the gas limit we wish to target when sealing a new block. - fn gas_ceil_target(&self) -> U256 { - self.gas_range_target.read().1 + self.params.read().gas_range_target.0 / 5.into() } - fn import_external_transactions( + fn import_external_transactions( &self, - client: &C, + chain: &C, transactions: Vec - ) -> Vec> { + ) -> Vec> { trace!(target: "external_tx", "Importing external transactions"); - let results = { - let mut transaction_queue = self.transaction_queue.write(); - self.add_transactions_to_queue( - client, transactions, TransactionOrigin::External, None, &mut transaction_queue - ) - }; + let client = self.pool_client(chain); + let results = self.transaction_queue.import( + client, + transactions.into_iter().map(pool::verifier::Transaction::Unverified).collect(), + ); - if !results.is_empty() && self.options.reseal_on_external_tx && self.tx_reseal_allowed() { + if !results.is_empty() && self.options.reseal_on_external_tx && self.sealing.lock().reseal_allowed() { // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | + // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- - self.update_sealing(client); + self.update_sealing(chain); } + results } - fn import_own_transaction( + fn import_own_transaction( &self, chain: &C, pending: PendingTransaction, - ) -> Result { + ) -> Result<(), transaction::Error> { trace!(target: "own_tx", "Importing transaction: {:?}", pending); - let imported = { - // Be sure to release the lock before we call prepare_work_sealing - let mut transaction_queue = self.transaction_queue.write(); - // We need to re-validate transactions - let import = self.add_transactions_to_queue( - chain, vec![pending.transaction.into()], TransactionOrigin::Local, pending.condition, &mut transaction_queue - ).pop().expect("one result returned per added transaction; one added => one result; qed"); - - match import { - Ok(_) => { - trace!(target: "own_tx", "Status: {:?}", transaction_queue.status()); - }, - Err(ref e) => { - trace!(target: "own_tx", "Status: {:?}", transaction_queue.status()); - warn!(target: "own_tx", "Error importing transaction: {:?}", e); - }, - } - import - }; + let client = self.pool_client(chain); + let imported = self.transaction_queue.import( + client, + vec![pool::verifier::Transaction::Local(pending)] + ).pop().expect("one result returned per added transaction; one added => one result; qed"); // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | + // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- - if imported.is_ok() && self.options.reseal_on_own_tx && self.tx_reseal_allowed() { + if imported.is_ok() && self.options.reseal_on_own_tx && self.sealing.lock().reseal_allowed() { // Make sure to do it after transaction is imported and lock is droped. // We need to create pending block and enable sealing. - if self.engine.seals_internally().unwrap_or(false) || !self.prepare_work_sealing(chain) { + if self.engine.seals_internally().unwrap_or(false) || !self.prepare_pending_block(chain) { // If new block has not been prepared (means we already had one) // or Engine might be able to seal internally, // we need to update sealing. @@ -959,215 +792,185 @@ impl MinerService for Miner { imported } - fn pending_transactions(&self) -> Vec { - let queue = self.transaction_queue.read(); - queue.pending_transactions(BlockNumber::max_value(), u64::max_value()) + fn local_transactions(&self) -> BTreeMap { + self.transaction_queue.local_transactions() } - fn local_transactions(&self) -> BTreeMap { - let queue = self.transaction_queue.read(); - queue.local_transactions() - .iter() - .map(|(hash, status)| (*hash, status.clone())) - .collect() + fn queued_transactions(&self) -> Vec> { + self.transaction_queue.all_transactions() } - fn future_transactions(&self) -> Vec { - self.transaction_queue.read().future_transactions() - } + fn ready_transactions(&self, chain: &C) -> Vec> where + C: ChainInfo + Nonce + Sync, + { + let chain_info = chain.chain_info(); - fn ready_transactions(&self, best_block: BlockNumber, best_block_timestamp: u64) -> Vec { - let queue = self.transaction_queue.read(); - match self.options.pending_set { - PendingSet::AlwaysQueue => queue.pending_transactions(best_block, best_block_timestamp), - PendingSet::SealingOrElseQueue => { - self.from_pending_block( - best_block, - || queue.pending_transactions(best_block, best_block_timestamp), - |sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect() - ) - }, - PendingSet::AlwaysSealing => { - self.from_pending_block( - best_block, - || vec![], - |sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect() - ) - }, - } - } + let from_queue = || { + self.transaction_queue.pending( + CachedNonceClient::new(chain, &self.nonce_cache), + chain_info.best_block_number, + chain_info.best_block_timestamp, + // We propagate transactions over the nonce cap. + // The mechanism is only to limit number of transactions in pending block + // those transactions are valid and will just be ready to be included in next block. + None, + ) + }; + + let from_pending = || { + self.map_existing_pending_block(|sealing| { + sealing.transactions() + .iter() + .map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone())) + .map(Arc::new) + .collect() + }, chain_info.best_block_number) + }; - fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec { - let queue = self.transaction_queue.read(); match self.options.pending_set { - PendingSet::AlwaysQueue => queue.pending_hashes(), - PendingSet::SealingOrElseQueue => { - self.from_pending_block( - best_block, - || queue.pending_hashes(), - |sealing| sealing.transactions().iter().map(|t| t.hash()).collect() - ) + PendingSet::AlwaysQueue => { + from_queue() }, PendingSet::AlwaysSealing => { - self.from_pending_block( - best_block, - || vec![], - |sealing| sealing.transactions().iter().map(|t| t.hash()).collect() - ) + from_pending().unwrap_or_default() }, - } - } - - fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option { - let queue = self.transaction_queue.read(); - match self.options.pending_set { - PendingSet::AlwaysQueue => queue.find(hash), PendingSet::SealingOrElseQueue => { - self.from_pending_block( - best_block, - || queue.find(hash), - |sealing| sealing.transactions().iter().find(|t| &t.hash() == hash).cloned().map(Into::into) - ) - }, - PendingSet::AlwaysSealing => { - self.from_pending_block( - best_block, - || None, - |sealing| sealing.transactions().iter().find(|t| &t.hash() == hash).cloned().map(Into::into) - ) + from_pending().unwrap_or_else(from_queue) }, } } - fn remove_pending_transaction(&self, chain: &C, hash: &H256) -> Option { - let mut queue = self.transaction_queue.write(); - let tx = queue.find(hash); - if tx.is_some() { - let fetch_nonce = |a: &Address| chain.latest_nonce(a); - queue.remove(hash, &fetch_nonce, RemovalReason::Canceled); - } - tx + fn next_nonce(&self, chain: &C, address: &Address) -> U256 where + C: Nonce + Sync, + { + self.transaction_queue.next_nonce(CachedNonceClient::new(chain, &self.nonce_cache), address) + .unwrap_or_else(|| chain.latest_nonce(address)) } - fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option { - self.from_pending_block( - best_block, - || None, - |pending| { - let txs = pending.transactions(); - txs.iter() - .map(|t| t.hash()) - .position(|t| t == *hash) - .map(|index| { - let prev_gas = if index == 0 { Default::default() } else { pending.receipts()[index - 1].gas_used }; - let tx = &txs[index]; - let receipt = &pending.receipts()[index]; - RichReceipt { - transaction_hash: hash.clone(), - transaction_index: index, - cumulative_gas_used: receipt.gas_used, - gas_used: receipt.gas_used - prev_gas, - contract_address: match tx.action { - Action::Call(_) => None, - Action::Create => { - let sender = tx.sender(); - Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data).0) - } - }, - logs: receipt.logs.clone(), - log_bloom: receipt.log_bloom, - outcome: receipt.outcome.clone(), - } - }) - } - ) + fn transaction(&self, hash: &H256) -> Option> { + self.transaction_queue.find(hash) } - fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap { - self.from_pending_block( - best_block, - BTreeMap::new, - |pending| { - let hashes = pending.transactions() - .iter() - .map(|t| t.hash()); - - let receipts = pending.receipts().iter().cloned(); + fn remove_transaction(&self, hash: &H256) -> Option> { + self.transaction_queue.remove(::std::iter::once(hash), false) + .pop() + .expect("remove() returns one result per hash; one hash passed; qed") + } - hashes.zip(receipts).collect() - } - ) + fn queue_status(&self) -> QueueStatus { + self.transaction_queue.status() } - fn last_nonce(&self, address: &Address) -> Option { - self.transaction_queue.read().last_nonce(address) + fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option { + self.map_existing_pending_block(|pending| { + let txs = pending.transactions(); + txs.iter() + .map(|t| t.hash()) + .position(|t| t == *hash) + .map(|index| { + let receipts = pending.receipts(); + let prev_gas = if index == 0 { Default::default() } else { receipts[index - 1].gas_used }; + let tx = &txs[index]; + let receipt = &receipts[index]; + RichReceipt { + transaction_hash: hash.clone(), + transaction_index: index, + cumulative_gas_used: receipt.gas_used, + gas_used: receipt.gas_used - prev_gas, + contract_address: match tx.action { + Action::Call(_) => None, + Action::Create => { + let sender = tx.sender(); + Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data).0) + } + }, + logs: receipt.logs.clone(), + log_bloom: receipt.log_bloom, + outcome: receipt.outcome.clone(), + } + }) + }, best_block).and_then(|x| x) } - fn can_produce_work_package(&self) -> bool { - self.engine.seals_internally().is_none() + fn pending_receipts(&self, best_block: BlockNumber) -> Option> { + self.map_existing_pending_block(|pending| { + let hashes = pending.transactions().iter().map(|t| t.hash()); + let receipts = pending.receipts().iter().cloned(); + + hashes.zip(receipts).collect() + }, best_block) } /// Update sealing if required. /// Prepare the block and work if the Engine does not seal internally. - fn update_sealing(&self, chain: &C) - where C: AccountData + BlockChain + RegistryInfo - + CallContract + BlockProducer + SealedBlockImporter + fn update_sealing(&self, chain: &C) where + C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, { trace!(target: "miner", "update_sealing"); - const NO_NEW_CHAIN_WITH_FORKS: &str = "Your chain specification contains one or more hard forks which are required to be \ - on by default. Please remove these forks and start your chain again."; - if self.requires_reseal(chain.chain_info().best_block_number) { - // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - trace!(target: "miner", "update_sealing: preparing a block"); - let (block, original_work_hash) = self.prepare_block(chain); - - // refuse to seal the first block of the chain if it contains hard forks - // which should be on by default. - if block.block().header().number() == 1 && self.engine.params().contains_bugfix_hard_fork() { - warn!("{}", NO_NEW_CHAIN_WITH_FORKS); - return; - } + // Do nothing if reseal is not required, + // but note that `requires_reseal` updates internal state. + if !self.requires_reseal(chain.chain_info().best_block_number) { + return; + } - match self.engine.seals_internally() { - Some(true) => { - trace!(target: "miner", "update_sealing: engine indicates internal sealing"); - if self.seal_and_import_block_internally(chain, block) { - trace!(target: "miner", "update_sealing: imported internally sealed block"); - } - }, - Some(false) => trace!(target: "miner", "update_sealing: engine is not keen to seal internally right now"), - None => { - trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); - self.prepare_work(block, original_work_hash) - }, - } + // -------------------------------------------------------------------------- + // | NOTE Code below requires sealing locks. | + // | Make sure to release the locks before calling that method. | + // -------------------------------------------------------------------------- + trace!(target: "miner", "update_sealing: preparing a block"); + let (block, original_work_hash) = self.prepare_block(chain); + + // refuse to seal the first block of the chain if it contains hard forks + // which should be on by default. + if block.block().header().number() == 1 && self.engine.params().contains_bugfix_hard_fork() { + warn!("Your chain specification contains one or more hard forks which are required to be \ + on by default. Please remove these forks and start your chain again."); + return; + } + + match self.engine.seals_internally() { + Some(true) => { + trace!(target: "miner", "update_sealing: engine indicates internal sealing"); + if self.seal_and_import_block_internally(chain, block) { + trace!(target: "miner", "update_sealing: imported internally sealed block"); + } + }, + Some(false) => { + trace!(target: "miner", "update_sealing: engine is not keen to seal internally right now"); + // anyway, save the block for later use + self.sealing.lock().queue.push(block); + }, + None => { + trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); + self.prepare_work(block, original_work_hash) + }, } } fn is_currently_sealing(&self) -> bool { - self.sealing_work.lock().queue.is_in_use() + self.sealing.lock().queue.is_in_use() } - fn map_sealing_work(&self, client: &C, f: F) -> Option - where C: AccountData + BlockChain + BlockProducer + CallContract, - F: FnOnce(&ClosedBlock) -> T + fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> where + C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, { - trace!(target: "miner", "map_sealing_work: entering"); - self.prepare_work_sealing(client); - trace!(target: "miner", "map_sealing_work: sealing prepared"); - let mut sealing_work = self.sealing_work.lock(); - let ret = sealing_work.queue.use_last_ref(); - trace!(target: "miner", "map_sealing_work: leaving use_last_ref={:?}", ret.as_ref().map(|b| b.block().header().hash())); - ret.map(f) + if self.engine.seals_internally().is_some() { + return None; + } + + self.prepare_pending_block(chain); + + self.sealing.lock().queue.use_last_ref().map(|b| { + let header = b.header(); + (header.hash(), header.number(), header.timestamp(), *header.difficulty()) + }) } - fn submit_seal(&self, chain: &C, block_hash: H256, seal: Vec) -> Result<(), Error> { + // Note used for external submission (PoW) and internally by sealing engines. + fn submit_seal(&self, block_hash: H256, seal: Vec) -> Result { let result = - if let Some(b) = self.sealing_work.lock().queue.get_used_if( + if let Some(b) = self.sealing.lock().queue.get_used_if( if self.options.enable_resubmission { GetAction::Clone } else { @@ -1184,18 +987,17 @@ impl MinerService for Miner { warn!(target: "miner", "Submitted solution rejected: Block unknown or out of date."); Err(Error::PowHashInvalid) }; + result.and_then(|sealed| { let n = sealed.header().number(); let h = sealed.header().hash(); - chain.import_sealed_block(sealed)?; info!(target: "miner", "Submitted block imported OK. #{}: {}", Colour::White.bold().paint(format!("{}", n)), Colour::White.bold().paint(format!("{:x}", h))); - Ok(()) + Ok(sealed) }) } - fn chain_new_blocks(&self, chain: &C, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) - where C: AccountData + BlockChain + CallContract + RegistryInfo - + BlockProducer + ScheduleInfo + SealedBlockImporter + fn chain_new_blocks(&self, chain: &C, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256], is_internal_import: bool) + where C: miner::BlockChainClient, { trace!(target: "miner", "chain_new_blocks"); @@ -1203,133 +1005,89 @@ impl MinerService for Miner { // 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that // are in those blocks - // First update gas limit in transaction queue - self.update_gas_limit(chain); + // Clear nonce cache + self.nonce_cache.write().clear(); - // Update minimal gas price - self.recalibrate_minimal_gas_price(); + // First update gas limit in transaction queue and minimal gas price. + let gas_limit = *chain.best_block_header().gas_limit(); + self.update_transaction_queue_limits(gas_limit); // Then import all transactions... + let client = self.pool_client(chain); { - - let mut transaction_queue = self.transaction_queue.write(); - for hash in retracted { - let block = chain.block(BlockId::Hash(*hash)) - .expect("Client is sending message after commit to db and inserting to chain; the block is available; qed"); - let txs = block.transactions(); - let _ = self.add_transactions_to_queue( - chain, txs, TransactionOrigin::RetractedBlock, None, &mut transaction_queue - ); - } + retracted + .par_iter() + .for_each(|hash| { + let block = chain.block(BlockId::Hash(*hash)) + .expect("Client is sending message after commit to db and inserting to chain; the block is available; qed"); + let txs = block.transactions() + .into_iter() + .map(pool::verifier::Transaction::Retracted) + .collect(); + let _ = self.transaction_queue.import( + client.clone(), + txs, + ); + }); } // ...and at the end remove the old ones - { - let fetch_account = |a: &Address| AccountDetails { - nonce: chain.latest_nonce(a), - balance: chain.latest_balance(a), - }; - let time = chain.chain_info().best_block_number; - let mut transaction_queue = self.transaction_queue.write(); - transaction_queue.remove_old(&fetch_account, time); - } + self.transaction_queue.cull(client); if enacted.len() > 0 || (imported.len() > 0 && self.options.reseal_on_uncle) { - // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - self.update_sealing(chain); + // Reset `next_allowed_reseal` in case a block is imported. + // Even if min_period is high, we will always attempt to create + // new pending block. + self.sealing.lock().next_allowed_reseal = Instant::now(); + + if !is_internal_import { + // -------------------------------------------------------------------------- + // | NOTE Code below requires sealing locks. | + // | Make sure to release the locks before calling that method. | + // -------------------------------------------------------------------------- + self.update_sealing(chain); + } } } fn pending_state(&self, latest_block_number: BlockNumber) -> Option { - Miner::pending_state(self, latest_block_number) + self.map_existing_pending_block(|b| b.state().clone(), latest_block_number) } fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
{ - Miner::pending_block_header(self, latest_block_number) + self.map_existing_pending_block(|b| b.header().clone(), latest_block_number) } fn pending_block(&self, latest_block_number: BlockNumber) -> Option { - Miner::pending_block(self, latest_block_number) + self.map_existing_pending_block(|b| b.to_base(), latest_block_number) } -} - -/// Action when service transaction is received -enum ServiceTransactionAction { - /// Refuse service transaction immediately - Refuse, - /// Accept if sender is certified to send service transactions - Check(ServiceTransactionChecker), -} -impl ServiceTransactionAction { - pub fn check(&self, client: &C, tx: &SignedTransaction) -> Result - { - match *self { - ServiceTransactionAction::Refuse => Err("configured to refuse service transactions".to_owned()), - ServiceTransactionAction::Check(ref checker) => checker.check(client, tx), - } - } -} - -struct TransactionDetailsProvider<'a, C: 'a> { - client: &'a C, - service_transaction_action: &'a ServiceTransactionAction, -} - -impl<'a, C> TransactionDetailsProvider<'a, C> { - pub fn new(client: &'a C, service_transaction_action: &'a ServiceTransactionAction) -> Self { - TransactionDetailsProvider { - client: client, - service_transaction_action: service_transaction_action, - } - } -} - -impl<'a, C> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a, C> - where C: AccountData + CallContract + RegistryInfo + ScheduleInfo -{ - fn fetch_account(&self, address: &Address) -> AccountDetails { - AccountDetails { - nonce: self.client.latest_nonce(address), - balance: self.client.latest_balance(address), - } - } - - fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256 { - tx.gas_required(&self.client.latest_schedule()).into() - } - - fn is_service_transaction_acceptable(&self, tx: &SignedTransaction) -> Result { - self.service_transaction_action.check(self.client, tx) + fn pending_transactions(&self, latest_block_number: BlockNumber) -> Option> { + self.map_existing_pending_block(|b| b.transactions().into_iter().cloned().collect(), latest_block_number) } } #[cfg(test)] mod tests { use super::*; - use ethcore_miner::transaction_queue::PrioritizationStrategy; - use ethereum_types::U256; use ethkey::{Generator, Random}; - use client::{TestBlockChainClient, EachBlockWith, ChainInfo}; use hash::keccak; use header::BlockNumber; use rustc_hex::FromHex; - use spec::Spec; - use transaction::{SignedTransaction, Transaction, PendingTransaction, Action}; + + use client::{TestBlockChainClient, EachBlockWith, ChainInfo, ImportSealedBlock}; use miner::MinerService; use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts}; + use transaction::{Transaction}; #[test] fn should_prepare_block_to_seal() { // given let client = TestBlockChainClient::default(); - let miner = Miner::with_spec(&Spec::new_test()); + let miner = Miner::new_for_tests(&Spec::new_test(), None); // when - let sealing_work = miner.map_sealing_work(&client, |_| ()); + let sealing_work = miner.work_package(&client); assert!(sealing_work.is_some(), "Expected closed block"); } @@ -1337,25 +1095,26 @@ mod tests { fn should_still_work_after_a_couple_of_blocks() { // given let client = TestBlockChainClient::default(); - let miner = Miner::with_spec(&Spec::new_test()); + let miner = Miner::new_for_tests(&Spec::new_test(), None); - let res = miner.map_sealing_work(&client, |b| b.block().header().hash()); - assert!(res.is_some()); - assert!(miner.submit_seal(&client, res.unwrap(), vec![]).is_ok()); + let res = miner.work_package(&client); + let hash = res.unwrap().0; + let block = miner.submit_seal(hash, vec![]).unwrap(); + client.import_sealed_block(block).unwrap(); // two more blocks mined, work requested. client.add_blocks(1, EachBlockWith::Uncle); - miner.map_sealing_work(&client, |b| b.block().header().hash()); + miner.work_package(&client); client.add_blocks(1, EachBlockWith::Uncle); - miner.map_sealing_work(&client, |b| b.block().header().hash()); + miner.work_package(&client); // solution to original work submitted. - assert!(miner.submit_seal(&client, res.unwrap(), vec![]).is_ok()); + assert!(miner.submit_seal(hash, vec![]).is_ok()); } fn miner() -> Miner { - Arc::try_unwrap(Miner::new( + Miner::new( MinerOptions { force_sealing: false, reseal_on_external_tx: false, @@ -1363,22 +1122,24 @@ mod tests { reseal_on_uncle: false, reseal_min_period: Duration::from_secs(5), reseal_max_period: Duration::from_secs(120), - tx_gas_limit: !U256::zero(), - tx_queue_size: 1024, - tx_queue_memory_limit: None, - tx_queue_gas_limit: GasLimit::None, - tx_queue_strategy: PrioritizationStrategy::GasFactorAndGasPrice, pending_set: PendingSet::AlwaysSealing, work_queue_size: 5, enable_resubmission: true, - tx_queue_banning: Banning::Disabled, - refuse_service_transactions: false, infinite_pending_block: false, + tx_queue_penalization: Penalization::Disabled, + tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, + refuse_service_transactions: false, + pool_limits: Default::default(), + pool_verification_options: pool::verifier::Options { + minimal_gas_price: 0.into(), + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + }, }, GasPricer::new_fixed(0u64.into()), &Spec::new_test(), None, // accounts provider - )).ok().expect("Miner was just created.") + ) } fn transaction() -> SignedTransaction { @@ -1408,13 +1169,12 @@ mod tests { let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None)); // then - assert_eq!(res.unwrap(), TransactionImportResult::Current); - assert_eq!(miner.pending_transactions().len(), 1); - assert_eq!(miner.ready_transactions(best_block, 0).len(), 1); - assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1); - assert_eq!(miner.pending_receipts(best_block).len(), 1); + assert_eq!(res.unwrap(), ()); + assert_eq!(miner.pending_transactions(best_block).unwrap().len(), 1); + assert_eq!(miner.pending_receipts(best_block).unwrap().len(), 1); + assert_eq!(miner.ready_transactions(&client).len(), 1); // This method will let us know if pending block was created (before calling that method) - assert!(!miner.prepare_work_sealing(&client)); + assert!(!miner.prepare_pending_block(&client)); } #[test] @@ -1428,11 +1188,10 @@ mod tests { let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None)); // then - assert_eq!(res.unwrap(), TransactionImportResult::Current); - assert_eq!(miner.pending_transactions().len(), 1); - assert_eq!(miner.ready_transactions(best_block, 0).len(), 0); - assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0); - assert_eq!(miner.pending_receipts(best_block).len(), 0); + assert_eq!(res.unwrap(), ()); + assert_eq!(miner.pending_transactions(best_block), None); + assert_eq!(miner.pending_receipts(best_block), None); + assert_eq!(miner.ready_transactions(&client).len(), 1); } #[test] @@ -1446,13 +1205,16 @@ mod tests { let res = miner.import_external_transactions(&client, vec![transaction]).pop().unwrap(); // then - assert_eq!(res.unwrap(), TransactionImportResult::Current); - assert_eq!(miner.pending_transactions().len(), 1); - assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0); - assert_eq!(miner.ready_transactions(best_block, 0).len(), 0); - assert_eq!(miner.pending_receipts(best_block).len(), 0); + assert_eq!(res.unwrap(), ()); + // By default we don't reseal on external transactions + assert_eq!(miner.pending_transactions(best_block), None); + assert_eq!(miner.pending_receipts(best_block), None); + // By default we use PendingSet::AlwaysSealing, so no transactions yet. + assert_eq!(miner.ready_transactions(&client).len(), 0); // This method will let us know if pending block was created (before calling that method) - assert!(miner.prepare_work_sealing(&client)); + assert!(miner.prepare_pending_block(&client)); + // After pending block is created we should see a transaction. + assert_eq!(miner.ready_transactions(&client).len(), 1); } #[test] @@ -1463,7 +1225,7 @@ mod tests { assert!(!miner.requires_reseal(1u8.into())); miner.import_external_transactions(&client, vec![transaction().into()]).pop().unwrap().unwrap(); - assert!(miner.prepare_work_sealing(&client)); + assert!(miner.prepare_pending_block(&client)); // Unless asked to prepare work. assert!(miner.requires_reseal(1u8.into())); } @@ -1471,18 +1233,19 @@ mod tests { #[test] fn internal_seals_without_work() { let spec = Spec::new_instant(); - let miner = Miner::with_spec(&spec); + let miner = Miner::new_for_tests(&spec, None); let client = generate_dummy_client(2); - assert_eq!(miner.import_external_transactions(&*client, vec![transaction_with_chain_id(spec.chain_id()).into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); + let import = miner.import_external_transactions(&*client, vec![transaction_with_chain_id(spec.chain_id()).into()]).pop().unwrap(); + assert_eq!(import.unwrap(), ()); miner.update_sealing(&*client); client.flush_queue(); assert!(miner.pending_block(0).is_none()); assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber); - assert_eq!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction_with_chain_id(spec.chain_id()).into(), None)).unwrap(), TransactionImportResult::Current); + assert!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction_with_chain_id(spec.chain_id()).into(), None)).is_ok()); miner.update_sealing(&*client); client.flush_queue(); @@ -1490,21 +1253,12 @@ mod tests { assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber); } - #[test] - fn should_fail_setting_engine_signer_on_pow() { - let spec = Spec::new_pow_test_spec; - let tap = Arc::new(AccountProvider::transient_provider()); - let addr = tap.insert_account(keccak("1").into(), "").unwrap(); - let client = generate_dummy_client_with_spec_and_accounts(spec, Some(tap.clone())); - assert!(match client.miner().set_engine_signer(addr, "".into()) { Err(AccountError::InappropriateChain) => true, _ => false }) - } - #[test] fn should_fail_setting_engine_signer_without_account_provider() { let spec = Spec::new_instant; let tap = Arc::new(AccountProvider::transient_provider()); let addr = tap.insert_account(keccak("1").into(), "").unwrap(); let client = generate_dummy_client_with_spec_and_accounts(spec, None); - assert!(match client.miner().set_engine_signer(addr, "".into()) { Err(AccountError::NotFound) => true, _ => false }); + assert!(match client.miner().set_author(addr, Some("".into())) { Err(AccountError::NotFound) => true, _ => false }); } } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 5f451fdc2a6..fbf4f11b7ad 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -17,191 +17,169 @@ #![warn(missing_docs)] //! Miner module -//! Keeps track of transactions and mined block. -//! -//! Usage example: -//! -//! ```rust -//! extern crate ethcore; -//! use std::env; -//! use ethcore::ethereum; -//! use ethcore::client::{Client, ClientConfig}; -//! use ethcore::miner::{Miner, MinerService}; -//! -//! fn main() { -//! let miner: Miner = Miner::with_spec(ðereum::new_foundation(&env::temp_dir())); -//! // get status -//! assert_eq!(miner.status().transactions_in_pending_queue, 0); -//! -//! // Check block for sealing -//! //assert!(miner.sealing_block(&*client).lock().is_some()); -//! } -//! ``` +//! Keeps track of transactions and currently sealed pending block. mod miner; -mod stratum; mod service_transaction_checker; -pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit}; -pub use self::stratum::{Stratum, Error as StratumError, Options as StratumOptions}; +pub mod pool_client; +pub mod stratum; -pub use ethcore_miner::local_transactions::Status as LocalTransactionStatus; +pub use self::miner::{Miner, MinerOptions, Penalization, PendingSet, AuthoringParams}; +use std::sync::Arc; use std::collections::BTreeMap; -use block::{ClosedBlock, Block}; use bytes::Bytes; +use ethereum_types::{H256, U256, Address}; +use ethcore_miner::pool::{VerifiedTransaction, QueueStatus, local_transactions}; + +use block::{Block, SealedBlock}; use client::{ - MiningBlockChainClient, CallContract, RegistryInfo, ScheduleInfo, - BlockChain, AccountData, BlockProducer, SealedBlockImporter + CallContract, RegistryInfo, ScheduleInfo, + BlockChain, BlockProducer, SealedBlockImporter, ChainInfo, + AccountData, Nonce, }; -use error::{Error}; -use ethereum_types::{H256, U256, Address}; +use error::Error; use header::{BlockNumber, Header}; use receipt::{RichReceipt, Receipt}; -use transaction::{UnverifiedTransaction, PendingTransaction, ImportResult as TransactionImportResult}; +use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; use state::StateInfo; +/// Provides methods to verify incoming external transactions +pub trait TransactionVerifierClient: Send + Sync + // Required for ServiceTransactionChecker + + CallContract + RegistryInfo + // Required for verifiying transactions + + BlockChain + ScheduleInfo + AccountData +{} + +/// Extended client interface used for mining +pub trait BlockChainClient: TransactionVerifierClient + BlockProducer + SealedBlockImporter {} + /// Miner client API pub trait MinerService : Send + Sync { /// Type representing chain state type State: StateInfo + 'static; - /// Returns miner's status. - fn status(&self) -> MinerStatus; - - /// Get the author that we will seal blocks as. - fn author(&self) -> Address; - - /// Set the author that we will seal blocks as. - fn set_author(&self, author: Address); + // Sealing - /// Set info necessary to sign consensus messages. - fn set_engine_signer(&self, address: Address, password: String) -> Result<(), ::account_provider::SignError>; - - /// Get the extra_data that we will seal blocks with. - fn extra_data(&self) -> Bytes; - - /// Set the extra_data that we will seal blocks with. - fn set_extra_data(&self, extra_data: Bytes); - - /// Get current minimal gas price for transactions accepted to queue. - fn minimal_gas_price(&self) -> U256; + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result; - /// Set minimal gas price of transaction to be accepted for mining. - fn set_minimal_gas_price(&self, min_gas_price: U256); + /// Is it currently sealing? + fn is_currently_sealing(&self) -> bool; - /// Get the lower bound of the gas limit we wish to target when sealing a new block. - fn gas_floor_target(&self) -> U256; + /// Get the sealing work package preparing it if doesn't exist yet. + /// + /// Returns `None` if engine seals internally. + fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> + where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; - /// Get the upper bound of the gas limit we wish to target when sealing a new block. - fn gas_ceil_target(&self) -> U256; + /// Update current pending block + fn update_sealing(&self, chain: &C) + where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; - // TODO: coalesce into single set_range function. - /// Set the lower bound of gas limit we wish to target when sealing a new block. - fn set_gas_floor_target(&self, target: U256); - /// Set the upper bound of gas limit we wish to target when sealing a new block. - fn set_gas_ceil_target(&self, target: U256); + // Notifications - /// Get current transactions limit in queue. - fn transactions_limit(&self) -> usize; + /// Called when blocks are imported to chain, updates transactions queue. + /// `is_internal_import` indicates that the block has just been created in miner and internally sealed by the engine, + /// so we shouldn't attempt creating new block again. + fn chain_new_blocks(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256], is_internal_import: bool) + where C: BlockChainClient; - /// Set maximal number of transactions kept in the queue (both current and future). - fn set_transactions_limit(&self, limit: usize); - /// Set maximum amount of gas allowed for any single transaction to mine. - fn set_tx_gas_limit(&self, limit: U256); + // Pending block - /// Imports transactions to transaction queue. - fn import_external_transactions(&self, client: &C, transactions: Vec) -> - Vec>; + /// Get a list of all pending receipts from pending block. + fn pending_receipts(&self, best_block: BlockNumber) -> Option>; - /// Imports own (node owner) transaction to queue. - fn import_own_transaction(&self, chain: &C, transaction: PendingTransaction) -> - Result; + /// Get a particular receipt from pending block. + fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option; - /// Returns hashes of transactions currently in pending - fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec; + /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. + fn pending_state(&self, latest_block_number: BlockNumber) -> Option; - /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, chain: &C); + /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. + fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
; - /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) - where C: AccountData + BlockChain + CallContract + RegistryInfo + BlockProducer + ScheduleInfo + SealedBlockImporter; + /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. + fn pending_block(&self, latest_block_number: BlockNumber) -> Option; - /// PoW chain - can produce work package - fn can_produce_work_package(&self) -> bool; + /// Get `Some` `clone()` of the current pending block transactions or `None` if we're not sealing. + fn pending_transactions(&self, latest_block_number: BlockNumber) -> Option>; - /// New chain head event. Restart mining operation. - fn update_sealing(&self, chain: &C) - where C: AccountData + BlockChain + RegistryInfo + CallContract + BlockProducer + SealedBlockImporter; + // Block authoring - /// Submit `seal` as a valid solution for the header of `pow_hash`. - /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, chain: &C, pow_hash: H256, seal: Vec) -> Result<(), Error>; + /// Get current authoring parameters. + fn authoring_params(&self) -> AuthoringParams; - /// Get the sealing work package and if `Some`, apply some transform. - fn map_sealing_work(&self, client: &C, f: F) -> Option - where C: AccountData + BlockChain + BlockProducer + CallContract, - F: FnOnce(&ClosedBlock) -> T, - Self: Sized; + /// Set the lower and upper bound of gas limit we wish to target when sealing a new block. + fn set_gas_range_target(&self, gas_range_target: (U256, U256)); - /// Query pending transactions for hash. - fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option; + /// Set the extra_data that we will seal blocks with. + fn set_extra_data(&self, extra_data: Bytes); - /// Removes transaction from the queue. - /// NOTE: The transaction is not removed from pending block if mining. - fn remove_pending_transaction(&self, chain: &C, hash: &H256) -> Option; + /// Set info necessary to sign consensus messages and block authoring. + /// + /// On PoW password is optional. + fn set_author(&self, address: Address, password: Option) -> Result<(), ::account_provider::SignError>; - /// Get a list of all pending transactions in the queue. - fn pending_transactions(&self) -> Vec; + // Transaction Pool - /// Get a list of all transactions that can go into the given block. - fn ready_transactions(&self, best_block: BlockNumber, best_block_timestamp: u64) -> Vec; + /// Imports transactions to transaction queue. + fn import_external_transactions(&self, client: &C, transactions: Vec) + -> Vec> + where C: BlockChainClient; - /// Get a list of all future transactions. - fn future_transactions(&self) -> Vec; + /// Imports own (node owner) transaction to queue. + fn import_own_transaction(&self, chain: &C, transaction: PendingTransaction) + -> Result<(), transaction::Error> + where C: BlockChainClient; + + /// Removes transaction from the pool. + /// + /// Attempts to "cancel" a transaction. If it was not propagated yet (or not accepted by other peers) + /// there is a good chance that the transaction will actually be removed. + /// NOTE: The transaction is not removed from pending block if there is one. + fn remove_transaction(&self, hash: &H256) -> Option>; + + /// Query transaction from the pool given it's hash. + fn transaction(&self, hash: &H256) -> Option>; + + /// Returns next valid nonce for given address. + /// + /// This includes nonces of all transactions from this address in the pending queue + /// if they are consecutive. + /// NOTE: pool may contain some future transactions that will become pending after + /// transaction with nonce returned from this function is signed on. + fn next_nonce(&self, chain: &C, address: &Address) -> U256 + where C: Nonce + Sync; + + /// Get a list of all ready transactions. + /// + /// Depending on the settings may look in transaction pool or only in pending block. + fn ready_transactions(&self, chain: &C) -> Vec> + where C: ChainInfo + Nonce + Sync; + + /// Get a list of all transactions in the pool (some of them might not be ready for inclusion yet). + fn queued_transactions(&self) -> Vec>; /// Get a list of local transactions with statuses. - fn local_transactions(&self) -> BTreeMap; - - /// Get a list of all pending receipts. - fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap; + fn local_transactions(&self) -> BTreeMap; - /// Get a particular reciept. - fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option; + /// Get current queue status. + /// + /// Status includes verification thresholds and current pool utilization and limits. + fn queue_status(&self) -> QueueStatus; - /// Returns highest transaction nonce for given address. - fn last_nonce(&self, address: &Address) -> Option; - - /// Is it currently sealing? - fn is_currently_sealing(&self) -> bool; + // Misc /// Suggested gas price. fn sensible_gas_price(&self) -> U256; /// Suggested gas limit. - fn sensible_gas_limit(&self) -> U256 { 21000.into() } - - /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. - fn pending_state(&self, latest_block_number: BlockNumber) -> Option; - - /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. - fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
; - - /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. - fn pending_block(&self, latest_block_number: BlockNumber) -> Option; -} - -/// Mining status -#[derive(Debug)] -pub struct MinerStatus { - /// Number of transactions in queue with state `pending` (ready to be included in block) - pub transactions_in_pending_queue: usize, - /// Number of transactions in queue with state `future` (not yet ready to be included in block) - pub transactions_in_future_queue: usize, - /// Number of transactions included in currently mined block - pub transactions_in_pending_block: usize, + fn sensible_gas_limit(&self) -> U256; } diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs new file mode 100644 index 00000000000..61153be0256 --- /dev/null +++ b/ethcore/src/miner/pool_client.rs @@ -0,0 +1,216 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain access for transaction pool. + +use std::fmt; +use std::collections::HashMap; + +use ethereum_types::{H256, U256, Address}; +use ethcore_miner::pool; +use ethcore_miner::pool::client::NonceClient; +use transaction::{ + self, + UnverifiedTransaction, + SignedTransaction, +}; +use parking_lot::RwLock; + +use account_provider::AccountProvider; +use client::{TransactionId, BlockInfo, CallContract, Nonce}; +use engines::EthEngine; +use header::Header; +use miner; +use miner::service_transaction_checker::ServiceTransactionChecker; + +type NoncesCache = RwLock>; + +const MAX_NONCE_CACHE_SIZE: usize = 4096; +const EXPECTED_NONCE_CACHE_SIZE: usize = 2048; + +/// Blockchain accesss for transaction pool. +pub struct PoolClient<'a, C: 'a> { + chain: &'a C, + cached_nonces: CachedNonceClient<'a, C>, + engine: &'a EthEngine, + accounts: Option<&'a AccountProvider>, + best_block_header: Header, + service_transaction_checker: Option, +} + +impl<'a, C: 'a> Clone for PoolClient<'a, C> { + fn clone(&self) -> Self { + PoolClient { + chain: self.chain, + cached_nonces: self.cached_nonces.clone(), + engine: self.engine, + accounts: self.accounts.clone(), + best_block_header: self.best_block_header.clone(), + service_transaction_checker: self.service_transaction_checker.clone(), + } + } +} + +impl<'a, C: 'a> PoolClient<'a, C> where +C: BlockInfo + CallContract, +{ + /// Creates new client given chain, nonce cache, accounts and service transaction verifier. + pub fn new( + chain: &'a C, + cache: &'a NoncesCache, + engine: &'a EthEngine, + accounts: Option<&'a AccountProvider>, + refuse_service_transactions: bool, + ) -> Self { + let best_block_header = chain.best_block_header(); + PoolClient { + chain, + cached_nonces: CachedNonceClient::new(chain, cache), + engine, + accounts, + best_block_header, + service_transaction_checker: if refuse_service_transactions { + None + } else { + Some(Default::default()) + }, + } + } + + /// Verifies if signed transaction is executable. + /// + /// This should perform any verifications that rely on chain status. + pub fn verify_signed(&self, tx: &SignedTransaction) -> Result<(), transaction::Error> { + self.engine.machine().verify_transaction(&tx, &self.best_block_header, self.chain) + } +} + +impl<'a, C: 'a> fmt::Debug for PoolClient<'a, C> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "PoolClient") + } +} + +impl<'a, C: 'a> pool::client::Client for PoolClient<'a, C> where + C: miner::TransactionVerifierClient + Sync, +{ + fn transaction_already_included(&self, hash: &H256) -> bool { + self.chain.transaction_block(TransactionId::Hash(*hash)).is_some() + } + + fn verify_transaction(&self, tx: UnverifiedTransaction)-> Result { + self.engine.verify_transaction_basic(&tx, &self.best_block_header)?; + let tx = self.engine.verify_transaction_unordered(tx, &self.best_block_header)?; + + self.verify_signed(&tx)?; + + Ok(tx) + } + + fn account_details(&self, address: &Address) -> pool::client::AccountDetails { + pool::client::AccountDetails { + nonce: self.cached_nonces.account_nonce(address), + balance: self.chain.latest_balance(address), + is_local: self.accounts.map_or(false, |accounts| accounts.has_account(*address).unwrap_or(false)), + } + } + + fn required_gas(&self, tx: &transaction::Transaction) -> U256 { + tx.gas_required(&self.chain.latest_schedule()).into() + } + + fn transaction_type(&self, tx: &SignedTransaction) -> pool::client::TransactionType { + match self.service_transaction_checker { + None => pool::client::TransactionType::Regular, + Some(ref checker) => match checker.check(self.chain, &tx) { + Ok(true) => pool::client::TransactionType::Service, + Ok(false) => pool::client::TransactionType::Regular, + Err(e) => { + debug!(target: "txqueue", "Unable to verify service transaction: {:?}", e); + pool::client::TransactionType::Regular + }, + } + } + } +} + +impl<'a, C: 'a> NonceClient for PoolClient<'a, C> where + C: Nonce + Sync, +{ + fn account_nonce(&self, address: &Address) -> U256 { + self.cached_nonces.account_nonce(address) + } +} + +pub(crate) struct CachedNonceClient<'a, C: 'a> { + client: &'a C, + cache: &'a NoncesCache, +} + +impl<'a, C: 'a> Clone for CachedNonceClient<'a, C> { + fn clone(&self) -> Self { + CachedNonceClient { + client: self.client, + cache: self.cache, + } + } +} + +impl<'a, C: 'a> fmt::Debug for CachedNonceClient<'a, C> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("CachedNonceClient") + .field("cache", &self.cache.read().len()) + .finish() + } +} + +impl<'a, C: 'a> CachedNonceClient<'a, C> { + pub fn new(client: &'a C, cache: &'a NoncesCache) -> Self { + CachedNonceClient { + client, + cache, + } + } +} + +impl<'a, C: 'a> NonceClient for CachedNonceClient<'a, C> where + C: Nonce + Sync, +{ + fn account_nonce(&self, address: &Address) -> U256 { + if let Some(nonce) = self.cache.read().get(address) { + return *nonce; + } + + // We don't check again if cache has been populated. + // It's not THAT expensive to fetch the nonce from state. + let mut cache = self.cache.write(); + let nonce = self.client.latest_nonce(address); + cache.insert(*address, nonce); + + if cache.len() < MAX_NONCE_CACHE_SIZE { + return nonce + } + + // Remove excessive amount of entries from the cache + while cache.len() > EXPECTED_NONCE_CACHE_SIZE { + // Just remove random entry + if let Some(key) = cache.keys().next().cloned() { + cache.remove(&key); + } + } + nonce + } +} diff --git a/ethcore/src/miner/service_transaction_checker.rs b/ethcore/src/miner/service_transaction_checker.rs index a555829c5f2..f085564d222 100644 --- a/ethcore/src/miner/service_transaction_checker.rs +++ b/ethcore/src/miner/service_transaction_checker.rs @@ -16,33 +16,38 @@ //! A service transactions contract checker. -use client::{RegistryInfo, CallContract}; +use client::{RegistryInfo, CallContract, BlockId}; use transaction::SignedTransaction; -use types::ids::BlockId; use_contract!(service_transaction, "ServiceTransaction", "res/contracts/service_transaction.json"); const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker"; /// Service transactions checker. -#[derive(Default)] +#[derive(Default, Clone)] pub struct ServiceTransactionChecker { contract: service_transaction::ServiceTransaction, } impl ServiceTransactionChecker { - /// Checks if service transaction can be appended to the transaction queue. + /// Checks if given address is whitelisted to send service transactions. pub fn check(&self, client: &C, tx: &SignedTransaction) -> Result { - assert!(tx.gas_price.is_zero()); + let sender = tx.sender(); + let hash = tx.hash(); + + // Skip checking the contract if the transaction does not have zero gas price + if !tx.gas_price.is_zero() { + return Ok(false) + } let address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) .ok_or_else(|| "contract is not configured")?; - trace!(target: "txqueue", "Checking service transaction checker contract from {}", address); + trace!(target: "txqueue", "[{:?}] Checking service transaction checker contract from {}", hash, sender); self.contract.functions() .certified() - .call(tx.sender(), &|data| client.call_contract(BlockId::Latest, address, data)) + .call(sender, &|data| client.call_contract(BlockId::Latest, address, data)) .map_err(|e| e.to_string()) } } diff --git a/ethcore/src/miner/stratum.rs b/ethcore/src/miner/stratum.rs index c8c387e5106..c63124dcd08 100644 --- a/ethcore/src/miner/stratum.rs +++ b/ethcore/src/miner/stratum.rs @@ -20,8 +20,7 @@ use std::sync::{Arc, Weak}; use std::net::{SocketAddr, AddrParseError}; use std::fmt; -use block::IsBlock; -use client::Client; +use client::{Client, ImportSealedBlock}; use ethereum_types::{H64, H256, clean_0x, U256}; use ethereum::ethash::Ethash; use ethash::SeedHashCompute; @@ -30,7 +29,7 @@ use ethcore_stratum::{ JobDispatcher, PushWorkHandler, Stratum as StratumService, Error as StratumServiceError, }; -use miner::{self, Miner, MinerService}; +use miner::{Miner, MinerService}; use parking_lot::Mutex; use rlp::encode; @@ -120,14 +119,9 @@ impl JobDispatcher for StratumJobDispatcher { } fn job(&self) -> Option { - self.with_core(|client, miner| miner.map_sealing_work(&*client, |b| { - let pow_hash = b.hash(); - let number = b.block().header().number(); - let difficulty = b.block().header().difficulty(); - - self.payload(pow_hash, *difficulty, number) - }) - ) + self.with_core(|client, miner| miner.work_package(&*client).map(|(pow_hash, number, _timestamp, difficulty)| { + self.payload(pow_hash, difficulty, number) + })) } fn submit(&self, payload: Vec) -> Result<(), StratumServiceError> { @@ -145,7 +139,10 @@ impl JobDispatcher for StratumJobDispatcher { self.with_core_result(|client, miner| { let seal = vec![encode(&payload.mix_hash).into_vec(), encode(&payload.nonce).into_vec()]; - match miner.submit_seal(&*client, payload.pow_hash, seal) { + + let import = miner.submit_seal(payload.pow_hash, seal) + .and_then(|block| client.import_sealed_block(block)); + match import { Ok(_) => Ok(()), Err(e) => { warn!(target: "stratum", "submit_seal error: {:?}", e); @@ -247,8 +244,8 @@ impl Stratum { /// Start STRATUM job dispatcher and register it in the miner pub fn register(cfg: &Options, miner: Arc, client: Weak) -> Result<(), Error> { - let stratum = miner::Stratum::start(cfg, Arc::downgrade(&miner.clone()), client)?; - miner.push_notifier(Box::new(stratum) as Box); + let stratum = Stratum::start(cfg, Arc::downgrade(&miner.clone()), client)?; + miner.add_work_listener(Box::new(stratum) as Box); Ok(()) } } diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index b0741b4c49e..4b1b3d6ad0e 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -107,13 +107,11 @@ fn make_chain(accounts: Arc, blocks_beyond: usize, transitions: trace!(target: "snapshot", "Pushing block #{}, {} txs, author={}", n, txs.len(), signers[idx]); - client.miner().set_author(signers[idx]); + client.miner().set_author(signers[idx], Some(PASS.into())).unwrap(); client.miner().import_external_transactions(&*client, txs.into_iter().map(Into::into).collect()); - let engine = client.engine(); - engine.set_signer(accounts.clone(), signers[idx], PASS.to_owned()); - engine.step(); + client.engine().step(); assert_eq!(client.chain_info().best_block_number, n); }; diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 7e81b05796f..d49e6fd63bf 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -58,7 +58,7 @@ fn restored_is_equivalent() { Default::default(), &spec, Arc::new(client_db), - Arc::new(::miner::Miner::with_spec(&spec)), + Arc::new(::miner::Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 4c013dd251d..8d10e4b3b8f 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -120,7 +120,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun ClientConfig::default(), &test_spec, client_db, - Arc::new(Miner::with_spec_and_accounts(&test_spec, accounts)), + Arc::new(Miner::new_for_tests(&test_spec, accounts)), IoChannel::disconnected(), ).unwrap(); let test_engine = &*test_spec.engine; @@ -243,7 +243,7 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> Arc { ClientConfig::default(), &test_spec, client_db, - Arc::new(Miner::with_spec(&test_spec)), + Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected(), ).unwrap(); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index e6333f56ad0..fc5f84bfaed 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -49,7 +49,7 @@ fn imports_from_empty() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); client.import_verified_blocks(); @@ -67,7 +67,7 @@ fn should_return_registrar() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let params = client.additional_params(); @@ -97,7 +97,7 @@ fn imports_good_block() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let good_block = get_good_dummy_block(); @@ -122,7 +122,7 @@ fn query_none_block() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let non_existant = client.block_header(BlockId::Number(188)); @@ -277,7 +277,7 @@ fn change_history_size() { ClientConfig::default(), &test_spec, client_db.clone(), - Arc::new(Miner::with_spec(&test_spec)), + Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected() ).unwrap(); @@ -295,7 +295,7 @@ fn change_history_size() { config, &test_spec, client_db, - Arc::new(Miner::with_spec(&test_spec)), + Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected(), ).unwrap(); assert_eq!(client.state().balance(&address).unwrap(), 100.into()); @@ -326,11 +326,11 @@ fn does_not_propagate_delayed_transactions() { client.miner().import_own_transaction(&*client, tx0).unwrap(); client.miner().import_own_transaction(&*client, tx1).unwrap(); assert_eq!(0, client.ready_transactions().len()); - assert_eq!(2, client.miner().pending_transactions().len()); + assert_eq!(0, client.miner().ready_transactions(&*client).len()); push_blocks_to_client(&client, 53, 2, 2); client.flush_queue(); assert_eq!(2, client.ready_transactions().len()); - assert_eq!(2, client.miner().pending_transactions().len()); + assert_eq!(2, client.miner().ready_transactions(&*client).len()); } #[test] diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 4646bc091fe..1626e828ccd 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -50,7 +50,7 @@ fn can_trace_block_and_uncle_reward() { client_config, &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index f4af2df9a82..e09e81ac161 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -163,7 +163,7 @@ mod test { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000001")).unwrap(); diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 62a237da48d..eeccb46112f 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -39,6 +39,7 @@ use light::Provider; use light::net::{self as light_net, LightProtocol, Params as LightParams, Capabilities, Handler as LightHandler, EventContext}; use network::IpFilter; use private_tx::PrivateTxHandler; +use transaction::UnverifiedTransaction; /// Parity sync protocol pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par"; @@ -486,9 +487,9 @@ impl ChainNotify for EthSync { }); } - fn transactions_received(&self, hashes: Vec, peer_id: PeerId) { + fn transactions_received(&self, txs: &[UnverifiedTransaction], peer_id: PeerId) { let mut sync = self.eth_handler.sync.write(); - sync.transactions_received(hashes, peer_id); + sync.transactions_received(txs, peer_id); } } diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index b2494e1f038..44ab1971a99 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -104,15 +104,16 @@ use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo}; use ethcore::error::*; use ethcore::snapshot::{ManifestData, RestorationStatus}; -use transaction::PendingTransaction; +use transaction::SignedTransaction; use sync_io::SyncIo; use super::{WarpSync, SyncConfig}; use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction}; use rand::Rng; use snapshot::{Snapshot, ChunkType}; use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; -use transactions_stats::{TransactionsStats, Stats as TransactionStats}; use private_tx::PrivateTxHandler; +use transactions_stats::{TransactionsStats, Stats as TransactionStats}; +use transaction::UnverifiedTransaction; known_heap_size!(0, PeerInfo); @@ -478,9 +479,9 @@ impl ChainSync { } /// Updates transactions were received by a peer - pub fn transactions_received(&mut self, hashes: Vec, peer_id: PeerId) { + pub fn transactions_received(&mut self, txs: &[UnverifiedTransaction], peer_id: PeerId) { if let Some(peer_info) = self.peers.get_mut(&peer_id) { - peer_info.last_sent_transactions.extend(&hashes); + peer_info.last_sent_transactions.extend(txs.iter().map(|tx| tx.hash())); } } @@ -2026,8 +2027,9 @@ impl ChainSync { return 0; } - let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.into_iter() - .partition(|tx| !tx.transaction.gas_price.is_zero()); + let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.iter() + .map(|tx| tx.signed()) + .partition(|tx| !tx.gas_price.is_zero()); // usual transactions could be propagated to all peers let mut affected_peers = HashSet::new(); @@ -2062,13 +2064,13 @@ impl ChainSync { .collect() } - fn propagate_transactions_to_peers(&mut self, io: &mut SyncIo, peers: Vec, transactions: Vec) -> HashSet { + fn propagate_transactions_to_peers(&mut self, io: &mut SyncIo, peers: Vec, transactions: Vec<&SignedTransaction>) -> HashSet { let all_transactions_hashes = transactions.iter() - .map(|tx| tx.transaction.hash()) + .map(|tx| tx.hash()) .collect::>(); let all_transactions_rlp = { let mut packet = RlpStream::new_list(transactions.len()); - for tx in &transactions { packet.append(&tx.transaction); } + for tx in &transactions { packet.append(&**tx); } packet.out() }; @@ -2112,10 +2114,10 @@ impl ChainSync { packet.begin_unbounded_list(); let mut pushed = 0; for tx in &transactions { - let hash = tx.transaction.hash(); + let hash = tx.hash(); if to_send.contains(&hash) { let mut transaction = RlpStream::new(); - tx.transaction.rlp_append(&mut transaction); + tx.rlp_append(&mut transaction); let appended = packet.append_raw_checked(&transaction.drain(), 1, MAX_TRANSACTION_PACKET_SIZE); if !appended { // Maximal packet size reached just proceed with sending @@ -2329,7 +2331,6 @@ mod tests { use ethcore::header::*; use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; use ethcore::miner::MinerService; - use transaction::UnverifiedTransaction; use private_tx::NoopPrivateTxHandler; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { @@ -3064,10 +3065,9 @@ mod tests { let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0); - assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 1); + assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); } // We need to update nonce status (because we say that the block has been imported) for h in &[good_blocks[0]] { @@ -3078,14 +3078,12 @@ mod tests { let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let mut io = TestIo::new(&client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks, false); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); } // then - let status = client.miner.status(); - assert_eq!(status.transactions_in_pending_queue, 1); - assert_eq!(status.transactions_in_future_queue, 0); + assert_eq!(client.miner.ready_transactions(&client).len(), 1); } #[test] @@ -3106,13 +3104,11 @@ mod tests { // when sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0); - assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 0); + assert_eq!(io.chain.miner.queue_status().status.transaction_count, 0); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); // then - let status = io.chain.miner.status(); - assert_eq!(status.transactions_in_pending_queue, 0); - assert_eq!(status.transactions_in_future_queue, 0); + let status = io.chain.miner.queue_status(); + assert_eq!(status.status.transaction_count, 0); } } diff --git a/ethcore/sync/src/tests/consensus.rs b/ethcore/sync/src/tests/consensus.rs index f4a58a18af4..287a61916a4 100644 --- a/ethcore/sync/src/tests/consensus.rs +++ b/ethcore/sync/src/tests/consensus.rs @@ -52,8 +52,8 @@ fn authority_round() { let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them gets lucky to produce a block. - net.peer(0).chain.miner().set_engine_signer(s0.address(), "".to_owned()).unwrap(); - net.peer(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap(); + net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".to_owned())).unwrap(); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1))); @@ -61,15 +61,15 @@ fn authority_round() { // exchange statuses net.sync(); // Trigger block proposal - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); // Sync a block net.sync(); assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); // Move to next proposer step. net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); @@ -78,8 +78,8 @@ fn authority_round() { assert_eq!(net.peer(1).chain.chain_info().best_block_number, 2); // Fork the network with equal height. - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); // Let both nodes build one block. net.peer(0).chain.engine().step(); let early_hash = net.peer(0).chain.chain_info().best_block_hash; @@ -101,8 +101,8 @@ fn authority_round() { assert_eq!(ci1.best_block_hash, early_hash); // Selfish miner - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 3.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 3.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 3.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 3.into(), chain_id)).unwrap(); // Node 0 is an earlier primary. net.peer(0).chain.engine().step(); assert_eq!(net.peer(0).chain.chain_info().best_block_number, 4); @@ -113,7 +113,7 @@ fn authority_round() { // Node 1 makes 2 blocks, but is a later primary on the first one. net.peer(1).chain.engine().step(); net.peer(1).chain.engine().step(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 4.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 4.into(), chain_id)).unwrap(); net.peer(1).chain.engine().step(); net.peer(1).chain.engine().step(); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 5); @@ -139,9 +139,9 @@ fn tendermint() { let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them issues a proposal. - net.peer(0).chain.miner().set_engine_signer(s0.address(), "".to_owned()).unwrap(); + net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); trace!(target: "poa", "Peer 0 is {}.", s0.address()); - net.peer(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".into())).unwrap(); trace!(target: "poa", "Peer 1 is {}.", s1.address()); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); @@ -150,7 +150,7 @@ fn tendermint() { // Exhange statuses net.sync(); // Propose - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); net.sync(); // Propose timeout, synchronous for now net.peer(0).chain.engine().step(); @@ -161,7 +161,7 @@ fn tendermint() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); // Commit timeout net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); @@ -175,8 +175,8 @@ fn tendermint() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 2); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 2); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); // Peers get disconnected. // Commit net.peer(0).chain.engine().step(); @@ -184,8 +184,8 @@ fn tendermint() { // Propose net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); // Send different prevotes net.sync(); // Prevote timeout diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 495603020dc..54b62c79a07 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -206,6 +206,7 @@ pub trait Peer { pub struct EthPeer where C: FlushingBlockChainClient { pub chain: Arc, + pub miner: Arc, pub snapshot_service: Arc, pub sync: RwLock, pub queue: RwLock>, @@ -340,6 +341,7 @@ impl TestNet> { sync: RwLock::new(sync), snapshot_service: ss, chain: Arc::new(chain), + miner: Arc::new(Miner::new_for_tests(&Spec::new_test(), None)), queue: RwLock::new(VecDeque::new()), private_tx_handler, io_queue: RwLock::new(VecDeque::new()), @@ -382,11 +384,12 @@ impl TestNet> { pub fn add_peer_with_private_config(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { let channel = IoChannel::disconnected(); + let miner = Arc::new(Miner::new_for_tests(&spec, accounts.clone())); let client = EthcoreClient::new( ClientConfig::default(), &spec, Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), - Arc::new(Miner::with_spec_and_accounts(&spec, accounts.clone())), + miner.clone(), channel.clone() ).unwrap(); @@ -397,6 +400,7 @@ impl TestNet> { sync: RwLock::new(sync), snapshot_service: ss, chain: client, + miner, queue: RwLock::new(VecDeque::new()), private_tx_handler, io_queue: RwLock::new(VecDeque::new()), @@ -408,11 +412,12 @@ impl TestNet> { } pub fn add_peer(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { + let miner = Arc::new(Miner::new_for_tests(&spec, accounts)); let client = EthcoreClient::new( ClientConfig::default(), &spec, Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), - Arc::new(Miner::with_spec_and_accounts(&spec, accounts)), + miner.clone(), IoChannel::disconnected(), ).unwrap(); @@ -422,8 +427,9 @@ impl TestNet> { let peer = Arc::new(EthPeer { sync: RwLock::new(sync), snapshot_service: ss, - chain: client, queue: RwLock::new(VecDeque::new()), + chain: client, + miner, private_tx_handler, io_queue: RwLock::new(VecDeque::new()), new_blocks_queue: RwLock::new(VecDeque::new()), diff --git a/ethcore/transaction/src/lib.rs b/ethcore/transaction/src/lib.rs index 6d6c269f30c..6a478b94635 100644 --- a/ethcore/transaction/src/lib.rs +++ b/ethcore/transaction/src/lib.rs @@ -33,14 +33,3 @@ mod transaction; pub use error::Error; pub use transaction::*; - -// TODO [ToDr] Move to miner! - -/// Represents the result of importing transaction. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum ImportResult { - /// Transaction was imported to current queue. - Current, - /// Transaction was imported to future queue. - Future -} diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 49f2534fac6..6e8e78cc48b 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -377,7 +377,7 @@ impl UnverifiedTransaction { } } - /// Get the hash of this header (keccak of the RLP). + /// Get the hash of this transaction (keccak of the RLP). pub fn hash(&self) -> H256 { self.hash } diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 4ee8d74c0f9..cf8eb0cdd8b 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -7,24 +7,31 @@ version = "1.11.0" authors = ["Parity Technologies "] [dependencies] -common-types = { path = "../ethcore/types" } -ethabi = "5.1" -ethabi-contract = "5.0" -ethabi-derive = "5.0" +# Only work_notify, consider a separate crate ethash = { path = "../ethash" } +fetch = { path = "../util/fetch" } +hyper = "0.11" +parity-reactor = { path = "../util/reactor" } +url = "1" + +# Miner +ansi_term = "0.10" +error-chain = "0.11" ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" -ethkey = { path = "../ethkey" } futures = "0.1" +futures-cpupool = "0.1" heapsize = "0.4" keccak-hash = { path = "../util/hash" } linked-hash-map = "0.5" log = "0.3" parking_lot = "0.5" +price-info = { path = "../price-info" } +rayon = "1.0" +trace-time = { path = "../util/trace-time" } +transaction-pool = { path = "../transaction-pool" } + +[dev-dependencies] +env_logger = "0.4" +ethkey = { path = "../ethkey" } rustc-hex = "1.0" -table = { path = "../util/table" } -transient-hashmap = "0.4" -fetch = { path = "../util/fetch" } -parity-reactor = { path = "../util/reactor" } -url = "1" -hyper = "0.11" diff --git a/miner/src/banning_queue.rs b/miner/src/banning_queue.rs deleted file mode 100644 index 388ae5e0015..00000000000 --- a/miner/src/banning_queue.rs +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Banning Queue -//! Transacton Queue wrapper maintaining additional list of banned senders and contract hashes. - -use std::time::Duration; -use std::ops::{Deref, DerefMut}; -use ethereum_types::{H256, U256, Address}; -use hash::keccak; -use transaction::{self, SignedTransaction, Action}; -use transient_hashmap::TransientHashMap; - -use transaction_queue::{TransactionQueue, TransactionDetailsProvider, TransactionOrigin, QueuingInstant}; - -type Count = u16; - -/// Auto-Banning threshold -pub enum Threshold { - /// Should ban after given number of misbehaves reported. - BanAfter(Count), - /// Should never ban anything - NeverBan -} - -impl Default for Threshold { - fn default() -> Self { - Threshold::NeverBan - } -} - -/// Transaction queue with banlist. -pub struct BanningTransactionQueue { - queue: TransactionQueue, - ban_threshold: Threshold, - senders_bans: TransientHashMap, - recipients_bans: TransientHashMap, - codes_bans: TransientHashMap, -} - -impl BanningTransactionQueue { - /// Creates new banlisting transaction queue - pub fn new(queue: TransactionQueue, ban_threshold: Threshold, ban_lifetime: Duration) -> Self { - let ban_lifetime_sec = ban_lifetime.as_secs() as u32; - assert!(ban_lifetime_sec > 0, "Lifetime has to be specified in seconds."); - BanningTransactionQueue { - queue: queue, - ban_threshold: ban_threshold, - senders_bans: TransientHashMap::new(ban_lifetime_sec), - recipients_bans: TransientHashMap::new(ban_lifetime_sec), - codes_bans: TransientHashMap::new(ban_lifetime_sec), - } - } - - /// Borrows internal queue. - /// NOTE: you can insert transactions to the queue even - /// if they would be rejected because of ban otherwise. - /// But probably you shouldn't. - pub fn queue(&mut self) -> &mut TransactionQueue { - &mut self.queue - } - - /// Add to the queue taking bans into consideration. - /// May reject transaction because of the banlist. - pub fn add_with_banlist( - &mut self, - transaction: SignedTransaction, - time: QueuingInstant, - details_provider: &TransactionDetailsProvider, - ) -> Result { - if let Threshold::BanAfter(threshold) = self.ban_threshold { - // NOTE In all checks use direct query to avoid increasing ban timeout. - - // Check sender - let sender = transaction.sender(); - let count = self.senders_bans.direct().get(&sender).cloned().unwrap_or(0); - if count > threshold { - debug!(target: "txqueue", "Ignoring transaction {:?} because sender is banned.", transaction.hash()); - return Err(transaction::Error::SenderBanned); - } - - // Check recipient - if let Action::Call(recipient) = transaction.action { - let count = self.recipients_bans.direct().get(&recipient).cloned().unwrap_or(0); - if count > threshold { - debug!(target: "txqueue", "Ignoring transaction {:?} because recipient is banned.", transaction.hash()); - return Err(transaction::Error::RecipientBanned); - } - } - - // Check code - if let Action::Create = transaction.action { - let code_hash = keccak(&transaction.data); - let count = self.codes_bans.direct().get(&code_hash).cloned().unwrap_or(0); - if count > threshold { - debug!(target: "txqueue", "Ignoring transaction {:?} because code is banned.", transaction.hash()); - return Err(transaction::Error::CodeBanned); - } - } - } - self.queue.add(transaction, TransactionOrigin::External, time, None, details_provider) - } - - /// Ban transaction with given hash. - /// Transaction has to be in the queue. - /// - /// Bans sender and recipient/code and returns `true` when any ban has reached threshold. - pub fn ban_transaction(&mut self, hash: &H256) -> bool { - let transaction = self.queue.find(hash); - match transaction { - Some(transaction) => { - let sender = transaction.sender(); - // Ban sender - let sender_banned = self.ban_sender(sender); - // Ban recipient and codehash - let recipient_or_code_banned = match transaction.action { - Action::Call(recipient) => { - self.ban_recipient(recipient) - }, - Action::Create => { - self.ban_codehash(keccak(&transaction.data)) - }, - }; - sender_banned || recipient_or_code_banned - }, - None => false, - } - } - - /// Ban given sender. - /// If bans threshold is reached all subsequent transactions from this sender will be rejected. - /// Reaching bans threshold also removes all existsing transaction from this sender that are already in the - /// queue. - fn ban_sender(&mut self, address: Address) -> bool { - let count = { - let count = self.senders_bans.entry(address).or_insert_with(|| 0); - *count = count.saturating_add(1); - *count - }; - match self.ban_threshold { - Threshold::BanAfter(threshold) if count > threshold => { - // Banlist the sender. - // Remove all transactions from the queue. - self.cull(address, !U256::zero()); - true - }, - _ => false - } - } - - /// Ban given recipient. - /// If bans threshold is reached all subsequent transactions to this address will be rejected. - /// Returns true if bans threshold has been reached. - fn ban_recipient(&mut self, address: Address) -> bool { - let count = { - let count = self.recipients_bans.entry(address).or_insert_with(|| 0); - *count = count.saturating_add(1); - *count - }; - match self.ban_threshold { - // TODO [ToDr] Consider removing other transactions to the same recipient from the queue? - Threshold::BanAfter(threshold) if count > threshold => true, - _ => false - } - } - - - /// Ban given codehash. - /// If bans threshold is reached all subsequent transactions to contracts with this codehash will be rejected. - /// Returns true if bans threshold has been reached. - fn ban_codehash(&mut self, code_hash: H256) -> bool { - let count = self.codes_bans.entry(code_hash).or_insert_with(|| 0); - *count = count.saturating_add(1); - - match self.ban_threshold { - // TODO [ToDr] Consider removing other transactions with the same code from the queue? - Threshold::BanAfter(threshold) if *count > threshold => true, - _ => false, - } - } -} - -impl Deref for BanningTransactionQueue { - type Target = TransactionQueue; - - fn deref(&self) -> &Self::Target { - &self.queue - } -} -impl DerefMut for BanningTransactionQueue { - fn deref_mut(&mut self) -> &mut Self::Target { - self.queue() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ethkey::{Random, Generator}; - use rustc_hex::FromHex; - use transaction_queue::test::DummyTransactionDetailsProvider; - use ethereum_types::{U256, Address}; - - fn queue() -> BanningTransactionQueue { - BanningTransactionQueue::new(TransactionQueue::default(), Threshold::BanAfter(1), Duration::from_secs(180)) - } - - fn default_tx_provider() -> DummyTransactionDetailsProvider { - DummyTransactionDetailsProvider::default().with_account_nonce(U256::zero()) - } - - fn transaction(action: Action) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - transaction::Transaction { - action: action, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: U256::from(100_000), - gas_price: U256::from(10), - nonce: U256::from(0), - }.sign(keypair.secret(), None) - } - - fn unwrap_err(res: Result) -> transaction::Error { - res.unwrap_err() - } - - #[test] - fn should_allow_to_borrow_the_queue() { - // given - let tx = transaction(Action::Create); - let mut txq = queue(); - - // when - txq.queue().add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - // should also deref to queue - assert_eq!(txq.status().pending, 1); - } - - #[test] - fn should_not_accept_transactions_from_banned_sender() { - // given - let tx = transaction(Action::Create); - let mut txq = queue(); - // Banlist once (threshold not reached) - let banlist1 = txq.ban_sender(tx.sender()); - assert!(!banlist1, "Threshold not reached yet."); - // Insert once - let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap(); - assert_eq!(import1, transaction::ImportResult::Current); - - // when - let banlist2 = txq.ban_sender(tx.sender()); - let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()); - - // then - assert!(banlist2, "Threshold should be reached - banned."); - assert_eq!(unwrap_err(import2), transaction::Error::SenderBanned); - // Should also remove transacion from the queue - assert_eq!(txq.find(&tx.hash()), None); - } - - #[test] - fn should_not_accept_transactions_to_banned_recipient() { - // given - let recipient = Address::default(); - let tx = transaction(Action::Call(recipient)); - let mut txq = queue(); - // Banlist once (threshold not reached) - let banlist1 = txq.ban_recipient(recipient); - assert!(!banlist1, "Threshold not reached yet."); - // Insert once - let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap(); - assert_eq!(import1, transaction::ImportResult::Current); - - // when - let banlist2 = txq.ban_recipient(recipient); - let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()); - - // then - assert!(banlist2, "Threshold should be reached - banned."); - assert_eq!(unwrap_err(import2), transaction::Error::RecipientBanned); - } - - #[test] - fn should_not_accept_transactions_with_banned_code() { - // given - let tx = transaction(Action::Create); - let codehash = keccak(&tx.data); - let mut txq = queue(); - // Banlist once (threshold not reached) - let banlist1 = txq.ban_codehash(codehash); - assert!(!banlist1, "Threshold not reached yet."); - // Insert once - let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap(); - assert_eq!(import1, transaction::ImportResult::Current); - - // when - let banlist2 = txq.ban_codehash(codehash); - let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()); - - // then - assert!(banlist2, "Threshold should be reached - banned."); - assert_eq!(unwrap_err(import2), transaction::Error::CodeBanned); - } -} diff --git a/miner/src/gas_pricer.rs b/miner/src/gas_pricer.rs new file mode 100644 index 00000000000..f826ccf77d5 --- /dev/null +++ b/miner/src/gas_pricer.rs @@ -0,0 +1,97 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Auto-updates minimal gas price requirement. + +use std::time::{Instant, Duration}; + +use ansi_term::Colour; +use ethereum_types::U256; +use futures_cpupool::CpuPool; +use price_info::{Client as PriceInfoClient, PriceInfo}; +use price_info::fetch::Client as FetchClient; + +/// Options for the dynamic gas price recalibrator. +#[derive(Debug, PartialEq)] +pub struct GasPriceCalibratorOptions { + /// Base transaction price to match against. + pub usd_per_tx: f32, + /// How frequently we should recalibrate. + pub recalibration_period: Duration, +} + +/// The gas price validator variant for a `GasPricer`. +#[derive(Debug, PartialEq)] +pub struct GasPriceCalibrator { + options: GasPriceCalibratorOptions, + next_calibration: Instant, + price_info: PriceInfoClient, +} + +impl GasPriceCalibrator { + fn recalibrate(&mut self, set_price: F) { + trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration); + if Instant::now() >= self.next_calibration { + let usd_per_tx = self.options.usd_per_tx; + trace!(target: "miner", "Getting price info"); + + self.price_info.get(move |price: PriceInfo| { + trace!(target: "miner", "Price info arrived: {:?}", price); + let usd_per_eth = price.ethusd; + let wei_per_usd: f32 = 1.0e18 / usd_per_eth; + let gas_per_tx: f32 = 21000.0; + let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; + info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas))); + set_price(U256::from(wei_per_gas as u64)); + }); + + self.next_calibration = Instant::now() + self.options.recalibration_period; + } + } +} + +/// Struct to look after updating the acceptable gas price of a miner. +#[derive(Debug, PartialEq)] +pub enum GasPricer { + /// A fixed gas price in terms of Wei - always the argument given. + Fixed(U256), + /// Gas price is calibrated according to a fixed amount of USD. + Calibrated(GasPriceCalibrator), +} + +impl GasPricer { + /// Create a new Calibrated `GasPricer`. + pub fn new_calibrated(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPricer { + GasPricer::Calibrated(GasPriceCalibrator { + options: options, + next_calibration: Instant::now(), + price_info: PriceInfoClient::new(fetch, p), + }) + } + + /// Create a new Fixed `GasPricer`. + pub fn new_fixed(gas_price: U256) -> GasPricer { + GasPricer::Fixed(gas_price) + } + + /// Recalibrate current gas price. + pub fn recalibrate(&mut self, set_price: F) { + match *self { + GasPricer::Fixed(ref max) => set_price(max.clone()), + GasPricer::Calibrated(ref mut cal) => cal.recalibrate(set_price), + } + } +} diff --git a/miner/src/lib.rs b/miner/src/lib.rs index e8a86bd02a4..197823aec79 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -19,27 +19,33 @@ //! Miner module //! Keeps track of transactions and mined block. -extern crate common_types as types; -extern crate ethabi; +extern crate ansi_term; extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate futures; +extern crate futures_cpupool; extern crate heapsize; extern crate keccak_hash as hash; extern crate linked_hash_map; extern crate parking_lot; -extern crate table; -extern crate transient_hashmap; +extern crate price_info; +extern crate rayon; +extern crate trace_time; +extern crate transaction_pool as txpool; -#[cfg(test)] -extern crate ethkey; +#[macro_use] +extern crate error_chain; #[macro_use] extern crate log; + #[cfg(test)] extern crate rustc_hex; +#[cfg(test)] +extern crate ethkey; +#[cfg(test)] +extern crate env_logger; -pub mod banning_queue; pub mod external; -pub mod local_transactions; -pub mod transaction_queue; +pub mod gas_pricer; +pub mod pool; pub mod work_notify; diff --git a/miner/src/local_transactions.rs b/miner/src/local_transactions.rs deleted file mode 100644 index e8d1988a4f6..00000000000 --- a/miner/src/local_transactions.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Local Transactions List. - -use ethereum_types::{H256, U256}; -use linked_hash_map::LinkedHashMap; -use transaction::{self, SignedTransaction, PendingTransaction}; - -/// Status of local transaction. -/// Can indicate that the transaction is currently part of the queue (`Pending/Future`) -/// or gives a reason why the transaction was removed. -#[derive(Debug, PartialEq, Clone)] -pub enum Status { - /// The transaction is currently in the transaction queue. - Pending, - /// The transaction is in future part of the queue. - Future, - /// Transaction is already mined. - Mined(SignedTransaction), - /// Transaction is dropped because of limit - Dropped(SignedTransaction), - /// Replaced because of higher gas price of another transaction. - Replaced(SignedTransaction, U256, H256), - /// Transaction was never accepted to the queue. - Rejected(SignedTransaction, transaction::Error), - /// Transaction is invalid. - Invalid(SignedTransaction), - /// Transaction was canceled. - Canceled(PendingTransaction), -} - -impl Status { - fn is_current(&self) -> bool { - *self == Status::Pending || *self == Status::Future - } -} - -/// Keeps track of local transactions that are in the queue or were mined/dropped recently. -#[derive(Debug)] -pub struct LocalTransactionsList { - max_old: usize, - transactions: LinkedHashMap, -} - -impl Default for LocalTransactionsList { - fn default() -> Self { - Self::new(10) - } -} - -impl LocalTransactionsList { - /// Create a new list of local transactions. - pub fn new(max_old: usize) -> Self { - LocalTransactionsList { - max_old: max_old, - transactions: Default::default(), - } - } - - /// Mark transaction with given hash as pending. - pub fn mark_pending(&mut self, hash: H256) { - debug!(target: "own_tx", "Imported to Current (hash {:?})", hash); - self.clear_old(); - self.transactions.insert(hash, Status::Pending); - } - - /// Mark transaction with given hash as future. - pub fn mark_future(&mut self, hash: H256) { - debug!(target: "own_tx", "Imported to Future (hash {:?})", hash); - self.transactions.insert(hash, Status::Future); - self.clear_old(); - } - - /// Mark given transaction as rejected from the queue. - pub fn mark_rejected(&mut self, tx: SignedTransaction, err: transaction::Error) { - debug!(target: "own_tx", "Transaction rejected (hash {:?}): {:?}", tx.hash(), err); - self.transactions.insert(tx.hash(), Status::Rejected(tx, err)); - self.clear_old(); - } - - /// Mark the transaction as replaced by transaction with given hash. - pub fn mark_replaced(&mut self, tx: SignedTransaction, gas_price: U256, hash: H256) { - debug!(target: "own_tx", "Transaction replaced (hash {:?}) by {:?} (new gas price: {:?})", tx.hash(), hash, gas_price); - self.transactions.insert(tx.hash(), Status::Replaced(tx, gas_price, hash)); - self.clear_old(); - } - - /// Mark transaction as invalid. - pub fn mark_invalid(&mut self, tx: SignedTransaction) { - warn!(target: "own_tx", "Transaction marked invalid (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Invalid(tx)); - self.clear_old(); - } - - /// Mark transaction as canceled. - pub fn mark_canceled(&mut self, tx: PendingTransaction) { - warn!(target: "own_tx", "Transaction canceled (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Canceled(tx)); - self.clear_old(); - } - - /// Mark transaction as dropped because of limit. - pub fn mark_dropped(&mut self, tx: SignedTransaction) { - warn!(target: "own_tx", "Transaction dropped (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Dropped(tx)); - self.clear_old(); - } - - /// Mark transaction as mined. - pub fn mark_mined(&mut self, tx: SignedTransaction) { - info!(target: "own_tx", "Transaction mined (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Mined(tx)); - self.clear_old(); - } - - /// Returns true if the transaction is already in local transactions. - pub fn contains(&self, hash: &H256) -> bool { - self.transactions.contains_key(hash) - } - - /// Return a map of all currently stored transactions. - pub fn all_transactions(&self) -> &LinkedHashMap { - &self.transactions - } - - fn clear_old(&mut self) { - let number_of_old = self.transactions - .values() - .filter(|status| !status.is_current()) - .count(); - - if self.max_old >= number_of_old { - return; - } - - let to_remove = self.transactions - .iter() - .filter(|&(_, status)| !status.is_current()) - .map(|(hash, _)| *hash) - .take(number_of_old - self.max_old) - .collect::>(); - - for hash in to_remove { - self.transactions.remove(&hash); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ethereum_types::U256; - use ethkey::{Random, Generator}; - - #[test] - fn should_add_transaction_as_pending() { - // given - let mut list = LocalTransactionsList::default(); - - // when - list.mark_pending(10.into()); - list.mark_future(20.into()); - - // then - assert!(list.contains(&10.into()), "Should contain the transaction."); - assert!(list.contains(&20.into()), "Should contain the transaction."); - let statuses = list.all_transactions().values().cloned().collect::>(); - assert_eq!(statuses, vec![Status::Pending, Status::Future]); - } - - #[test] - fn should_clear_old_transactions() { - // given - let mut list = LocalTransactionsList::new(1); - let tx1 = new_tx(10.into()); - let tx1_hash = tx1.hash(); - let tx2 = new_tx(50.into()); - let tx2_hash = tx2.hash(); - - list.mark_pending(10.into()); - list.mark_invalid(tx1); - list.mark_dropped(tx2); - assert!(list.contains(&tx2_hash)); - assert!(!list.contains(&tx1_hash)); - assert!(list.contains(&10.into())); - - // when - list.mark_future(15.into()); - - // then - assert!(list.contains(&10.into())); - assert!(list.contains(&15.into())); - } - - fn new_tx(nonce: U256) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - transaction::Transaction { - action: transaction::Action::Create, - value: U256::from(100), - data: Default::default(), - gas: U256::from(10), - gas_price: U256::from(1245), - nonce: nonce - }.sign(keypair.secret(), None) - } -} diff --git a/miner/src/pool/client.rs b/miner/src/pool/client.rs new file mode 100644 index 00000000000..4243e8d26bf --- /dev/null +++ b/miner/src/pool/client.rs @@ -0,0 +1,71 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Transaction Pool state client. +//! +//! `Client` encapsulates all external data required for the verifaction and readiness. +//! It includes any Ethereum state parts required for checking the transaction and +//! any consensus-required structure of the transaction. + +use std::fmt; + +use ethereum_types::{U256, H256, H160 as Address}; +use transaction; + +/// Account Details +#[derive(Debug, Clone)] +pub struct AccountDetails { + /// Current account nonce + pub nonce: U256, + /// Current account balance + pub balance: U256, + /// Is this account a local account? + pub is_local: bool, +} + +/// Transaction type +#[derive(Debug, PartialEq)] +pub enum TransactionType { + /// Regular transaction + Regular, + /// Service transaction (allowed by a contract to have gas_price=0) + Service, +} + +/// Verification client. +pub trait Client: fmt::Debug + Sync { + /// Is transaction with given hash already in the blockchain? + fn transaction_already_included(&self, hash: &H256) -> bool; + + /// Structurarily verify given transaction. + fn verify_transaction(&self, tx: transaction::UnverifiedTransaction) + -> Result; + + /// Estimate minimal gas requirurement for given transaction. + fn required_gas(&self, tx: &transaction::Transaction) -> U256; + + /// Fetch account details for given sender. + fn account_details(&self, address: &Address) -> AccountDetails; + + /// Classify transaction (check if transaction is filtered by some contracts). + fn transaction_type(&self, tx: &transaction::SignedTransaction) -> TransactionType; +} + +/// State nonce client +pub trait NonceClient: fmt::Debug + Sync { + /// Fetch only account nonce for given sender. + fn account_nonce(&self, address: &Address) -> U256; +} diff --git a/miner/src/pool/listener.rs b/miner/src/pool/listener.rs new file mode 100644 index 00000000000..3f42372e840 --- /dev/null +++ b/miner/src/pool/listener.rs @@ -0,0 +1,161 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Notifier for new transaction hashes. + +use std::fmt; +use std::sync::Arc; + +use ethereum_types::H256; +use txpool::{self, VerifiedTransaction}; + +use pool::VerifiedTransaction as Transaction; + +type Listener = Box; + +/// Manages notifications to pending transaction listeners. +#[derive(Default)] +pub struct Notifier { + listeners: Vec, + pending: Vec, +} + +impl fmt::Debug for Notifier { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Notifier") + .field("listeners", &self.listeners.len()) + .field("pending", &self.pending) + .finish() + } +} + +impl Notifier { + /// Add new listener to receive notifications. + pub fn add(&mut self, f: Listener) { + self.listeners.push(f) + } + + /// Notify listeners about all currently pending transactions. + pub fn notify(&mut self) { + for l in &self.listeners { + (l)(&self.pending); + } + + self.pending.clear(); + } +} + +impl txpool::Listener for Notifier { + fn added(&mut self, tx: &Arc, _old: Option<&Arc>) { + self.pending.push(*tx.hash()); + } +} + + +/// Transaction pool logger. +#[derive(Default, Debug)] +pub struct Logger; + +impl txpool::Listener for Logger { + fn added(&mut self, tx: &Arc, old: Option<&Arc>) { + debug!(target: "txqueue", "[{:?}] Added to the pool.", tx.hash()); + debug!( + target: "txqueue", + "[{hash:?}] Sender: {sender}, nonce: {nonce}, gasPrice: {gas_price}, gas: {gas}, value: {value}, dataLen: {data}))", + hash = tx.hash(), + sender = tx.sender(), + nonce = tx.signed().nonce, + gas_price = tx.signed().gas_price, + gas = tx.signed().gas, + value = tx.signed().value, + data = tx.signed().data.len(), + ); + + if let Some(old) = old { + debug!(target: "txqueue", "[{:?}] Dropped. Replaced by [{:?}]", old.hash(), tx.hash()); + } + } + + fn rejected(&mut self, _tx: &Arc, reason: &txpool::ErrorKind) { + trace!(target: "txqueue", "Rejected {}.", reason); + } + + fn dropped(&mut self, tx: &Arc, new: Option<&Transaction>) { + match new { + Some(new) => debug!(target: "txqueue", "[{:?}] Pushed out by [{:?}]", tx.hash(), new.hash()), + None => debug!(target: "txqueue", "[{:?}] Dropped.", tx.hash()), + } + } + + fn invalid(&mut self, tx: &Arc) { + debug!(target: "txqueue", "[{:?}] Marked as invalid by executor.", tx.hash()); + } + + fn canceled(&mut self, tx: &Arc) { + debug!(target: "txqueue", "[{:?}] Canceled by the user.", tx.hash()); + } + + fn mined(&mut self, tx: &Arc) { + debug!(target: "txqueue", "[{:?}] Mined.", tx.hash()); + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use parking_lot::Mutex; + use transaction; + use txpool::Listener; + + #[test] + fn should_notify_listeners() { + // given + let received = Arc::new(Mutex::new(vec![])); + let r = received.clone(); + let listener = Box::new(move |hashes: &[H256]| { + *r.lock() = hashes.iter().map(|x| *x).collect(); + }); + + let mut tx_listener = Notifier::default(); + tx_listener.add(listener); + + // when + let tx = new_tx(); + tx_listener.added(&tx, None); + assert_eq!(*received.lock(), vec![]); + + // then + tx_listener.notify(); + assert_eq!( + *received.lock(), + vec!["13aff4201ac1dc49daf6a7cf07b558ed956511acbaabf9502bdacc353953766d".parse().unwrap()] + ); + } + + fn new_tx() -> Arc { + let signed = transaction::Transaction { + action: transaction::Action::Create, + data: vec![1, 2, 3], + nonce: 5.into(), + gas: 21_000.into(), + gas_price: 5.into(), + value: 0.into(), + }.fake_sign(5.into()); + + Arc::new(Transaction::from_pending_block_transaction(signed)) + } +} diff --git a/miner/src/pool/local_transactions.rs b/miner/src/pool/local_transactions.rs new file mode 100644 index 00000000000..12ffa84c19b --- /dev/null +++ b/miner/src/pool/local_transactions.rs @@ -0,0 +1,273 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Local Transactions List. + +use std::sync::Arc; + +use ethereum_types::H256; +use linked_hash_map::LinkedHashMap; +use pool::VerifiedTransaction as Transaction; +use txpool::{self, VerifiedTransaction}; + +/// Status of local transaction. +/// Can indicate that the transaction is currently part of the queue (`Pending/Future`) +/// or gives a reason why the transaction was removed. +#[derive(Debug, PartialEq, Clone)] +pub enum Status { + /// The transaction is currently in the transaction queue. + Pending(Arc), + /// Transaction is already mined. + Mined(Arc), + /// Transaction is dropped because of limit + Dropped(Arc), + /// Replaced because of higher gas price of another transaction. + Replaced { + /// Replaced transaction + old: Arc, + /// Transaction that replaced this one. + new: Arc, + }, + /// Transaction was never accepted to the queue. + /// It means that it was too cheap to replace any transaction already in the pool. + Rejected(Arc, String), + /// Transaction is invalid. + Invalid(Arc), + /// Transaction was canceled. + Canceled(Arc), +} + +impl Status { + fn is_pending(&self) -> bool { + match *self { + Status::Pending(_) => true, + _ => false, + } + } +} + +/// Keeps track of local transactions that are in the queue or were mined/dropped recently. +#[derive(Debug)] +pub struct LocalTransactionsList { + max_old: usize, + transactions: LinkedHashMap, + pending: usize, +} + +impl Default for LocalTransactionsList { + fn default() -> Self { + Self::new(10) + } +} + +impl LocalTransactionsList { + /// Create a new list of local transactions. + pub fn new(max_old: usize) -> Self { + LocalTransactionsList { + max_old, + transactions: Default::default(), + pending: 0, + } + } + + /// Returns true if the transaction is already in local transactions. + pub fn contains(&self, hash: &H256) -> bool { + self.transactions.contains_key(hash) + } + + /// Return a map of all currently stored transactions. + pub fn all_transactions(&self) -> &LinkedHashMap { + &self.transactions + } + + /// Returns true if there are pending local transactions. + pub fn has_pending(&self) -> bool { + self.pending > 0 + } + + fn clear_old(&mut self) { + let number_of_old = self.transactions.len() - self.pending; + if self.max_old >= number_of_old { + return; + } + + let to_remove: Vec<_> = self.transactions + .iter() + .filter(|&(_, status)| !status.is_pending()) + .map(|(hash, _)| *hash) + .take(number_of_old - self.max_old) + .collect(); + + for hash in to_remove { + self.transactions.remove(&hash); + } + } + + fn insert(&mut self, hash: H256, status: Status) { + let result = self.transactions.insert(hash, status); + if let Some(old) = result { + if old.is_pending() { + self.pending -= 1; + } + } + } +} + +impl txpool::Listener for LocalTransactionsList { + fn added(&mut self, tx: &Arc, old: Option<&Arc>) { + if !tx.priority().is_local() { + return; + } + + debug!(target: "own_tx", "Imported to the pool (hash {:?})", tx.hash()); + self.clear_old(); + self.insert(*tx.hash(), Status::Pending(tx.clone())); + self.pending += 1; + + if let Some(old) = old { + if self.transactions.contains_key(old.hash()) { + self.insert(*old.hash(), Status::Replaced { + old: old.clone(), + new: tx.clone(), + }); + } + } + } + + fn rejected(&mut self, tx: &Arc, reason: &txpool::ErrorKind) { + if !tx.priority().is_local() { + return; + } + + debug!(target: "own_tx", "Transaction rejected (hash {:?}). {}", tx.hash(), reason); + self.insert(*tx.hash(), Status::Rejected(tx.clone(), format!("{}", reason))); + self.clear_old(); + } + + fn dropped(&mut self, tx: &Arc, new: Option<&Transaction>) { + if !tx.priority().is_local() { + return; + } + + match new { + Some(new) => warn!(target: "own_tx", "Transaction pushed out because of limit (hash {:?}, replacement: {:?})", tx.hash(), new.hash()), + None => warn!(target: "own_tx", "Transaction dropped because of limit (hash: {:?})", tx.hash()), + } + self.insert(*tx.hash(), Status::Dropped(tx.clone())); + self.clear_old(); + } + + fn invalid(&mut self, tx: &Arc) { + if !tx.priority().is_local() { + return; + } + + warn!(target: "own_tx", "Transaction marked invalid (hash {:?})", tx.hash()); + self.insert(*tx.hash(), Status::Invalid(tx.clone())); + self.clear_old(); + } + + fn canceled(&mut self, tx: &Arc) { + if !tx.priority().is_local() { + return; + } + + warn!(target: "own_tx", "Transaction canceled (hash {:?})", tx.hash()); + self.insert(*tx.hash(), Status::Canceled(tx.clone())); + self.clear_old(); + } + + + /// The transaction has been mined. + fn mined(&mut self, tx: &Arc) { + if !tx.priority().is_local() { + return; + } + + info!(target: "own_tx", "Transaction mined (hash {:?})", tx.hash()); + self.insert(*tx.hash(), Status::Mined(tx.clone())); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ethereum_types::U256; + use ethkey::{Random, Generator}; + use transaction; + use txpool::Listener; + + use pool; + + #[test] + fn should_add_transaction_as_pending() { + // given + let mut list = LocalTransactionsList::default(); + let tx1 = new_tx(10); + let tx2 = new_tx(20); + + // when + list.added(&tx1, None); + list.added(&tx2, None); + + // then + assert!(list.contains(tx1.hash())); + assert!(list.contains(tx2.hash())); + let statuses = list.all_transactions().values().cloned().collect::>(); + assert_eq!(statuses, vec![Status::Pending(tx1), Status::Pending(tx2)]); + } + + #[test] + fn should_clear_old_transactions() { + // given + let mut list = LocalTransactionsList::new(1); + let tx1 = new_tx(10); + let tx2 = new_tx(50); + let tx3 = new_tx(51); + + list.added(&tx1, None); + list.invalid(&tx1); + list.dropped(&tx2, None); + assert!(!list.contains(tx1.hash())); + assert!(list.contains(tx2.hash())); + assert!(!list.contains(tx3.hash())); + + // when + list.added(&tx3, Some(&tx1)); + + // then + assert!(!list.contains(tx1.hash())); + assert!(list.contains(tx2.hash())); + assert!(list.contains(tx3.hash())); + } + + fn new_tx>(nonce: T) -> Arc { + let keypair = Random.generate().unwrap(); + let signed = transaction::Transaction { + action: transaction::Action::Create, + value: U256::from(100), + data: Default::default(), + gas: U256::from(10), + gas_price: U256::from(1245), + nonce: nonce.into(), + }.sign(keypair.secret(), None); + + let mut tx = Transaction::from_pending_block_transaction(signed); + tx.priority = pool::Priority::Local; + + Arc::new(tx) + } +} diff --git a/miner/src/pool/mod.rs b/miner/src/pool/mod.rs new file mode 100644 index 00000000000..7950510c6d0 --- /dev/null +++ b/miner/src/pool/mod.rs @@ -0,0 +1,135 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Transaction Pool + +use ethereum_types::{H256, Address}; +use heapsize::HeapSizeOf; +use transaction; +use txpool; + +mod listener; +mod queue; +mod ready; +mod scoring; + +pub mod client; +pub mod local_transactions; +pub mod verifier; + +#[cfg(test)] +mod tests; + +pub use self::queue::{TransactionQueue, Status as QueueStatus}; +pub use self::txpool::{VerifiedTransaction as PoolVerifiedTransaction, Options}; + +/// How to prioritize transactions in the pool +/// +/// TODO [ToDr] Implement more strategies. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PrioritizationStrategy { + /// Simple gas-price based prioritization. + GasPriceOnly, +} + +/// Transaction priority. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub(crate) enum Priority { + /// Local transactions (high priority) + /// + /// Transactions either from a local account or + /// submitted over local RPC connection via `eth_sendRawTransaction` + Local, + /// Transactions from retracted blocks (medium priority) + /// + /// When block becomes non-canonical we re-import the transactions it contains + /// to the queue and boost their priority. + Retracted, + /// Regular transactions received over the network. (no priority boost) + Regular, +} + +impl Priority { + fn is_local(&self) -> bool { + match *self { + Priority::Local => true, + _ => false, + } + } +} + +/// Verified transaction stored in the pool. +#[derive(Debug, PartialEq, Eq)] +pub struct VerifiedTransaction { + transaction: transaction::PendingTransaction, + // TODO [ToDr] hash and sender should go directly from the transaction + hash: H256, + sender: Address, + priority: Priority, + insertion_id: usize, +} + +impl VerifiedTransaction { + /// Create `VerifiedTransaction` directly from `SignedTransaction`. + /// + /// This method should be used only: + /// 1. for tests + /// 2. In case we are converting pending block transactions that are already in the queue to match the function signature. + pub fn from_pending_block_transaction(tx: transaction::SignedTransaction) -> Self { + let hash = tx.hash(); + let sender = tx.sender(); + VerifiedTransaction { + transaction: tx.into(), + hash, + sender, + priority: Priority::Retracted, + insertion_id: 0, + } + } + + /// Gets transaction priority. + pub(crate) fn priority(&self) -> Priority { + self.priority + } + + /// Gets wrapped `SignedTransaction` + pub fn signed(&self) -> &transaction::SignedTransaction { + &self.transaction + } + + /// Gets wrapped `PendingTransaction` + pub fn pending(&self) -> &transaction::PendingTransaction { + &self.transaction + } +} + +impl txpool::VerifiedTransaction for VerifiedTransaction { + fn hash(&self) -> &H256 { + &self.hash + } + + fn mem_usage(&self) -> usize { + self.transaction.heap_size_of_children() + } + + fn sender(&self) -> &Address { + &self.sender + } + + fn insertion_id(&self) -> u64 { + self.insertion_id as u64 + } +} diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs new file mode 100644 index 00000000000..edc092a119f --- /dev/null +++ b/miner/src/pool/queue.rs @@ -0,0 +1,445 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Ethereum Transaction Queue + +use std::{cmp, fmt}; +use std::sync::Arc; +use std::sync::atomic::{self, AtomicUsize}; +use std::collections::BTreeMap; + +use ethereum_types::{H256, U256, Address}; +use parking_lot::RwLock; +use rayon::prelude::*; +use transaction; +use txpool::{self, Verifier}; + +use pool::{self, scoring, verifier, client, ready, listener, PrioritizationStrategy}; +use pool::local_transactions::LocalTransactionsList; + +type Listener = (LocalTransactionsList, (listener::Notifier, listener::Logger)); +type Pool = txpool::Pool; + +/// Max cache time in milliseconds for pending transactions. +/// +/// Pending transactions are cached and will only be computed again +/// if last cache has been created earler than `TIMESTAMP_CACHE` ms ago. +/// This timeout applies only if there are local pending transactions +/// since it only affects transaction Condition. +const TIMESTAMP_CACHE: u64 = 1000; + +/// Transaction queue status. +#[derive(Debug, Clone, PartialEq)] +pub struct Status { + /// Verifier options. + pub options: verifier::Options, + /// Current status of the transaction pool. + pub status: txpool::LightStatus, + /// Current limits of the transaction pool. + pub limits: txpool::Options, +} + +impl fmt::Display for Status { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + writeln!( + fmt, + "Pool: {current}/{max} ({senders} senders; {mem}/{mem_max} kB) [minGasPrice: {gp} Mwei, maxGas: {max_gas}]", + current = self.status.transaction_count, + max = self.limits.max_count, + senders = self.status.senders, + mem = self.status.mem_usage / 1024, + mem_max = self.limits.max_mem_usage / 1024, + gp = self.options.minimal_gas_price / 1_000_000.into(), + max_gas = cmp::min(self.options.block_gas_limit, self.options.tx_gas_limit), + ) + } +} + +#[derive(Debug)] +struct CachedPending { + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + has_local_pending: bool, + pending: Option>>, +} + +impl CachedPending { + /// Creates new `CachedPending` without cached set. + pub fn none() -> Self { + CachedPending { + block_number: 0, + current_timestamp: 0, + has_local_pending: false, + pending: None, + nonce_cap: None, + } + } + + /// Remove cached pending set. + pub fn clear(&mut self) { + self.pending = None; + } + + /// Returns cached pending set (if any) if it's valid. + pub fn pending( + &self, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option<&U256>, + ) -> Option>> { + // First check if we have anything in cache. + let pending = self.pending.as_ref()?; + + if block_number != self.block_number { + return None; + } + + // In case we don't have any local pending transactions + // there is no need to invalidate the cache because of timestamp. + // Timestamp only affects local `PendingTransactions` with `Condition::Timestamp`. + if self.has_local_pending && current_timestamp > self.current_timestamp + TIMESTAMP_CACHE { + return None; + } + + // It's fine to return limited set even if `nonce_cap` is `None`. + // The worst thing that may happen is that some transactions won't get propagated in current round, + // but they are not really valid in current block anyway. We will propagate them in the next round. + // Also there is no way to have both `Some` with different numbers since it depends on the block number + // and a constant parameter in schedule (`nonce_cap_increment`) + if self.nonce_cap.is_none() && nonce_cap.is_some() { + return None; + } + + Some(pending.clone()) + } +} + +/// Ethereum Transaction Queue +/// +/// Responsible for: +/// - verifying incoming transactions +/// - maintaining a pool of verified transactions. +/// - returning an iterator for transactions that are ready to be included in block (pending) +#[derive(Debug)] +pub struct TransactionQueue { + insertion_id: Arc, + pool: RwLock, + options: RwLock, + cached_pending: RwLock, +} + +impl TransactionQueue { + /// Create new queue with given pool limits and initial verification options. + pub fn new( + limits: txpool::Options, + verification_options: verifier::Options, + strategy: PrioritizationStrategy, + ) -> Self { + TransactionQueue { + insertion_id: Default::default(), + pool: RwLock::new(txpool::Pool::new(Default::default(), scoring::NonceAndGasPrice(strategy), limits)), + options: RwLock::new(verification_options), + cached_pending: RwLock::new(CachedPending::none()), + } + } + + /// Update verification options + /// + /// Some parameters of verification may vary in time (like block gas limit or minimal gas price). + pub fn set_verifier_options(&self, options: verifier::Options) { + *self.options.write() = options; + } + + /// Import a set of transactions to the pool. + /// + /// Given blockchain and state access (Client) + /// verifies and imports transactions to the pool. + pub fn import( + &self, + client: C, + transactions: Vec, + ) -> Vec> { + // Run verification + let _timer = ::trace_time::PerfTimer::new("queue::verifyAndImport"); + let options = self.options.read().clone(); + + let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone()); + let results = transactions + .into_par_iter() + .map(|transaction| verifier.verify_transaction(transaction)) + .map(|result| result.and_then(|verified| { + self.pool.write().import(verified) + .map(|_imported| ()) + .map_err(convert_error) + })) + .collect::>(); + + // Notify about imported transactions. + (self.pool.write().listener_mut().1).0.notify(); + + if results.iter().any(|r| r.is_ok()) { + self.cached_pending.write().clear(); + } + + results + } + + /// Returns all transactions in the queue ordered by priority. + pub fn all_transactions(&self) -> Vec> { + let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready; + self.pool.read().pending(ready).collect() + } + + /// Returns current pneding transactions. + /// + /// NOTE: This may return a cached version of pending transaction set. + /// Re-computing the pending set is possible with `#collect_pending` method, + /// but be aware that it's a pretty expensive operation. + pub fn pending( + &self, + client: C, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + ) -> Vec> where + C: client::NonceClient, + { + + if let Some(pending) = self.cached_pending.read().pending(block_number, current_timestamp, nonce_cap.as_ref()) { + return pending; + } + + // Double check after acquiring write lock + let mut cached_pending = self.cached_pending.write(); + if let Some(pending) = cached_pending.pending(block_number, current_timestamp, nonce_cap.as_ref()) { + return pending; + } + + let pending: Vec<_> = self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| i.collect()); + + *cached_pending = CachedPending { + block_number, + current_timestamp, + nonce_cap, + has_local_pending: self.has_local_pending_transactions(), + pending: Some(pending.clone()), + }; + + pending + } + + /// Collect pending transactions. + /// + /// NOTE This is re-computing the pending set and it might be expensive to do so. + /// Prefer using cached pending set using `#pending` method. + pub fn collect_pending( + &self, + client: C, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + collect: F, + ) -> T where + C: client::NonceClient, + F: FnOnce(txpool::PendingIterator< + pool::VerifiedTransaction, + (ready::Condition, ready::State), + scoring::NonceAndGasPrice, + Listener, + >) -> T, + { + let pending_readiness = ready::Condition::new(block_number, current_timestamp); + // don't mark any transactions as stale at this point. + let stale_id = None; + let state_readiness = ready::State::new(client, stale_id, nonce_cap); + + let ready = (pending_readiness, state_readiness); + + collect(self.pool.read().pending(ready)) + } + + /// Culls all stalled transactions from the pool. + pub fn cull( + &self, + client: C, + ) { + // We don't care about future transactions, so nonce_cap is not important. + let nonce_cap = None; + // We want to clear stale transactions from the queue as well. + // (Transactions that are occuping the queue for a long time without being included) + let stale_id = { + let current_id = self.insertion_id.load(atomic::Ordering::Relaxed) as u64; + // wait at least for half of the queue to be replaced + let gap = self.pool.read().options().max_count / 2; + // but never less than 100 transactions + let gap = cmp::max(100, gap) as u64; + + current_id.checked_sub(gap) + }; + + let state_readiness = ready::State::new(client, stale_id, nonce_cap); + + let removed = self.pool.write().cull(None, state_readiness); + debug!(target: "txqueue", "Removed {} stalled transactions. {}", removed, self.status()); + } + + /// Returns next valid nonce for given sender + /// or `None` if there are no pending transactions from that sender. + pub fn next_nonce( + &self, + client: C, + address: &Address, + ) -> Option { + // Do not take nonce_cap into account when determining next nonce. + let nonce_cap = None; + // Also we ignore stale transactions in the queue. + let stale_id = None; + + let state_readiness = ready::State::new(client, stale_id, nonce_cap); + + self.pool.read().pending_from_sender(state_readiness, address) + .last() + .map(|tx| tx.signed().nonce + 1.into()) + } + + /// Retrieve a transaction from the pool. + /// + /// Given transaction hash looks up that transaction in the pool + /// and returns a shared pointer to it or `None` if it's not present. + pub fn find( + &self, + hash: &H256, + ) -> Option> { + self.pool.read().find(hash) + } + + /// Remove a set of transactions from the pool. + /// + /// Given an iterator of transaction hashes + /// removes them from the pool. + /// That method should be used if invalid transactions are detected + /// or you want to cancel a transaction. + pub fn remove<'a, T: IntoIterator>( + &self, + hashes: T, + is_invalid: bool, + ) -> Vec>> { + let results = { + let mut pool = self.pool.write(); + + hashes + .into_iter() + .map(|hash| pool.remove(hash, is_invalid)) + .collect::>() + }; + + if results.iter().any(Option::is_some) { + self.cached_pending.write().clear(); + } + + results + } + + /// Clear the entire pool. + pub fn clear(&self) { + self.pool.write().clear(); + } + + /// Penalize given senders. + pub fn penalize<'a, T: IntoIterator>(&self, senders: T) { + let mut pool = self.pool.write(); + for sender in senders { + pool.update_scores(sender, ()); + } + } + + /// Returns gas price of currently the worst transaction in the pool. + pub fn current_worst_gas_price(&self) -> U256 { + match self.pool.read().worst_transaction() { + Some(tx) => tx.signed().gas_price, + None => self.options.read().minimal_gas_price, + } + } + + /// Returns a status of the queue. + pub fn status(&self) -> Status { + let pool = self.pool.read(); + let status = pool.light_status(); + let limits = pool.options(); + let options = self.options.read().clone(); + + Status { + options, + status, + limits, + } + } + + /// Check if there are any local transactions in the pool. + /// + /// Returns `true` if there are any transactions in the pool + /// that has been marked as local. + /// + /// Local transactions are the ones from accounts managed by this node + /// and transactions submitted via local RPC (`eth_sendRawTransaction`) + pub fn has_local_pending_transactions(&self) -> bool { + self.pool.read().listener().0.has_pending() + } + + /// Returns status of recently seen local transactions. + pub fn local_transactions(&self) -> BTreeMap { + self.pool.read().listener().0.all_transactions().iter().map(|(a, b)| (*a, b.clone())).collect() + } + + /// Add a callback to be notified about all transactions entering the pool. + pub fn add_listener(&self, f: Box) { + let mut pool = self.pool.write(); + (pool.listener_mut().1).0.add(f); + } +} + + +fn convert_error(err: txpool::Error) -> transaction::Error { + use self::txpool::ErrorKind; + + match *err.kind() { + ErrorKind::AlreadyImported(..) => transaction::Error::AlreadyImported, + ErrorKind::TooCheapToEnter(..) => transaction::Error::LimitReached, + ErrorKind::TooCheapToReplace(..) => transaction::Error::TooCheapToReplace, + ref e => { + warn!(target: "txqueue", "Unknown import error: {:?}", e); + transaction::Error::NotAllowed + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use pool::tests::client::TestClient; + + #[test] + fn should_get_pending_transactions() { + let queue = TransactionQueue::new(txpool::Options::default(), verifier::Options::default(), PrioritizationStrategy::GasPriceOnly); + + let pending: Vec<_> = queue.pending(TestClient::default(), 0, 0, None); + + for tx in pending { + assert!(tx.signed().nonce > 0.into()); + } + } +} diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs new file mode 100644 index 00000000000..54b5aec3a9f --- /dev/null +++ b/miner/src/pool/ready.rs @@ -0,0 +1,212 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Transaction Readiness indicator +//! +//! Transaction readiness is responsible for indicating if +//! particular transaction can be included in the block. +//! +//! Regular transactions are ready iff the current state nonce +//! (obtained from `NonceClient`) equals to the transaction nonce. +//! +//! Let's define `S = state nonce`. Transactions are processed +//! in order, so we first include transaction with nonce `S`, +//! but then we are able to include the one with `S + 1` nonce. +//! So bear in mind that transactions can be included in chains +//! and their readiness is dependent on previous transactions from +//! the same sender. +//! +//! There are three possible outcomes: +//! - The transaction is old (stalled; state nonce > transaction nonce) +//! - The transaction is ready (current; state nonce == transaction nonce) +//! - The transaction is not ready yet (future; state nonce < transaction nonce) +//! +//! NOTE The transactions are always checked for readines in order they are stored within the queue. +//! First `Readiness::Future` response also causes all subsequent transactions from the same sender +//! to be marked as `Future`. + +use std::cmp; +use std::collections::HashMap; + +use ethereum_types::{U256, H160 as Address}; +use transaction; +use txpool::{self, VerifiedTransaction as PoolVerifiedTransaction}; + +use super::client::NonceClient; +use super::VerifiedTransaction; + +/// Checks readiness of transactions by comparing the nonce to state nonce. +#[derive(Debug)] +pub struct State { + nonces: HashMap, + state: C, + max_nonce: Option, + stale_id: Option, +} + +impl State { + /// Create new State checker, given client interface. + pub fn new( + state: C, + stale_id: Option, + max_nonce: Option, + ) -> Self { + State { + nonces: Default::default(), + state, + max_nonce, + stale_id, + } + } +} + +impl txpool::Ready for State { + fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness { + // Check max nonce + match self.max_nonce { + Some(nonce) if tx.transaction.nonce > nonce => { + return txpool::Readiness::Future; + }, + _ => {}, + } + + + let sender = tx.sender(); + let state = &self.state; + let state_nonce = || state.account_nonce(sender); + let nonce = self.nonces.entry(*sender).or_insert_with(state_nonce); + match tx.transaction.nonce.cmp(nonce) { + // Before marking as future check for stale ids + cmp::Ordering::Greater => match self.stale_id { + Some(id) if tx.insertion_id() < id => txpool::Readiness::Stalled, + _ => txpool::Readiness::Future, + }, + cmp::Ordering::Less => txpool::Readiness::Stalled, + cmp::Ordering::Equal => { + *nonce = *nonce + 1.into(); + txpool::Readiness::Ready + }, + } + } +} + +/// Checks readines of Pending transactions by comparing it with current time and block number. +#[derive(Debug)] +pub struct Condition { + block_number: u64, + now: u64, +} + +impl Condition { + /// Create a new condition checker given current block number and UTC timestamp. + pub fn new(block_number: u64, now: u64) -> Self { + Condition { + block_number, + now, + } + } +} + +impl txpool::Ready for Condition { + fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness { + match tx.transaction.condition { + Some(transaction::Condition::Number(block)) if block > self.block_number => txpool::Readiness::Future, + Some(transaction::Condition::Timestamp(time)) if time > self.now => txpool::Readiness::Future, + _ => txpool::Readiness::Ready, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use txpool::Ready; + use pool::tests::client::TestClient; + use pool::tests::tx::{Tx, TxExt}; + + #[test] + fn should_return_correct_state_readiness() { + // given + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + let (tx1, tx2, tx3) = (tx1.verified(), tx2.verified(), tx3.verified()); + + // when + assert_eq!(State::new(TestClient::new(), None, None).is_ready(&tx3), txpool::Readiness::Future); + assert_eq!(State::new(TestClient::new(), None, None).is_ready(&tx2), txpool::Readiness::Future); + + let mut ready = State::new(TestClient::new(), None, None); + + // then + assert_eq!(ready.is_ready(&tx1), txpool::Readiness::Ready); + assert_eq!(ready.is_ready(&tx2), txpool::Readiness::Ready); + assert_eq!(ready.is_ready(&tx3), txpool::Readiness::Ready); + } + + #[test] + fn should_return_future_if_nonce_cap_reached() { + // given + let tx = Tx::default().signed().verified(); + + // when + let res1 = State::new(TestClient::new(), None, Some(10.into())).is_ready(&tx); + let res2 = State::new(TestClient::new(), None, Some(124.into())).is_ready(&tx); + + // then + assert_eq!(res1, txpool::Readiness::Future); + assert_eq!(res2, txpool::Readiness::Ready); + } + + #[test] + fn should_return_stale_if_nonce_does_not_match() { + // given + let tx = Tx::default().signed().verified(); + + // when + let res = State::new(TestClient::new().with_nonce(125), None, None).is_ready(&tx); + + // then + assert_eq!(res, txpool::Readiness::Stalled); + } + + #[test] + fn should_return_stale_for_old_transactions() { + // given + let (_, tx) = Tx::default().signed_pair().verified(); + + // when + let res = State::new(TestClient::new(), Some(1), None).is_ready(&tx); + + // then + assert_eq!(res, txpool::Readiness::Stalled); + } + + #[test] + fn should_check_readiness_of_condition() { + // given + let tx = Tx::default().signed(); + let v = |tx: transaction::PendingTransaction| TestClient::new().verify(tx); + let tx1 = v(transaction::PendingTransaction::new(tx.clone(), transaction::Condition::Number(5).into())); + let tx2 = v(transaction::PendingTransaction::new(tx.clone(), transaction::Condition::Timestamp(3).into())); + let tx3 = v(transaction::PendingTransaction::new(tx.clone(), None)); + + // when/then + assert_eq!(Condition::new(0, 0).is_ready(&tx1), txpool::Readiness::Future); + assert_eq!(Condition::new(0, 0).is_ready(&tx2), txpool::Readiness::Future); + assert_eq!(Condition::new(0, 0).is_ready(&tx3), txpool::Readiness::Ready); + assert_eq!(Condition::new(5, 0).is_ready(&tx1), txpool::Readiness::Ready); + assert_eq!(Condition::new(0, 3).is_ready(&tx2), txpool::Readiness::Ready); + } +} diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs new file mode 100644 index 00000000000..b9f074ecb0f --- /dev/null +++ b/miner/src/pool/scoring.rs @@ -0,0 +1,171 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Transaction Scoring and Ordering +//! +//! Ethereum transactions from the same sender are ordered by `nonce`. +//! Low nonces need to be included first. If there are two transactions from the same sender +//! and with the same `nonce` only one of them can be included. +//! We choose the one with higher gas price, but also require that gas price increment +//! is high enough to prevent attacking miners by requiring them to reshuffle/reexecute +//! the queue too often. +//! +//! Transactions between senders are prioritized using `gas price`. Higher `gas price` +//! yields more profits for miners. Additionally we prioritize transactions that originate +//! from our local node (own transactions). + +use std::cmp; +use std::sync::Arc; + +use ethereum_types::U256; +use txpool; +use super::{PrioritizationStrategy, VerifiedTransaction}; + +/// Transaction with the same (sender, nonce) can be replaced only if +/// `new_gas_price > old_gas_price + old_gas_price >> SHIFT` +const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25% + +/// Simple, gas-price based scoring for transactions. +/// +/// NOTE: Currently penalization does not apply to new transactions that enter the pool. +/// We might want to store penalization status in some persistent state. +#[derive(Debug)] +pub struct NonceAndGasPrice(pub PrioritizationStrategy); + +impl txpool::Scoring for NonceAndGasPrice { + type Score = U256; + type Event = (); + + fn compare(&self, old: &VerifiedTransaction, other: &VerifiedTransaction) -> cmp::Ordering { + old.transaction.nonce.cmp(&other.transaction.nonce) + } + + fn choose(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> txpool::scoring::Choice { + if old.transaction.nonce != new.transaction.nonce { + return txpool::scoring::Choice::InsertNew + } + + let old_gp = old.transaction.gas_price; + let new_gp = new.transaction.gas_price; + + let min_required_gp = old_gp + (old_gp >> GAS_PRICE_BUMP_SHIFT); + + match min_required_gp.cmp(&new_gp) { + cmp::Ordering::Greater => txpool::scoring::Choice::RejectNew, + _ => txpool::scoring::Choice::ReplaceOld, + } + } + + fn update_scores(&self, txs: &[Arc], scores: &mut [U256], change: txpool::scoring::Change) { + use self::txpool::scoring::Change; + + match change { + Change::Culled(_) => {}, + Change::RemovedAt(_) => {} + Change::InsertedAt(i) | Change::ReplacedAt(i) => { + assert!(i < txs.len()); + assert!(i < scores.len()); + + scores[i] = txs[i].transaction.gas_price; + let boost = match txs[i].priority() { + super::Priority::Local => 15, + super::Priority::Retracted => 10, + super::Priority::Regular => 0, + }; + scores[i] = scores[i] << boost; + }, + // We are only sending an event in case of penalization. + // So just lower the priority of all non-local transactions. + Change::Event(_) => { + for (score, tx) in scores.iter_mut().zip(txs) { + // Never penalize local transactions. + if !tx.priority().is_local() { + *score = *score >> 3; + } + } + }, + } + } + + fn should_replace(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> bool { + if old.sender == new.sender { + // prefer earliest transaction + if new.transaction.nonce < old.transaction.nonce { + return true + } + } + + self.choose(old, new) == txpool::scoring::Choice::ReplaceOld + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use pool::tests::tx::{Tx, TxExt}; + use txpool::Scoring; + + #[test] + fn should_calculate_score_correctly() { + // given + let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + let transactions = vec![tx1, tx2, tx3].into_iter().enumerate().map(|(i, tx)| { + let mut verified = tx.verified(); + verified.priority = match i { + 0 => ::pool::Priority::Local, + 1 => ::pool::Priority::Retracted, + _ => ::pool::Priority::Regular, + }; + Arc::new(verified) + }).collect::>(); + let initial_scores = vec![U256::from(0), 0.into(), 0.into()]; + + // No update required + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(0)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(1)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(2)); + assert_eq!(scores, initial_scores); + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(0)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(1)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(2)); + assert_eq!(scores, initial_scores); + + // Compute score at given index + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(0)); + assert_eq!(scores, vec![32768.into(), 0.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(1)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(2)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]); + + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(0)); + assert_eq!(scores, vec![32768.into(), 0.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(1)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(2)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]); + + // Check penalization + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Event(())); + assert_eq!(scores, vec![32768.into(), 128.into(), 0.into()]); + } +} diff --git a/miner/src/pool/tests/client.rs b/miner/src/pool/tests/client.rs new file mode 100644 index 00000000000..7f7be64cc8d --- /dev/null +++ b/miner/src/pool/tests/client.rs @@ -0,0 +1,125 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use ethereum_types::{U256, H256, Address}; +use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; + +use pool; +use pool::client::AccountDetails; + +#[derive(Debug, Clone)] +pub struct TestClient { + account_details: AccountDetails, + gas_required: U256, + is_service_transaction: bool, + local_address: Address, +} + +impl Default for TestClient { + fn default() -> Self { + TestClient { + account_details: AccountDetails { + nonce: 123.into(), + balance: 63_100.into(), + is_local: false, + }, + gas_required: 21_000.into(), + is_service_transaction: false, + local_address: Default::default(), + } + } +} + +impl TestClient { + pub fn new() -> Self { + TestClient::default() + } + + pub fn with_balance>(mut self, balance: T) -> Self { + self.account_details.balance = balance.into(); + self + } + + pub fn with_nonce>(mut self, nonce: T) -> Self { + self.account_details.nonce = nonce.into(); + self + } + + pub fn with_gas_required>(mut self, gas_required: T) -> Self { + self.gas_required = gas_required.into(); + self + } + + pub fn with_local(mut self, address: &Address) -> Self { + self.local_address = *address; + self + } + + pub fn with_service_transaction(mut self) -> Self { + self.is_service_transaction = true; + self + } + + pub fn verify>(&self, tx: T) -> pool::VerifiedTransaction { + let tx = tx.into(); + pool::VerifiedTransaction { + hash: tx.hash(), + sender: tx.sender(), + priority: pool::Priority::Regular, + transaction: tx, + insertion_id: 1, + } + } +} + +impl pool::client::Client for TestClient { + fn transaction_already_included(&self, _hash: &H256) -> bool { + false + } + + fn verify_transaction(&self, tx: UnverifiedTransaction) + -> Result + { + Ok(SignedTransaction::new(tx)?) + } + + fn account_details(&self, address: &Address) -> AccountDetails { + let mut details = self.account_details.clone(); + if address == &self.local_address { + details.is_local = true; + } + + details + } + + fn required_gas(&self, _tx: &Transaction) -> U256 { + self.gas_required + } + + fn transaction_type(&self, _tx: &SignedTransaction) -> pool::client::TransactionType { + if self.is_service_transaction { + pool::client::TransactionType::Service + } else { + pool::client::TransactionType::Regular + } + } +} + +impl pool::client::NonceClient for TestClient { + fn account_nonce(&self, _address: &Address) -> U256 { + self.account_details.nonce + } +} diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs new file mode 100644 index 00000000000..340cb751586 --- /dev/null +++ b/miner/src/pool/tests/mod.rs @@ -0,0 +1,757 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use ethereum_types::U256; +use transaction::{self, PendingTransaction}; +use txpool; + +use pool::{verifier, TransactionQueue, PrioritizationStrategy}; + +pub mod tx; +pub mod client; + +use self::tx::{Tx, TxExt, PairExt}; +use self::client::TestClient; + +fn new_queue() -> TransactionQueue { + TransactionQueue::new( + txpool::Options { + max_count: 3, + max_per_sender: 3, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ) +} + +#[test] +fn should_return_correct_nonces_when_dropped_because_of_limit() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 3, + max_per_sender: 1, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let (tx1, tx2) = Tx::gas_price(2).signed_pair(); + let sender = tx1.sender(); + let nonce = tx1.nonce; + + // when + let result = txq.import(TestClient::new(), vec![tx1, tx2].local()); + assert_eq!(result, vec![Ok(()), Err(transaction::Error::LimitReached)]); + assert_eq!(txq.status().status.transaction_count, 1); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1.into())); + + // when + let tx1 = Tx::gas_price(2).signed(); + let tx2 = Tx::gas_price(2).signed(); + let tx3 = Tx::gas_price(1).signed(); + let tx4 = Tx::gas_price(3).signed(); + let res = txq.import(TestClient::new(), vec![tx1, tx2].local()); + let res2 = txq.import(TestClient::new(), vec![tx3, tx4].local()); + + // then + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(res2, vec![Err(transaction::Error::LimitReached), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 3); + // First inserted transacton got dropped because of limit + assert_eq!(txq.next_nonce(TestClient::new(), &sender), None); +} + +#[test] +fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::default().signed_replacement(); + let hash = tx2.hash(); + let client = TestClient::new().with_nonce(122); + + // First insert one transaction to future + let res = txq.import(client.clone(), vec![tx].local()); + assert_eq!(res, vec![Ok(())]); + // next_nonce === None -> transaction is in future + assert_eq!(txq.next_nonce(client.clone(), &tx2.sender()), None); + + // now import second transaction to current + let res = txq.import(TestClient::new(), vec![tx2.local()]); + + // and then there should be only one transaction in current (the one with higher gas_price) + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); +} + +#[test] +fn should_move_all_transactions_from_future() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + let (hash, hash2) = txs.hash(); + let (tx, tx2) = txs; + let client = TestClient::new().with_nonce(122); + + // First insert one transaction to future + let res = txq.import(client.clone(), vec![tx.local()]); + assert_eq!(res, vec![Ok(())]); + // next_nonce === None -> transaction is in future + assert_eq!(txq.next_nonce(client.clone(), &tx2.sender()), None); + + // now import second transaction to current + let res = txq.import(client.clone(), vec![tx2.local()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); + assert_eq!(top[1].hash, hash2); +} + +#[test] +fn should_drop_transactions_from_senders_without_balance() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + let client = TestClient::new().with_balance(1); + + // when + let res = txq.import(client, vec![tx.local()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::InsufficientBalance { + balance: U256::from(1), + cost: U256::from(21_100), + })]); + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_not_import_transaction_below_min_gas_price_threshold_if_external() { + // given + let txq = new_queue(); + let tx = Tx::default(); + txq.set_verifier_options(verifier::Options { + minimal_gas_price: 3.into(), + ..Default::default() + }); + + // when + let res = txq.import(TestClient::new(), vec![tx.signed().unverified()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::InsufficientGasPrice { + minimal: U256::from(3), + got: U256::from(1), + })]); + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_import_transaction_below_min_gas_price_threshold_if_local() { + // given + let txq = new_queue(); + let tx = Tx::default(); + txq.set_verifier_options(verifier::Options { + minimal_gas_price: 3.into(), + ..Default::default() + }); + + // when + let res = txq.import(TestClient::new(), vec![tx.signed().local()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); +} + +#[test] +fn should_import_txs_from_same_sender() { + // given + let txq = new_queue(); + + let txs = Tx::default().signed_pair(); + let (hash, hash2) = txs.hash(); + + // when + txq.import(TestClient::new(), txs.local().into_vec()); + + // then + let top = txq.pending(TestClient::new(), 0 ,0, None); + assert_eq!(top[0].hash, hash); + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_prioritize_local_transactions_within_same_nonce_height() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + // the second one has same nonce but higher `gas_price` + let tx2 = Tx::gas_price(2).signed(); + let (hash, hash2) = (tx.hash(), tx2.hash()); + let client = TestClient::new().with_local(&tx.sender()); + + // when + // first insert the one with higher gas price + let res = txq.import(client.clone(), vec![tx.local(), tx2.unverified()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(client, 0, 0, None); + assert_eq!(top[0].hash, hash); // local should be first + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_prioritize_reimported_transactions_within_same_nonce_height() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + // the second one has same nonce but higher `gas_price` + let tx2 = Tx::gas_price(2).signed(); + let (hash, hash2) = (tx.hash(), tx2.hash()); + + // when + // first insert local one with higher gas price + // then the one with lower gas price, but from retracted block + let res = txq.import(TestClient::new(), vec![tx2.unverified(), tx.retracted()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); // retracted should be first + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_not_prioritize_local_transactions_with_different_nonce_height() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + let (hash, hash2) = txs.hash(); + let (tx, tx2) = txs; + + // when + let res = txq.import(TestClient::new(), vec![tx.unverified(), tx2.local()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_put_transaction_to_futures_if_gap_detected() { + // given + let txq = new_queue(); + let (tx, _, tx2) = Tx::default().signed_triple(); + let hash = tx.hash(); + + // when + let res = txq.import(TestClient::new(), vec![tx, tx2].local()); + + // then + assert_eq!(res, vec![Ok(()), Ok(())]); + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top.len(), 1); + assert_eq!(top[0].hash, hash); +} + +#[test] +fn should_handle_min_block() { + // given + let txq = new_queue(); + + let (tx, tx2) = Tx::default().signed_pair(); + + // when + let res = txq.import(TestClient::new(), vec![ + verifier::Transaction::Local(PendingTransaction::new(tx, transaction::Condition::Number(1).into())), + tx2.local() + ]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top.len(), 0); + let top = txq.pending(TestClient::new(), 1, 0, None); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_correctly_update_futures_when_removing() { + // given + let txq = new_queue(); + let txs= Tx::default().signed_pair(); + + let res = txq.import(TestClient::new().with_nonce(121), txs.local().into_vec()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + + // when + txq.cull(TestClient::new().with_nonce(125)); + // should remove both transactions since they are stalled + + // then + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_move_transactions_if_gap_filled() { + // given + let txq = new_queue(); + let (tx, tx1, tx2) = Tx::default().signed_triple(); + + let res = txq.import(TestClient::new(), vec![tx, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + + // when + let res = txq.import(TestClient::new(), vec![tx1.local()]); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.status().status.transaction_count, 3); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); +} + +#[test] +fn should_remove_transaction() { + // given + let txq = new_queue(); + let (tx, _, tx2) = Tx::default().signed_triple(); + + let res = txq.import(TestClient::default(), vec![tx, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + + // when + txq.cull(TestClient::new().with_nonce(124)); + assert_eq!(txq.status().status.transaction_count, 1); + assert_eq!(txq.pending(TestClient::new().with_nonce(125), 0, 0, None).len(), 1); + txq.cull(TestClient::new().with_nonce(126)); + + // then + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_move_transactions_to_future_if_gap_introduced() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::default().signed_pair(); + let hash = tx.hash(); + let tx3 = Tx::default().signed(); + + let res = txq.import(TestClient::new(), vec![tx3, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + + let res = txq.import(TestClient::new(), vec![tx].local()); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 3); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); + + // when + txq.remove(vec![&hash], true); + + // then + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); +} + +#[test] +fn should_clear_queue() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + + // add + txq.import(TestClient::new(), txs.local().into_vec()); + assert_eq!(txq.status().status.transaction_count, 2); + + // when + txq.clear(); + + // then + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_prefer_current_transactions_when_hitting_the_limit() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 1, + max_per_sender: 2, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let (tx, tx2) = Tx::default().signed_pair(); + let hash = tx.hash(); + let sender = tx.sender(); + + let res = txq.import(TestClient::new(), vec![tx2.unverified()]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + // when + let res = txq.import(TestClient::new(), vec![tx.unverified()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top.len(), 1); + assert_eq!(top[0].hash, hash); + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(124.into())); +} + +#[test] +fn should_drop_transactions_with_old_nonces() { + let txq = new_queue(); + let tx = Tx::default().signed(); + + // when + let res = txq.import(TestClient::new().with_nonce(125), vec![tx.unverified()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::Old)]); + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_not_insert_same_transaction_twice() { + // given + let txq = new_queue(); + let (_tx1, tx2) = Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![tx2.clone().local()]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + // when + let res = txq.import(TestClient::new(), vec![tx2.local()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::AlreadyImported)]); + assert_eq!(txq.status().status.transaction_count, 1); +} + +#[test] +fn should_accept_same_transaction_twice_if_removed() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + let (tx1, _) = txs.clone(); + let (hash, _) = txs.hash(); + + + let res = txq.import(TestClient::new(), txs.local().into_vec()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); + + // when + txq.remove(vec![&hash], true); + assert_eq!(txq.status().status.transaction_count, 1); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 0); + + let res = txq.import(TestClient::new(), vec![tx1].local()); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); +} + +#[test] +fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::gas_price(20).signed_replacement(); + let (tx3, tx4) = Tx::gas_price(1).signed_replacement(); + let client = TestClient::new().with_balance(1_000_000); + + // when + let res = txq.import(client.clone(), vec![tx, tx3].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + + let res = txq.import(client.clone(), vec![tx2, tx4].local()); + + // then + assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(client.clone(), 0, 0, None)[0].signed().gas_price, U256::from(20)); + assert_eq!(txq.pending(client.clone(), 0, 0, None)[1].signed().gas_price, U256::from(2)); +} + +#[test] +fn should_return_none_when_transaction_from_given_address_does_not_exist() { + // given + let txq = new_queue(); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &Default::default()), None); +} + +#[test] +fn should_return_correct_nonce_when_transactions_from_given_address_exist() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + let from = tx.sender(); + let nonce = tx.nonce; + + // when + txq.import(TestClient::new(), vec![tx.local()]); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &from), Some(nonce + 1.into())); +} + +#[test] +fn should_return_valid_last_nonce_after_cull() { + // given + let txq = new_queue(); + let (tx1, _, tx2) = Tx::default().signed_triple(); + let sender = tx1.sender(); + + // when + // Second should go to future + let res = txq.import(TestClient::new(), vec![tx1, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + // Now block is imported + let client = TestClient::new().with_nonce(124); + txq.cull(client.clone()); + // tx2 should be not be promoted to current + assert_eq!(txq.pending(client.clone(), 0, 0, None).len(), 0); + + // then + assert_eq!(txq.next_nonce(client.clone(), &sender), None); + assert_eq!(txq.next_nonce(client.with_nonce(125), &sender), Some(126.into())); +} + +#[test] +fn should_return_true_if_there_is_local_transaction_pending() { + // given + let txq = new_queue(); + let (tx1, tx2) = Tx::default().signed_pair(); + assert_eq!(txq.has_local_pending_transactions(), false); + let client = TestClient::new().with_local(&tx1.sender()); + + // when + let res = txq.import(client.clone(), vec![tx1.unverified(), tx2.local()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + assert_eq!(txq.has_local_pending_transactions(), true); +} + +#[test] +fn should_reject_transactions_below_base_gas() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + + // when + let res = txq.import(TestClient::new().with_gas_required(100_001), vec![tx].local()); + + // then + assert_eq!(res, vec![Err(transaction::Error::InsufficientGas { + minimal: 100_001.into(), + got: 21_000.into(), + })]); +} + +#[test] +fn should_remove_out_of_date_transactions_occupying_queue() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 105, + max_per_sender: 3, + max_mem_usage: 5_000_000, + }, + verifier::Options { + minimal_gas_price: 10.into(), + ..Default::default() + }, + PrioritizationStrategy::GasPriceOnly, + ); + // that transaction will be occupying the queue + let (_, tx) = Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![tx.local()]); + assert_eq!(res, vec![Ok(())]); + // This should not clear the transaction (yet) + txq.cull(TestClient::new()); + assert_eq!(txq.status().status.transaction_count, 1); + + // Now insert at least 100 transactions to have the other one marked as future. + for _ in 0..34 { + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + txq.import(TestClient::new(), vec![tx1, tx2, tx3].local()); + } + assert_eq!(txq.status().status.transaction_count, 103); + + // when + txq.cull(TestClient::new()); + + // then + assert_eq!(txq.status().status.transaction_count, 102); +} + +#[test] +fn should_accept_local_transactions_below_min_gas_price() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 3, + max_per_sender: 3, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 10.into(), + ..Default::default() + }, + PrioritizationStrategy::GasPriceOnly, + ); + let tx = Tx::gas_price(1).signed(); + + // when + let res = txq.import(TestClient::new(), vec![tx.local()]); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); +} + +#[test] +fn should_accept_local_service_transaction() { + // given + let txq = new_queue(); + let tx = Tx::gas_price(0).signed(); + + // when + let res = txq.import( + TestClient::new() + .with_local(&tx.sender()), + vec![tx.local()] + ); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); +} + +#[test] +fn should_not_accept_external_service_transaction_if_sender_not_certified() { + // given + let txq = new_queue(); + let tx1 = Tx::gas_price(0).signed().unverified(); + let tx2 = Tx::gas_price(0).signed().retracted(); + let tx3 = Tx::gas_price(0).signed().unverified(); + + // when + let res = txq.import(TestClient::new(), vec![tx1, tx2]); + assert_eq!(res, vec![ + Err(transaction::Error::InsufficientGasPrice { + minimal: 1.into(), + got: 0.into(), + }), + Err(transaction::Error::InsufficientGasPrice { + minimal: 1.into(), + got: 0.into(), + }), + ]); + + // then + let res = txq.import(TestClient::new().with_service_transaction(), vec![tx3]); + assert_eq!(res, vec![Ok(())]); +} + +#[test] +fn should_not_return_transactions_over_nonce_cap() { + // given + let txq = new_queue(); + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + let res = txq.import( + TestClient::new(), + vec![tx1, tx2, tx3].local() + ); + assert_eq!(res, vec![Ok(()), Ok(()), Ok(())]); + + // when + let all = txq.pending(TestClient::new(), 0, 0, None); + // This should invalidate the cache! + let limited = txq.pending(TestClient::new(), 0, 0, Some(123.into())); + + + // then + assert_eq!(all.len(), 3); + assert_eq!(limited.len(), 1); +} + +#[test] +fn should_clear_cache_after_timeout_for_local() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![ + verifier::Transaction::Local(PendingTransaction::new(tx, transaction::Condition::Timestamp(1000).into())), + tx2.local() + ]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // This should populate cache and set timestamp to 1 + // when + assert_eq!(txq.pending(TestClient::new(), 0, 1, None).len(), 0); + assert_eq!(txq.pending(TestClient::new(), 0, 1000, None).len(), 0); + + // This should invalidate the cache and trigger transaction ready. + // then + assert_eq!(txq.pending(TestClient::new(), 0, 1002, None).len(), 2); +} diff --git a/miner/src/pool/tests/tx.rs b/miner/src/pool/tests/tx.rs new file mode 100644 index 00000000000..ee0a7390eed --- /dev/null +++ b/miner/src/pool/tests/tx.rs @@ -0,0 +1,185 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use ethereum_types::{U256, H256}; +use ethkey::{Random, Generator}; +use rustc_hex::FromHex; +use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; + +use pool::{verifier, VerifiedTransaction}; + +#[derive(Clone)] +pub struct Tx { + nonce: u64, + gas: u64, + gas_price: u64, +} + +impl Default for Tx { + fn default() -> Self { + Tx { + nonce: 123, + gas: 21_000, + gas_price: 1, + } + } +} + +impl Tx { + pub fn gas_price(gas_price: u64) -> Self { + Tx { + gas_price, + ..Default::default() + } + } + + pub fn signed(self) -> SignedTransaction { + let keypair = Random.generate().unwrap(); + self.unsigned().sign(keypair.secret(), None) + } + + pub fn signed_pair(self) -> (SignedTransaction, SignedTransaction) { + let (tx1, tx2, _) = self.signed_triple(); + (tx1, tx2) + } + + pub fn signed_triple(mut self) -> (SignedTransaction, SignedTransaction, SignedTransaction) { + let keypair = Random.generate().unwrap(); + let tx1 = self.clone().unsigned().sign(keypair.secret(), None); + self.nonce += 1; + let tx2 = self.clone().unsigned().sign(keypair.secret(), None); + self.nonce += 1; + let tx3 = self.unsigned().sign(keypair.secret(), None); + + + (tx1, tx2, tx3) + } + + pub fn signed_replacement(mut self) -> (SignedTransaction, SignedTransaction) { + let keypair = Random.generate().unwrap(); + let tx1 = self.clone().unsigned().sign(keypair.secret(), None); + self.gas_price += 1; + let tx2 = self.unsigned().sign(keypair.secret(), None); + + (tx1, tx2) + } + + pub fn unsigned(self) -> Transaction { + Transaction { + action: transaction::Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: self.gas.into(), + gas_price: self.gas_price.into(), + nonce: self.nonce.into() + } + } +} +pub trait TxExt: Sized { + type Out; + type Verified; + type Hash; + + fn hash(&self) -> Self::Hash; + + fn local(self) -> Self::Out; + + fn retracted(self) -> Self::Out; + + fn unverified(self) -> Self::Out; + + fn verified(self) -> Self::Verified; +} + +impl TxExt for (A, B) where + A: TxExt, + B: TxExt, +{ + type Out = (O, O); + type Verified = (V, V); + type Hash = (H, H); + + fn hash(&self) -> Self::Hash { (self.0.hash(), self.1.hash()) } + fn local(self) -> Self::Out { (self.0.local(), self.1.local()) } + fn retracted(self) -> Self::Out { (self.0.retracted(), self.1.retracted()) } + fn unverified(self) -> Self::Out { (self.0.unverified(), self.1.unverified()) } + fn verified(self) -> Self::Verified { (self.0.verified(), self.1.verified()) } +} + +impl TxExt for SignedTransaction { + type Out = verifier::Transaction; + type Verified = VerifiedTransaction; + type Hash = H256; + + fn hash(&self) -> Self::Hash { + UnverifiedTransaction::hash(self) + } + + fn local(self) -> Self::Out { + verifier::Transaction::Local(self.into()) + } + + fn retracted(self) -> Self::Out { + verifier::Transaction::Retracted(self.into()) + } + + fn unverified(self) -> Self::Out { + verifier::Transaction::Unverified(self.into()) + } + + fn verified(self) -> Self::Verified { + VerifiedTransaction::from_pending_block_transaction(self) + } +} + +impl TxExt for Vec { + type Out = Vec; + type Verified = Vec; + type Hash = Vec; + + fn hash(&self) -> Self::Hash { + self.iter().map(|tx| tx.hash()).collect() + } + + fn local(self) -> Self::Out { + self.into_iter().map(Into::into).map(verifier::Transaction::Local).collect() + } + + fn retracted(self) -> Self::Out { + self.into_iter().map(Into::into).map(verifier::Transaction::Retracted).collect() + } + + fn unverified(self) -> Self::Out { + self.into_iter().map(Into::into).map(verifier::Transaction::Unverified).collect() + } + + fn verified(self) -> Self::Verified { + self.into_iter().map(VerifiedTransaction::from_pending_block_transaction).collect() + } +} + +pub trait PairExt { + type Type; + + fn into_vec(self) -> Vec; +} + +impl PairExt for (A, A) { + type Type = A; + fn into_vec(self) -> Vec { + vec![self.0, self.1] + } +} diff --git a/miner/src/pool/verifier.rs b/miner/src/pool/verifier.rs new file mode 100644 index 00000000000..92d2eb9c86b --- /dev/null +++ b/miner/src/pool/verifier.rs @@ -0,0 +1,288 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Transaction Verifier +//! +//! Responsible for verifying a transaction before importing to the pool. +//! Should make sure that the transaction is structuraly valid. +//! +//! May have some overlap with `Readiness` since we don't want to keep around +//! stalled transactions. + +use std::cmp; +use std::sync::Arc; +use std::sync::atomic::{self, AtomicUsize}; + +use ethereum_types::{U256, H256}; +use transaction; +use txpool; + +use super::client::{Client, TransactionType}; +use super::VerifiedTransaction; + +/// Verification options. +#[derive(Debug, Clone, PartialEq)] +pub struct Options { + /// Minimal allowed gas price. + pub minimal_gas_price: U256, + /// Current block gas limit. + pub block_gas_limit: U256, + /// Maximal gas limit for a single transaction. + pub tx_gas_limit: U256, +} + +#[cfg(test)] +impl Default for Options { + fn default() -> Self { + Options { + minimal_gas_price: 0.into(), + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + } + } +} + +/// Transaction to verify. +pub enum Transaction { + /// Fresh, never verified transaction. + /// + /// We need to do full verification of such transactions + Unverified(transaction::UnverifiedTransaction), + + /// Transaction from retracted block. + /// + /// We could skip some parts of verification of such transactions + Retracted(transaction::UnverifiedTransaction), + + /// Locally signed or retracted transaction. + /// + /// We can skip consistency verifications and just verify readiness. + Local(transaction::PendingTransaction), +} + +impl Transaction { + fn hash(&self) -> H256 { + match *self { + Transaction::Unverified(ref tx) => tx.hash(), + Transaction::Retracted(ref tx) => tx.hash(), + Transaction::Local(ref tx) => tx.hash(), + } + } + + fn gas(&self) -> &U256 { + match *self { + Transaction::Unverified(ref tx) => &tx.gas, + Transaction::Retracted(ref tx) => &tx.gas, + Transaction::Local(ref tx) => &tx.gas, + } + } + + + fn gas_price(&self) -> &U256 { + match *self { + Transaction::Unverified(ref tx) => &tx.gas_price, + Transaction::Retracted(ref tx) => &tx.gas_price, + Transaction::Local(ref tx) => &tx.gas_price, + } + } + + fn transaction(&self) -> &transaction::Transaction { + match *self { + Transaction::Unverified(ref tx) => &*tx, + Transaction::Retracted(ref tx) => &*tx, + Transaction::Local(ref tx) => &*tx, + } + } + + fn is_local(&self) -> bool { + match *self { + Transaction::Local(..) => true, + _ => false, + } + } + + fn is_retracted(&self) -> bool { + match *self { + Transaction::Retracted(..) => true, + _ => false, + } + } +} + +/// Transaction verifier. +/// +/// Verification can be run in parallel for all incoming transactions. +#[derive(Debug)] +pub struct Verifier { + client: C, + options: Options, + id: Arc, +} + +impl Verifier { + /// Creates new transaction verfier with specified options. + pub fn new(client: C, options: Options, id: Arc) -> Self { + Verifier { + client, + options, + id, + } + } +} + +impl txpool::Verifier for Verifier { + type Error = transaction::Error; + type VerifiedTransaction = VerifiedTransaction; + + fn verify_transaction(&self, tx: Transaction) -> Result { + // The checks here should be ordered by cost/complexity. + // Cheap checks should be done as early as possible to discard unneeded transactions early. + + let hash = tx.hash(); + + if self.client.transaction_already_included(&hash) { + trace!(target: "txqueue", "[{:?}] Rejected tx already in the blockchain", hash); + bail!(transaction::Error::AlreadyImported) + } + + let gas_limit = cmp::min(self.options.tx_gas_limit, self.options.block_gas_limit); + if tx.gas() > &gas_limit { + debug!( + target: "txqueue", + "[{:?}] Dropping transaction above gas limit: {} > min({}, {})", + hash, + tx.gas(), + self.options.block_gas_limit, + self.options.tx_gas_limit, + ); + bail!(transaction::Error::GasLimitExceeded { + limit: gas_limit, + got: *tx.gas(), + }); + } + + let minimal_gas = self.client.required_gas(tx.transaction()); + if tx.gas() < &minimal_gas { + trace!(target: "txqueue", + "[{:?}] Dropping transaction with insufficient gas: {} < {}", + hash, + tx.gas(), + minimal_gas, + ); + + bail!(transaction::Error::InsufficientGas { + minimal: minimal_gas, + got: *tx.gas(), + }) + } + + let is_own = tx.is_local(); + // Quick exit for non-service transactions + if tx.gas_price() < &self.options.minimal_gas_price + && !tx.gas_price().is_zero() + && !is_own + { + trace!( + target: "txqueue", + "[{:?}] Rejected tx below minimal gas price threshold: {} < {}", + hash, + tx.gas_price(), + self.options.minimal_gas_price, + ); + bail!(transaction::Error::InsufficientGasPrice { + minimal: self.options.minimal_gas_price, + got: *tx.gas_price(), + }); + } + + // Some more heavy checks below. + // Actually recover sender and verify that transaction + let is_retracted = tx.is_retracted(); + let transaction = match tx { + Transaction::Retracted(tx) | Transaction::Unverified(tx) => match self.client.verify_transaction(tx) { + Ok(signed) => signed.into(), + Err(err) => { + debug!(target: "txqueue", "[{:?}] Rejected tx {:?}", hash, err); + bail!(err) + }, + }, + Transaction::Local(tx) => tx, + }; + + let sender = transaction.sender(); + let account_details = self.client.account_details(&sender); + + if transaction.gas_price < self.options.minimal_gas_price { + let transaction_type = self.client.transaction_type(&transaction); + if let TransactionType::Service = transaction_type { + debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash); + } else if is_own || account_details.is_local { + info!(target: "own_tx", "Local tx {:?} below minimal gas price accepted", hash); + } else { + trace!( + target: "txqueue", + "[{:?}] Rejected tx below minimal gas price threshold: {} < {}", + hash, + transaction.gas_price, + self.options.minimal_gas_price, + ); + bail!(transaction::Error::InsufficientGasPrice { + minimal: self.options.minimal_gas_price, + got: transaction.gas_price, + }); + } + } + + let cost = transaction.value + transaction.gas_price * transaction.gas; + if account_details.balance < cost { + debug!( + target: "txqueue", + "[{:?}] Rejected tx with not enough balance: {} < {}", + hash, + account_details.balance, + cost, + ); + bail!(transaction::Error::InsufficientBalance { + cost: cost, + balance: account_details.balance, + }); + } + + if transaction.nonce < account_details.nonce { + debug!( + target: "txqueue", + "[{:?}] Rejected tx with old nonce ({} < {})", + hash, + transaction.nonce, + account_details.nonce, + ); + bail!(transaction::Error::Old); + } + + let priority = match (is_own || account_details.is_local, is_retracted) { + (true, _) => super::Priority::Local, + (false, false) => super::Priority::Regular, + (false, true) => super::Priority::Retracted, + }; + Ok(VerifiedTransaction { + transaction, + priority, + hash, + sender, + insertion_id: self.id.fetch_add(1, atomic::Ordering::AcqRel), + }) + } +} diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs deleted file mode 100644 index 2be7fc8a3b8..00000000000 --- a/miner/src/transaction_queue.rs +++ /dev/null @@ -1,2944 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Transaction Queue -//! -//! `TransactionQueue` keeps track of all transactions seen by the node (received from other peers) and own transactions -//! and orders them by priority. Top priority transactions are those with low nonce height (difference between -//! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used -//! for comparison (higher gas price = higher priority). -//! -//! # Usage Example -//! -//! ```rust -//! extern crate ethereum_types; -//! extern crate ethcore_miner as miner; -//! extern crate ethcore_transaction as transaction; -//! extern crate ethkey; -//! extern crate rustc_hex; -//! -//! use ethereum_types::{U256, Address}; -//! use ethkey::{Random, Generator}; -//! use miner::transaction_queue::{TransactionQueue, TransactionDetailsProvider, AccountDetails, TransactionOrigin, RemovalReason}; -//! use transaction::*; -//! use rustc_hex::FromHex; -//! -//! #[derive(Default)] -//! struct DummyTransactionDetailsProvider; -//! -//! impl TransactionDetailsProvider for DummyTransactionDetailsProvider { -//! fn fetch_account(&self, _address: &Address) -> AccountDetails { -//! AccountDetails { -//! nonce: U256::from(10), -//! balance: U256::from(1_000_000) -//! } -//! } -//! -//! fn estimate_gas_required(&self, _tx: &SignedTransaction) -> U256 { -//! 2.into() -//! } -//! -//! fn is_service_transaction_acceptable(&self, _tx: &SignedTransaction) -> Result { -//! Ok(true) -//! } -//! } -//! -//! fn main() { -//! let key = Random.generate().unwrap(); -//! let t1 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), -//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(10) }; -//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), -//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) }; -//! -//! let st1 = t1.sign(&key.secret(), None); -//! let st2 = t2.sign(&key.secret(), None); -//! let details_provider = DummyTransactionDetailsProvider::default(); -//! -//! let mut txq = TransactionQueue::default(); -//! txq.add(st2.clone(), TransactionOrigin::External, 0, None, &details_provider).unwrap(); -//! txq.add(st1.clone(), TransactionOrigin::External, 0, None, &details_provider).unwrap(); -//! -//! // Check status -//! assert_eq!(txq.status().pending, 2); -//! // Check top transactions -//! let top = txq.top_transactions(); -//! assert_eq!(top.len(), 2); -//! assert_eq!(top[0], st1); -//! assert_eq!(top[1], st2); -//! -//! // And when transaction is removed (but nonce haven't changed) -//! // it will move subsequent transactions to future -//! txq.remove(&st1.hash(), &|_| 10.into(), RemovalReason::Invalid); -//! assert_eq!(txq.status().pending, 0); -//! assert_eq!(txq.status().future, 1); -//! assert_eq!(txq.top_transactions().len(), 0); -//! } -//! ``` -//! -//! # Maintaing valid state -//! -//! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling). -//! 2. Whenever invalid transaction is removed: -//! - When it's removed from `future` - all `future` transactions heights are recalculated and then -//! we check if the transactions should go to `current` (comparing state nonce) -//! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated. -//! 3. `cull` is used to inform the queue about client (state) nonce changes. -//! - It removes all transactions (either from `current` or `future`) with nonce < client nonce -//! - It moves matching `future` transactions to `current` -//! 4. `remove_old` is used as convenient method to update the state nonce for all senders in the queue. -//! - Invokes `cull` with latest state nonce for all senders. - -use std::cmp::Ordering; -use std::cmp; -use std::collections::{HashSet, HashMap, BTreeSet, BTreeMap}; -use std::ops::Deref; - -use ethereum_types::{H256, U256, Address}; -use heapsize::HeapSizeOf; -use linked_hash_map::LinkedHashMap; -use local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus}; -use table::Table; -use transaction::{self, SignedTransaction, PendingTransaction}; - -type BlockNumber = u64; - -/// Transaction origin -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum TransactionOrigin { - /// Transaction coming from local RPC - Local, - /// External transaction received from network - External, - /// Transactions from retracted blocks - RetractedBlock, -} - -impl PartialOrd for TransactionOrigin { - fn partial_cmp(&self, other: &TransactionOrigin) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TransactionOrigin { - fn cmp(&self, other: &TransactionOrigin) -> Ordering { - if *other == *self { - return Ordering::Equal; - } - - match (*self, *other) { - (TransactionOrigin::RetractedBlock, _) => Ordering::Less, - (_, TransactionOrigin::RetractedBlock) => Ordering::Greater, - (TransactionOrigin::Local, _) => Ordering::Less, - _ => Ordering::Greater, - } - } -} - -impl TransactionOrigin { - fn is_local(&self) -> bool { - *self == TransactionOrigin::Local - } -} - -#[derive(Clone, Debug)] -/// Light structure used to identify transaction and its order -struct TransactionOrder { - /// Primary ordering factory. Difference between transaction nonce and expected nonce in state - /// (e.g. Tx(nonce:5), State(nonce:0) -> height: 5) - /// High nonce_height = Low priority (processed later) - nonce_height: U256, - /// Gas Price of the transaction. - /// Low gas price = Low priority (processed later) - gas_price: U256, - /// Gas usage priority factor. Usage depends on strategy. - /// Represents the linear increment in required gas price for heavy transactions. - /// - /// High gas limit + Low gas price = Very Low priority - /// High gas limit + High gas price = High priority - gas_factor: U256, - /// Gas (limit) of the transaction. Usage depends on strategy. - /// Low gas limit = High priority (processed earlier) - gas: U256, - /// Heap usage of this transaction. - mem_usage: usize, - /// Transaction ordering strategy - strategy: PrioritizationStrategy, - /// Hash to identify associated transaction - hash: H256, - /// Incremental id assigned when transaction is inserted to the queue. - insertion_id: u64, - /// Origin of the transaction - origin: TransactionOrigin, - /// Penalties - penalties: usize, -} - - -impl TransactionOrder { - - fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256, min_gas_price: U256, strategy: PrioritizationStrategy) -> Self { - let factor = (tx.transaction.gas >> 15) * min_gas_price; - TransactionOrder { - nonce_height: tx.nonce() - base_nonce, - gas_price: tx.transaction.gas_price, - gas_factor: factor, - gas: tx.transaction.gas, - mem_usage: tx.transaction.heap_size_of_children(), - strategy: strategy, - hash: tx.hash(), - insertion_id: tx.insertion_id, - origin: tx.origin, - penalties: 0, - } - } - - fn update_height(mut self, nonce: U256, base_nonce: U256) -> Self { - self.nonce_height = nonce - base_nonce; - self - } - - fn penalize(mut self) -> Self { - self.penalties = self.penalties.saturating_add(1); - self - } -} - -impl Eq for TransactionOrder {} -impl PartialEq for TransactionOrder { - fn eq(&self, other: &TransactionOrder) -> bool { - self.cmp(other) == Ordering::Equal - } -} -impl PartialOrd for TransactionOrder { - fn partial_cmp(&self, other: &TransactionOrder) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TransactionOrder { - fn cmp(&self, b: &TransactionOrder) -> Ordering { - // First check number of penalties - if self.penalties != b.penalties { - return self.penalties.cmp(&b.penalties); - } - - // Local transactions should always have priority - if self.origin != b.origin { - return self.origin.cmp(&b.origin); - } - - // Check nonce_height - if self.nonce_height != b.nonce_height { - return self.nonce_height.cmp(&b.nonce_height); - } - - match self.strategy { - PrioritizationStrategy::GasAndGasPrice => { - if self.gas != b.gas { - return self.gas.cmp(&b.gas); - } - }, - PrioritizationStrategy::GasFactorAndGasPrice => { - // avoiding overflows - // (gp1 - g1) > (gp2 - g2) <=> - // (gp1 + g2) > (gp2 + g1) - let f_a = self.gas_price + b.gas_factor; - let f_b = b.gas_price + self.gas_factor; - if f_a != f_b { - return f_b.cmp(&f_a); - } - }, - PrioritizationStrategy::GasPriceOnly => {}, - } - - // Then compare gas_prices - if self.gas_price != b.gas_price { - return b.gas_price.cmp(&self.gas_price); - } - - // Lastly compare insertion_id - self.insertion_id.cmp(&b.insertion_id) - } -} - -/// Verified transaction -#[derive(Debug)] -struct VerifiedTransaction { - /// Transaction. - transaction: SignedTransaction, - /// Transaction origin. - origin: TransactionOrigin, - /// Delay until specified condition is met. - condition: Option, - /// Insertion time - insertion_time: QueuingInstant, - /// ID assigned upon insertion, should be unique. - insertion_id: u64, -} - -impl VerifiedTransaction { - fn new( - transaction: SignedTransaction, - origin: TransactionOrigin, - condition: Option, - insertion_time: QueuingInstant, - insertion_id: u64, - ) -> Self { - VerifiedTransaction { - transaction, - origin, - condition, - insertion_time, - insertion_id, - } - } - - fn hash(&self) -> H256 { - self.transaction.hash() - } - - fn nonce(&self) -> U256 { - self.transaction.nonce - } - - fn sender(&self) -> Address { - self.transaction.sender() - } - - fn cost(&self) -> U256 { - self.transaction.value + self.transaction.gas_price * self.transaction.gas - } -} - -#[derive(Debug, Default)] -struct GasPriceQueue { - backing: BTreeMap>, -} - -impl GasPriceQueue { - /// Insert an item into a BTreeMap/HashSet "multimap". - pub fn insert(&mut self, gas_price: U256, hash: H256) -> bool { - self.backing.entry(gas_price).or_insert_with(Default::default).insert(hash) - } - - /// Remove an item from a BTreeMap/HashSet "multimap". - /// Returns true if the item was removed successfully. - pub fn remove(&mut self, gas_price: &U256, hash: &H256) -> bool { - if let Some(hashes) = self.backing.get_mut(gas_price) { - let only_one_left = hashes.len() == 1; - if !only_one_left { - // Operation may be ok: only if hash is in gas-price's Set. - return hashes.remove(hash); - } - if hash != hashes.iter().next().expect("We know there is only one element in collection, tested above; qed") { - // Operation failed: hash not the single item in gas-price's Set. - return false; - } - } else { - // Operation failed: gas-price not found in Map. - return false; - } - // Operation maybe ok: only if hash not found in gas-price Set. - self.backing.remove(gas_price).is_some() - } -} - -impl Deref for GasPriceQueue { - type Target=BTreeMap>; - - fn deref(&self) -> &Self::Target { - &self.backing - } -} - -/// Holds transactions accessible by (address, nonce) and by priority -/// -/// `TransactionSet` keeps number of entries below limit, but it doesn't -/// automatically happen during `insert/remove` operations. -/// You have to call `enforce_limit` to remove lowest priority transactions from set. -struct TransactionSet { - by_priority: BTreeSet, - by_address: Table, - by_gas_price: GasPriceQueue, - limit: usize, - total_gas_limit: U256, - memory_limit: usize, -} - -impl TransactionSet { - /// Inserts `TransactionOrder` to this set. Transaction does not need to be unique - - /// the same transaction may be validly inserted twice. Any previous transaction that - /// it replaces (i.e. with the same `sender` and `nonce`) should be returned. - fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) -> Option { - if !self.by_priority.insert(order.clone()) { - return Some(order.clone()); - } - let order_hash = order.hash.clone(); - let order_gas_price = order.gas_price.clone(); - let by_address_replaced = self.by_address.insert(sender, nonce, order); - // If transaction was replaced remove it from priority queue - if let Some(ref old_order) = by_address_replaced { - assert!(self.by_priority.remove(old_order), "hash is in `by_address`; all transactions in `by_address` must be in `by_priority`; qed"); - assert!(self.by_gas_price.remove(&old_order.gas_price, &old_order.hash), - "hash is in `by_address`; all transactions' gas_prices in `by_address` must be in `by_gas_limit`; qed"); - } - self.by_gas_price.insert(order_gas_price, order_hash); - assert_eq!(self.by_priority.len(), self.by_address.len()); - assert_eq!(self.by_gas_price.values().map(|v| v.len()).fold(0, |a, b| a + b), self.by_address.len()); - by_address_replaced - } - - /// Remove low priority transactions if there is more than specified by given `limit`. - /// - /// It drops transactions from this set but also removes associated `VerifiedTransaction`. - /// Returns addresses and lowest nonces of transactions removed because of limit. - fn enforce_limit(&mut self, by_hash: &mut HashMap, local: &mut LocalTransactionsList) -> Option> { - let mut count = 0; - let mut mem_usage = 0; - let mut gas: U256 = 0.into(); - let to_drop : Vec<(Address, U256)> = { - self.by_priority - .iter() - .filter(|order| { - // update transaction count and mem usage - count += 1; - mem_usage += order.mem_usage; - - // calculate current gas usage - let r = gas.overflowing_add(order.gas); - if r.1 { return false } - gas = r.0; - - let is_own_or_retracted = order.origin.is_local() || order.origin == TransactionOrigin::RetractedBlock; - // Own and retracted transactions are allowed to go above all limits. - !is_own_or_retracted && (mem_usage > self.memory_limit || count > self.limit || gas > self.total_gas_limit) - }) - .map(|order| by_hash.get(&order.hash) - .expect("All transactions in `self.by_priority` and `self.by_address` are kept in sync with `by_hash`.")) - .map(|tx| (tx.sender(), tx.nonce())) - .collect() - }; - - Some(to_drop.into_iter() - .fold(HashMap::new(), |mut removed, (sender, nonce)| { - let order = self.drop(&sender, &nonce) - .expect("Transaction has just been found in `by_priority`; so it is in `by_address` also."); - trace!(target: "txqueue", "Dropped out of limit transaction: {:?}", order.hash); - - let order = by_hash.remove(&order.hash) - .expect("hash is in `by_priorty`; all hashes in `by_priority` must be in `by_hash`; qed"); - - if order.origin.is_local() { - local.mark_dropped(order.transaction); - } - - let min = removed.get(&sender).map_or(nonce, |val| cmp::min(*val, nonce)); - removed.insert(sender, min); - removed - })) - } - - /// Drop transaction from this set (remove from `by_priority` and `by_address`) - fn drop(&mut self, sender: &Address, nonce: &U256) -> Option { - if let Some(tx_order) = self.by_address.remove(sender, nonce) { - assert!(self.by_gas_price.remove(&tx_order.gas_price, &tx_order.hash), - "hash is in `by_address`; all transactions' gas_prices in `by_address` must be in `by_gas_limit`; qed"); - assert!(self.by_priority.remove(&tx_order), - "hash is in `by_address`; all transactions' gas_prices in `by_address` must be in `by_priority`; qed"); - assert_eq!(self.by_priority.len(), self.by_address.len()); - assert_eq!(self.by_gas_price.values().map(|v| v.len()).fold(0, |a, b| a + b), self.by_address.len()); - return Some(tx_order); - } - assert_eq!(self.by_priority.len(), self.by_address.len()); - assert_eq!(self.by_gas_price.values().map(|v| v.len()).fold(0, |a, b| a + b), self.by_address.len()); - None - } - - /// Drop all transactions. - fn clear(&mut self) { - self.by_priority.clear(); - self.by_address.clear(); - self.by_gas_price.backing.clear(); - } - - /// Sets new limit for number of transactions in this `TransactionSet`. - /// Note the limit is not applied (no transactions are removed) by calling this method. - fn set_limit(&mut self, limit: usize) { - self.limit = limit; - } - - /// Get the minimum gas price that we can accept into this queue that wouldn't cause the transaction to - /// immediately be dropped. 0 if the queue isn't at capacity; 1 plus the lowest if it is. - fn gas_price_entry_limit(&self) -> U256 { - match self.by_gas_price.keys().next() { - Some(k) if self.by_priority.len() >= self.limit => *k + 1.into(), - _ => U256::default(), - } - } -} - -#[derive(Debug)] -/// Current status of the queue -pub struct TransactionQueueStatus { - /// Number of pending transactions (ready to go to block) - pub pending: usize, - /// Number of future transactions (waiting for transactions with lower nonces first) - pub future: usize, -} - -/// Details of account -pub struct AccountDetails { - /// Most recent account nonce - pub nonce: U256, - /// Current account balance - pub balance: U256, -} - -/// Transaction with the same (sender, nonce) can be replaced only if -/// `new_gas_price > old_gas_price + old_gas_price >> SHIFT` -const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25% - -/// Describes the strategy used to prioritize transactions in the queue. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum PrioritizationStrategy { - /// Use only gas price. Disregards the actual computation cost of the transaction. - /// i.e. Higher gas price = Higher priority - GasPriceOnly, - /// Use gas limit and then gas price. - /// i.e. Higher gas limit = Lower priority - GasAndGasPrice, - /// Calculate and use priority based on gas and gas price. - /// PRIORITY = GAS_PRICE - GAS/2^15 * MIN_GAS_PRICE - /// - /// Rationale: - /// Heavy transactions are paying linear cost (GAS * GAS_PRICE) - /// while the computation might be more expensive. - /// - /// i.e. - /// 1M gas tx with `gas_price=30*min` has the same priority - /// as 32k gas tx with `gas_price=min` - GasFactorAndGasPrice, -} - -/// Reason to remove single transaction from the queue. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum RemovalReason { - /// Transaction is invalid - Invalid, - /// Transaction was canceled - Canceled, - /// Transaction is not allowed, - NotAllowed, -} - -/// Point in time when transaction was inserted. -pub type QueuingInstant = BlockNumber; -const DEFAULT_QUEUING_PERIOD: BlockNumber = 128; - -/// `TransactionQueue` transaction details provider. -pub trait TransactionDetailsProvider { - /// Fetch transaction-related account details. - fn fetch_account(&self, address: &Address) -> AccountDetails; - /// Estimate gas required for transaction. - fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256; - /// Check if this service transaction can be accepted by `TransactionQueue`. - fn is_service_transaction_acceptable(&self, tx: &SignedTransaction) -> Result; -} - -/// `TransactionQueue` implementation -pub struct TransactionQueue { - /// Prioritization strategy for this queue - strategy: PrioritizationStrategy, - /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) - minimal_gas_price: U256, - /// The maximum amount of gas any individual transaction may use. - tx_gas_limit: U256, - /// Current gas limit (block gas limit). Transactions above the limit will not be accepted (default to !0) - block_gas_limit: U256, - /// Maximal time transaction may occupy the queue. - /// When we reach `max_time_in_queue / 2^3` we re-validate - /// account balance. - max_time_in_queue: QueuingInstant, - /// Priority queue for transactions that can go to block - current: TransactionSet, - /// Priority queue for transactions that has been received but are not yet valid to go to block - future: TransactionSet, - /// All transactions managed by queue indexed by hash - by_hash: HashMap, - /// Last nonce of transaction in current (to quickly check next expected transaction) - last_nonces: HashMap, - /// List of local transactions and their statuses. - local_transactions: LocalTransactionsList, - /// Next id that should be assigned to a transaction imported to the queue. - next_transaction_id: u64, -} - -impl Default for TransactionQueue { - fn default() -> Self { - TransactionQueue::new(PrioritizationStrategy::GasPriceOnly) - } -} - -impl TransactionQueue { - /// Creates new instance of this Queue - pub fn new(strategy: PrioritizationStrategy) -> Self { - Self::with_limits(strategy, 8192, usize::max_value(), !U256::zero(), !U256::zero()) - } - - /// Create new instance of this Queue with specified limits - pub fn with_limits( - strategy: PrioritizationStrategy, - limit: usize, - memory_limit: usize, - total_gas_limit: U256, - tx_gas_limit: U256, - ) -> Self { - let current = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit, - total_gas_limit, - memory_limit, - }; - - let future = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - total_gas_limit, - limit, - memory_limit, - }; - - TransactionQueue { - strategy, - minimal_gas_price: U256::zero(), - block_gas_limit: !U256::zero(), - tx_gas_limit, - max_time_in_queue: DEFAULT_QUEUING_PERIOD, - current, - future, - by_hash: HashMap::new(), - last_nonces: HashMap::new(), - local_transactions: LocalTransactionsList::default(), - next_transaction_id: 0, - } - } - - /// Set the new limit for `current` and `future` queue. - pub fn set_limit(&mut self, limit: usize) { - self.current.set_limit(limit); - self.future.set_limit(limit); - // And ensure the limits - self.current.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - } - - /// Returns current limit of transactions in the queue. - pub fn limit(&self) -> usize { - self.current.limit - } - - /// Get the minimal gas price. - pub fn minimal_gas_price(&self) -> &U256 { - &self.minimal_gas_price - } - - /// Sets new gas price threshold for incoming transactions. - /// Any transaction already imported to the queue is not affected. - pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) { - self.minimal_gas_price = min_gas_price; - } - - /// Get one more than the lowest gas price in the queue iff the pool is - /// full, otherwise 0. - pub fn effective_minimum_gas_price(&self) -> U256 { - self.current.gas_price_entry_limit() - } - - /// Sets new gas limit. Transactions with gas over the limit will not be accepted. - /// Any transaction already imported to the queue is not affected. - pub fn set_gas_limit(&mut self, gas_limit: U256) { - self.block_gas_limit = gas_limit; - } - - /// Sets new total gas limit. - pub fn set_total_gas_limit(&mut self, total_gas_limit: U256) { - self.current.total_gas_limit = total_gas_limit; - self.future.total_gas_limit = total_gas_limit; - self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - } - - /// Set the new limit for the amount of gas any individual transaction may have. - /// Any transaction already imported to the queue is not affected. - pub fn set_tx_gas_limit(&mut self, limit: U256) { - self.tx_gas_limit = limit; - } - - /// Returns current status for this queue - pub fn status(&self) -> TransactionQueueStatus { - TransactionQueueStatus { - pending: self.current.by_priority.len(), - future: self.future.by_priority.len(), - } - } - - /// Add signed transaction to queue to be verified and imported. - /// - /// NOTE details_provider methods should be cheap to compute - /// otherwise it might open up an attack vector. - pub fn add( - &mut self, - tx: SignedTransaction, - origin: TransactionOrigin, - time: QueuingInstant, - condition: Option, - details_provider: &TransactionDetailsProvider, - ) -> Result { - if origin == TransactionOrigin::Local { - let hash = tx.hash(); - let cloned_tx = tx.clone(); - - let result = self.add_internal(tx, origin, time, condition, details_provider); - match result { - Ok(transaction::ImportResult::Current) => { - self.local_transactions.mark_pending(hash); - }, - Ok(transaction::ImportResult::Future) => { - self.local_transactions.mark_future(hash); - }, - Err(ref err) => { - // Sometimes transactions are re-imported, so - // don't overwrite transactions if they are already on the list - if !self.local_transactions.contains(&hash) { - self.local_transactions.mark_rejected(cloned_tx, err.clone()); - } - }, - } - result - } else { - self.add_internal(tx, origin, time, condition, details_provider) - } - } - - /// Adds signed transaction to the queue. - fn add_internal( - &mut self, - tx: SignedTransaction, - origin: TransactionOrigin, - time: QueuingInstant, - condition: Option, - details_provider: &TransactionDetailsProvider, - ) -> Result { - if origin != TransactionOrigin::Local && tx.gas_price < self.minimal_gas_price { - // if it is non-service-transaction => drop - let is_service_transaction = tx.gas_price.is_zero(); - if !is_service_transaction { - trace!(target: "txqueue", - "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", - tx.hash(), - tx.gas_price, - self.minimal_gas_price - ); - - return Err(transaction::Error::InsufficientGasPrice { - minimal: self.minimal_gas_price, - got: tx.gas_price, - }); - } - - let is_service_transaction_accepted = match details_provider.is_service_transaction_acceptable(&tx) { - Ok(true) => true, - Ok(false) => { - trace!(target: "txqueue", - "Dropping service transaction as sender is not certified to send service transactions: {:?} (sender: {:?})", - tx.hash(), - tx.sender(), - ); - - false - }, - Err(contract_err) => { - trace!(target: "txqueue", - "Dropping service transaction as service contract returned error: {:?} (error: {:?})", - tx.hash(), - contract_err, - ); - - false - }, - }; - - if !is_service_transaction_accepted { - return Err(transaction::Error::InsufficientGasPrice { - minimal: self.minimal_gas_price, - got: tx.gas_price, - }); - } - } - - let full_queues_lowest = self.effective_minimum_gas_price(); - if tx.gas_price < full_queues_lowest && origin != TransactionOrigin::Local { - trace!(target: "txqueue", - "Dropping transaction below lowest gas price in a full queue: {:?} (gp: {} < {})", - tx.hash(), - tx.gas_price, - full_queues_lowest - ); - - return Err(transaction::Error::InsufficientGasPrice { - minimal: full_queues_lowest, - got: tx.gas_price, - }); - } - - let gas_limit = cmp::min(self.tx_gas_limit, self.block_gas_limit); - if tx.gas > gas_limit { - trace!(target: "txqueue", - "Dropping transaction above gas limit: {:?} ({} > min({}, {}))", - tx.hash(), - tx.gas, - self.block_gas_limit, - self.tx_gas_limit - ); - return Err(transaction::Error::GasLimitExceeded { - limit: gas_limit, - got: tx.gas, - }); - } - - let minimal_gas = details_provider.estimate_gas_required(&tx); - if tx.gas < minimal_gas { - trace!(target: "txqueue", - "Dropping transaction with insufficient gas: {:?} ({} > {})", - tx.hash(), - tx.gas, - minimal_gas, - ); - - return Err(transaction::Error::InsufficientGas { - minimal: minimal_gas, - got: tx.gas, - }); - } - - let client_account = details_provider.fetch_account(&tx.sender()); - let cost = tx.value + tx.gas_price * tx.gas; - if client_account.balance < cost { - trace!(target: "txqueue", - "Dropping transaction without sufficient balance: {:?} ({} < {})", - tx.hash(), - client_account.balance, - cost - ); - - return Err(transaction::Error::InsufficientBalance { - cost: cost, - balance: client_account.balance - }); - } - tx.check_low_s()?; - // No invalid transactions beyond this point. - let id = self.next_transaction_id; - self.next_transaction_id += 1; - let vtx = VerifiedTransaction::new(tx, origin, condition, time, id); - let r = self.import_tx(vtx, client_account.nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - r - } - - /// Removes all transactions from particular sender up to (excluding) given client (state) nonce. - /// Client (State) Nonce = next valid nonce for this sender. - pub fn cull(&mut self, sender: Address, client_nonce: U256) { - // Check if there is anything in current... - let should_check_in_current = self.current.by_address.row(&sender) - // If nonce == client_nonce nothing is changed - .and_then(|by_nonce| by_nonce.keys().find(|nonce| *nonce < &client_nonce)) - .map(|_| ()); - // ... or future - let should_check_in_future = self.future.by_address.row(&sender) - // if nonce == client_nonce we need to promote to current - .and_then(|by_nonce| by_nonce.keys().find(|nonce| *nonce <= &client_nonce)) - .map(|_| ()); - - if should_check_in_current.or(should_check_in_future).is_none() { - return; - } - - self.cull_internal(sender, client_nonce); - } - - /// Always updates future and moves transactions from current to future. - fn cull_internal(&mut self, sender: Address, client_nonce: U256) { - // We will either move transaction to future or remove it completely - // so there will be no transactions from this sender in current - self.last_nonces.remove(&sender); - // First update height of transactions in future to avoid collisions - self.update_future(&sender, client_nonce); - // This should move all current transactions to future and remove old transactions - self.move_all_to_future(&sender, client_nonce); - // And now lets check if there is some batch of transactions in future - // that should be placed in current. It should also update last_nonces. - self.move_matching_future_to_current(sender, client_nonce, client_nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - } - - /// Checks the current nonce for all transactions' senders in the queue and removes the old transactions. - pub fn remove_old(&mut self, fetch_account: &F, current_time: QueuingInstant) where - F: Fn(&Address) -> AccountDetails, - { - let senders = self.current.by_address.keys() - .chain(self.future.by_address.keys()) - .map(|sender| (*sender, fetch_account(sender))) - .collect::>(); - - for (sender, details) in senders.iter() { - self.cull(*sender, details.nonce); - } - - let max_time = self.max_time_in_queue; - let balance_check = max_time >> 3; - // Clear transactions occupying the queue too long - let invalid = self.by_hash.iter() - .filter(|&(_, ref tx)| !tx.origin.is_local()) - .map(|(hash, tx)| (hash, tx, current_time.saturating_sub(tx.insertion_time))) - .filter_map(|(hash, tx, time_diff)| { - if time_diff > max_time { - return Some(*hash); - } - - if time_diff > balance_check { - return match senders.get(&tx.sender()) { - Some(details) if tx.cost() > details.balance => { - Some(*hash) - }, - _ => None, - }; - } - - None - }) - .collect::>(); - let fetch_nonce = |a: &Address| senders.get(a) - .expect("We fetch details for all senders from both current and future") - .nonce; - for hash in invalid { - self.remove(&hash, &fetch_nonce, RemovalReason::Invalid); - } - } - - /// Penalize transactions from sender of transaction with given hash. - /// I.e. it should change the priority of the transaction in the queue. - /// - /// NOTE: We need to penalize all transactions from particular sender - /// to avoid breaking invariants in queue (ordered by nonces). - /// Consecutive transactions from this sender would fail otherwise (because of invalid nonce). - pub fn penalize(&mut self, transaction_hash: &H256) { - let transaction = match self.by_hash.get(transaction_hash) { - None => return, - Some(t) => t, - }; - - // Never penalize local transactions - if transaction.origin.is_local() { - return; - } - - let sender = transaction.sender(); - - // Penalize all transactions from this sender - let nonces_from_sender = match self.current.by_address.row(&sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - for k in nonces_from_sender { - let order = self.current.drop(&sender, &k).expect("transaction known to be in self.current; qed"); - self.current.insert(sender, k, order.penalize()); - } - // Same thing for future - let nonces_from_sender = match self.future.by_address.row(&sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - for k in nonces_from_sender { - let order = self.future.drop(&sender, &k).expect("transaction known to be in self.future; qed"); - self.future.insert(sender, k, order.penalize()); - } - } - - /// Removes invalid transaction identified by hash from queue. - /// Assumption is that this transaction nonce is not related to client nonce, - /// so transactions left in queue are processed according to client nonce. - /// - /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &F, reason: RemovalReason) - where F: Fn(&Address) -> U256 { - - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - let transaction = self.by_hash.remove(transaction_hash); - if transaction.is_none() { - // We don't know this transaction - return; - } - - let transaction = transaction.expect("None is tested in early-exit condition above; qed"); - let sender = transaction.sender(); - let nonce = transaction.nonce(); - let current_nonce = fetch_nonce(&sender); - - trace!(target: "txqueue", "Removing invalid transaction: {:?}", transaction.hash()); - - // Mark in locals - if self.local_transactions.contains(transaction_hash) { - match reason { - RemovalReason::Invalid => self.local_transactions.mark_invalid( - transaction.transaction.into() - ), - RemovalReason::NotAllowed => self.local_transactions.mark_invalid( - transaction.transaction.into() - ), - RemovalReason::Canceled => self.local_transactions.mark_canceled( - PendingTransaction::new(transaction.transaction, transaction.condition) - ), - } - } - - // Remove from future - let order = self.future.drop(&sender, &nonce); - if order.is_some() { - self.update_future(&sender, current_nonce); - // And now lets check if there is some chain of transactions in future - // that should be placed in current - self.move_matching_future_to_current(sender, current_nonce, current_nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - return; - } - - // Remove from current - let order = self.current.drop(&sender, &nonce); - if order.is_some() { - // This will keep consistency in queue - // Moves all to future and then promotes a batch from current: - self.cull_internal(sender, current_nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - return; - } - } - - /// Marks all transactions from particular sender as local transactions - fn mark_transactions_local(&mut self, sender: &Address) { - fn mark_local(sender: &Address, set: &mut TransactionSet, mut mark: F) { - // Mark all transactions from this sender as local - let nonces_from_sender = set.by_address.row(sender) - .map(|row_map| { - row_map.iter().filter_map(|(nonce, order)| if order.origin.is_local() { - None - } else { - Some(*nonce) - }).collect::>() - }) - .unwrap_or_else(Vec::new); - - for k in nonces_from_sender { - let mut order = set.drop(sender, &k).expect("transaction known to be in self.current/self.future; qed"); - order.origin = TransactionOrigin::Local; - mark(order.hash); - set.insert(*sender, k, order); - } - } - - let local = &mut self.local_transactions; - mark_local(sender, &mut self.current, |hash| local.mark_pending(hash)); - mark_local(sender, &mut self.future, |hash| local.mark_future(hash)); - } - - /// Update height of all transactions in future transactions set. - fn update_future(&mut self, sender: &Address, current_nonce: U256) { - // We need to drain all transactions for current sender from future and reinsert them with updated height - let all_nonces_from_sender = match self.future.by_address.row(sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - for k in all_nonces_from_sender { - let order = self.future.drop(sender, &k).expect("iterating over a collection that has been retrieved above; qed"); - if k >= current_nonce { - self.future.insert(*sender, k, order.update_height(k, current_nonce)); - } else { - trace!(target: "txqueue", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); - // Remove the transaction completely - self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`"); - } - } - } - - /// Drop all transactions from given sender from `current`. - /// Either moves them to `future` or removes them from queue completely. - fn move_all_to_future(&mut self, sender: &Address, current_nonce: U256) { - let all_nonces_from_sender = match self.current.by_address.row(sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - - for k in all_nonces_from_sender { - // Goes to future or is removed - let order = self.current.drop(sender, &k).expect("iterating over a collection that has been retrieved above; - qed"); - if k >= current_nonce { - let order = order.update_height(k, current_nonce); - if order.origin.is_local() { - self.local_transactions.mark_future(order.hash); - } - if let Some(old) = self.future.insert(*sender, k, order.clone()) { - Self::replace_orders(*sender, k, old, order, &mut self.future, &mut self.by_hash, &mut self.local_transactions); - } - } else { - trace!(target: "txqueue", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); - let tx = self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`"); - if tx.origin.is_local() { - self.local_transactions.mark_mined(tx.transaction); - } - } - } - self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - } - - /// Returns top transactions from the queue ordered by priority. - pub fn top_transactions(&self) -> Vec { - self.top_transactions_at(BlockNumber::max_value(), u64::max_value(), None) - - } - - fn filter_pending_transaction(&self, best_block: BlockNumber, best_timestamp: u64, nonce_cap: Option, mut f: F) - where F: FnMut(&VerifiedTransaction) { - - let mut delayed = HashSet::new(); - for t in self.current.by_priority.iter() { - let tx = self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"); - let sender = tx.sender(); - if delayed.contains(&sender) { - continue; - } - if let Some(max_nonce) = nonce_cap { - if tx.nonce() >= max_nonce { - continue; - } - } - let delay = match tx.condition { - Some(transaction::Condition::Number(n)) => n > best_block, - Some(transaction::Condition::Timestamp(t)) => t > best_timestamp, - None => false, - }; - if delay { - delayed.insert(sender); - continue; - } - f(&tx); - } - } - - /// Returns top transactions from the queue ordered by priority. - pub fn top_transactions_at(&self, best_block: BlockNumber, best_timestamp: u64, nonce_cap: Option) -> Vec { - let mut r = Vec::new(); - self.filter_pending_transaction(best_block, best_timestamp, nonce_cap, |tx| r.push(tx.transaction.clone())); - r - } - - /// Return all ready transactions. - pub fn pending_transactions(&self, best_block: BlockNumber, best_timestamp: u64) -> Vec { - let mut r = Vec::new(); - self.filter_pending_transaction(best_block, best_timestamp, None, |tx| r.push(PendingTransaction::new(tx.transaction.clone(), tx.condition.clone()))); - r - } - - /// Return all future transactions. - pub fn future_transactions(&self) -> Vec { - self.future.by_priority - .iter() - .map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`")) - .map(|t| PendingTransaction { transaction: t.transaction.clone(), condition: t.condition.clone() }) - .collect() - } - - /// Returns local transactions (some of them might not be part of the queue anymore). - pub fn local_transactions(&self) -> &LinkedHashMap { - self.local_transactions.all_transactions() - } - - /// Returns hashes of all transactions from current, ordered by priority. - pub fn pending_hashes(&self) -> Vec { - self.current.by_priority - .iter() - .map(|t| t.hash) - .collect() - } - - /// Returns true if there is at least one local transaction pending - pub fn has_local_pending_transactions(&self) -> bool { - self.current.by_priority.iter().any(|tx| tx.origin == TransactionOrigin::Local) - } - - /// Finds transaction in the queue by hash (if any) - pub fn find(&self, hash: &H256) -> Option { - self.by_hash.get(hash).map(|tx| PendingTransaction { transaction: tx.transaction.clone(), condition: tx.condition.clone() }) - } - - /// Removes all elements (in any state) from the queue - pub fn clear(&mut self) { - self.current.clear(); - self.future.clear(); - self.by_hash.clear(); - self.last_nonces.clear(); - } - - /// Returns highest transaction nonce for given address. - pub fn last_nonce(&self, address: &Address) -> Option { - self.last_nonces.get(address).cloned() - } - - /// Checks if there are any transactions in `future` that should actually be promoted to `current` - /// (because nonce matches). - fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { - let mut update_last_nonce_to = None; - { - let by_nonce = self.future.by_address.row_mut(&address); - if by_nonce.is_none() { - return; - } - let by_nonce = by_nonce.expect("None is tested in early-exit condition above; qed"); - while let Some(order) = by_nonce.remove(¤t_nonce) { - // remove also from priority and gas_price - self.future.by_priority.remove(&order); - self.future.by_gas_price.remove(&order.gas_price, &order.hash); - // Put to current - let order = order.update_height(current_nonce, first_nonce); - if order.origin.is_local() { - self.local_transactions.mark_pending(order.hash); - } - if let Some(old) = self.current.insert(address, current_nonce, order.clone()) { - Self::replace_orders(address, current_nonce, old, order, &mut self.current, &mut self.by_hash, &mut self.local_transactions); - } - update_last_nonce_to = Some(current_nonce); - current_nonce = current_nonce + U256::one(); - } - } - self.future.by_address.clear_if_empty(&address); - if let Some(x) = update_last_nonce_to { - // Update last inserted nonce - self.last_nonces.insert(address, x); - } - } - - /// Adds VerifiedTransaction to this queue. - /// - /// Determines if it should be placed in current or future. When transaction is - /// imported to `current` also checks if there are any `future` transactions that should be promoted because of - /// this. - /// - /// It ignores transactions that has already been imported (same `hash`) and replaces the transaction - /// iff `(address, nonce)` is the same but `gas_price` is higher. - /// - /// Returns `true` when transaction was imported successfuly - fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) -> Result { - - if self.by_hash.get(&tx.hash()).is_some() { - // Transaction is already imported. - trace!(target: "txqueue", "Dropping already imported transaction: {:?}", tx.hash()); - return Err(transaction::Error::AlreadyImported); - } - - let min_gas_price = (self.minimal_gas_price, self.strategy); - let address = tx.sender(); - let nonce = tx.nonce(); - let hash = tx.hash(); - - // The transaction might be old, let's check that. - // This has to be the first test, otherwise calculating - // nonce height would result in overflow. - if nonce < state_nonce { - // Droping transaction - trace!(target: "txqueue", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, state_nonce); - return Err(transaction::Error::Old); - } - - // Update nonces of transactions in future (remove old transactions) - self.update_future(&address, state_nonce); - // State nonce could be updated. Maybe there are some more items waiting in future? - self.move_matching_future_to_current(address, state_nonce, state_nonce); - // Check the next expected nonce (might be updated by move above) - let next_nonce = self.last_nonces - .get(&address) - .cloned() - .map_or(state_nonce, |n| n + U256::one()); - - if tx.origin.is_local() { - self.mark_transactions_local(&address); - } - - // Future transaction - if nonce > next_nonce { - // We have a gap - put to future. - // Insert transaction (or replace old one with lower gas price) - check_too_cheap( - Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.future, &mut self.by_hash, &mut self.local_transactions) - )?; - // Enforce limit in Future - let removed = self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - // Return an error if this transaction was not imported because of limit. - check_if_removed(&address, &nonce, removed)?; - - debug!(target: "txqueue", "Importing transaction to future: {:?}", hash); - debug!(target: "txqueue", "status: {:?}", self.status()); - return Ok(transaction::ImportResult::Future); - } - - // We might have filled a gap - move some more transactions from future - self.move_matching_future_to_current(address, nonce, state_nonce); - self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); - - // Replace transaction if any - check_too_cheap( - Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.current, &mut self.by_hash, &mut self.local_transactions) - )?; - // Keep track of highest nonce stored in current - let new_max = self.last_nonces.get(&address).map_or(nonce, |n| cmp::max(nonce, *n)); - self.last_nonces.insert(address, new_max); - - // Also enforce the limit - let removed = self.current.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - // If some transaction were removed because of limit we need to update last_nonces also. - self.update_last_nonces(&removed); - // Trigger error if the transaction we are importing was removed. - check_if_removed(&address, &nonce, removed)?; - - debug!(target: "txqueue", "Imported transaction to current: {:?}", hash); - debug!(target: "txqueue", "status: {:?}", self.status()); - Ok(transaction::ImportResult::Current) - } - - /// Updates - fn update_last_nonces(&mut self, removed_min_nonces: &Option>) { - if let Some(ref min_nonces) = *removed_min_nonces { - for (sender, nonce) in min_nonces.iter() { - if *nonce == U256::zero() { - self.last_nonces.remove(sender); - } else { - self.last_nonces.insert(*sender, *nonce - U256::one()); - } - } - } - } - - /// Replaces transaction in given set (could be `future` or `current`). - /// - /// If there is already transaction with same `(sender, nonce)` it will be replaced iff `gas_price` is higher. - /// One of the transactions is dropped from set and also removed from queue entirely (from `by_hash`). - /// - /// Returns `true` if transaction actually got to the queue (`false` if there was already a transaction with higher - /// gas_price) - fn replace_transaction( - tx: VerifiedTransaction, - base_nonce: U256, - min_gas_price: (U256, PrioritizationStrategy), - set: &mut TransactionSet, - by_hash: &mut HashMap, - local: &mut LocalTransactionsList, - ) -> bool { - let order = TransactionOrder::for_transaction(&tx, base_nonce, min_gas_price.0, min_gas_price.1); - let hash = tx.hash(); - let address = tx.sender(); - let nonce = tx.nonce(); - - let old_hash = by_hash.insert(hash, tx); - assert!(old_hash.is_none(), "Each hash has to be inserted exactly once."); - - trace!(target: "txqueue", "Inserting: {:?}", order); - - if let Some(old) = set.insert(address, nonce, order.clone()) { - Self::replace_orders(address, nonce, old, order, set, by_hash, local) - } else { - true - } - } - - fn replace_orders( - address: Address, - nonce: U256, - old: TransactionOrder, - order: TransactionOrder, - set: &mut TransactionSet, - by_hash: &mut HashMap, - local: &mut LocalTransactionsList, - ) -> bool { - // There was already transaction in queue. Let's check which one should stay - let old_hash = old.hash; - let new_hash = order.hash; - - let old_gas_price = old.gas_price; - let new_gas_price = order.gas_price; - let min_required_gas_price = old_gas_price + (old_gas_price >> GAS_PRICE_BUMP_SHIFT); - - if min_required_gas_price > new_gas_price { - trace!(target: "txqueue", "Didn't insert transaction because gas price was too low: {:?} ({:?} stays in the queue)", order.hash, old.hash); - // Put back old transaction since it has greater priority (higher gas_price) - set.insert(address, nonce, old); - // and remove new one - let order = by_hash.remove(&order.hash).expect("The hash has been just inserted and no other line is altering `by_hash`."); - if order.origin.is_local() { - local.mark_replaced(order.transaction, old_gas_price, old_hash); - } - false - } else { - trace!(target: "txqueue", "Replaced transaction: {:?} with transaction with higher gas price: {:?}", old.hash, order.hash); - // Make sure we remove old transaction entirely - let old = by_hash.remove(&old.hash).expect("The hash is coming from `future` so it has to be in `by_hash`."); - if old.origin.is_local() { - local.mark_replaced(old.transaction, new_gas_price, new_hash); - } - true - } - } -} - -fn check_too_cheap(is_in: bool) -> Result<(), transaction::Error> { - if is_in { - Ok(()) - } else { - Err(transaction::Error::TooCheapToReplace) - } -} - -fn check_if_removed(sender: &Address, nonce: &U256, dropped: Option>) -> Result<(), - transaction::Error> { - match dropped { - Some(ref dropped) => match dropped.get(sender) { - Some(min) if nonce >= min => { - Err(transaction::Error::LimitReached) - }, - _ => Ok(()), - }, - _ => Ok(()), - } -} - - -#[cfg(test)] -pub mod test { - use ethereum_types::{U256, Address}; - use super::*; - use ethkey::{Random, Generator}; - use rustc_hex::FromHex; - use transaction::Transaction; - - pub struct DummyTransactionDetailsProvider { - account_details: AccountDetails, - gas_required: U256, - service_transactions_check_result: Result, - } - - impl Default for DummyTransactionDetailsProvider { - fn default() -> Self { - DummyTransactionDetailsProvider { - account_details: default_account_details(), - gas_required: U256::zero(), - service_transactions_check_result: Ok(false), - } - } - } - - impl DummyTransactionDetailsProvider { - pub fn with_account(mut self, account_details: AccountDetails) -> Self { - self.account_details = account_details; - self - } - - pub fn with_account_nonce(mut self, nonce: U256) -> Self { - self.account_details.nonce = nonce; - self - } - - pub fn with_tx_gas_required(mut self, gas_required: U256) -> Self { - self.gas_required = gas_required; - self - } - - pub fn service_transaction_checker_returns_error(mut self, error: &str) -> Self { - self.service_transactions_check_result = Err(error.to_owned()); - self - } - - pub fn service_transaction_checker_accepts(mut self, accepts: bool) -> Self { - self.service_transactions_check_result = Ok(accepts); - self - } - } - - impl TransactionDetailsProvider for DummyTransactionDetailsProvider { - fn fetch_account(&self, _address: &Address) -> AccountDetails { - AccountDetails { - nonce: self.account_details.nonce, - balance: self.account_details.balance, - } - } - - fn estimate_gas_required(&self, _tx: &SignedTransaction) -> U256 { - self.gas_required - } - - fn is_service_transaction_acceptable(&self, _tx: &SignedTransaction) -> Result { - self.service_transactions_check_result.clone() - } - } - - fn unwrap_tx_err(err: Result) -> transaction::Error { - err.unwrap_err() - } - - fn default_nonce() -> U256 { 123.into() } - fn default_gas_val() -> U256 { 100_000.into() } - fn default_gas_price() -> U256 { 1.into() } - - fn new_unsigned_tx(nonce: U256, gas: U256, gas_price: U256) -> Transaction { - Transaction { - action: transaction::Action::Create, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: gas, - gas_price: gas_price, - nonce: nonce - } - } - - fn new_tx(nonce: U256, gas_price: U256) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret(), None) - } - - fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret(), None) - } - - fn new_tx_default() -> SignedTransaction { - new_tx(default_nonce(), default_gas_price()) - } - - fn default_account_details() -> AccountDetails { - AccountDetails { - nonce: default_nonce(), - balance: !U256::zero() - } - } - - fn default_account_details_for_addr(_a: &Address) -> AccountDetails { - default_account_details() - } - - fn default_tx_provider() -> DummyTransactionDetailsProvider { - DummyTransactionDetailsProvider::default() - } - - fn new_tx_pair(nonce: U256, gas_price: U256, nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { - let tx1 = new_unsigned_tx(nonce, default_gas_val(), gas_price); - let tx2 = new_unsigned_tx(nonce + nonce_increment, default_gas_val(), gas_price + gas_price_increment); - - let keypair = Random.generate().unwrap(); - let secret = &keypair.secret(); - (tx1.sign(secret, None).into(), tx2.sign(secret, None).into()) - } - - /// Returns two consecutive transactions, both with increased gas price - fn new_tx_pair_with_gas_price_increment(gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { - let gas = default_gas_price() + gas_price_increment; - let tx1 = new_unsigned_tx(default_nonce(), default_gas_val(), gas); - let tx2 = new_unsigned_tx(default_nonce() + 1.into(), default_gas_val(), gas); - - let keypair = Random.generate().unwrap(); - let secret = &keypair.secret(); - (tx1.sign(secret, None).into(), tx2.sign(secret, None).into()) - } - - fn new_tx_pair_default(nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { - new_tx_pair(default_nonce(), default_gas_price(), nonce_increment, gas_price_increment) - } - - /// Returns two transactions with identical (sender, nonce) but different gas price/hash. - fn new_similar_tx_pair() -> (SignedTransaction, SignedTransaction) { - new_tx_pair_default(0.into(), 1.into()) - } - - #[test] - fn test_ordering() { - assert_eq!(TransactionOrigin::Local.cmp(&TransactionOrigin::External), Ordering::Less); - assert_eq!(TransactionOrigin::RetractedBlock.cmp(&TransactionOrigin::Local), Ordering::Less); - assert_eq!(TransactionOrigin::RetractedBlock.cmp(&TransactionOrigin::External), Ordering::Less); - - assert_eq!(TransactionOrigin::External.cmp(&TransactionOrigin::Local), Ordering::Greater); - assert_eq!(TransactionOrigin::Local.cmp(&TransactionOrigin::RetractedBlock), Ordering::Greater); - assert_eq!(TransactionOrigin::External.cmp(&TransactionOrigin::RetractedBlock), Ordering::Greater); - } - - fn transaction_order(tx: &VerifiedTransaction, nonce: U256) -> TransactionOrder { - TransactionOrder::for_transaction(tx, nonce, 0.into(), PrioritizationStrategy::GasPriceOnly) - } - - #[test] - fn should_return_correct_nonces_when_dropped_because_of_limit() { - // given - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 2, - usize::max_value(), - !U256::zero(), - !U256::zero(), - ); - let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into()); - let sender = tx1.sender(); - let nonce = tx1.nonce; - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into())); - - // when - let tx = new_tx(123.into(), 1.into()); - let res = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - // No longer the case as we don't even consider a transaction that isn't above a full - // queue's minimum gas price. - // We may want to reconsider this in the near future so leaving this code in as a - // possible alternative. - /* - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.last_nonce(&sender), Some(nonce)); - */ - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientGasPrice { - minimal: 2.into(), - got: 1.into(), - }); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.last_nonce(&sender), Some(tx2.nonce)); - } - - #[test] - fn should_create_transaction_set() { - // given - let mut local = LocalTransactionsList::default(); - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 1, - total_gas_limit: !U256::zero(), - memory_limit: usize::max_value(), - }; - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None, 0, 1); - let mut by_hash = { - let mut x = HashMap::new(); - let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None, 0, 1); - x.insert(tx1.hash(), tx1); - x.insert(tx2.hash(), tx2); - x - }; - // Insert both transactions - let order1 = transaction_order(&tx1, U256::zero()); - set.insert(tx1.sender(), tx1.nonce(), order1.clone()); - let order2 = transaction_order(&tx2, U256::zero()); - set.insert(tx2.sender(), tx2.nonce(), order2.clone()); - assert_eq!(set.by_priority.len(), 2); - assert_eq!(set.by_address.len(), 2); - - // when - set.enforce_limit(&mut by_hash, &mut local); - - // then - assert_eq!(by_hash.len(), 1); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_priority.iter().next().unwrap().clone(), order1); - set.clear(); - assert_eq!(set.by_priority.len(), 0); - assert_eq!(set.by_address.len(), 0); - } - - #[test] - fn should_replace_transaction_in_set() { - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 1, - total_gas_limit: !U256::zero(), - memory_limit: 0, - }; - // Create two transactions with same nonce - // (same hash) - let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into()); - let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None, 0, 1); - let by_hash = { - let mut x = HashMap::new(); - let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None, 0, 1); - x.insert(tx1.hash(), tx1); - x.insert(tx2.hash(), tx2); - x - }; - // Insert both transactions - let order1 = transaction_order(&tx1, U256::zero()); - set.insert(tx1.sender(), tx1.nonce(), order1.clone()); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_gas_price.len(), 1); - assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into()); - assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1); - // Two different orders (imagine nonce changed in the meantime) - let order2 = transaction_order(&tx2, U256::one()); - set.insert(tx2.sender(), tx2.nonce(), order2.clone()); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_gas_price.len(), 1); - assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into()); - assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1); - - // then - assert_eq!(by_hash.len(), 1); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_gas_price.len(), 1); - assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into()); - assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1); - assert_eq!(set.by_priority.iter().next().unwrap().clone(), order2); - } - - #[test] - fn should_not_insert_same_transaction_twice_into_set() { - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 2, - total_gas_limit: !U256::zero(), - memory_limit: 0, - }; - let tx = new_tx_default(); - let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None, 0, 0); - let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); - assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none()); - let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External, None, 0, 1); - let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); - assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some()); - } - - #[test] - fn should_give_correct_gas_price_entry_limit() { - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 1, - total_gas_limit: !U256::zero(), - memory_limit: 0, - }; - - assert_eq!(set.gas_price_entry_limit(), 0.into()); - let tx = new_tx_default(); - let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None, 0, 0); - let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); - assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none()); - assert_eq!(set.gas_price_entry_limit(), 2.into()); - } - - #[test] - fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_similar_tx_pair(); - let prev_nonce = default_account_details().nonce - U256::one(); - - // First insert one transaction to future - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)); - assert_eq!(res.unwrap(), transaction::ImportResult::Future); - assert_eq!(txq.status().future, 1); - - // now import second transaction to current - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // and then there should be only one transaction in current (the one with higher gas_price) - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.status().pending, 1); - assert_eq!(txq.status().future, 0); - assert_eq!(txq.current.by_priority.len(), 1); - assert_eq!(txq.current.by_address.len(), 1); - let top = txq.top_transactions(); - assert_eq!(top[0], tx2); - } - - #[test] - fn should_move_all_transactions_from_future() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 1.into()); - let prev_nonce = default_account_details().nonce - U256::one(); - - // First insert one transaction to future - let res = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)); - assert_eq!(res.unwrap(), transaction::ImportResult::Future); - assert_eq!(txq.status().future, 1); - - // now import second transaction to current - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.status().future, 0); - assert_eq!(txq.current.by_priority.len(), 2); - assert_eq!(txq.current.by_address.len(), 2); - let top = txq.top_transactions(); - assert_eq!(top[0], tx); - assert_eq!(top[1], tx2); - } - - #[test] - fn should_import_tx() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - } - - #[test] - fn should_order_by_gas() { - // given - let mut txq = TransactionQueue::new(PrioritizationStrategy::GasAndGasPrice); - let tx1 = new_tx_with_gas(50000.into(), 40.into()); - let tx2 = new_tx_with_gas(40000.into(), 30.into()); - let tx3 = new_tx_with_gas(30000.into(), 10.into()); - let tx4 = new_tx_with_gas(50000.into(), 20.into()); - txq.set_minimal_gas_price(15.into()); - - // when - let res1 = txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res2 = txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res3 = txq.add(tx3, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res4 = txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res1.unwrap(), transaction::ImportResult::Current); - assert_eq!(res2.unwrap(), transaction::ImportResult::Current); - assert_eq!(unwrap_tx_err(res3), transaction::Error::InsufficientGasPrice { - minimal: U256::from(15), - got: U256::from(10), - }); - assert_eq!(res4.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 3); - assert_eq!(txq.top_transactions()[0].gas, 40000.into()); - assert_eq!(txq.top_transactions()[1].gas, 50000.into()); - assert_eq!(txq.top_transactions()[2].gas, 50000.into()); - assert_eq!(txq.top_transactions()[1].gas_price, 40.into()); - assert_eq!(txq.top_transactions()[2].gas_price, 20.into()); - } - - #[test] - fn should_order_by_gas_factor() { - // given - let mut txq = TransactionQueue::new(PrioritizationStrategy::GasFactorAndGasPrice); - - let tx1 = new_tx_with_gas(150_000.into(), 40.into()); - let tx2 = new_tx_with_gas(40_000.into(), 16.into()); - let tx3 = new_tx_with_gas(30_000.into(), 15.into()); - let tx4 = new_tx_with_gas(150_000.into(), 62.into()); - txq.set_minimal_gas_price(15.into()); - - // when - let res1 = txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res2 = txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res3 = txq.add(tx3, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res4 = txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res1.unwrap(), transaction::ImportResult::Current); - assert_eq!(res2.unwrap(), transaction::ImportResult::Current); - assert_eq!(res3.unwrap(), transaction::ImportResult::Current); - assert_eq!(res4.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 4); - assert_eq!(txq.top_transactions()[0].gas, 30_000.into()); - assert_eq!(txq.top_transactions()[1].gas, 150_000.into()); - assert_eq!(txq.top_transactions()[2].gas, 40_000.into()); - assert_eq!(txq.top_transactions()[3].gas, 150_000.into()); - assert_eq!(txq.top_transactions()[0].gas_price, 15.into()); - assert_eq!(txq.top_transactions()[1].gas_price, 62.into()); - assert_eq!(txq.top_transactions()[2].gas_price, 16.into()); - assert_eq!(txq.top_transactions()[3].gas_price, 40.into()); - } - - #[test] - fn tx_gas_limit_should_never_overflow() { - // given - let mut txq = TransactionQueue::default(); - txq.set_gas_limit(U256::zero()); - assert_eq!(txq.block_gas_limit, U256::zero()); - - // when - txq.set_gas_limit(!U256::zero()); - - // then - assert_eq!(txq.block_gas_limit, !U256::zero()); - } - - #[test] - fn should_not_import_transaction_above_gas_limit() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let gas = tx.gas; - let limit = gas / U256::from(2); - txq.set_gas_limit(limit); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::GasLimitExceeded { - limit: U256::from(50_000), - got: gas, - }); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - - #[test] - fn should_drop_transactions_from_senders_without_balance() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let account = AccountDetails { - nonce: default_account_details().nonce, - balance: U256::one() - }; - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account(account)); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientBalance { - balance: U256::from(1), - cost: U256::from(100_100), - }); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_not_import_transaction_below_min_gas_price_threshold_if_external() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - txq.set_minimal_gas_price(tx.gas_price + U256::one()); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientGasPrice { - minimal: U256::from(2), - got: U256::from(1), - }); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_import_transaction_below_min_gas_price_threshold_if_local() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - txq.set_minimal_gas_price(tx.gas_price + U256::one()); - - // when - let res = txq.add(tx, TransactionOrigin::Local, 0, None, &default_tx_provider()); - - // then - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_import_txs_from_same_sender() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_prioritize_local_transactions_within_same_nonce_height() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - // the second one has same nonce but higher `gas_price` - let (_, tx2) = new_similar_tx_pair(); - - // when - // first insert the one with higher gas price - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - // then the one with lower gas price, but local - txq.add(tx.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); // local should be first - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn when_importing_local_should_mark_others_from_the_same_sender_as_local() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - // the second one has same nonce but higher `gas_price` - let (_, tx0) = new_similar_tx_pair(); - - txq.add(tx0.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - // the one with higher gas price is first - let top = txq.top_transactions(); - assert_eq!(top[0], tx0); - assert_eq!(top[1], tx1); - - // when - // insert second as local - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - // the order should be updated - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], tx2); - assert_eq!(top[2], tx0); - } - - #[test] - fn should_prioritize_reimported_transactions_within_same_nonce_height() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - // the second one has same nonce but higher `gas_price` - let (_, tx2) = new_similar_tx_pair(); - - // when - // first insert local one with higher gas price - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - // then the one with lower gas price, but from retracted block - txq.add(tx.clone(), TransactionOrigin::RetractedBlock, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); // retracted should be first - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_not_prioritize_local_transactions_with_different_nonce_height() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_penalize_transactions_from_sender_in_future() { - // given - let prev_nonce = default_account_details().nonce - U256::one(); - let mut txq = TransactionQueue::default(); - // txa, txb - slightly bigger gas price to have consistent ordering - let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); - let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); - - // insert everything - txq.add(txa.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(txb.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - - assert_eq!(txq.status().future, 4); - - // when - txq.penalize(&tx1.hash()); - - // then - let top: Vec<_> = txq.future_transactions().into_iter().map(|tx| tx.transaction).collect(); - assert_eq!(top[0], txa); - assert_eq!(top[1], txb); - assert_eq!(top[2], tx1); - assert_eq!(top[3], tx2); - assert_eq!(top.len(), 4); - } - - #[test] - fn should_not_penalize_local_transactions() { - // given - let mut txq = TransactionQueue::default(); - // txa, txb - slightly bigger gas price to have consistent ordering - let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); - let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); - - // insert everything - txq.add(txa.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(txb.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], txa); - assert_eq!(top[2], tx2); - assert_eq!(top[3], txb); - assert_eq!(top.len(), 4); - - // when - txq.penalize(&tx1.hash()); - - // then (order is the same) - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], txa); - assert_eq!(top[2], tx2); - assert_eq!(top[3], txb); - assert_eq!(top.len(), 4); - } - - #[test] - fn should_penalize_transactions_from_sender() { - // given - let mut txq = TransactionQueue::default(); - // txa, txb - slightly bigger gas price to have consistent ordering - let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); - let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); - - // insert everything - txq.add(txa.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(txb.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], txa); - assert_eq!(top[2], tx2); - assert_eq!(top[3], txb); - assert_eq!(top.len(), 4); - - // when - txq.penalize(&tx1.hash()); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], txa); - assert_eq!(top[1], txb); - assert_eq!(top[2], tx1); - assert_eq!(top[3], tx2); - assert_eq!(top.len(), 4); - } - - #[test] - fn should_return_pending_hashes() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.pending_hashes(); - assert_eq!(top[0], tx.hash()); - assert_eq!(top[1], tx2.hash()); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_put_transaction_to_futures_if_gap_detected() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(2.into(), 0.into()); - - // when - let res1 = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - let res2 = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(res1, transaction::ImportResult::Current); - assert_eq!(res2, transaction::ImportResult::Future); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 1); - let top = txq.top_transactions(); - assert_eq!(top.len(), 1); - assert_eq!(top[0], tx); - } - - #[test] - fn should_handle_min_block() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - let res1 = txq.add(tx.clone(), TransactionOrigin::External, 0, Some(transaction::Condition::Number(1)), &default_tx_provider()).unwrap(); - let res2 = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(res1, transaction::ImportResult::Current); - assert_eq!(res2, transaction::ImportResult::Current); - let top = txq.top_transactions_at(0, 0, None); - assert_eq!(top.len(), 0); - let top = txq.top_transactions_at(1, 0, None); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_correctly_update_futures_when_removing() { - // given - let prev_nonce = default_account_details().nonce - U256::one(); - let next2_nonce = default_nonce() + U256::from(3); - - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - assert_eq!(txq.status().future, 2); - - // when - txq.cull(tx.sender(), next2_nonce); - // should remove both transactions since they are not valid - - // then - assert_eq!(txq.status().pending, 0); - assert_eq!(txq.status().future, 0); - } - - #[test] - fn should_move_transactions_if_gap_filled() { - // given - let mut txq = TransactionQueue::default(); - let kp = Random.generate().unwrap(); - let secret = kp.secret(); - let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret, None).into(); - let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None).into(); - let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None).into(); - - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 1); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - - // when - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.pending, 3); - assert_eq!(stats.future, 0); - assert_eq!(txq.future.by_priority.len(), 0); - assert_eq!(txq.future.by_address.len(), 0); - assert_eq!(txq.future.by_gas_price.len(), 0); - } - - #[test] - fn should_remove_transaction() { - // given - let mut txq2 = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(3.into(), 0.into()); - txq2.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq2.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq2.status().pending, 1); - assert_eq!(txq2.status().future, 1); - - // when - txq2.cull(tx.sender(), tx.nonce + U256::one()); - txq2.cull(tx2.sender(), tx2.nonce + U256::one()); - - // then - let stats = txq2.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_move_transactions_to_future_if_gap_introduced() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - let tx3 = new_tx_default(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 3); - - // when - txq.remove(&tx.hash(), &|_| default_nonce(), RemovalReason::Invalid); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 1); - assert_eq!(stats.pending, 1); - } - - #[test] - fn should_clear_queue() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // add - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - let stats = txq.status(); - assert_eq!(stats.pending, 2); - - // when - txq.clear(); - - // then - let stats = txq.status(); - assert_eq!(stats.pending, 0); - } - - #[test] - fn should_drop_old_transactions_when_hitting_the_limit() { - // given - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 1, - usize::max_value(), - !U256::zero(), - !U256::zero() - ); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - let sender = tx.sender(); - let nonce = tx.nonce; - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 1); - - // when - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - let t = txq.top_transactions(); - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientGasPrice { minimal: 2.into(), got: 1.into() }); - assert_eq!(txq.status().pending, 1); - assert_eq!(t.len(), 1); - assert_eq!(t[0], tx); - assert_eq!(txq.last_nonce(&sender), Some(nonce)); - } - - #[test] - fn should_limit_future_transactions() { - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 1, - usize::max_value(), - !U256::zero(), - !U256::zero(), - ); - txq.current.set_limit(10); - let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into()); - let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into()); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 2); - - // when - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx4.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(txq.status().future, 1); - } - - #[test] - fn should_limit_by_gas() { - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 100, - usize::max_value(), - default_gas_val() * U256::from(2), - !U256::zero() - ); - let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); - let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - // limited by gas - txq.add(tx4.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap_err(); - assert_eq!(txq.status().pending, 2); - } - - #[test] - fn should_keep_own_transactions_above_gas_limit() { - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 100, - usize::max_value(), - default_gas_val() * U256::from(2), - !U256::zero() - ); - let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); - let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); - let (tx5, _) = new_tx_pair_default(U256::from(1), U256::from(2)); - txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - // Not accepted because of limit - txq.add(tx5.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap_err(); - txq.add(tx3.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx4.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 4); - } - - #[test] - fn should_drop_transactions_with_old_nonces() { - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let last_nonce = tx.nonce + U256::one(); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(last_nonce)); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::Old); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_not_insert_same_transaction_twice() { - // given - let nonce = default_account_details().nonce + U256::one(); - let mut txq = TransactionQueue::default(); - let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - assert_eq!(txq.status().pending, 0); - - // when - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce)); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::AlreadyImported); - let stats = txq.status(); - assert_eq!(stats.future, 1); - assert_eq!(stats.pending, 0); - } - - #[test] - fn should_accept_same_transaction_twice_if_removed() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 2); - - // when - txq.remove(&tx1.hash(), &|_| default_nonce(), RemovalReason::Invalid); - assert_eq!(txq.status().pending, 0); - assert_eq!(txq.status().future, 1); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 2); - } - - #[test] - fn should_not_move_to_future_if_state_nonce_is_higher() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - let tx3 = new_tx_default(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 3); - - // when - txq.cull(tx.sender(), default_nonce() + U256::one()); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 2); - } - - #[test] - fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() { - // given - let mut txq = TransactionQueue::default(); - let keypair = Random.generate().unwrap(); - let tx = new_unsigned_tx(123.into(), default_gas_val(), 20.into()).sign(keypair.secret(), None); - let tx2 = { - let mut tx2 = (**tx).clone(); - tx2.gas_price = U256::from(21); - tx2.sign(keypair.secret(), None) - }; - - // when - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - let res = txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::TooCheapToReplace); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 0); - assert_eq!(txq.top_transactions()[0].gas_price, U256::from(20)); - } - - #[test] - fn should_replace_same_transaction_when_has_higher_fee() { - // given - let mut txq = TransactionQueue::default(); - let keypair = Random.generate().unwrap(); - let tx = new_unsigned_tx(123.into(), default_gas_val(), 10.into()).sign(keypair.secret(), None); - let tx2 = { - let mut tx2 = (**tx).clone(); - tx2.gas_price = U256::from(20); - tx2.sign(keypair.secret(), None) - }; - - // when - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 0); - assert_eq!(txq.top_transactions()[0].gas_price, U256::from(20)); - } - - #[test] - fn should_replace_same_transaction_when_importing_to_futures() { - // given - let mut txq = TransactionQueue::default(); - let keypair = Random.generate().unwrap(); - let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret(), None); - let tx1 = { - let mut tx1 = (**tx0).clone(); - tx1.nonce = U256::from(124); - tx1.sign(keypair.secret(), None) - }; - let tx2 = { - let mut tx2 = (**tx1).clone(); - tx2.gas_price = U256::from(200); - tx2.sign(keypair.secret(), None) - }; - - // when - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx0, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 2); - assert_eq!(txq.top_transactions()[1].gas_price, U256::from(200)); - } - - #[test] - fn should_recalculate_height_when_removing_from_future() { - // given - let previous_nonce = default_account_details().nonce - U256::one(); - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(previous_nonce)).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(previous_nonce)).unwrap(); - assert_eq!(txq.status().future, 2); - - // when - txq.remove(&tx1.hash(), &|_| default_nonce() + 1.into(), RemovalReason::Invalid); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 1); - } - - #[test] - fn should_return_none_when_transaction_from_given_address_does_not_exist() { - // given - let txq = TransactionQueue::default(); - - // then - assert_eq!(txq.last_nonce(&Address::default()), None); - } - - #[test] - fn should_return_correct_nonce_when_transactions_from_given_address_exist() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let from = tx.sender(); - let nonce = tx.nonce; - - // when - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce)).unwrap(); - - // then - assert_eq!(txq.last_nonce(&from), Some(nonce)); - } - - #[test] - fn should_remove_old_transaction_even_if_newer_transaction_was_not_known() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let (nonce1, nonce2) = (tx1.nonce, tx2.nonce); - - // Insert first transaction - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce1)).unwrap(); - - // when - txq.cull(tx2.sender(), nonce2 + U256::one()); - - // then - assert!(txq.top_transactions().is_empty()); - } - - #[test] - fn should_return_valid_last_nonce_after_cull() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(4.into(), 0.into()); - let sender = tx1.sender(); - let (nonce1, nonce2) = (tx1.nonce, tx2.nonce); - - // when - // Insert first transaction - assert_eq!(txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce1)).unwrap(), transaction::ImportResult::Current); - // Second should go to future - assert_eq!(txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce1)).unwrap(), transaction::ImportResult::Future); - // Now block is imported - txq.cull(sender, nonce2 - U256::from(1)); - // tx2 should be not be promoted to current - assert_eq!(txq.status().pending, 0); - assert_eq!(txq.status().future, 1); - - // then - assert_eq!(txq.last_nonce(&sender), None); - } - - #[test] - fn should_return_true_if_there_is_local_transaction_pending() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - assert_eq!(txq.has_local_pending_transactions(), false); - - // when - assert_eq!(txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.has_local_pending_transactions(), false); - assert_eq!(txq.add(tx2, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(), - transaction::ImportResult::Current); - - // then - assert_eq!(txq.has_local_pending_transactions(), true); - } - - #[test] - fn should_keep_right_order_in_future() { - // given - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 1, - usize::max_value(), - !U256::zero(), - !U256::zero() - ); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let prev_nonce = default_account_details().nonce - U256::one(); - - // when - assert_eq!(txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(), transaction::ImportResult::Future); - assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(), transaction::ImportResult::Future); - - // then - assert_eq!(txq.future.by_priority.len(), 1); - assert_eq!(txq.future.by_priority.iter().next().unwrap().hash, tx1.hash()); - } - - #[test] - fn should_return_correct_last_nonce() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2, tx2_2, tx3) = { - let keypair = Random.generate().unwrap(); - let secret = &keypair.secret(); - let nonce = 123.into(); - let gas = default_gas_val(); - let tx = new_unsigned_tx(nonce, gas, 1.into()); - let tx2 = new_unsigned_tx(nonce + 1.into(), gas, 1.into()); - let tx2_2 = new_unsigned_tx(nonce + 1.into(), gas, 5.into()); - let tx3 = new_unsigned_tx(nonce + 2.into(), gas, 1.into()); - - - (tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None)) - }; - let sender = tx1.sender(); - txq.add(tx1, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.future.by_priority.len(), 0); - assert_eq!(txq.current.by_priority.len(), 3); - - // when - let res = txq.add(tx2_2, TransactionOrigin::Local, 0, None, &default_tx_provider()); - - // then - assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into()); - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.current.by_priority.len(), 3); - } - - #[test] - fn should_reject_transactions_below_base_gas() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let high_gas = 100_001.into(); - - // when - let res1 = txq.add(tx1, TransactionOrigin::Local, 0, None, &default_tx_provider()); - let res2 = txq.add(tx2, TransactionOrigin::Local, 0, None, &default_tx_provider().with_tx_gas_required(high_gas)); - - // then - assert_eq!(res1.unwrap(), transaction::ImportResult::Current); - assert_eq!(unwrap_tx_err(res2), transaction::Error::InsufficientGas { - minimal: 100_001.into(), - got: 100_000.into(), - }); - - } - - #[test] - fn should_clear_all_old_transactions() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let (tx3, tx4) = new_tx_pair_default(1.into(), 0.into()); - let next_nonce = |_: &Address| - AccountDetails { nonce: default_nonce() + U256::one(), balance: !U256::zero() }; - - // Insert all transactions - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.top_transactions().len(), 4); - - // when - txq.remove_old(&next_nonce, 0); - - // then - assert_eq!(txq.top_transactions().len(), 2); - } - - #[test] - fn should_remove_out_of_date_transactions_occupying_queue() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let (tx3, tx4) = new_tx_pair_default(2.into(), 0.into()); - - // Insert all transactions - txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 5, None, &default_tx_provider()).unwrap(); - txq.add(tx3.clone(), TransactionOrigin::External, 10, None, &default_tx_provider()).unwrap(); - txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.top_transactions().len(), 3); - assert_eq!(txq.future_transactions().len(), 1); - - // when - txq.remove_old(&default_account_details_for_addr, 9 + super::DEFAULT_QUEUING_PERIOD); - - // then - assert_eq!(txq.top_transactions().len(), 2); - assert_eq!(txq.future_transactions().len(), 0); - assert_eq!(txq.top_transactions(), vec![tx1, tx3]); - } - - #[test] - fn should_accept_local_service_transaction() { - // given - let tx = new_tx(123.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - txq.add(tx, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(txq.top_transactions().len(), 1); - } - - #[test] - fn should_not_accept_external_service_transaction_if_sender_not_certified() { - // given - let tx1 = new_tx(123.into(), 0.into()); - let tx2 = new_tx(456.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - assert_eq!(unwrap_tx_err(txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider())), - transaction::Error::InsufficientGasPrice { - minimal: 100.into(), - got: 0.into(), - }); - assert_eq!(unwrap_tx_err(txq.add(tx2, TransactionOrigin::RetractedBlock, 0, None, &default_tx_provider())), - transaction::Error::InsufficientGasPrice { - minimal: 100.into(), - got: 0.into(), - }); - - // then - assert_eq!(txq.top_transactions().len(), 0); - } - - #[test] - fn should_not_accept_external_service_transaction_if_contract_returns_error() { - // given - let tx = new_tx(123.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - let details_provider = default_tx_provider().service_transaction_checker_returns_error("Contract error"); - assert_eq!(unwrap_tx_err(txq.add(tx, TransactionOrigin::External, 0, None, &details_provider)), - transaction::Error::InsufficientGasPrice { - minimal: 100.into(), - got: 0.into(), - }); - - // then - assert_eq!(txq.top_transactions().len(), 0); - } - - #[test] - fn should_accept_external_service_transaction_if_sender_is_certified() { - // given - let tx = new_tx(123.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - let details_provider = default_tx_provider().service_transaction_checker_accepts(true); - txq.add(tx, TransactionOrigin::External, 0, None, &details_provider).unwrap(); - - // then - assert_eq!(txq.top_transactions().len(), 1); - } - - #[test] - fn should_not_order_transactions_by_hash() { - // given - let secret1 = "0000000000000000000000000000000000000000000000000000000000000002".parse().unwrap(); - let secret2 = "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap(); - let tx1 = new_unsigned_tx(123.into(), default_gas_val(), 0.into()).sign(&secret1, None); - let tx2 = new_unsigned_tx(123.into(), default_gas_val(), 0.into()).sign(&secret2, None); - let mut txq = TransactionQueue::default(); - - // when - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(txq.top_transactions()[0], tx1); - assert_eq!(txq.top_transactions().len(), 2); - } - - #[test] - fn should_not_return_transactions_over_nonce_cap() { - // given - let keypair = Random.generate().unwrap(); - let mut txq = TransactionQueue::default(); - // when - for nonce in 123..130 { - let tx = new_unsigned_tx(nonce.into(), default_gas_val(), default_gas_price()).sign(keypair.secret(), None); - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - } - - // then - assert_eq!(txq.top_transactions_at(BlockNumber::max_value(), u64::max_value(), Some(127.into())).len(), 4); - } -} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index c2c6f2aa5cf..4a4441b89fe 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -390,10 +390,12 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { &snapshot_path, restoration_db_handler, &cmd.dirs.ipc_path(), - Arc::new(Miner::with_spec(&spec)), + // TODO [ToDr] don't use test miner here + // (actually don't require miner at all) + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; // free up the spec in memory. @@ -580,10 +582,12 @@ fn start_client( &snapshot_path, restoration_db_handler, &dirs.ipc_path(), - Arc::new(Miner::with_spec(&spec)), + // It's fine to use test version here, + // since we don't care about miner parameters at all + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; drop(spec); diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index cb6470e9b81..c7c484e2bda 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -721,29 +721,25 @@ usage! { "--gas-cap=[GAS]", "A cap on how large we will raise the gas limit per block due to transaction volume.", - ARG arg_tx_queue_mem_limit: (u32) = 2u32, or |c: &Config| c.mining.as_ref()?.tx_queue_mem_limit.clone(), + ARG arg_tx_queue_mem_limit: (u32) = 4u32, or |c: &Config| c.mining.as_ref()?.tx_queue_mem_limit.clone(), "--tx-queue-mem-limit=[MB]", "Maximum amount of memory that can be used by the transaction queue. Setting this parameter to 0 disables limiting.", - ARG arg_tx_queue_size: (usize) = 8192usize, or |c: &Config| c.mining.as_ref()?.tx_queue_size.clone(), + ARG arg_tx_queue_size: (usize) = 8_192usize, or |c: &Config| c.mining.as_ref()?.tx_queue_size.clone(), "--tx-queue-size=[LIMIT]", "Maximum amount of transactions in the queue (waiting to be included in next block).", + ARG arg_tx_queue_per_sender: (Option) = None, or |c: &Config| c.mining.as_ref()?.tx_queue_per_sender.clone(), + "--tx-queue-per-sender=[LIMIT]", + "Maximum number of transactions per sender in the queue. By default it's 1% of the entire queue, but not less than 16.", + ARG arg_tx_queue_gas: (String) = "off", or |c: &Config| c.mining.as_ref()?.tx_queue_gas.clone(), "--tx-queue-gas=[LIMIT]", "Maximum amount of total gas for external transactions in the queue. LIMIT can be either an amount of gas or 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit.", ARG arg_tx_queue_strategy: (String) = "gas_price", or |c: &Config| c.mining.as_ref()?.tx_queue_strategy.clone(), "--tx-queue-strategy=[S]", - "Prioritization strategy used to order transactions in the queue. S may be: gas - Prioritize txs with low gas limit; gas_price - Prioritize txs with high gas price; gas_factor - Prioritize txs using gas price and gas limit ratio.", - - ARG arg_tx_queue_ban_count: (u16) = 1u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_count.clone(), - "--tx-queue-ban-count=[C]", - "Number of times maximal time for execution (--tx-time-limit) can be exceeded before banning sender/recipient/code.", - - ARG arg_tx_queue_ban_time: (u16) = 180u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_time.clone(), - "--tx-queue-ban-time=[SEC]", - "Banning time (in seconds) for offenders of specified execution time limit. Also number of offending actions have to reach the threshold within that time.", + "Prioritization strategy used to order transactions in the queue. S may be: gas_price - Prioritize txs with high gas price", ARG arg_stratum_interface: (String) = "local", or |c: &Config| c.stratum.as_ref()?.interface.clone(), "--stratum-interface=[IP]", @@ -775,7 +771,7 @@ usage! { ARG arg_tx_time_limit: (Option) = None, or |c: &Config| c.mining.as_ref()?.tx_time_limit.clone(), "--tx-time-limit=[MS]", - "Maximal time for processing single transaction. If enabled senders/recipients/code of transactions offending the limit will be banned from being included in transaction queue for 180 seconds.", + "Maximal time for processing single transaction. If enabled senders of transactions offending the limit will get other transactions penalized.", ARG arg_extra_data: (Option) = None, or |c: &Config| c.mining.as_ref()?.extra_data.clone(), "--extra-data=[STRING]", @@ -1028,6 +1024,13 @@ usage! { "--cache=[MB]", "Equivalent to --cache-size MB.", + ARG arg_tx_queue_ban_count: (u16) = 1u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_count.clone(), + "--tx-queue-ban-count=[C]", + "Not supported.", + + ARG arg_tx_queue_ban_time: (u16) = 180u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_time.clone(), + "--tx-queue-ban-time=[SEC]", + "Not supported.", } } @@ -1232,6 +1235,7 @@ struct Mining { gas_cap: Option, extra_data: Option, tx_queue_size: Option, + tx_queue_per_sender: Option, tx_queue_mem_limit: Option, tx_queue_gas: Option, tx_queue_strategy: Option, @@ -1654,7 +1658,8 @@ mod tests { arg_gas_cap: "6283184".into(), arg_extra_data: Some("Parity".into()), arg_tx_queue_size: 8192usize, - arg_tx_queue_mem_limit: 2u32, + arg_tx_queue_per_sender: None, + arg_tx_queue_mem_limit: 4u32, arg_tx_queue_gas: "off".into(), arg_tx_queue_strategy: "gas_factor".into(), arg_tx_queue_ban_count: 1u16, @@ -1911,6 +1916,7 @@ mod tests { gas_floor_target: None, gas_cap: None, tx_queue_size: Some(8192), + tx_queue_per_sender: None, tx_queue_mem_limit: None, tx_queue_gas: Some("off".into()), tx_queue_strategy: None, diff --git a/parity/cli/presets/config.mining.toml b/parity/cli/presets/config.mining.toml index f6c39bdd6df..6d22a0f0878 100644 --- a/parity/cli/presets/config.mining.toml +++ b/parity/cli/presets/config.mining.toml @@ -19,12 +19,13 @@ force_sealing = true reseal_on_txs = "all" # New pending block will be created only once per 4000 milliseconds. reseal_min_period = 4000 -# Parity will keep/relay at most 2048 transactions in queue. -tx_queue_size = 2048 +# Parity will keep/relay at most 8192 transactions in queue. +tx_queue_size = 8192 +tx_queue_per_sender = 128 [footprint] -# If defined will never use more then 256MB for all caches. (Overrides other cache settings). -cache_size = 256 +# If defined will never use more then 1024MB for all caches. (Overrides other cache settings). +cache_size = 1024 [misc] # Logging pattern (`=`, e.g. `own_tx=trace`). diff --git a/parity/configuration.rs b/parity/configuration.rs index d921c9377b4..93cc9a4dd6a 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::cmp::{max, min}; use std::time::Duration; use std::io::Read; use std::net::SocketAddr; use std::path::{Path, PathBuf}; use std::collections::BTreeMap; +use std::cmp; use std::str::FromStr; use cli::{Args, ArgsError}; use hash::keccak; @@ -30,15 +30,15 @@ use ansi_term::Colour; use sync::{NetworkConfiguration, validate_node_url, self}; use ethcore::ethstore::ethkey::{Secret, Public}; use ethcore::client::{VMType}; -use ethcore::miner::{MinerOptions, Banning, StratumOptions}; +use ethcore::miner::{stratum, MinerOptions}; use ethcore::verification::queue::VerifierSettings; +use miner::pool; use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}; use rpc_apis::ApiSet; use parity_rpc::NetworkSettings; use cache::CacheConfig; -use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, -to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy, passwords_from_files}; +use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files}; use dir::helpers::{replace_home, replace_home_and_local}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType}; use ethcore_logger::Config as LogConfig; @@ -352,7 +352,6 @@ impl Configuration { daemon: daemon, logger_config: logger_config.clone(), miner_options: self.miner_options()?, - work_notify: self.work_notify(), gas_price_percentile: self.args.arg_gas_price_percentile, ntp_servers: self.ntp_servers(), ws_conf: ws_conf, @@ -411,12 +410,14 @@ impl Configuration { } fn miner_extras(&self) -> Result { + let floor = to_u256(&self.args.arg_gas_floor_target)?; + let ceil = to_u256(&self.args.arg_gas_cap)?; let extras = MinerExtras { author: self.author()?, extra_data: self.extra_data()?, - gas_floor_target: to_u256(&self.args.arg_gas_floor_target)?, - gas_ceil_target: to_u256(&self.args.arg_gas_cap)?, + gas_range_target: (floor, ceil), engine_signer: self.engine_signer()?, + work_notify: self.work_notify(), }; Ok(extras) @@ -471,7 +472,7 @@ impl Configuration { fn max_peers(&self) -> u32 { self.args.arg_max_peers - .or(max(self.args.arg_min_peers, Some(DEFAULT_MAX_PEERS))) + .or(cmp::max(self.args.arg_min_peers, Some(DEFAULT_MAX_PEERS))) .unwrap_or(DEFAULT_MAX_PEERS) as u32 } @@ -484,7 +485,7 @@ impl Configuration { fn min_peers(&self) -> u32 { self.args.arg_min_peers - .or(min(self.args.arg_max_peers, Some(DEFAULT_MIN_PEERS))) + .or(cmp::min(self.args.arg_max_peers, Some(DEFAULT_MIN_PEERS))) .unwrap_or(DEFAULT_MIN_PEERS) as u32 } @@ -514,9 +515,9 @@ impl Configuration { Ok(cfg) } - fn stratum_options(&self) -> Result, String> { + fn stratum_options(&self) -> Result, String> { if self.args.flag_stratum { - Ok(Some(StratumOptions { + Ok(Some(stratum::Options { io_path: self.directories().db, listen_addr: self.stratum_interface(), port: self.args.arg_ports_shift + self.args.arg_stratum_port, @@ -538,36 +539,51 @@ impl Configuration { reseal_on_external_tx: reseal.external, reseal_on_own_tx: reseal.own, reseal_on_uncle: self.args.flag_reseal_on_uncle, - tx_gas_limit: match self.args.arg_tx_gas_limit { - Some(ref d) => to_u256(d)?, - None => U256::max_value(), - }, - tx_queue_size: self.args.arg_tx_queue_size, - tx_queue_memory_limit: if self.args.arg_tx_queue_mem_limit > 0 { - Some(self.args.arg_tx_queue_mem_limit as usize * 1024 * 1024) - } else { None }, - tx_queue_gas_limit: to_gas_limit(&self.args.arg_tx_queue_gas)?, - tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?, - pending_set: to_pending_set(&self.args.arg_relay_set)?, reseal_min_period: Duration::from_millis(self.args.arg_reseal_min_period), reseal_max_period: Duration::from_millis(self.args.arg_reseal_max_period), + + pending_set: to_pending_set(&self.args.arg_relay_set)?, work_queue_size: self.args.arg_work_queue_size, enable_resubmission: !self.args.flag_remove_solved, - tx_queue_banning: match self.args.arg_tx_time_limit { - Some(limit) => Banning::Enabled { - min_offends: self.args.arg_tx_queue_ban_count, - offend_threshold: Duration::from_millis(limit), - ban_duration: Duration::from_secs(self.args.arg_tx_queue_ban_time as u64), - }, - None => Banning::Disabled, - }, - refuse_service_transactions: self.args.flag_refuse_service_transactions, infinite_pending_block: self.args.flag_infinite_pending_block, + + tx_queue_penalization: to_queue_penalization(self.args.arg_tx_time_limit)?, + tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?, + refuse_service_transactions: self.args.flag_refuse_service_transactions, + + pool_limits: self.pool_limits()?, + pool_verification_options: self.pool_verification_options()?, }; Ok(options) } + fn pool_limits(&self) -> Result { + let max_count = self.args.arg_tx_queue_size; + + Ok(pool::Options { + max_count, + max_per_sender: self.args.arg_tx_queue_per_sender.unwrap_or_else(|| cmp::max(16, max_count / 100)), + max_mem_usage: if self.args.arg_tx_queue_mem_limit > 0 { + self.args.arg_tx_queue_mem_limit as usize * 1024 * 1024 + } else { + usize::max_value() + }, + }) + } + + fn pool_verification_options(&self) -> Result{ + Ok(pool::verifier::Options { + // NOTE min_gas_price and block_gas_limit will be overwritten right after start. + minimal_gas_price: U256::from(20_000_000) * 1_000u32, + block_gas_limit: U256::max_value(), + tx_gas_limit: match self.args.arg_tx_gas_limit { + Some(ref d) => to_u256(d)?, + None => U256::max_value(), + }, + }) + } + fn ui_port(&self) -> u16 { self.args.arg_ports_shift + self.args.arg_ui_port } @@ -690,12 +706,7 @@ impl Configuration { let usd_per_tx = to_price(&self.args.arg_usd_per_tx)?; if "auto" == self.args.arg_usd_per_eth.as_str() { - // Just a very rough estimate to avoid accepting - // ZGP transactions before the price is fetched - // if user does not want it. - let last_known_usd_per_eth = 10.0; return Ok(GasPricerConfig::Calibrated { - initial_minimum: wei_per_gas(usd_per_tx, last_known_usd_per_eth), usd_per_tx: usd_per_tx, recalibration_period: to_duration(self.args.arg_price_update_period.as_str())?, }); @@ -1233,7 +1244,7 @@ mod tests { use tempdir::TempDir; use ethcore::client::{VMType, BlockId}; use ethcore::miner::MinerOptions; - use miner::transaction_queue::PrioritizationStrategy; + use miner::pool::PrioritizationStrategy; use parity_rpc::NetworkSettings; use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack}; @@ -1526,7 +1537,6 @@ mod tests { no_hardcoded_sync: false, no_persistent_txqueue: false, whisper: Default::default(), - work_notify: Vec::new(), }; expected.secretstore_conf.enabled = cfg!(feature = "secretstore"); expected.secretstore_conf.http_enabled = cfg!(feature = "secretstore"); @@ -1540,18 +1550,12 @@ mod tests { // when let conf0 = parse(&["parity"]); - let conf1 = parse(&["parity", "--tx-queue-strategy", "gas_factor"]); let conf2 = parse(&["parity", "--tx-queue-strategy", "gas_price"]); - let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]); // then assert_eq!(conf0.miner_options().unwrap(), mining_options); - mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice; - assert_eq!(conf1.miner_options().unwrap(), mining_options); mining_options.tx_queue_strategy = PrioritizationStrategy::GasPriceOnly; assert_eq!(conf2.miner_options().unwrap(), mining_options); - mining_options.tx_queue_strategy = PrioritizationStrategy::GasAndGasPrice; - assert_eq!(conf3.miner_options().unwrap(), mining_options); } #[test] @@ -1883,8 +1887,8 @@ mod tests { assert_eq!(c.miner_options.reseal_on_external_tx, true); assert_eq!(c.miner_options.reseal_on_own_tx, true); assert_eq!(c.miner_options.reseal_min_period, Duration::from_millis(4000)); - assert_eq!(c.miner_options.tx_queue_size, 2048); - assert_eq!(c.cache_config, CacheConfig::new_with_total_cache_size(256)); + assert_eq!(c.miner_options.pool_limits.max_count, 8192); + assert_eq!(c.cache_config, CacheConfig::new_with_total_cache_size(1024)); assert_eq!(c.logger_config.mode.unwrap(), "miner=trace,own_tx=trace"); }, _ => panic!("Should be Cmd::Run"), diff --git a/parity/helpers.rs b/parity/helpers.rs index 0494be40d8e..cdd951c2b70 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -23,9 +23,9 @@ use std::path::Path; use ethereum_types::{U256, clean_0x, Address}; use journaldb::Algorithm; use ethcore::client::{Mode, BlockId, VMType, DatabaseCompactionProfile, ClientConfig, VerifierType}; -use ethcore::miner::{PendingSet, GasLimit}; use ethcore::db::NUM_COLUMNS; -use miner::transaction_queue::PrioritizationStrategy; +use ethcore::miner::{PendingSet, Penalization}; +use miner::pool::PrioritizationStrategy; use cache::CacheConfig; use dir::DatabaseDirectories; use dir::helpers::replace_home; @@ -101,23 +101,22 @@ pub fn to_pending_set(s: &str) -> Result { } } -pub fn to_gas_limit(s: &str) -> Result { - match s { - "auto" => Ok(GasLimit::Auto), - "off" => Ok(GasLimit::None), - other => Ok(GasLimit::Fixed(to_u256(other)?)), - } -} - pub fn to_queue_strategy(s: &str) -> Result { match s { - "gas" => Ok(PrioritizationStrategy::GasAndGasPrice), "gas_price" => Ok(PrioritizationStrategy::GasPriceOnly), - "gas_factor" => Ok(PrioritizationStrategy::GasFactorAndGasPrice), other => Err(format!("Invalid queue strategy: {}", other)), } } +pub fn to_queue_penalization(time: Option) -> Result { + Ok(match time { + Some(threshold_ms) => Penalization::Enabled { + offend_threshold: Duration::from_millis(threshold_ms), + }, + None => Penalization::Disabled, + }) +} + pub fn to_address(s: Option) -> Result { match s { Some(ref a) => clean_0x(a).parse().map_err(|_| format!("Invalid address: {:?}", a)), diff --git a/parity/params.rs b/parity/params.rs index 59676108ed8..957b2801935 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -16,15 +16,16 @@ use std::{str, fs, fmt}; use std::time::Duration; + +use ethcore::client::Mode; +use ethcore::ethereum; +use ethcore::spec::{Spec, SpecParams}; use ethereum_types::{U256, Address}; use futures_cpupool::CpuPool; -use parity_version::version_data; -use journaldb::Algorithm; -use ethcore::spec::{Spec, SpecParams}; -use ethcore::ethereum; -use ethcore::client::Mode; -use ethcore::miner::{GasPricer, GasPriceCalibratorOptions}; use hash_fetch::fetch::Client as FetchClient; +use journaldb::Algorithm; +use miner::gas_pricer::{GasPricer, GasPriceCalibratorOptions}; +use parity_version::version_data; use user_defaults::UserDefaults; #[derive(Debug, PartialEq)] @@ -223,25 +224,14 @@ impl Default for AccountsConfig { pub enum GasPricerConfig { Fixed(U256), Calibrated { - initial_minimum: U256, usd_per_tx: f32, recalibration_period: Duration, } } -impl GasPricerConfig { - pub fn initial_min(&self) -> U256 { - match *self { - GasPricerConfig::Fixed(ref min) => min.clone(), - GasPricerConfig::Calibrated { ref initial_minimum, .. } => initial_minimum.clone(), - } - } -} - impl Default for GasPricerConfig { fn default() -> Self { GasPricerConfig::Calibrated { - initial_minimum: 476190464u64.into(), usd_per_tx: 0.0001f32, recalibration_period: Duration::from_secs(3600), } @@ -269,20 +259,20 @@ impl GasPricerConfig { #[derive(Debug, PartialEq)] pub struct MinerExtras { pub author: Address, - pub extra_data: Vec, - pub gas_floor_target: U256, - pub gas_ceil_target: U256, pub engine_signer: Address, + pub extra_data: Vec, + pub gas_range_target: (U256, U256), + pub work_notify: Vec, } impl Default for MinerExtras { fn default() -> Self { MinerExtras { author: Default::default(), - extra_data: version_data(), - gas_floor_target: U256::from(4_700_000), - gas_ceil_target: U256::from(6_283_184), engine_signer: Default::default(), + extra_data: version_data(), + gas_range_target: (4_700_000.into(), 6_283_184.into()), + work_notify: Default::default(), } } } diff --git a/parity/run.rs b/parity/run.rs index 4cc7b29b04d..f4e892b4b97 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -24,11 +24,10 @@ use std::net::{TcpListener}; use ansi_term::{Colour, Style}; use ctrlc::CtrlC; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; -use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient}; +use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; use ethcore::db::NUM_COLUMNS; use ethcore::ethstore::ethkey; -use ethcore::miner::{Miner, MinerService, MinerOptions}; -use ethcore::miner::{StratumOptions, Stratum}; +use ethcore::miner::{stratum, Miner, MinerService, MinerOptions}; use ethcore::snapshot; use ethcore::spec::{SpecParams, OptimizeFor}; use ethcore::verification::queue::VerifierSettings; @@ -128,7 +127,7 @@ pub struct RunCmd { pub ui: bool, pub name: String, pub custom_bootnodes: bool, - pub stratum: Option, + pub stratum: Option, pub no_periodic_snapshot: bool, pub check_seal: bool, pub download_old_blocks: bool, @@ -138,7 +137,6 @@ pub struct RunCmd { pub no_persistent_txqueue: bool, pub whisper: ::whisper::Config, pub no_hardcoded_sync: bool, - pub work_notify: Vec, } pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { @@ -176,11 +174,12 @@ impl ::local_store::NodeInfo for FullNodeInfo { None => return Vec::new(), }; - let local_txs = miner.local_transactions(); - miner.pending_transactions() - .into_iter() - .chain(miner.future_transactions()) - .filter(|tx| local_txs.contains_key(&tx.hash())) + miner.local_transactions() + .values() + .filter_map(|status| match *status { + ::miner::pool::local_transactions::Status::Pending(ref tx) => Some(tx.pending().clone()), + _ => None, + }) .collect() } } @@ -559,19 +558,21 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let fetch = fetch::Client::new().map_err(|e| format!("Error starting fetch client: {:?}", e))?; // create miner - let initial_min_gas_price = cmd.gas_pricer_conf.initial_min(); - let miner = Miner::new(cmd.miner_options, cmd.gas_pricer_conf.to_gas_pricer(fetch.clone(), cpu_pool.clone()), &spec, Some(account_provider.clone())); - miner.set_author(cmd.miner_extras.author); - miner.set_gas_floor_target(cmd.miner_extras.gas_floor_target); - miner.set_gas_ceil_target(cmd.miner_extras.gas_ceil_target); + let miner = Arc::new(Miner::new( + cmd.miner_options, + cmd.gas_pricer_conf.to_gas_pricer(fetch.clone(), cpu_pool.clone()), + &spec, + Some(account_provider.clone()) + )); + miner.set_author(cmd.miner_extras.author, None).expect("Fails only if password is Some; password is None; qed"); + miner.set_gas_range_target(cmd.miner_extras.gas_range_target); miner.set_extra_data(cmd.miner_extras.extra_data); - miner.set_minimal_gas_price(initial_min_gas_price); - miner.recalibrate_minimal_gas_price(); - if !cmd.work_notify.is_empty() { - miner.push_notifier(Box::new(WorkPoster::new(&cmd.work_notify, fetch.clone(), event_loop.remote()))); + if !cmd.miner_extras.work_notify.is_empty() { + miner.add_work_listener(Box::new( + WorkPoster::new(&cmd.miner_extras.work_notify, fetch.clone(), event_loop.remote()) + )); } let engine_signer = cmd.miner_extras.engine_signer; - if engine_signer != Default::default() { // Check if engine signer exists if !account_provider.has_account(engine_signer).unwrap_or(false) { @@ -584,7 +585,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: } // Attempt to sign in the engine signer. - if !passwords.iter().any(|p| miner.set_engine_signer(engine_signer, (*p).clone()).is_ok()) { + if !passwords.iter().any(|p| miner.set_author(engine_signer, Some(p.to_owned())).is_ok()) { return Err(format!("No valid password for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT)); } } @@ -646,6 +647,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // take handle to client let client = service.client(); + // Update miners block gas limit + miner.update_transaction_queue_limits(*client.best_block_header().gas_limit()); + // take handle to private transactions service let private_tx_service = service.private_tx_service(); let private_tx_provider = private_tx_service.provider(); @@ -695,7 +699,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // start stratum if let Some(ref stratum_config) = cmd.stratum { - Stratum::register(stratum_config, miner.clone(), Arc::downgrade(&client)) + stratum::Stratum::register(stratum_config, miner.clone(), Arc::downgrade(&client)) .map_err(|e| format!("Stratum start error: {:?}", e))?; } diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 90967328083..56b166ac62d 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -194,10 +194,12 @@ impl SnapshotCommand { &snapshot_path, restoration_db_handler, &self.dirs.ipc_path(), - Arc::new(Miner::with_spec(&spec)), + // TODO [ToDr] don't use test miner here + // (actually don't require miner at all) + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; Ok(service) diff --git a/price-info/src/lib.rs b/price-info/src/lib.rs index 9685fc7eee9..e3594ad2ae9 100644 --- a/price-info/src/lib.rs +++ b/price-info/src/lib.rs @@ -98,7 +98,7 @@ impl Client { } /// Gets the current ETH price and calls `set_price` with the result. - pub fn get(&self, set_price: G) { + pub fn get(&self, set_price: G) { let future = self.fetch.get(&self.api_endpoint, fetch::Abort::default()) .from_err() .and_then(|response| { diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index a0639c4ccc2..d35a64af9d0 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -66,8 +66,9 @@ stats = { path = "../util/stats" } vm = { path = "../ethcore/vm" } [dev-dependencies] -pretty_assertions = "0.1" -macros = { path = "../util/macros" } ethcore-network = { path = "../util/network" } -kvdb-memorydb = { path = "../util/kvdb-memorydb" } fake-fetch = { path = "../util/fake-fetch" } +kvdb-memorydb = { path = "../util/kvdb-memorydb" } +macros = { path = "../util/macros" } +pretty_assertions = "0.1" +transaction-pool = { path = "../transaction-pool" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index f3ba68a0650..9d97c3c992c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -79,6 +79,8 @@ extern crate serde_derive; #[cfg(test)] extern crate ethjson; +#[cfg(test)] +extern crate transaction_pool as txpool; #[cfg(test)] #[macro_use] diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index b1fc07a22d7..1f43ef008ef 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -34,8 +34,8 @@ use stats::Corpus; use ethkey::Signature; use sync::LightSync; use ethcore::ids::BlockId; -use ethcore::miner::MinerService; -use ethcore::client::MiningBlockChainClient; +use ethcore::client::BlockChainClient; +use ethcore::miner::{self, MinerService}; use ethcore::account_provider::AccountProvider; use crypto::DEFAULT_MAC; use transaction::{Action, SignedTransaction, PendingTransaction, Transaction}; @@ -117,10 +117,9 @@ impl Clone for FullDispatcher { } } -impl FullDispatcher { +impl FullDispatcher { fn state_nonce(&self, from: &Address) -> U256 { - self.miner.last_nonce(from).map(|nonce| nonce + U256::one()) - .unwrap_or_else(|| self.client.latest_nonce(from)) + self.miner.next_nonce(&*self.client, from) } /// Imports transaction to the miner's queue. @@ -133,7 +132,7 @@ impl FullDispatcher { } } -impl Dispatcher for FullDispatcher { +impl Dispatcher for FullDispatcher { fn fill_optional_fields(&self, request: TransactionRequest, default_sender: Address, force_nonce: bool) -> BoxFuture { @@ -747,7 +746,7 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: S /// Extract the default gas price from a client and miner. pub fn default_gas_price(client: &C, miner: &M, percentile: usize) -> U256 where - C: MiningBlockChainClient, + C: BlockChainClient, M: MinerService, { client.gas_price_corpus(100).percentile(percentile).cloned().unwrap_or_else(|| miner.sensible_gas_price()) diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 6e8836c20d4..aa660efc9c9 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -391,11 +391,11 @@ pub fn no_light_peers() -> Error { } } -pub fn deprecated>>(message: T) -> Error { +pub fn deprecated, T: Into>>(message: T) -> Error { Error { code: ErrorCode::ServerError(codes::DEPRECATED), message: "Method deprecated".into(), - data: message.into().map(Value::String), + data: message.into().map(Into::into).map(Value::String), } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index c833e3ee7f7..37f918466e8 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -26,13 +26,12 @@ use parking_lot::Mutex; use ethash::SeedHashCompute; use ethcore::account_provider::{AccountProvider, DappId}; -use ethcore::block::IsBlock; -use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo}; +use ethcore::client::{BlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo}; use ethcore::ethereum::Ethash; use ethcore::filter::Filter as EthcoreFilter; use ethcore::header::{BlockNumber as EthBlockNumber}; use ethcore::log_entry::LogEntry; -use ethcore::miner::MinerService; +use ethcore::miner::{self, MinerService}; use ethcore::snapshot::SnapshotService; use ethcore::encoded; use sync::{SyncProvider}; @@ -92,7 +91,7 @@ impl Default for EthClientOptions { /// Eth rpc implementation. pub struct EthClient where - C: MiningBlockChainClient, + C: miner::BlockChainClient + BlockChainClient, SN: SnapshotService, S: SyncProvider, M: MinerService, @@ -142,7 +141,7 @@ enum PendingTransactionId { } impl EthClient where - C: MiningBlockChainClient + StateClient + Call + EngineInfo, + C: miner::BlockChainClient + BlockChainClient + StateClient + Call + EngineInfo, SN: SnapshotService, S: SyncProvider, M: MinerService, @@ -420,7 +419,7 @@ impl EthClient(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFilter) -> Vec where M: MinerService { - let receipts = miner.pending_receipts(best_block); + let receipts = miner.pending_receipts(best_block).unwrap_or_default(); let pending_logs = receipts.into_iter() .flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::>()) @@ -438,7 +437,7 @@ pub fn pending_logs(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFi result } -fn check_known(client: &C, number: BlockNumber) -> Result<()> where C: MiningBlockChainClient { +fn check_known(client: &C, number: BlockNumber) -> Result<()> where C: BlockChainClient { use ethcore::block_status::BlockStatus; let id = match number { @@ -458,7 +457,7 @@ fn check_known(client: &C, number: BlockNumber) -> Result<()> where C: Mining const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6. impl Eth for EthClient where - C: MiningBlockChainClient + StateClient + Call + EngineInfo + 'static, + C: miner::BlockChainClient + BlockChainClient + StateClient + Call + EngineInfo + 'static, SN: SnapshotService + 'static, S: SyncProvider + 'static, M: MinerService + 'static, @@ -506,7 +505,7 @@ impl Eth for EthClient< fn author(&self, meta: Metadata) -> Result { let dapp = meta.dapp_id(); - let mut miner = self.miner.author(); + let mut miner = self.miner.authoring_params().author; if miner == 0.into() { miner = self.dapp_accounts(dapp.into())?.get(0).cloned().unwrap_or_default(); } @@ -571,16 +570,8 @@ impl Eth for EthClient< let res = match num.unwrap_or_default() { BlockNumber::Pending if self.options.pending_nonce_from_queue => { - let nonce = self.miner.last_nonce(&address) - .map(|n| n + 1.into()) - .or_else(|| self.client.nonce(&address, BlockId::Latest)); - - match nonce { - Some(nonce) => Ok(nonce.into()), - None => Err(errors::database("latest nonce missing")) - } - }, - + Ok(self.miner.next_nonce(&*self.client, &address).into()) + } BlockNumber::Pending => { let info = self.client.chain_info(); let nonce = self.miner @@ -596,7 +587,6 @@ impl Eth for EthClient< None => Err(errors::database("latest nonce missing")) } }, - number => { try_bf!(check_known(&*self.client, number.clone())); match self.client.nonce(&address, block_number_to_id(number)) { @@ -615,13 +605,13 @@ impl Eth for EthClient< } fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture> { + let block_number = self.client.chain_info().best_block_number; + Box::new(future::ok(match num { - BlockNumber::Pending => Some( - self.miner.status().transactions_in_pending_block.into() - ), + BlockNumber::Pending => + self.miner.pending_transactions(block_number).map(|x| x.len().into()), _ => - self.client.block(block_number_to_id(num)) - .map(|block| block.transactions_count().into()) + self.client.block(block_number_to_id(num)).map(|block| block.transactions_count().into()) })) } @@ -665,8 +655,8 @@ impl Eth for EthClient< let hash: H256 = hash.into(); let block_number = self.client.chain_info().best_block_number; let tx = try_bf!(self.transaction(PendingTransactionId::Hash(hash))).or_else(|| { - self.miner.transaction(block_number, &hash) - .map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)) + self.miner.transaction(&hash) + .map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition)) }); Box::new(future::ok(tx)) @@ -745,11 +735,6 @@ impl Eth for EthClient< } fn work(&self, no_new_work_timeout: Trailing) -> Result { - if !self.miner.can_produce_work_package() { - warn!(target: "miner", "Cannot give work package - engine seals internally."); - return Err(errors::no_work_required()) - } - let no_new_work_timeout = no_new_work_timeout.unwrap_or_default(); // check if we're still syncing and return empty strings in that case @@ -768,50 +753,58 @@ impl Eth for EthClient< } } - if self.miner.author().is_zero() { + if self.miner.authoring_params().author.is_zero() { warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!"); return Err(errors::no_author()) } - self.miner.map_sealing_work(&*self.client, |b| { - let pow_hash = b.hash(); - let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); - let seed_hash = self.seed_compute.lock().hash_block_number(b.block().header().number()); - - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs(); - if no_new_work_timeout > 0 && b.block().header().timestamp() + no_new_work_timeout < now { - Err(errors::no_new_work()) - } else if self.options.send_block_number_in_get_work { - let block_number = b.block().header().number(); - Ok(Work { - pow_hash: pow_hash.into(), - seed_hash: seed_hash.into(), - target: target.into(), - number: Some(block_number), - }) - } else { - Ok(Work { - pow_hash: pow_hash.into(), - seed_hash: seed_hash.into(), - target: target.into(), - number: None - }) - } - }).unwrap_or(Err(errors::internal("No work found.", ""))) - } - fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result { - if !self.miner.can_produce_work_package() { - warn!(target: "miner", "Cannot submit work - engine seals internally."); - return Err(errors::no_work_required()) + let work = self.miner.work_package(&*self.client).ok_or_else(|| { + warn!(target: "miner", "Cannot give work package - engine seals internally."); + errors::no_work_required() + })?; + + let (pow_hash, number, timestamp, difficulty) = work; + let target = Ethash::difficulty_to_boundary(&difficulty); + let seed_hash = self.seed_compute.lock().hash_block_number(number); + + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs(); + if no_new_work_timeout > 0 && timestamp + no_new_work_timeout < now { + Err(errors::no_new_work()) + } else if self.options.send_block_number_in_get_work { + Ok(Work { + pow_hash: pow_hash.into(), + seed_hash: seed_hash.into(), + target: target.into(), + number: Some(number), + }) + } else { + Ok(Work { + pow_hash: pow_hash.into(), + seed_hash: seed_hash.into(), + target: target.into(), + number: None + }) } + } + fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result { + // TODO [ToDr] Should disallow submissions in case of PoA? let nonce: H64 = nonce.into(); let pow_hash: H256 = pow_hash.into(); let mix_hash: H256 = mix_hash.into(); trace!(target: "miner", "submit_work: Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash); let seal = vec![rlp::encode(&mix_hash).into_vec(), rlp::encode(&nonce).into_vec()]; - Ok(self.miner.submit_seal(&*self.client, pow_hash, seal).is_ok()) + let import = self.miner.submit_seal(pow_hash, seal) + .and_then(|block| self.client.import_sealed_block(block)); + + match import { + Ok(_) => Ok(true), + Err(err) => { + warn!(target: "miner", "Cannot submit work - {:?}.", err); + Ok(false) + }, + } } fn submit_hashrate(&self, rate: RpcU256, id: RpcH256) -> Result { diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 9e2f2f88874..6ca1c355f30 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use std::collections::HashSet; -use ethcore::miner::MinerService; +use ethcore::miner::{self, MinerService}; use ethcore::filter::Filter as EthcoreFilter; use ethcore::client::{BlockChainClient, BlockId}; use ethereum_types::H256; @@ -42,7 +42,7 @@ pub trait Filterable { fn block_hash(&self, id: BlockId) -> Option; /// pending transaction hashes at the given block. - fn pending_transactions_hashes(&self, block_number: u64) -> Vec; + fn pending_transactions_hashes(&self) -> Vec; /// Get logs that match the given filter. fn logs(&self, filter: EthcoreFilter) -> BoxFuture>; @@ -55,16 +55,13 @@ pub trait Filterable { } /// Eth filter rpc implementation for a full node. -pub struct EthFilterClient where - C: BlockChainClient, - M: MinerService { - +pub struct EthFilterClient { client: Arc, miner: Arc, polls: Mutex>, } -impl EthFilterClient where C: BlockChainClient, M: MinerService { +impl EthFilterClient { /// Creates new Eth filter client. pub fn new(client: Arc, miner: Arc) -> Self { EthFilterClient { @@ -75,7 +72,10 @@ impl EthFilterClient where C: BlockChainClient, M: MinerService { } } -impl Filterable for EthFilterClient where C: BlockChainClient, M: MinerService { +impl Filterable for EthFilterClient where + C: miner::BlockChainClient + BlockChainClient, + M: MinerService, +{ fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number } @@ -84,8 +84,11 @@ impl Filterable for EthFilterClient where C: BlockChainClient, M: Mi self.client.block_hash(id).map(Into::into) } - fn pending_transactions_hashes(&self, best: u64) -> Vec { - self.miner.pending_transactions_hashes(best) + fn pending_transactions_hashes(&self) -> Vec { + self.miner.ready_transactions(&*self.client) + .into_iter() + .map(|tx| tx.signed().hash()) + .collect() } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { @@ -118,8 +121,7 @@ impl EthFilter for T { fn new_pending_transaction_filter(&self) -> Result { let mut polls = self.polls().lock(); - let best_block = self.best_block_number(); - let pending_transactions = self.pending_transactions_hashes(best_block); + let pending_transactions = self.pending_transactions_hashes(); let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); Ok(id.into()) } @@ -143,8 +145,7 @@ impl EthFilter for T { }, PollFilter::PendingTransaction(ref mut previous_hashes) => { // get hashes of pending transactions - let best_block = self.best_block_number(); - let current_hashes = self.pending_transactions_hashes(best_block); + let current_hashes = self.pending_transactions_hashes(); let new_hashes = { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index c617c03b1d7..73e041abac3 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -533,7 +533,7 @@ impl Filterable for EthClient { self.client.block_hash(id).map(Into::into) } - fn pending_transactions_hashes(&self, _block_number: u64) -> Vec<::ethereum_types::H256> { + fn pending_transactions_hashes(&self) -> Vec<::ethereum_types::H256> { Vec::new() } diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index e1dc8d4d3d8..9db7488b6fa 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -275,6 +275,21 @@ impl Parity for ParityClient { ) } + fn all_transactions(&self) -> Result> { + let txq = self.light_dispatch.transaction_queue.read(); + let chain_info = self.light_dispatch.client.chain_info(); + + let current = txq.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp); + let future = txq.future_transactions(chain_info.best_block_number, chain_info.best_block_timestamp); + Ok( + current + .into_iter() + .chain(future.into_iter()) + .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) + .collect::>() + ) + } + fn future_transactions(&self) -> Result> { let txq = self.light_dispatch.transaction_queue.read(); let chain_info = self.light_dispatch.client.chain_info(); diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 451556e856a..d091d7a999c 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -27,9 +27,9 @@ use ethkey::{Brain, Generator}; use ethstore::random_phrase; use sync::{SyncProvider, ManageNetwork}; use ethcore::account_provider::AccountProvider; -use ethcore::client::{MiningBlockChainClient, StateClient, Call}; +use ethcore::client::{BlockChainClient, StateClient, Call}; use ethcore::ids::BlockId; -use ethcore::miner::MinerService; +use ethcore::miner::{self, MinerService}; use ethcore::mode::Mode; use ethcore::state::StateInfo; use ethcore_logger::RotatingLogger; @@ -72,7 +72,7 @@ pub struct ParityClient { } impl ParityClient where - C: MiningBlockChainClient, + C: BlockChainClient, { /// Creates new `ParityClient`. pub fn new( @@ -116,7 +116,7 @@ impl ParityClient where impl Parity for ParityClient where S: StateInfo + 'static, - C: MiningBlockChainClient + StateClient + Call + 'static, + C: miner::BlockChainClient + BlockChainClient + StateClient + Call + 'static, M: MinerService + 'static, U: UpdateService + 'static, { @@ -170,23 +170,23 @@ impl Parity for ParityClient where } fn transactions_limit(&self) -> Result { - Ok(self.miner.transactions_limit()) + Ok(self.miner.queue_status().limits.max_count) } fn min_gas_price(&self) -> Result { - Ok(U256::from(self.miner.minimal_gas_price())) + Ok(self.miner.queue_status().options.minimal_gas_price.into()) } fn extra_data(&self) -> Result { - Ok(Bytes::new(self.miner.extra_data())) + Ok(Bytes::new(self.miner.authoring_params().extra_data)) } fn gas_floor_target(&self) -> Result { - Ok(U256::from(self.miner.gas_floor_target())) + Ok(U256::from(self.miner.authoring_params().gas_range_target.0)) } fn gas_ceil_target(&self) -> Result { - Ok(U256::from(self.miner.gas_ceil_target())) + Ok(U256::from(self.miner.authoring_params().gas_range_target.1)) } fn dev_logs(&self) -> Result> { @@ -315,12 +315,28 @@ impl Parity for ParityClient where fn pending_transactions(&self) -> Result> { let block_number = self.client.chain_info().best_block_number; - Ok(self.miner.pending_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::>()) + let ready_transactions = self.miner.ready_transactions(&*self.client); + + Ok(ready_transactions + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) + .collect() + ) } - fn future_transactions(&self) -> Result> { + fn all_transactions(&self) -> Result> { let block_number = self.client.chain_info().best_block_number; - Ok(self.miner.future_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::>()) + let all_transactions = self.miner.queued_transactions(); + + Ok(all_transactions + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) + .collect() + ) + } + + fn future_transactions(&self) -> Result> { + Err(errors::deprecated("Use `parity_allTransaction` instead.")) } fn pending_transactions_stats(&self) -> Result> { @@ -359,11 +375,7 @@ impl Parity for ParityClient where fn next_nonce(&self, address: H160) -> BoxFuture { let address: Address = address.into(); - Box::new(future::ok(self.miner.last_nonce(&address) - .map(|n| n + 1.into()) - .unwrap_or_else(|| self.client.latest_nonce(&address)) - .into() - )) + Box::new(future::ok(self.miner.next_nonce(&*self.client, &address).into())) } fn mode(&self) -> Result { diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 475f5e01959..612e6aa78b7 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -18,8 +18,8 @@ use std::io; use std::sync::Arc; +use ethcore::client::BlockChainClient; use ethcore::miner::MinerService; -use ethcore::client::MiningBlockChainClient; use ethcore::mode::Mode; use sync::ManageNetwork; use fetch::{self, Fetch}; @@ -47,7 +47,7 @@ pub struct ParitySetClient { } impl ParitySetClient - where C: MiningBlockChainClient + 'static, + where C: BlockChainClient + 'static, { /// Creates new `ParitySetClient` with given `Fetch`. pub fn new( @@ -73,24 +73,38 @@ impl ParitySetClient } impl ParitySet for ParitySetClient where - C: MiningBlockChainClient + 'static, + C: BlockChainClient + 'static, M: MinerService + 'static, U: UpdateService + 'static, F: Fetch + 'static, { - fn set_min_gas_price(&self, gas_price: U256) -> Result { - self.miner.set_minimal_gas_price(gas_price.into()); - Ok(true) + fn set_min_gas_price(&self, _gas_price: U256) -> Result { + warn!("setMinGasPrice is deprecated. Ignoring request."); + Ok(false) + } + + fn set_transactions_limit(&self, _limit: usize) -> Result { + warn!("setTransactionsLimit is deprecated. Ignoring request."); + Ok(false) + } + + fn set_tx_gas_limit(&self, _limit: U256) -> Result { + warn!("setTxGasLimit is deprecated. Ignoring request."); + Ok(false) } fn set_gas_floor_target(&self, target: U256) -> Result { - self.miner.set_gas_floor_target(target.into()); + let mut range = self.miner.authoring_params().gas_range_target.clone(); + range.0 = target.into(); + self.miner.set_gas_range_target(range); Ok(true) } fn set_gas_ceil_target(&self, target: U256) -> Result { - self.miner.set_gas_ceil_target(target.into()); + let mut range = self.miner.authoring_params().gas_range_target.clone(); + range.1 = target.into(); + self.miner.set_gas_range_target(range); Ok(true) } @@ -99,23 +113,13 @@ impl ParitySet for ParitySetClient where Ok(true) } - fn set_author(&self, author: H160) -> Result { - self.miner.set_author(author.into()); + fn set_author(&self, address: H160) -> Result { + self.miner.set_author(address.into(), None).map_err(Into::into).map_err(errors::password)?; Ok(true) } fn set_engine_signer(&self, address: H160, password: String) -> Result { - self.miner.set_engine_signer(address.into(), password).map_err(Into::into).map_err(errors::password)?; - Ok(true) - } - - fn set_transactions_limit(&self, limit: usize) -> Result { - self.miner.set_transactions_limit(limit); - Ok(true) - } - - fn set_tx_gas_limit(&self, limit: U256) -> Result { - self.miner.set_tx_gas_limit(limit.into()); + self.miner.set_author(address.into(), Some(password)).map_err(Into::into).map_err(errors::password)?; Ok(true) } @@ -202,6 +206,8 @@ impl ParitySet for ParitySetClient where let block_number = self.client.chain_info().best_block_number; let hash = hash.into(); - Ok(self.miner.remove_pending_transaction(&*self.client, &hash).map(|t| Transaction::from_pending(t, block_number, self.eip86_transition))) + Ok(self.miner.remove_transaction(&hash) + .map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition)) + ) } } diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 0ee1afd5fa7..06df83b752b 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -18,7 +18,7 @@ use std::sync::Arc; -use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId}; +use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId}; use rlp::UntrustedRlp; use transaction::SignedTransaction; @@ -53,7 +53,7 @@ impl TracesClient { impl Traces for TracesClient where S: StateInfo + 'static, - C: MiningBlockChainClient + StateClient + Call + 'static + C: BlockChainClient + StateClient + Call + 'static { type Metadata = Metadata; diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 747c10200df..6aacbc865d7 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -17,15 +17,14 @@ //! rpc integration tests. use std::env; use std::sync::Arc; -use std::time::Duration; -use ethereum_types::{U256, H256, Address}; +use ethereum_types::{H256, Address}; use ethcore::account_provider::AccountProvider; use ethcore::block::Block; use ethcore::client::{BlockChainClient, Client, ClientConfig, ChainInfo, ImportBlock}; use ethcore::ethereum; use ethcore::ids::BlockId; -use ethcore::miner::{MinerOptions, Banning, GasPricer, Miner, PendingSet, GasLimit}; +use ethcore::miner::Miner; use ethcore::spec::{Genesis, Spec}; use ethcore::views::BlockView; use ethjson::blockchain::BlockChain; @@ -33,7 +32,6 @@ use ethjson::state::test::ForkSpec; use io::IoChannel; use kvdb_memorydb; use miner::external::ExternalMiner; -use miner::transaction_queue::PrioritizationStrategy; use parking_lot::Mutex; use jsonrpc_core::IoHandler; @@ -58,30 +56,7 @@ fn sync_provider() -> Arc { } fn miner_service(spec: &Spec, accounts: Arc) -> Arc { - Miner::new( - MinerOptions { - force_sealing: true, - reseal_on_external_tx: true, - reseal_on_own_tx: true, - reseal_on_uncle: false, - tx_queue_size: 1024, - tx_gas_limit: !U256::zero(), - tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, - tx_queue_gas_limit: GasLimit::None, - tx_queue_banning: Banning::Disabled, - tx_queue_memory_limit: None, - pending_set: PendingSet::SealingOrElseQueue, - reseal_min_period: Duration::from_secs(0), - reseal_max_period: Duration::from_secs(120), - work_queue_size: 50, - enable_resubmission: true, - refuse_service_transactions: false, - infinite_pending_block: false, - }, - GasPricer::new_fixed(20_000_000_000u64.into()), - &spec, - Some(accounts), - ) + Arc::new(Miner::new_for_tests(spec, Some(accounts))) } fn snapshot_service() -> Arc { diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index ca9993baea4..6781d10b95b 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -16,82 +16,68 @@ //! Test implementation of miner service. +use std::sync::Arc; use std::collections::{BTreeMap, HashMap}; -use std::collections::hash_map::Entry; use bytes::Bytes; use ethcore::account_provider::SignError as AccountError; -use ethcore::block::{Block, ClosedBlock}; +use ethcore::block::{Block, SealedBlock, IsBlock}; use ethcore::client::{Nonce, PrepareOpenBlock, StateClient, EngineInfo}; use ethcore::engines::EthEngine; use ethcore::error::Error; use ethcore::header::{BlockNumber, Header}; use ethcore::ids::BlockId; -use ethcore::miner::{MinerService, MinerStatus}; +use ethcore::miner::{MinerService, AuthoringParams}; use ethcore::receipt::{Receipt, RichReceipt}; use ethereum_types::{H256, U256, Address}; -use miner::local_transactions::Status as LocalTransactionStatus; +use miner::pool::local_transactions::Status as LocalTransactionStatus; +use miner::pool::{verifier, VerifiedTransaction, QueueStatus}; use parking_lot::{RwLock, Mutex}; -use transaction::{UnverifiedTransaction, SignedTransaction, PendingTransaction, ImportResult as TransactionImportResult}; +use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; +use txpool; /// Test miner service. pub struct TestMinerService { /// Imported transactions. pub imported_transactions: Mutex>, - /// Latest closed block. - pub latest_closed_block: Mutex>, /// Pre-existed pending transactions pub pending_transactions: Mutex>, /// Pre-existed local transactions pub local_transactions: Mutex>, /// Pre-existed pending receipts pub pending_receipts: Mutex>, - /// Last nonces. - pub last_nonces: RwLock>, + /// Next nonces. + pub next_nonces: RwLock>, /// Password held by Engine. pub password: RwLock, - min_gas_price: RwLock, - gas_range_target: RwLock<(U256, U256)>, - author: RwLock
, - extra_data: RwLock, - limit: RwLock, - tx_gas_limit: RwLock, + authoring_params: RwLock, } impl Default for TestMinerService { fn default() -> TestMinerService { TestMinerService { imported_transactions: Mutex::new(Vec::new()), - latest_closed_block: Mutex::new(None), pending_transactions: Mutex::new(HashMap::new()), local_transactions: Mutex::new(BTreeMap::new()), pending_receipts: Mutex::new(BTreeMap::new()), - last_nonces: RwLock::new(HashMap::new()), - min_gas_price: RwLock::new(U256::from(20_000_000)), - gas_range_target: RwLock::new((U256::from(12345), U256::from(54321))), - author: RwLock::new(Address::zero()), + next_nonces: RwLock::new(HashMap::new()), password: RwLock::new(String::new()), - extra_data: RwLock::new(vec![1, 2, 3, 4]), - limit: RwLock::new(1024), - tx_gas_limit: RwLock::new(!U256::zero()), + authoring_params: RwLock::new(AuthoringParams { + author: Address::zero(), + gas_range_target: (12345.into(), 54321.into()), + extra_data: vec![1, 2, 3, 4], + }), } } } impl TestMinerService { - /// Increments last nonce for given address. - pub fn increment_last_nonce(&self, address: Address) { - let mut last_nonces = self.last_nonces.write(); - match last_nonces.entry(address) { - Entry::Occupied(mut occupied) => { - let val = *occupied.get(); - *occupied.get_mut() = val + 1.into(); - }, - Entry::Vacant(vacant) => { - vacant.insert(0.into()); - }, - } + /// Increments nonce for given address. + pub fn increment_nonce(&self, address: &Address) { + let mut next_nonces = self.next_nonces.write(); + let nonce = next_nonces.entry(*address).or_insert_with(|| 0.into()); + *nonce = *nonce + 1.into(); } } @@ -129,164 +115,112 @@ impl MinerService for TestMinerService { None } - /// Returns miner's status. - fn status(&self) -> MinerStatus { - MinerStatus { - transactions_in_pending_queue: 0, - transactions_in_future_queue: 0, - transactions_in_pending_block: 1 - } - } - - fn set_author(&self, author: Address) { - *self.author.write() = author; + fn authoring_params(&self) -> AuthoringParams { + self.authoring_params.read().clone() } - fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> { - *self.author.write() = address; - *self.password.write() = password; + fn set_author(&self, author: Address, password: Option) -> Result<(), AccountError> { + self.authoring_params.write().author = author; + if let Some(password) = password { + *self.password.write() = password; + } Ok(()) } fn set_extra_data(&self, extra_data: Bytes) { - *self.extra_data.write() = extra_data; - } - - /// Set the lower gas limit we wish to target when sealing a new block. - fn set_gas_floor_target(&self, target: U256) { - self.gas_range_target.write().0 = target; - } - - /// Set the upper gas limit we wish to target when sealing a new block. - fn set_gas_ceil_target(&self, target: U256) { - self.gas_range_target.write().1 = target; - } - - fn set_minimal_gas_price(&self, min_gas_price: U256) { - *self.min_gas_price.write() = min_gas_price; - } - - fn set_transactions_limit(&self, limit: usize) { - *self.limit.write() = limit; - } - - fn set_tx_gas_limit(&self, limit: U256) { - *self.tx_gas_limit.write() = limit; - } - - fn transactions_limit(&self) -> usize { - *self.limit.read() - } - - fn author(&self) -> Address { - *self.author.read() - } - - fn minimal_gas_price(&self) -> U256 { - *self.min_gas_price.read() + self.authoring_params.write().extra_data = extra_data; } - fn extra_data(&self) -> Bytes { - self.extra_data.read().clone() - } - - fn gas_floor_target(&self) -> U256 { - self.gas_range_target.read().0 - } - - fn gas_ceil_target(&self) -> U256 { - self.gas_range_target.read().1 + fn set_gas_range_target(&self, target: (U256, U256)) { + self.authoring_params.write().gas_range_target = target; } /// Imports transactions to transaction queue. - fn import_external_transactions(&self, _chain: &C, transactions: Vec) -> - Vec> { + fn import_external_transactions(&self, chain: &C, transactions: Vec) + -> Vec> + { // lets assume that all txs are valid let transactions: Vec<_> = transactions.into_iter().map(|tx| SignedTransaction::new(tx).unwrap()).collect(); self.imported_transactions.lock().extend_from_slice(&transactions); for sender in transactions.iter().map(|tx| tx.sender()) { - let nonce = self.last_nonce(&sender).expect("last_nonce must be populated in tests"); - self.last_nonces.write().insert(sender, nonce + U256::from(1)); + let nonce = self.next_nonce(chain, &sender); + self.next_nonces.write().insert(sender, nonce); } + transactions .iter() - .map(|_| Ok(TransactionImportResult::Current)) + .map(|_| Ok(())) .collect() } /// Imports transactions to transaction queue. - fn import_own_transaction(&self, chain: &C, pending: PendingTransaction) -> - Result { + fn import_own_transaction(&self, chain: &C, pending: PendingTransaction) + -> Result<(), transaction::Error> { // keep the pending nonces up to date let sender = pending.transaction.sender(); - let nonce = self.last_nonce(&sender).unwrap_or(chain.latest_nonce(&sender)); - self.last_nonces.write().insert(sender, nonce + U256::from(1)); + let nonce = self.next_nonce(chain, &sender); + self.next_nonces.write().insert(sender, nonce); // lets assume that all txs are valid self.imported_transactions.lock().push(pending.transaction); - Ok(TransactionImportResult::Current) - } - - /// Returns hashes of transactions currently in pending - fn pending_transactions_hashes(&self, _best_block: BlockNumber) -> Vec { - vec![] - } - - /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, _chain: &C) { - unimplemented!(); + Ok(()) } /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { + fn chain_new_blocks(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256], _is_internal: bool) { unimplemented!(); } - /// PoW chain - can produce work package - fn can_produce_work_package(&self) -> bool { - true - } - /// New chain head event. Restart mining operation. fn update_sealing(&self, _chain: &C) { unimplemented!(); } - fn map_sealing_work(&self, chain: &C, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { - let open_block = chain.prepare_open_block(self.author(), *self.gas_range_target.write(), self.extra_data()); - Some(f(&open_block.close())) + fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> { + let params = self.authoring_params(); + let open_block = chain.prepare_open_block(params.author, params.gas_range_target, params.extra_data); + let closed = open_block.close(); + let header = closed.header(); + + Some((header.hash(), header.number(), header.timestamp(), *header.difficulty())) } - fn transaction(&self, _best_block: BlockNumber, hash: &H256) -> Option { - self.pending_transactions.lock().get(hash).cloned().map(Into::into) + fn transaction(&self, hash: &H256) -> Option> { + self.pending_transactions.lock().get(hash).cloned().map(|tx| { + Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) + }) } - fn remove_pending_transaction(&self, _chain: &C, hash: &H256) -> Option { - self.pending_transactions.lock().remove(hash).map(Into::into) + fn remove_transaction(&self, hash: &H256) -> Option> { + self.pending_transactions.lock().remove(hash).map(|tx| { + Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) + }) } - fn pending_transactions(&self) -> Vec { - self.pending_transactions.lock().values().cloned().map(Into::into).collect() + fn pending_transactions(&self, _best_block: BlockNumber) -> Option> { + Some(self.pending_transactions.lock().values().cloned().collect()) } fn local_transactions(&self) -> BTreeMap { self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect() } - fn ready_transactions(&self, _best_block: BlockNumber, _best_timestamp: u64) -> Vec { - self.pending_transactions.lock().values().cloned().map(Into::into).collect() + fn ready_transactions(&self, _chain: &C) -> Vec> { + self.queued_transactions() } - fn future_transactions(&self) -> Vec { - vec![] + fn queued_transactions(&self) -> Vec> { + self.pending_transactions.lock().values().cloned().map(|tx| { + Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) + }).collect() } fn pending_receipt(&self, _best_block: BlockNumber, hash: &H256) -> Option { // Not much point implementing this since the logic is complex and the only thing it relies on is pending_receipts, which is already tested. - self.pending_receipts(0).get(hash).map(|r| + self.pending_receipts(0).unwrap().get(hash).map(|r| RichReceipt { transaction_hash: Default::default(), transaction_index: Default::default(), @@ -300,25 +234,49 @@ impl MinerService for TestMinerService { ) } - fn pending_receipts(&self, _best_block: BlockNumber) -> BTreeMap { - self.pending_receipts.lock().clone() + fn pending_receipts(&self, _best_block: BlockNumber) -> Option> { + Some(self.pending_receipts.lock().clone()) } - fn last_nonce(&self, address: &Address) -> Option { - self.last_nonces.read().get(address).cloned() + fn next_nonce(&self, _chain: &C, address: &Address) -> U256 { + self.next_nonces.read().get(address).cloned().unwrap_or_default() } fn is_currently_sealing(&self) -> bool { false } + fn queue_status(&self) -> QueueStatus { + QueueStatus { + options: verifier::Options { + minimal_gas_price: 0x1312d00.into(), + block_gas_limit: 5_000_000.into(), + tx_gas_limit: 5_000_000.into(), + }, + status: txpool::LightStatus { + mem_usage: 1_000, + transaction_count: 52, + senders: 1, + }, + limits: txpool::Options { + max_count: 1_024, + max_per_sender: 16, + max_mem_usage: 5_000, + }, + } + } + /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, _chain: &C, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { + fn submit_seal(&self, _pow_hash: H256, _seal: Vec) -> Result { unimplemented!(); } fn sensible_gas_price(&self) -> U256 { - 20000000000u64.into() + 20_000_000_000u64.into() + } + + fn sensible_gas_limit(&self) -> U256 { + 0x5208.into() } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index c79b02c2d23..badf5bff728 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -368,7 +368,7 @@ fn rpc_eth_author() { for i in 0..20 { let addr = tester.accounts_provider.new_account(&format!("{}", i)).unwrap(); - tester.miner.set_author(addr.clone()); + tester.miner.set_author(addr.clone(), None).unwrap(); assert_eq!(tester.io.handle_request_sync(req), Some(make_res(addr))); } @@ -377,7 +377,7 @@ fn rpc_eth_author() { #[test] fn rpc_eth_mining() { let tester = EthTester::default(); - tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "eth_mining", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; @@ -498,7 +498,7 @@ fn rpc_eth_transaction_count_next_nonce() { let tester = EthTester::new_with_options(EthClientOptions::with(|options| { options.pending_nonce_from_queue = true; })); - tester.miner.increment_last_nonce(1.into()); + tester.miner.increment_nonce(&1.into()); let request1 = r#"{ "jsonrpc": "2.0", @@ -553,7 +553,7 @@ fn rpc_eth_transaction_count_by_number_pending() { "params": ["pending"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x1","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0","id":1}"#; assert_eq!(EthTester::default().io.handle_request_sync(request), Some(response.to_owned())); } @@ -835,7 +835,7 @@ fn rpc_eth_send_transaction() { assert_eq!(tester.io.handle_request_sync(&request), Some(response)); - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); let t = Transaction { nonce: U256::one(), @@ -905,7 +905,7 @@ fn rpc_eth_sign_transaction() { r#""value":"0x9184e72a""# + r#"}},"id":1}"#; - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); assert_eq!(tester.io.handle_request_sync(&request), Some(response)); } @@ -1118,7 +1118,7 @@ fn rpc_get_work_returns_no_work_if_cant_mine() { #[test] fn rpc_get_work_returns_correct_work_package() { let eth_tester = EthTester::default(); - eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x76c7bd86693aee93d1a80a408a09a0585b1a1292afcb56192f171d925ea18e2d","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000","0x1"],"id":1}"#; @@ -1131,7 +1131,7 @@ fn rpc_get_work_should_not_return_block_number() { let eth_tester = EthTester::new_with_options(EthClientOptions::with(|options| { options.send_block_number_in_get_work = false; })); - eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x76c7bd86693aee93d1a80a408a09a0585b1a1292afcb56192f171d925ea18e2d","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000"],"id":1}"#; @@ -1142,10 +1142,10 @@ fn rpc_get_work_should_not_return_block_number() { #[test] fn rpc_get_work_should_timeout() { let eth_tester = EthTester::default(); - eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() - 1000; // Set latest block to 1000 seconds ago eth_tester.client.set_latest_block_timestamp(timestamp); - let hash = eth_tester.miner.map_sealing_work(&*eth_tester.client, |b| b.hash()).unwrap(); + let hash = eth_tester.miner.work_package(&*eth_tester.client).unwrap().0; // Request without providing timeout. This should work since we're disabling timeout. let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 18f76c6719b..5835e2e82c8 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -17,13 +17,13 @@ use std::sync::Arc; use ethcore::account_provider::AccountProvider; use ethcore::client::{TestBlockChainClient, Executed}; -use ethcore::miner::LocalTransactionStatus; use ethcore_logger::RotatingLogger; +use ethereum_types::{Address, U256, H256}; use ethstore::ethkey::{Generator, Random}; -use sync::ManageNetwork; +use miner::pool::local_transactions::Status as LocalTransactionStatus; use node_health::{self, NodeHealth}; use parity_reactor; -use ethereum_types::{Address, U256, H256}; +use sync::ManageNetwork; use jsonrpc_core::IoHandler; use v1::{Parity, ParityClient}; @@ -455,7 +455,9 @@ fn rpc_parity_next_nonce() { let address = Address::default(); let io1 = deps.default_client(); let deps = Dependencies::new(); - deps.miner.last_nonces.write().insert(address.clone(), 2.into()); + deps.miner.increment_nonce(&address); + deps.miner.increment_nonce(&address); + deps.miner.increment_nonce(&address); let io2 = deps.default_client(); let request = r#"{ @@ -486,11 +488,20 @@ fn rpc_parity_transactions_stats() { fn rpc_parity_local_transactions() { let deps = Dependencies::new(); let io = deps.default_client(); - deps.miner.local_transactions.lock().insert(10.into(), LocalTransactionStatus::Pending); - deps.miner.local_transactions.lock().insert(15.into(), LocalTransactionStatus::Future); + let tx = ::transaction::Transaction { + value: 5.into(), + gas: 3.into(), + gas_price: 2.into(), + action: ::transaction::Action::Create, + data: vec![1, 2, 3], + nonce: 0.into(), + }.fake_sign(3.into()); + let tx = Arc::new(::miner::pool::VerifiedTransaction::from_pending_block_transaction(tx)); + deps.miner.local_transactions.lock().insert(10.into(), LocalTransactionStatus::Pending(tx.clone())); + deps.miner.local_transactions.lock().insert(15.into(), LocalTransactionStatus::Pending(tx.clone())); let request = r#"{"jsonrpc": "2.0", "method": "parity_localTransactions", "params":[], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":{"0x000000000000000000000000000000000000000000000000000000000000000a":{"status":"pending"},"0x000000000000000000000000000000000000000000000000000000000000000f":{"status":"future"}},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"0x000000000000000000000000000000000000000000000000000000000000000a":{"status":"pending"},"0x000000000000000000000000000000000000000000000000000000000000000f":{"status":"pending"}},"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index af08236fdf6..78c73f94794 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -109,10 +109,9 @@ fn rpc_parity_set_min_gas_price() { io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "parity_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.minimal_gas_price(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); } #[test] @@ -129,7 +128,7 @@ fn rpc_parity_set_gas_floor_target() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.gas_floor_target(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); + assert_eq!(miner.authoring_params().gas_range_target.0, U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); } #[test] @@ -146,7 +145,7 @@ fn rpc_parity_set_extra_data() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.extra_data(), "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap()); + assert_eq!(miner.authoring_params().extra_data, "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap()); } #[test] @@ -162,7 +161,7 @@ fn rpc_parity_set_author() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); + assert_eq!(miner.authoring_params().author, Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); } #[test] @@ -178,7 +177,7 @@ fn rpc_parity_set_engine_signer() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); + assert_eq!(miner.authoring_params().author, Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); assert_eq!(*miner.password.read(), "password".to_string()); } @@ -193,10 +192,9 @@ fn rpc_parity_set_transactions_limit() { io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "parity_setTransactionsLimit", "params":[10240240], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.transactions_limit(), 10_240_240); } #[test] diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 502a5905822..c11aca42fb7 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -220,7 +220,7 @@ fn sign_and_send_test(method: &str) { assert_eq!(tester.io.handle_request_sync(request.as_ref()), Some(response)); - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); let t = Transaction { nonce: U256::one(), diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 118bbe91ce3..3a56c5a0d30 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -327,7 +327,7 @@ fn should_add_sign_transaction_to_the_queue() { r#"}},"id":1}"#; // then - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); let promise = tester.io.handle_request(&request); // the future must be polled at least once before request is queued. diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 81c406fb3a3..165cf63d677 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -143,7 +143,13 @@ build_rpc_trait! { #[rpc(name = "parity_pendingTransactions")] fn pending_transactions(&self) -> Result>; - /// Returns all future transactions from transaction queue. + /// Returns all transactions from transaction queue. + /// + /// Some of them might not be ready to be included in a block yet. + #[rpc(name = "parity_allTransactions")] + fn all_transactions(&self) -> Result>; + + /// Returns all future transactions from transaction queue (deprecated) #[rpc(name = "parity_futureTransactions")] fn future_transactions(&self) -> Result>; diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index c5dd63624f5..0ac3e374542 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -14,12 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::sync::Arc; + use serde::{Serialize, Serializer}; use serde::ser::SerializeStruct; -use ethcore::miner; use ethcore::{contract_address, CreateContractAddress}; +use miner; use transaction::{LocalizedTransaction, Action, PendingTransaction, SignedTransaction}; -use v1::helpers::errors; use v1::types::{Bytes, H160, H256, U256, H512, U64, TransactionCondition}; /// Transaction @@ -248,17 +249,23 @@ impl Transaction { impl LocalTransactionStatus { /// Convert `LocalTransactionStatus` into RPC `LocalTransactionStatus`. - pub fn from(s: miner::LocalTransactionStatus, block_number: u64, eip86_transition: u64) -> Self { - use ethcore::miner::LocalTransactionStatus::*; + pub fn from(s: miner::pool::local_transactions::Status, block_number: u64, eip86_transition: u64) -> Self { + let convert = |tx: Arc| { + Transaction::from_signed(tx.signed().clone(), block_number, eip86_transition) + }; + use miner::pool::local_transactions::Status::*; match s { - Pending => LocalTransactionStatus::Pending, - Future => LocalTransactionStatus::Future, - Mined(tx) => LocalTransactionStatus::Mined(Transaction::from_signed(tx, block_number, eip86_transition)), - Dropped(tx) => LocalTransactionStatus::Dropped(Transaction::from_signed(tx, block_number, eip86_transition)), - Rejected(tx, err) => LocalTransactionStatus::Rejected(Transaction::from_signed(tx, block_number, eip86_transition), errors::transaction_message(err)), - Replaced(tx, gas_price, hash) => LocalTransactionStatus::Replaced(Transaction::from_signed(tx, block_number, eip86_transition), gas_price.into(), hash.into()), - Invalid(tx) => LocalTransactionStatus::Invalid(Transaction::from_signed(tx, block_number, eip86_transition)), - Canceled(tx) => LocalTransactionStatus::Canceled(Transaction::from_pending(tx, block_number, eip86_transition)), + Pending(_) => LocalTransactionStatus::Pending, + Mined(tx) => LocalTransactionStatus::Mined(convert(tx)), + Dropped(tx) => LocalTransactionStatus::Dropped(convert(tx)), + Rejected(tx, reason) => LocalTransactionStatus::Rejected(convert(tx), reason), + Invalid(tx) => LocalTransactionStatus::Invalid(convert(tx)), + Canceled(tx) => LocalTransactionStatus::Canceled(convert(tx)), + Replaced { old, new } => LocalTransactionStatus::Replaced( + convert(old), + new.signed().gas_price.into(), + new.signed().hash().into(), + ), } } } diff --git a/secret_store/src/trusted_client.rs b/secret_store/src/trusted_client.rs index 5a9efe4b680..94b1c0174de 100644 --- a/secret_store/src/trusted_client.rs +++ b/secret_store/src/trusted_client.rs @@ -74,7 +74,7 @@ impl TrustedClient { let transaction = Transaction { nonce: client.latest_nonce(&self.self_key_pair.address()), action: Action::Call(contract), - gas: miner.gas_floor_target(), + gas: miner.authoring_params().gas_range_target.0, gas_price: miner.sensible_gas_price(), value: Default::default(), data: tx_data, diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index b9db0f6d214..fd191929937 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -9,4 +9,5 @@ authors = ["Parity Technologies "] error-chain = "0.11" log = "0.3" smallvec = "0.4" +trace-time = { path = "../util/trace-time" } ethereum-types = "0.3" diff --git a/transaction-pool/src/error.rs b/transaction-pool/src/error.rs index 706a5b77b19..2e8ac739897 100644 --- a/transaction-pool/src/error.rs +++ b/transaction-pool/src/error.rs @@ -21,17 +21,17 @@ error_chain! { /// Transaction is already imported AlreadyImported(hash: H256) { description("transaction is already in the pool"), - display("[{:?}] transaction already imported", hash) + display("[{:?}] already imported", hash) } /// Transaction is too cheap to enter the queue - TooCheapToEnter(hash: H256) { + TooCheapToEnter(hash: H256, min_score: String) { description("the pool is full and transaction is too cheap to replace any transaction"), - display("[{:?}] transaction too cheap to enter the pool", hash) + display("[{:?}] too cheap to enter the pool. Min score: {}", hash, min_score) } /// Transaction is too cheap to replace existing transaction that occupies the same slot. TooCheapToReplace(old_hash: H256, hash: H256) { description("transaction is too cheap to replace existing transaction in the pool"), - display("[{:?}] transaction too cheap to replace: {:?}", hash, old_hash) + display("[{:?}] too cheap to replace: {:?}", hash, old_hash) } } } @@ -43,7 +43,7 @@ impl PartialEq for ErrorKind { match (self, other) { (&AlreadyImported(ref h1), &AlreadyImported(ref h2)) => h1 == h2, - (&TooCheapToEnter(ref h1), &TooCheapToEnter(ref h2)) => h1 == h2, + (&TooCheapToEnter(ref h1, ref s1), &TooCheapToEnter(ref h2, ref s2)) => h1 == h2 && s1 == s2, (&TooCheapToReplace(ref old1, ref new1), &TooCheapToReplace(ref old2, ref new2)) => old1 == old2 && new1 == new2, _ => false, } diff --git a/transaction-pool/src/lib.rs b/transaction-pool/src/lib.rs index 29353a10008..33d17f4b0fc 100644 --- a/transaction-pool/src/lib.rs +++ b/transaction-pool/src/lib.rs @@ -76,6 +76,8 @@ extern crate error_chain; #[macro_use] extern crate log; +extern crate trace_time; + #[cfg(test)] mod tests; @@ -90,6 +92,7 @@ mod verifier; pub mod scoring; +pub use self::error::{Error, ErrorKind}; pub use self::listener::{Listener, NoopListener}; pub use self::options::Options; pub use self::pool::{Pool, PendingIterator}; diff --git a/transaction-pool/src/listener.rs b/transaction-pool/src/listener.rs index 2fc55528fe8..728a035e314 100644 --- a/transaction-pool/src/listener.rs +++ b/transaction-pool/src/listener.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::sync::Arc; +use error::ErrorKind; /// Transaction pool listener. /// @@ -28,16 +29,16 @@ pub trait Listener { /// The transaction was rejected from the pool. /// It means that it was too cheap to replace any transaction already in the pool. - fn rejected(&mut self, _tx: T) {} + fn rejected(&mut self, _tx: &Arc, _reason: &ErrorKind) {} - /// The transaction was dropped from the pool because of a limit. - fn dropped(&mut self, _tx: &Arc) {} + /// The transaction was pushed out from the pool because of the limit. + fn dropped(&mut self, _tx: &Arc, _by: Option<&T>) {} /// The transaction was marked as invalid by executor. fn invalid(&mut self, _tx: &Arc) {} - /// The transaction has been cancelled. - fn cancelled(&mut self, _tx: &Arc) {} + /// The transaction has been canceled. + fn canceled(&mut self, _tx: &Arc) {} /// The transaction has been mined. fn mined(&mut self, _tx: &Arc) {} @@ -47,3 +48,38 @@ pub trait Listener { #[derive(Debug)] pub struct NoopListener; impl Listener for NoopListener {} + +impl Listener for (A, B) where + A: Listener, + B: Listener, +{ + fn added(&mut self, tx: &Arc, old: Option<&Arc>) { + self.0.added(tx, old); + self.1.added(tx, old); + } + + fn rejected(&mut self, tx: &Arc, reason: &ErrorKind) { + self.0.rejected(tx, reason); + self.1.rejected(tx, reason); + } + + fn dropped(&mut self, tx: &Arc, by: Option<&T>) { + self.0.dropped(tx, by); + self.1.dropped(tx, by); + } + + fn invalid(&mut self, tx: &Arc) { + self.0.invalid(tx); + self.1.invalid(tx); + } + + fn canceled(&mut self, tx: &Arc) { + self.0.canceled(tx); + self.1.canceled(tx); + } + + fn mined(&mut self, tx: &Arc) { + self.0.mined(tx); + self.1.mined(tx); + } +} diff --git a/transaction-pool/src/options.rs b/transaction-pool/src/options.rs index ddec912864f..8ccf8adfd16 100644 --- a/transaction-pool/src/options.rs +++ b/transaction-pool/src/options.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . /// Transaction Pool options. -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct Options { /// Maximal number of transactions in the pool. pub max_count: usize, diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index 4f4a63920f1..fa28cdcdfe5 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -109,17 +109,17 @@ impl Pool where ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(*transaction.hash())); - // TODO [ToDr] Most likely move this after the transsaction is inserted. + // TODO [ToDr] Most likely move this after the transaction is inserted. // Avoid using should_replace, but rather use scoring for that. { let remove_worst = |s: &mut Self, transaction| { match s.remove_worst(&transaction) { Err(err) => { - s.listener.rejected(transaction); + s.listener.rejected(&Arc::new(transaction), err.kind()); Err(err) }, Ok(removed) => { - s.listener.dropped(&removed); + s.listener.dropped(&removed, Some(&transaction)); s.finalize_remove(removed.hash()); Ok(transaction) }, @@ -127,10 +127,12 @@ impl Pool where }; while self.by_hash.len() + 1 > self.options.max_count { + trace!("Count limit reached: {} > {}", self.by_hash.len() + 1, self.options.max_count); transaction = remove_worst(self, transaction)?; } while self.mem_usage + mem_usage > self.options.max_mem_usage { + trace!("Mem limit reached: {} > {}", self.mem_usage + mem_usage, self.options.max_mem_usage); transaction = remove_worst(self, transaction)?; } } @@ -160,14 +162,14 @@ impl Pool where Ok(new) }, AddResult::TooCheap { new, old } => { - let hash = *new.hash(); - self.listener.rejected(new); - bail!(error::ErrorKind::TooCheapToReplace(*old.hash(), hash)) + let error = error::ErrorKind::TooCheapToReplace(*old.hash(), *new.hash()); + self.listener.rejected(&Arc::new(new), &error); + bail!(error) }, - AddResult::TooCheapToEnter(new) => { - let hash = *new.hash(); - self.listener.rejected(new); - bail!(error::ErrorKind::TooCheapToEnter(hash)) + AddResult::TooCheapToEnter(new, score) => { + let error = error::ErrorKind::TooCheapToEnter(*new.hash(), format!("{:?}", score)); + self.listener.rejected(&Arc::new(new), &error); + bail!(error) } } } @@ -241,14 +243,14 @@ impl Pool where // No elements to remove? and the pool is still full? None => { warn!("The pool is full but there are no transactions to remove."); - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash()).into()); + return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), "unknown".into()).into()); }, Some(old) => if self.scoring.should_replace(&old.transaction, transaction) { // New transaction is better than the worst one so we can replace it. old.clone() } else { // otherwise fail - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash()).into()) + return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), format!("{:?}", old.score)).into()) }, }; @@ -256,6 +258,7 @@ impl Pool where self.remove_from_set(to_remove.transaction.sender(), |set, scoring| { set.remove(&to_remove.transaction, scoring) }); + Ok(to_remove.transaction) } @@ -283,7 +286,7 @@ impl Pool where self.worst_transactions.clear(); for (_hash, tx) in self.by_hash.drain() { - self.listener.dropped(&tx) + self.listener.dropped(&tx, None) } } @@ -298,7 +301,7 @@ impl Pool where if is_invalid { self.listener.invalid(&tx); } else { - self.listener.cancelled(&tx); + self.listener.canceled(&tx); } Some(tx) } else { @@ -345,6 +348,16 @@ impl Pool where removed } + /// Returns a transaction if it's part of the pool or `None` otherwise. + pub fn find(&self, hash: &H256) -> Option> { + self.by_hash.get(hash).cloned() + } + + /// Returns worst transaction in the queue (if any). + pub fn worst_transaction(&self) -> Option> { + self.worst_transactions.iter().next().map(|x| x.transaction.clone()) + } + /// Returns an iterator of pending (ready) transactions. pub fn pending>(&self, ready: R) -> PendingIterator { PendingIterator { @@ -354,6 +367,41 @@ impl Pool where } } + /// Returns pending (ready) transactions from given sender. + pub fn pending_from_sender>(&self, ready: R, sender: &Sender) -> PendingIterator { + let best_transactions = self.transactions.get(sender) + .and_then(|transactions| transactions.worst_and_best()) + .map(|(_, best)| ScoreWithRef::new(best.0, best.1)) + .map(|s| { + let mut set = BTreeSet::new(); + set.insert(s); + set + }) + .unwrap_or_default(); + + PendingIterator { + ready, + best_transactions, + pool: self + } + } + + /// Update score of transactions of a particular sender. + pub fn update_scores(&mut self, sender: &Sender, event: S::Event) { + let res = if let Some(set) = self.transactions.get_mut(sender) { + let prev = set.worst_and_best(); + set.update_scores(&self.scoring, event); + let current = set.worst_and_best(); + Some((prev, current)) + } else { + None + }; + + if let Some((prev, current)) = res { + self.update_senders_worst_and_best(prev, current); + } + } + /// Computes the full status of the pool (including readiness). pub fn status>(&self, mut ready: R) -> Status { let mut status = Status::default(); @@ -383,6 +431,21 @@ impl Pool where senders: self.transactions.len(), } } + + /// Returns current pool options. + pub fn options(&self) -> Options { + self.options.clone() + } + + /// Borrows listener instance. + pub fn listener(&self) -> &L { + &self.listener + } + + /// Borrows listener mutably. + pub fn listener_mut(&mut self) -> &mut L { + &mut self.listener + } } /// An iterator over all pending (ready) transactions. @@ -424,7 +487,7 @@ impl<'a, T, R, S, L> Iterator for PendingIterator<'a, T, R, S, L> where return Some(best.transaction) }, - state => warn!("[{:?}] Ignoring {:?} transaction.", best.transaction.hash(), state), + state => trace!("[{:?}] Ignoring {:?} transaction.", best.transaction.hash(), state), } } diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index e4f923c9b5a..4e7a9833a16 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -42,7 +42,7 @@ pub enum Choice { /// The `Scoring` implementations can use this information /// to update the `Score` table more efficiently. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Change { +pub enum Change { /// New transaction has been inserted at given index. /// The Score at that index is initialized with default value /// and needs to be filled in. @@ -56,8 +56,12 @@ pub enum Change { /// The score at that index needs to be update (it contains value from previous transaction). ReplacedAt(usize), /// Given number of stalled transactions has been culled from the beginning. - /// Usually the score will have to be re-computed from scratch. + /// The scores has been removed from the beginning as well. + /// For simple scoring algorithms no action is required here. Culled(usize), + /// Custom event to update the score triggered outside of the pool. + /// Handling this event is up to scoring implementation. + Event(T), } /// A transaction ordering. @@ -69,7 +73,7 @@ pub enum Change { /// Implementation notes: /// - Returned `Score`s should match ordering of `compare` method. /// - `compare` will be called only within a context of transactions from the same sender. -/// - `choose` will be called only if `compare` returns `Ordering::Equal` +/// - `choose` may be called even if `compare` returns `Ordering::Equal` /// - `should_replace` is used to decide if new transaction should push out an old transaction already in the queue. /// - `Score`s and `compare` should align with `Ready` implementation. /// @@ -79,9 +83,11 @@ pub enum Change { /// - `update_scores`: score defined as `gasPrice` if `n==0` and `max(scores[n-1], gasPrice)` if `n>0` /// - `should_replace`: compares `gasPrice` (decides if transaction from a different sender is more valuable) /// -pub trait Scoring { +pub trait Scoring: fmt::Debug { /// A score of a transaction. type Score: cmp::Ord + Clone + Default + fmt::Debug; + /// Custom scoring update event type. + type Event: fmt::Debug; /// Decides on ordering of `T`s from a particular sender. fn compare(&self, old: &T, other: &T) -> cmp::Ordering; @@ -92,7 +98,7 @@ pub trait Scoring { /// Updates the transaction scores given a list of transactions and a change to previous scoring. /// NOTE: you can safely assume that both slices have the same length. /// (i.e. score at index `i` represents transaction at the same index) - fn update_scores(&self, txs: &[Arc], scores: &mut [Self::Score], change: Change); + fn update_scores(&self, txs: &[Arc], scores: &mut [Self::Score], change: Change); /// Decides if `new` should push out `old` transaction from the pool. fn should_replace(&self, old: &T, new: &T) -> bool; diff --git a/transaction-pool/src/status.rs b/transaction-pool/src/status.rs index 5862f75a1eb..a03bc6b062a 100644 --- a/transaction-pool/src/status.rs +++ b/transaction-pool/src/status.rs @@ -16,7 +16,7 @@ /// Light pool status. /// This status is cheap to compute and can be called frequently. -#[derive(Default, Debug, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct LightStatus { /// Memory usage in bytes. pub mem_usage: usize, @@ -29,7 +29,7 @@ pub struct LightStatus { /// A full queue status. /// To compute this status it is required to provide `Ready`. /// NOTE: To compute the status we need to visit each transaction in the pool. -#[derive(Default, Debug, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Status { /// Number of stalled transactions. pub stalled: usize, diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index 4e03cc89612..ab5b2a334b0 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -21,11 +21,12 @@ use ethereum_types::U256; use {scoring, Scoring, Ready, Readiness, Address as Sender}; use super::{Transaction, SharedTransaction}; -#[derive(Default)] +#[derive(Debug, Default)] pub struct DummyScoring; impl Scoring for DummyScoring { type Score = U256; + type Event = (); fn compare(&self, old: &Transaction, new: &Transaction) -> cmp::Ordering { old.nonce.cmp(&new.nonce) @@ -43,9 +44,17 @@ impl Scoring for DummyScoring { } } - fn update_scores(&self, txs: &[SharedTransaction], scores: &mut [Self::Score], _change: scoring::Change) { - for i in 0..txs.len() { - scores[i] = txs[i].gas_price; + fn update_scores(&self, txs: &[SharedTransaction], scores: &mut [Self::Score], change: scoring::Change) { + if let scoring::Change::Event(_) = change { + // In case of event reset all scores to 0 + for i in 0..txs.len() { + scores[i] = 0.into(); + } + } else { + // Set to a gas price otherwise + for i in 0..txs.len() { + scores[i] = txs[i].gas_price; + } } } diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index 05b72284b5a..5113a4663c3 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -125,7 +125,7 @@ fn should_reject_if_above_count() { let tx2 = b.tx().nonce(1).new(); let hash = *tx2.hash(); txq.import(tx1).unwrap(); - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); txq.clear(); @@ -151,7 +151,7 @@ fn should_reject_if_above_mem_usage() { let tx2 = b.tx().nonce(2).mem_usage(2).new(); let hash = *tx2.hash(); txq.import(tx1).unwrap(); - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); txq.clear(); @@ -177,7 +177,7 @@ fn should_reject_if_above_sender_count() { let tx2 = b.tx().nonce(2).new(); let hash = *tx2.hash(); txq.import(tx1).unwrap(); - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); txq.clear(); @@ -188,7 +188,7 @@ fn should_reject_if_above_sender_count() { let hash = *tx2.hash(); txq.import(tx1).unwrap(); // This results in error because we also compare nonces - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); } @@ -249,6 +249,66 @@ fn should_construct_pending() { assert_eq!(pending.next(), None); } +#[test] +fn should_update_scoring_correctly() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::default(); + + let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap(); + let tx2 = txq.import(b.tx().nonce(2).new()).unwrap(); + // this transaction doesn't get to the block despite high gas price + // because of block gas limit and simplistic ordering algorithm. + txq.import(b.tx().nonce(3).gas_price(4).new()).unwrap(); + //gap + txq.import(b.tx().nonce(5).new()).unwrap(); + + let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap(); + let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap(); + let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap(); + let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap(); + // gap + txq.import(b.tx().sender(1).nonce(5).new()).unwrap(); + + let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap(); + assert_eq!(txq.light_status().transaction_count, 11); + assert_eq!(txq.status(NonceReady::default()), Status { + stalled: 0, + pending: 9, + future: 2, + }); + assert_eq!(txq.status(NonceReady::new(1)), Status { + stalled: 3, + pending: 6, + future: 2, + }); + + txq.update_scores(&0.into(), ()); + + // when + let mut current_gas = U256::zero(); + let limit = (21_000 * 8).into(); + let mut pending = txq.pending(NonceReady::default()).take_while(|tx| { + let should_take = tx.gas + current_gas <= limit; + if should_take { + current_gas = current_gas + tx.gas + } + should_take + }); + + assert_eq!(pending.next(), Some(tx9)); + assert_eq!(pending.next(), Some(tx5)); + assert_eq!(pending.next(), Some(tx6)); + assert_eq!(pending.next(), Some(tx7)); + assert_eq!(pending.next(), Some(tx8)); + // penalized transactions + assert_eq!(pending.next(), Some(tx0)); + assert_eq!(pending.next(), Some(tx1)); + assert_eq!(pending.next(), Some(tx2)); + assert_eq!(pending.next(), None); +} + #[test] fn should_remove_transaction() { // given @@ -375,6 +435,20 @@ fn should_re_insert_after_cull() { }); } +#[test] +fn should_return_worst_transaction() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::default(); + assert!(txq.worst_transaction().is_none()); + + // when + txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + + // then + assert!(txq.worst_transaction().is_some()); +} + mod listener { use std::cell::RefCell; use std::rc::Rc; @@ -389,11 +463,11 @@ mod listener { self.0.borrow_mut().push(if old.is_some() { "replaced" } else { "added" }); } - fn rejected(&mut self, _tx: Transaction) { + fn rejected(&mut self, _tx: &SharedTransaction, _reason: &error::ErrorKind) { self.0.borrow_mut().push("rejected".into()); } - fn dropped(&mut self, _tx: &SharedTransaction) { + fn dropped(&mut self, _tx: &SharedTransaction, _new: Option<&Transaction>) { self.0.borrow_mut().push("dropped".into()); } @@ -401,8 +475,8 @@ mod listener { self.0.borrow_mut().push("invalid".into()); } - fn cancelled(&mut self, _tx: &SharedTransaction) { - self.0.borrow_mut().push("cancelled".into()); + fn canceled(&mut self, _tx: &SharedTransaction) { + self.0.borrow_mut().push("canceled".into()); } fn mined(&mut self, _tx: &SharedTransaction) { @@ -461,9 +535,9 @@ mod listener { // then txq.remove(&tx1.hash(), false); - assert_eq!(*results.borrow(), &["added", "added", "cancelled"]); + assert_eq!(*results.borrow(), &["added", "added", "canceled"]); txq.remove(&tx2.hash(), true); - assert_eq!(*results.borrow(), &["added", "added", "cancelled", "invalid"]); + assert_eq!(*results.borrow(), &["added", "added", "canceled", "invalid"]); assert_eq!(txq.light_status().transaction_count, 0); } diff --git a/transaction-pool/src/transactions.rs b/transaction-pool/src/transactions.rs index 39fd08e931c..c839d9e6853 100644 --- a/transaction-pool/src/transactions.rs +++ b/transaction-pool/src/transactions.rs @@ -23,9 +23,9 @@ use ready::{Ready, Readiness}; use scoring::{self, Scoring}; #[derive(Debug)] -pub enum AddResult { +pub enum AddResult { Ok(Arc), - TooCheapToEnter(T), + TooCheapToEnter(T, S), TooCheap { old: Arc, new: T, @@ -93,10 +93,11 @@ impl> Transactions { }) } - fn push_cheapest_transaction(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { + fn push_cheapest_transaction(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { let index = self.transactions.len(); if index == max_count { - AddResult::TooCheapToEnter(tx) + let min_score = self.scores[index - 1].clone(); + AddResult::TooCheapToEnter(tx, min_score) } else { let shared = Arc::new(tx); self.transactions.push(shared.clone()); @@ -107,7 +108,11 @@ impl> Transactions { } } - pub fn add(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { + pub fn update_scores(&mut self, scoring: &S, event: S::Event) { + scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::Event(event)); + } + + pub fn add(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { let index = match self.transactions.binary_search_by(|old| scoring.compare(old, &tx)) { Ok(index) => index, Err(index) => index, @@ -192,6 +197,10 @@ impl> Transactions { } } + if first_non_stalled == 0 { + return result; + } + // reverse the vectors to easily remove first elements. self.transactions.reverse(); self.scores.reverse(); diff --git a/util/table/Cargo.toml b/util/table/Cargo.toml deleted file mode 100644 index f2faca184dc..00000000000 --- a/util/table/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "table" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] diff --git a/util/table/src/lib.rs b/util/table/src/lib.rs deleted file mode 100644 index 78b2c646ae0..00000000000 --- a/util/table/src/lib.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! A collection associating pair of keys (row and column) with a single value. - -use std::hash::Hash; -use std::collections::HashMap; -use std::collections::hash_map::Keys; - -/// Structure to hold double-indexed values -/// -/// You can obviously use `HashMap<(Row,Col), Val>`, but this structure gives -/// you better access to all `Columns` in Specific `Row`. Namely you can get sub-hashmap -/// `HashMap` for specific `Row` -#[derive(Default, Debug, PartialEq)] -pub struct Table - where Row: Eq + Hash + Clone, - Col: Eq + Hash { - map: HashMap>, -} - -impl Table - where Row: Eq + Hash + Clone, - Col: Eq + Hash { - /// Creates new Table - pub fn new() -> Self { - Table { - map: HashMap::new(), - } - } - - /// Returns keys iterator for this Table. - pub fn keys(&self) -> Keys> { - self.map.keys() - } - - /// Removes all elements from this Table - pub fn clear(&mut self) { - self.map.clear(); - } - - /// Returns length of the Table (number of (row, col, val) tuples) - pub fn len(&self) -> usize { - self.map.values().fold(0, |acc, v| acc + v.len()) - } - - /// Check if there is any element in this Table - pub fn is_empty(&self) -> bool { - self.map.is_empty() || self.map.values().all(|v| v.is_empty()) - } - - /// Get mutable reference for single Table row. - pub fn row_mut(&mut self, row: &Row) -> Option<&mut HashMap> { - self.map.get_mut(row) - } - - /// Checks if row is defined for that table (note that even if defined it might be empty) - pub fn has_row(&self, row: &Row) -> bool { - self.map.contains_key(row) - } - - /// Get immutable reference for single row in this Table - pub fn row(&self, row: &Row) -> Option<&HashMap> { - self.map.get(row) - } - - /// Get element in cell described by `(row, col)` - pub fn get(&self, row: &Row, col: &Col) -> Option<&Val> { - self.map.get(row).and_then(|r| r.get(col)) - } - - /// Remove value from specific cell - /// - /// It will remove the row if it's the last value in it - pub fn remove(&mut self, row: &Row, col: &Col) -> Option { - let (val, is_empty) = { - let row_map = self.map.get_mut(row); - if let None = row_map { - return None; - } - let row_map = row_map.unwrap(); - let val = row_map.remove(col); - (val, row_map.is_empty()) - }; - // Clean row - if is_empty { - self.map.remove(row); - } - val - } - - /// Remove given row from Table if there are no values defined in it - /// - /// When using `#row_mut` it may happen that all values from some row are drained. - /// Table however will not be aware that row is empty. - /// You can use this method to explicitly remove row entry from the Table. - pub fn clear_if_empty(&mut self, row: &Row) { - let is_empty = self.map.get(row).map_or(false, |m| m.is_empty()); - if is_empty { - self.map.remove(row); - } - } - - /// Inserts new value to specified cell - /// - /// Returns previous value (if any) - pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option { - self.map.entry(row).or_insert_with(HashMap::new).insert(col, val) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn should_create_empty_table() { - // when - let table : Table = Table::new(); - - // then - assert!(table.is_empty()); - assert_eq!(table.len(), 0); - } - - #[test] - fn should_insert_elements_and_return_previous_if_any() { - // given - let mut table = Table::new(); - - // when - let r1 = table.insert(5, 4, true); - let r2 = table.insert(10, 4, true); - let r3 = table.insert(10, 10, true); - let r4 = table.insert(10, 10, false); - - // then - assert!(r1.is_none()); - assert!(r2.is_none()); - assert!(r3.is_none()); - assert!(r4.is_some()); - assert!(!table.is_empty()); - assert_eq!(r4.unwrap(), true); - assert_eq!(table.len(), 3); - } - - #[test] - fn should_remove_element() { - // given - let mut table = Table::new(); - table.insert(5, 4, true); - assert!(!table.is_empty()); - assert_eq!(table.len(), 1); - - // when - let r = table.remove(&5, &4); - - // then - assert!(table.is_empty()); - assert_eq!(table.len() ,0); - assert_eq!(r.unwrap(), true); - } - - #[test] - fn should_return_none_if_trying_to_remove_non_existing_element() { - // given - let mut table : Table = Table::new(); - assert!(table.is_empty()); - - // when - let r = table.remove(&5, &4); - - // then - assert!(r.is_none()); - } - - #[test] - fn should_clear_row_if_removing_last_element() { - // given - let mut table = Table::new(); - table.insert(5, 4, true); - assert!(table.has_row(&5)); - - // when - let r = table.remove(&5, &4); - - // then - assert!(r.is_some()); - assert!(!table.has_row(&5)); - } - - #[test] - fn should_return_element_given_row_and_col() { - // given - let mut table = Table::new(); - table.insert(1551, 1234, 123); - - // when - let r1 = table.get(&1551, &1234); - let r2 = table.get(&5, &4); - - // then - assert!(r1.is_some()); - assert!(r2.is_none()); - assert_eq!(r1.unwrap(), &123); - } - - #[test] - fn should_clear_table() { - // given - let mut table = Table::new(); - table.insert(1, 1, true); - table.insert(1, 2, false); - table.insert(2, 2, false); - assert_eq!(table.len(), 3); - - // when - table.clear(); - - // then - assert!(table.is_empty()); - assert_eq!(table.len(), 0); - assert_eq!(table.has_row(&1), false); - assert_eq!(table.has_row(&2), false); - } - - #[test] - fn should_return_mutable_row() { - // given - let mut table = Table::new(); - table.insert(1, 1, true); - table.insert(1, 2, false); - table.insert(2, 2, false); - - // when - { - let row = table.row_mut(&1).unwrap(); - row.remove(&1); - row.remove(&2); - } - assert!(table.has_row(&1)); - table.clear_if_empty(&1); - - // then - assert!(!table.has_row(&1)); - assert_eq!(table.len(), 1); - } -} diff --git a/util/using_queue/src/lib.rs b/util/using_queue/src/lib.rs index 3ce822094a7..03862e9c8a5 100644 --- a/util/using_queue/src/lib.rs +++ b/util/using_queue/src/lib.rs @@ -82,13 +82,13 @@ impl UsingQueue where T: Clone { /// Returns `Some` item which is the first that `f` returns `true` with a reference to it /// as a parameter or `None` if no such item exists in the queue. - pub fn take_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { + fn take_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { self.in_use.iter().position(|r| predicate(r)).map(|i| self.in_use.remove(i)) } /// Returns `Some` item which is the first that `f` returns `true` with a reference to it /// as a parameter or `None` if no such item exists in the queue. - pub fn clone_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { + fn clone_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { self.in_use.iter().find(|r| predicate(r)).cloned() } From d6d53fffb99b1dfcbfd4c5d80241e3dfd9107982 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 13 Apr 2018 21:00:14 +0200 Subject: [PATCH 014/147] clarify that windows need perl and yasm (#8402) --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e4a12bf02d..bfa7bde7bf6 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,11 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do $ rustup default stable-x86_64-pc-windows-msvc ``` -Once you have rustup, install Parity or download and build from source +Once you have rustup installed, then you need to install: +* [Perl](https://www.perl.org) +* [Yasm](http://yasm.tortall.net) + +Make sure that these binaries are in your `PATH`. After that you should be able to build parity from source. ---- From 0256d2be05ebcb71219d4a430c8a2abe90a9b73a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 14 Apr 2018 03:14:53 +0800 Subject: [PATCH 015/147] Unify and limit rocksdb dependency places (#8371) * secret_store: remove kvdb_rocksdb dependency * cli: init db mod for open dispatch * cli: move db, client_db, restoration_db, secretstore_db to a separate mod * migration: rename to migration-rocksdb and remove ethcore-migrations * ethcore: re-move kvdb-rocksdb dep to test * mark test_helpers as test only and fix migration mod naming * Move restoration_db_handler to test_helpers_internal * Fix missing preambles in test_helpers_internal and rocksdb/helpers * Move test crates downward * Fix missing docs * cli, db::open_db: move each argument to a separate line * Use featuregate instead of dead code for `open_secretstore_db` * Move pathbuf import to open_secretstore_db Because it's only used there behind a feature gate --- Cargo.lock | 12 +-- Cargo.toml | 3 +- ethcore/Cargo.toml | 2 +- ethcore/migrations/Cargo.toml | 7 -- ethcore/src/lib.rs | 6 +- ethcore/src/snapshot/service.rs | 2 +- ethcore/src/snapshot/tests/service.rs | 3 +- ethcore/src/test_helpers.rs | 20 ---- ethcore/src/test_helpers_internal.rs | 39 ++++++++ parity/blockchain.rs | 39 +++----- .../migrations/src/lib.rs => parity/db/mod.rs | 26 ++---- parity/db/rocksdb/helpers.rs | 38 ++++++++ parity/{ => db/rocksdb}/migration.rs | 41 +++++++-- parity/db/rocksdb/mod.rs | 91 +++++++++++++++++++ parity/export_hardcoded_sync.rs | 26 ++---- parity/helpers.rs | 55 +---------- parity/main.rs | 5 +- parity/run.rs | 33 ++----- parity/secretstore.rs | 5 +- parity/snapshot.rs | 10 +- secret_store/Cargo.toml | 2 +- secret_store/src/key_storage.rs | 76 ++++++---------- secret_store/src/lib.rs | 9 +- secret_store/src/types/all.rs | 2 - .../Cargo.toml | 2 +- .../src/lib.rs | 0 .../tests/tests.rs | 2 +- 27 files changed, 295 insertions(+), 261 deletions(-) delete mode 100644 ethcore/migrations/Cargo.toml create mode 100644 ethcore/src/test_helpers_internal.rs rename ethcore/migrations/src/lib.rs => parity/db/mod.rs (56%) create mode 100644 parity/db/rocksdb/helpers.rs rename parity/{ => db/rocksdb}/migration.rs (84%) create mode 100644 parity/db/rocksdb/mod.rs rename util/{migration => migration-rocksdb}/Cargo.toml (91%) rename util/{migration => migration-rocksdb}/src/lib.rs (100%) rename util/{migration => migration-rocksdb}/tests/tests.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 70f7a026617..402327b2e20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -641,13 +641,6 @@ dependencies = [ "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethcore-migrations" -version = "0.1.0" -dependencies = [ - "migration 0.1.0", -] - [[package]] name = "ethcore-miner" version = "1.11.0" @@ -1630,7 +1623,7 @@ dependencies = [ ] [[package]] -name = "migration" +name = "migration-rocksdb" version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1933,7 +1926,6 @@ dependencies = [ "ethcore-io 1.11.0", "ethcore-light 1.11.0", "ethcore-logger 1.11.0", - "ethcore-migrations 0.1.0", "ethcore-miner 1.11.0", "ethcore-network 1.11.0", "ethcore-private-tx 1.0.0", @@ -1956,7 +1948,7 @@ dependencies = [ "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", - "migration 0.1.0", + "migration-rocksdb 0.1.0", "node-filter 1.11.0", "node-health 0.1.0", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 5103c2b2b73..9daf4fb5586 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,6 @@ ethcore-bytes = { path = "util/bytes" } ethcore-io = { path = "util/io" } ethcore-light = { path = "ethcore/light" } ethcore-logger = { path = "logger" } -ethcore-migrations = { path = "ethcore/migrations" } ethcore-miner = { path = "miner" } ethcore-network = { path = "util/network" } ethcore-private-tx = { path = "ethcore/private-tx" } @@ -64,7 +63,7 @@ path = { path = "util/path" } dir = { path = "util/dir" } panic_hook = { path = "util/panic_hook" } keccak-hash = { path = "util/hash" } -migration = { path = "util/migration" } +migration-rocksdb = { path = "util/migration-rocksdb" } kvdb = { path = "util/kvdb" } kvdb-rocksdb = { path = "util/kvdb-rocksdb" } journaldb = { path = "util/journaldb" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index b8035f07124..69166297581 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -51,7 +51,6 @@ rlp_compress = { path = "../util/rlp_compress" } rlp_derive = { path = "../util/rlp_derive" } kvdb = { path = "../util/kvdb" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } util-error = { path = "../util/error" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } @@ -71,6 +70,7 @@ journaldb = { path = "../util/journaldb" } [dev-dependencies] tempdir = "0.3" trie-standardmap = { path = "../util/trie-standardmap" } +kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } [features] # Display EVM debug traces. diff --git a/ethcore/migrations/Cargo.toml b/ethcore/migrations/Cargo.toml deleted file mode 100644 index 561925be4c5..00000000000 --- a/ethcore/migrations/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "ethcore-migrations" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -migration = { path = "../../util/migration" } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index abb680c952b..1b0a1e35461 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -92,7 +92,6 @@ extern crate ansi_term; extern crate unexpected; extern crate kvdb; extern crate kvdb_memorydb; -extern crate kvdb_rocksdb; extern crate util_error; extern crate snappy; @@ -128,6 +127,9 @@ extern crate evm; pub extern crate ethstore; +#[cfg(test)] +extern crate kvdb_rocksdb; + pub mod account_provider; pub mod block; pub mod client; @@ -167,6 +169,8 @@ mod tests; #[cfg(test)] #[cfg(feature="json-tests")] mod json_tests; +#[cfg(test)] +mod test_helpers_internal; pub use types::*; pub use executive::contract_address; diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 7d5eea1eff4..9cfb2eb63f4 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -635,7 +635,7 @@ mod tests { use snapshot::{ManifestData, RestorationStatus, SnapshotService}; use super::*; use tempdir::TempDir; - use test_helpers::restoration_db_handler; + use test_helpers_internal::restoration_db_handler; struct NoopDBRestore; impl DatabaseRestore for NoopDBRestore { diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index d49e6fd63bf..3e3087f2bf7 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -24,7 +24,8 @@ use ids::BlockId; use snapshot::service::{Service, ServiceParams}; use snapshot::{self, ManifestData, SnapshotService}; use spec::Spec; -use test_helpers::{generate_dummy_client_with_spec_and_data, restoration_db_handler}; +use test_helpers::generate_dummy_client_with_spec_and_data; +use test_helpers_internal::restoration_db_handler; use io::IoChannel; use kvdb_rocksdb::{Database, DatabaseConfig}; diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 8d10e4b3b8f..692f029c86f 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -35,11 +35,8 @@ use spec::Spec; use state_db::StateDB; use state::*; use std::sync::Arc; -use std::path::Path; use transaction::{Action, Transaction, SignedTransaction}; use views::BlockView; -use kvdb::{KeyValueDB, KeyValueDBHandler}; -use kvdb_rocksdb::{Database, DatabaseConfig}; /// Creates test block with corresponding header pub fn create_test_block(header: &Header) -> Bytes { @@ -402,20 +399,3 @@ impl ChainNotify for TestNotify { self.messages.write().push(data); } } - -/// Creates new instance of KeyValueDBHandler -pub fn restoration_db_handler(config: DatabaseConfig) -> Box { - use kvdb::Error; - - struct RestorationDBHandler { - config: DatabaseConfig, - } - - impl KeyValueDBHandler for RestorationDBHandler { - fn open(&self, db_path: &Path) -> Result, Error> { - Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) - } - } - - Box::new(RestorationDBHandler { config }) -} diff --git a/ethcore/src/test_helpers_internal.rs b/ethcore/src/test_helpers_internal.rs new file mode 100644 index 00000000000..ef98c7c85b5 --- /dev/null +++ b/ethcore/src/test_helpers_internal.rs @@ -0,0 +1,39 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Internal helpers for client tests + +use std::path::Path; +use std::sync::Arc; +use kvdb::{KeyValueDB, KeyValueDBHandler}; +use kvdb_rocksdb::{Database, DatabaseConfig}; + +/// Creates new instance of KeyValueDBHandler +pub fn restoration_db_handler(config: DatabaseConfig) -> Box { + use kvdb::Error; + + struct RestorationDBHandler { + config: DatabaseConfig, + } + + impl KeyValueDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> Result, Error> { + Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + } + } + + Box::new(RestorationDBHandler { config }) +} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 4a4441b89fe..586313ab416 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -27,20 +27,19 @@ use bytes::ToPretty; use rlp::PayloadInfo; use ethcore::account_provider::AccountProvider; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock}; -use ethcore::db::NUM_COLUMNS; use ethcore::error::ImportError; use ethcore::miner::Miner; use ethcore::verification::queue::VerifierSettings; use ethcore_service::ClientService; use cache::CacheConfig; use informant::{Informant, FullNodeInformantData, MillisecondDuration}; -use kvdb_rocksdb::{Database, DatabaseConfig}; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool}; -use helpers::{to_client_config, execute_upgrades, open_client_db, client_db_config, restoration_db_handler, compaction_profile}; +use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; use fdlimit; use ethcore_private_tx; +use db; #[derive(Debug, PartialEq)] pub enum DataFormat { @@ -188,8 +187,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { let client_path = db_dirs.client_path(algorithm); // execute upgrades - let compaction = compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()); - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction)?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(false, false, false)?; @@ -210,19 +208,10 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { config.queue.verifier_settings = cmd.verifier_settings; // initialize database. - let db = { - let db_config = DatabaseConfig { - memory_budget: Some(cmd.cache_config.blockchain() as usize * 1024 * 1024), - compaction: compaction, - wal: cmd.wal, - .. DatabaseConfig::with_columns(NUM_COLUMNS) - }; - - Arc::new(Database::open( - &db_config, - &client_path.to_str().expect("DB path could not be converted to string.") - ).map_err(|e| format!("Failed to open database: {}", e))?) - }; + let db = db::open_db(&client_path.to_str().expect("DB path could not be converted to string."), + &cmd.cache_config, + &cmd.compaction, + cmd.wal)?; // TODO: could epoch signals be avilable at the end of the file? let fetch = ::light::client::fetch::unavailable(); @@ -354,7 +343,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(false, false, false)?; @@ -378,9 +367,8 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { client_config.queue.verifier_settings = cmd.verifier_settings; - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); // build client let service = ClientService::start( @@ -549,7 +537,7 @@ fn start_client( let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&dirs.base, &db_dirs, algorithm, compaction_profile(&compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&dirs.base, &db_dirs, algorithm, &compaction)?; // create dirs used by parity dirs.create_dirs(false, false, false)?; @@ -571,9 +559,8 @@ fn start_client( true, ); - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); let service = ClientService::start( client_config, diff --git a/ethcore/migrations/src/lib.rs b/parity/db/mod.rs similarity index 56% rename from ethcore/migrations/src/lib.rs rename to parity/db/mod.rs index 429c39102cb..39f43fd145e 100644 --- a/ethcore/migrations/src/lib.rs +++ b/parity/db/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,24 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Database migrations. +//! Database-related operations. -extern crate migration; +#[path="rocksdb/mod.rs"] +mod impls; -use migration::ChangeColumns; +pub use self::impls::{open_db, open_client_db, restoration_db_handler, migrate}; -/// The migration from v10 to v11. -/// Adds a column for node info. -pub const TO_V11: ChangeColumns = ChangeColumns { - pre_columns: Some(6), - post_columns: Some(7), - version: 11, -}; - -/// The migration from v11 to v12. -/// Adds a column for light chain storage. -pub const TO_V12: ChangeColumns = ChangeColumns { - pre_columns: Some(7), - post_columns: Some(8), - version: 12, -}; +#[cfg(feature = "secretstore")] +pub use self::impls::open_secretstore_db; diff --git a/parity/db/rocksdb/helpers.rs b/parity/db/rocksdb/helpers.rs new file mode 100644 index 00000000000..ca685d3e86d --- /dev/null +++ b/parity/db/rocksdb/helpers.rs @@ -0,0 +1,38 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::path::Path; +use ethcore::db::NUM_COLUMNS; +use ethcore::client::{ClientConfig, DatabaseCompactionProfile}; +use super::kvdb_rocksdb::{CompactionProfile, DatabaseConfig}; + +pub fn compaction_profile(profile: &DatabaseCompactionProfile, db_path: &Path) -> CompactionProfile { + match profile { + &DatabaseCompactionProfile::Auto => CompactionProfile::auto(db_path), + &DatabaseCompactionProfile::SSD => CompactionProfile::ssd(), + &DatabaseCompactionProfile::HDD => CompactionProfile::hdd(), + } +} + +pub fn client_db_config(client_path: &Path, client_config: &ClientConfig) -> DatabaseConfig { + let mut client_db_config = DatabaseConfig::with_columns(NUM_COLUMNS); + + client_db_config.memory_budget = client_config.db_cache_size; + client_db_config.compaction = compaction_profile(&client_config.db_compaction, &client_path); + client_db_config.wal = client_config.db_wal; + + client_db_config +} diff --git a/parity/migration.rs b/parity/db/rocksdb/migration.rs similarity index 84% rename from parity/migration.rs rename to parity/db/rocksdb/migration.rs index bd659cba015..df6a4b5dc9c 100644 --- a/parity/migration.rs +++ b/parity/db/rocksdb/migration.rs @@ -18,9 +18,28 @@ use std::fs; use std::io::{Read, Write, Error as IoError, ErrorKind}; use std::path::{Path, PathBuf}; use std::fmt::{Display, Formatter, Error as FmtError}; -use migr::{self, Manager as MigrationManager, Config as MigrationConfig}; -use kvdb_rocksdb::CompactionProfile; -use migrations; +use super::migration_rocksdb::{self, Manager as MigrationManager, Config as MigrationConfig, ChangeColumns}; +use super::kvdb_rocksdb::CompactionProfile; +use ethcore::client::DatabaseCompactionProfile; + +use super::helpers; + +/// The migration from v10 to v11. +/// Adds a column for node info. +pub const TO_V11: ChangeColumns = ChangeColumns { + pre_columns: Some(6), + post_columns: Some(7), + version: 11, +}; + +/// The migration from v11 to v12. +/// Adds a column for light chain storage. +pub const TO_V12: ChangeColumns = ChangeColumns { + pre_columns: Some(7), + post_columns: Some(8), + version: 12, +}; + /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; @@ -43,7 +62,7 @@ pub enum Error { /// Migration is not possible. MigrationImpossible, /// Internal migration error. - Internal(migr::Error), + Internal(migration_rocksdb::Error), /// Migration was completed succesfully, /// but there was a problem with io. Io(IoError), @@ -69,10 +88,10 @@ impl From for Error { } } -impl From for Error { - fn from(err: migr::Error) -> Self { +impl From for Error { + fn from(err: migration_rocksdb::Error) -> Self { match err.into() { - migr::ErrorKind::Io(e) => Error::Io(e), + migration_rocksdb::ErrorKind::Io(e) => Error::Io(e), err => Error::Internal(err.into()), } } @@ -134,8 +153,8 @@ pub fn default_migration_settings(compaction_profile: &CompactionProfile) -> Mig /// Migrations on the consolidated database. fn consolidated_database_migrations(compaction_profile: &CompactionProfile) -> Result { let mut manager = MigrationManager::new(default_migration_settings(compaction_profile)); - manager.add_migration(migrations::TO_V11).map_err(|_| Error::MigrationImpossible)?; - manager.add_migration(migrations::TO_V12).map_err(|_| Error::MigrationImpossible)?; + manager.add_migration(TO_V11).map_err(|_| Error::MigrationImpossible)?; + manager.add_migration(TO_V12).map_err(|_| Error::MigrationImpossible)?; Ok(manager) } @@ -176,7 +195,9 @@ fn exists(path: &Path) -> bool { } /// Migrates the database. -pub fn migrate(path: &Path, compaction_profile: CompactionProfile) -> Result<(), Error> { +pub fn migrate(path: &Path, compaction_profile: &DatabaseCompactionProfile) -> Result<(), Error> { + let compaction_profile = helpers::compaction_profile(&compaction_profile, path); + // read version file. let version = current_version(path)?; diff --git a/parity/db/rocksdb/mod.rs b/parity/db/rocksdb/mod.rs new file mode 100644 index 00000000000..7bfd28f6502 --- /dev/null +++ b/parity/db/rocksdb/mod.rs @@ -0,0 +1,91 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate kvdb_rocksdb; +extern crate migration_rocksdb; + +use std::sync::Arc; +use std::path::Path; +use ethcore::db::NUM_COLUMNS; +use ethcore::client::{ClientConfig, DatabaseCompactionProfile}; +use kvdb::{KeyValueDB, KeyValueDBHandler}; +use self::kvdb_rocksdb::{Database, DatabaseConfig}; + +use cache::CacheConfig; + +mod migration; +mod helpers; + +pub use self::migration::migrate; + +/// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path. +#[cfg(feature = "secretstore")] +pub fn open_secretstore_db(data_path: &str) -> Result, String> { + use std::path::PathBuf; + + let mut db_path = PathBuf::from(data_path); + db_path.push("db"); + let db_path = db_path.to_str().ok_or_else(|| "Invalid secretstore path".to_string())?; + Ok(Arc::new(Database::open_default(&db_path).map_err(|e| format!("Error opening database: {:?}", e))?)) +} + +/// Open a new client DB. +pub fn open_client_db(client_path: &Path, client_config: &ClientConfig) -> Result, String> { + let client_db_config = helpers::client_db_config(client_path, client_config); + + let client_db = Arc::new(Database::open( + &client_db_config, + &client_path.to_str().expect("DB path could not be converted to string.") + ).map_err(|e| format!("Client service database error: {:?}", e))?); + + Ok(client_db) +} + +/// Create a restoration db handler using the config generated by `client_path` and `client_config`. +pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig) -> Box { + use kvdb::Error; + + let client_db_config = helpers::client_db_config(client_path, client_config); + + struct RestorationDBHandler { + config: DatabaseConfig, + } + + impl KeyValueDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> Result, Error> { + Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + } + } + + Box::new(RestorationDBHandler { + config: client_db_config, + }) +} + +/// Open a new main DB. +pub fn open_db(client_path: &str, cache_config: &CacheConfig, compaction: &DatabaseCompactionProfile, wal: bool) -> Result, String> { + let db_config = DatabaseConfig { + memory_budget: Some(cache_config.blockchain() as usize * 1024 * 1024), + compaction: helpers::compaction_profile(&compaction, &Path::new(client_path)), + wal: wal, + .. DatabaseConfig::with_columns(NUM_COLUMNS) + }; + + Ok(Arc::new(Database::open( + &db_config, + client_path + ).map_err(|e| format!("Failed to open database: {}", e))?)) +} diff --git a/parity/export_hardcoded_sync.rs b/parity/export_hardcoded_sync.rs index accb6159fa3..3aa2b561490 100644 --- a/parity/export_hardcoded_sync.rs +++ b/parity/export_hardcoded_sync.rs @@ -18,17 +18,16 @@ use std::sync::Arc; use std::time::Duration; use ethcore::client::DatabaseCompactionProfile; -use ethcore::db::NUM_COLUMNS; use ethcore::spec::{SpecParams, OptimizeFor}; -use kvdb_rocksdb::{Database, DatabaseConfig}; use light::client::fetch::Unavailable as UnavailableDataFetcher; use light::Cache as LightDataCache; use params::{SpecType, Pruning}; -use helpers::{execute_upgrades, compaction_profile}; +use helpers::execute_upgrades; use dir::Directories; use cache::CacheConfig; use user_defaults::UserDefaults; +use db; // Number of minutes before a given gas price corpus should expire. // Light client only. @@ -66,10 +65,8 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { // select pruning algorithm let algorithm = cmd.pruning.to_algorithm(&user_defaults); - let compaction = compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()); - // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction.clone())?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(false, false, false)?; @@ -90,19 +87,10 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024; // initialize database. - let db = { - let db_config = DatabaseConfig { - memory_budget: Some(cmd.cache_config.blockchain() as usize * 1024 * 1024), - compaction: compaction, - wal: cmd.wal, - .. DatabaseConfig::with_columns(NUM_COLUMNS) - }; - - Arc::new(Database::open( - &db_config, - &db_dirs.client_path(algorithm).to_str().expect("DB path could not be converted to string.") - ).map_err(|e| format!("Error opening database: {}", e))?) - }; + let db = db::open_db(&db_dirs.client_path(algorithm).to_str().expect("DB path could not be converted to string."), + &cmd.cache_config, + &cmd.compaction, + cmd.wal)?; let service = light_client::Service::start(config, &spec, UnavailableDataFetcher, db, cache) .map_err(|e| format!("Error starting light client: {}", e))?; diff --git a/parity/helpers.rs b/parity/helpers.rs index cdd951c2b70..80ade509834 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -18,22 +18,17 @@ use std::io; use std::io::{Write, BufReader, BufRead}; use std::time::Duration; use std::fs::File; -use std::sync::Arc; -use std::path::Path; use ethereum_types::{U256, clean_0x, Address}; use journaldb::Algorithm; use ethcore::client::{Mode, BlockId, VMType, DatabaseCompactionProfile, ClientConfig, VerifierType}; -use ethcore::db::NUM_COLUMNS; use ethcore::miner::{PendingSet, Penalization}; use miner::pool::PrioritizationStrategy; use cache::CacheConfig; use dir::DatabaseDirectories; use dir::helpers::replace_home; use upgrade::{upgrade, upgrade_data_paths}; -use migration::migrate; use sync::{validate_node_url, self}; -use kvdb::{KeyValueDB, KeyValueDBHandler}; -use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile}; +use db::migrate; use path; pub fn to_duration(s: &str) -> Result { @@ -258,57 +253,11 @@ pub fn to_client_config( client_config } -// We assume client db has similar config as restoration db. -pub fn client_db_config(client_path: &Path, client_config: &ClientConfig) -> DatabaseConfig { - let mut client_db_config = DatabaseConfig::with_columns(NUM_COLUMNS); - - client_db_config.memory_budget = client_config.db_cache_size; - client_db_config.compaction = compaction_profile(&client_config.db_compaction, &client_path); - client_db_config.wal = client_config.db_wal; - - client_db_config -} - -pub fn open_client_db(client_path: &Path, client_db_config: &DatabaseConfig) -> Result, String> { - let client_db = Arc::new(Database::open( - &client_db_config, - &client_path.to_str().expect("DB path could not be converted to string.") - ).map_err(|e| format!("Client service database error: {:?}", e))?); - - Ok(client_db) -} - -pub fn restoration_db_handler(client_db_config: DatabaseConfig) -> Box { - use kvdb::Error; - - struct RestorationDBHandler { - config: DatabaseConfig, - } - - impl KeyValueDBHandler for RestorationDBHandler { - fn open(&self, db_path: &Path) -> Result, Error> { - Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) - } - } - - Box::new(RestorationDBHandler { - config: client_db_config, - }) -} - -pub fn compaction_profile(profile: &DatabaseCompactionProfile, db_path: &Path) -> CompactionProfile { - match profile { - &DatabaseCompactionProfile::Auto => CompactionProfile::auto(db_path), - &DatabaseCompactionProfile::SSD => CompactionProfile::ssd(), - &DatabaseCompactionProfile::HDD => CompactionProfile::hdd(), - } -} - pub fn execute_upgrades( base_path: &str, dirs: &DatabaseDirectories, pruning: Algorithm, - compaction_profile: CompactionProfile + compaction_profile: &DatabaseCompactionProfile ) -> Result<(), String> { upgrade_data_paths(base_path, dirs, pruning); diff --git a/parity/main.rs b/parity/main.rs index d7d5b137e32..24b53ae2c92 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -50,7 +50,6 @@ extern crate ethcore_bytes as bytes; extern crate ethcore_io as io; extern crate ethcore_light as light; extern crate ethcore_logger; -extern crate ethcore_migrations as migrations; extern crate ethcore_miner as miner; extern crate ethcore_network as network; extern crate ethcore_private_tx; @@ -60,8 +59,6 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethkey; extern crate kvdb; -extern crate kvdb_rocksdb; -extern crate migration as migr; extern crate node_health; extern crate panic_hook; extern crate parity_hash_fetch as hash_fetch; @@ -112,7 +109,6 @@ mod deprecated; mod helpers; mod informant; mod light_helpers; -mod migration; mod modules; mod params; mod presale; @@ -126,6 +122,7 @@ mod upgrade; mod url; mod user_defaults; mod whisper; +mod db; #[cfg(feature="stratum")] mod stratum; diff --git a/parity/run.rs b/parity/run.rs index f4e892b4b97..6ccd4caf562 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -25,7 +25,6 @@ use ansi_term::{Colour, Style}; use ctrlc::CtrlC; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; -use ethcore::db::NUM_COLUMNS; use ethcore::ethstore::ethkey; use ethcore::miner::{stratum, Miner, MinerService, MinerOptions}; use ethcore::snapshot; @@ -40,7 +39,6 @@ use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; use journaldb::Algorithm; -use kvdb_rocksdb::{Database, DatabaseConfig}; use light::Cache as LightDataCache; use miner::external::ExternalMiner; use node_filter::NodeFilter; @@ -55,7 +53,7 @@ use params::{ SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch, tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool }; -use helpers::{to_client_config, execute_upgrades, passwords_from_files, client_db_config, open_client_db, restoration_db_handler, compaction_profile}; +use helpers::{to_client_config, execute_upgrades, passwords_from_files}; use upgrade::upgrade_key_location; use dir::{Directories, DatabaseDirectories}; use cache::CacheConfig; @@ -68,6 +66,7 @@ use rpc_apis; use secretstore; use signer; use url; +use db; // how often to take periodic snapshots. const SNAPSHOT_PERIOD: u64 = 5000; @@ -210,10 +209,8 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?; @@ -623,9 +611,8 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // set network path. net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); // create client service. let service = ClientService::start( diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 9c130a59a92..168a9b3fcf1 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -117,6 +117,7 @@ mod server { use ethcore_secretstore; use ethkey::KeyPair; use ansi_term::Colour::Red; + use db; use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress}; fn into_service_contract_address(address: ContractAddress) -> ethcore_secretstore::ContractAddress { @@ -173,7 +174,6 @@ mod server { service_contract_srv_retr_address: conf.service_contract_srv_retr_address.map(into_service_contract_address), service_contract_doc_store_address: conf.service_contract_doc_store_address.map(into_service_contract_address), service_contract_doc_sretr_address: conf.service_contract_doc_sretr_address.map(into_service_contract_address), - data_path: conf.data_path.clone(), acl_check_enabled: conf.acl_check_enabled, cluster_config: ethcore_secretstore::ClusterConfiguration { threads: 4, @@ -193,7 +193,8 @@ mod server { cconf.cluster_config.nodes.insert(self_secret.public().clone(), cconf.cluster_config.listener_address.clone()); - let key_server = ethcore_secretstore::start(deps.client, deps.sync, deps.miner, self_secret, cconf) + let db = db::open_secretstore_db(&conf.data_path)?; + let key_server = ethcore_secretstore::start(deps.client, deps.sync, deps.miner, self_secret, cconf, db) .map_err(|e| format!("Error starting KeyServer {}: {}", key_server_name, e))?; Ok(KeyServer { diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 56b166ac62d..ad93801c0b5 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -32,11 +32,12 @@ use ethcore_service::ClientService; use cache::CacheConfig; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool}; -use helpers::{to_client_config, execute_upgrades, client_db_config, open_client_db, restoration_db_handler, compaction_profile}; +use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; use fdlimit; use ethcore_private_tx; +use db; /// Kinds of snapshot commands. #[derive(Debug, PartialEq, Clone, Copy)] @@ -164,7 +165,7 @@ impl SnapshotCommand { let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&self.dirs.base, &db_dirs, algorithm, compaction_profile(&self.compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&self.dirs.base, &db_dirs, algorithm, &self.compaction)?; // prepare client config let client_config = to_client_config( @@ -183,9 +184,8 @@ impl SnapshotCommand { true ); - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); let service = ClientService::start( client_config, diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index 91889d7012e..fee832d069c 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -31,7 +31,6 @@ ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" kvdb = { path = "../util/kvdb" } -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } keccak-hash = { path = "../util/hash" } ethkey = { path = "../ethkey" } lazy_static = "1.0" @@ -41,3 +40,4 @@ ethabi-contract = "5.0" [dev-dependencies] tempdir = "0.3" +kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index 1d4b968c07c..fee73c2ae1a 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -14,14 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::path::PathBuf; use std::collections::BTreeMap; +use std::sync::Arc; use serde_json; use tiny_keccak::Keccak; use ethereum_types::{H256, Address}; use ethkey::{Secret, Public, public_to_address}; -use kvdb_rocksdb::{Database, DatabaseIterator}; -use types::all::{Error, ServiceConfiguration, ServerKeyId, NodeId}; +use kvdb::KeyValueDB; +use types::all::{Error, ServerKeyId, NodeId}; use serialization::{SerializablePublic, SerializableSecret, SerializableH256, SerializableAddress}; /// Key of version value. @@ -82,17 +82,17 @@ pub trait KeyStorage: Send + Sync { /// Persistent document encryption keys storage pub struct PersistentKeyStorage { - db: Database, + db: Arc, } /// Persistent document encryption keys storage iterator pub struct PersistentKeyStorageIterator<'a> { - iter: Option>, + iter: Box, Box<[u8]>)> + 'a>, } /// V0 of encrypted key share, as it is stored by key storage on the single key server. #[derive(Serialize, Deserialize)] -struct SerializableDocumentKeyShareV0 { +pub struct SerializableDocumentKeyShareV0 { /// Decryption threshold (at least threshold + 1 nodes are required to decrypt data). pub threshold: usize, /// Nodes ids numbers. @@ -172,12 +172,7 @@ type SerializableDocumentKeyShareVersionV3 = SerializableDocumentKeyShareVersion impl PersistentKeyStorage { /// Create new persistent document encryption keys storage - pub fn new(config: &ServiceConfiguration) -> Result { - let mut db_path = PathBuf::from(&config.data_path); - db_path.push("db"); - let db_path = db_path.to_str().ok_or_else(|| Error::Database("Invalid secretstore path".to_owned()))?; - - let db = Database::open_default(&db_path)?; + pub fn new(db: Arc) -> Result { let db = upgrade_db(db)?; Ok(PersistentKeyStorage { @@ -186,14 +181,14 @@ impl PersistentKeyStorage { } } -fn upgrade_db(db: Database) -> Result { +fn upgrade_db(db: Arc) -> Result, Error> { let version = db.get(None, DB_META_KEY_VERSION)?; let version = version.and_then(|v| v.get(0).cloned()).unwrap_or(0); match version { 0 => { let mut batch = db.transaction(); batch.put(None, DB_META_KEY_VERSION, &[CURRENT_VERSION]); - for (db_key, db_value) in db.iter(None).into_iter().flat_map(|inner| inner).filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { + for (db_key, db_value) in db.iter(None).into_iter().filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { let v0_key = serde_json::from_slice::(&db_value).map_err(|e| Error::Database(e.to_string()))?; let current_key = CurrentSerializableDocumentKeyShare { // author is used in separate generation + encrypt sessions. @@ -218,7 +213,7 @@ fn upgrade_db(db: Database) -> Result { 1 => { let mut batch = db.transaction(); batch.put(None, DB_META_KEY_VERSION, &[CURRENT_VERSION]); - for (db_key, db_value) in db.iter(None).into_iter().flat_map(|inner| inner).filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { + for (db_key, db_value) in db.iter(None).into_iter().filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { let v1_key = serde_json::from_slice::(&db_value).map_err(|e| Error::Database(e.to_string()))?; let current_key = CurrentSerializableDocumentKeyShare { author: public_to_address(&v1_key.author).into(), // added in v1 + changed in v3 @@ -241,7 +236,7 @@ fn upgrade_db(db: Database) -> Result { 2 => { let mut batch = db.transaction(); batch.put(None, DB_META_KEY_VERSION, &[CURRENT_VERSION]); - for (db_key, db_value) in db.iter(None).into_iter().flat_map(|inner| inner).filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { + for (db_key, db_value) in db.iter(None).into_iter().filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { let v2_key = serde_json::from_slice::(&db_value).map_err(|e| Error::Database(e.to_string()))?; let current_key = CurrentSerializableDocumentKeyShare { author: public_to_address(&v2_key.author).into(), // changed in v3 @@ -319,11 +314,10 @@ impl<'a> Iterator for PersistentKeyStorageIterator<'a> { type Item = (ServerKeyId, DocumentKeyShare); fn next(&mut self) -> Option<(ServerKeyId, DocumentKeyShare)> { - self.iter.as_mut() - .and_then(|iter| iter.next() - .and_then(|(db_key, db_val)| serde_json::from_slice::(&db_val) - .ok() - .map(|key| ((*db_key).into(), key.into())))) + self.iter.as_mut().next() + .and_then(|(db_key, db_val)| serde_json::from_slice::(&db_val) + .ok() + .map(|key| ((*db_key).into(), key.into()))) } } @@ -417,14 +411,15 @@ impl From for DocumentKeyShare { pub mod tests { extern crate tempdir; - use std::collections::{BTreeMap, HashMap}; + use std::collections::HashMap; + use std::sync::Arc; use parking_lot::RwLock; use serde_json; use self::tempdir::TempDir; use ethereum_types::{Address, H256}; use ethkey::{Random, Generator, Public, Secret, public_to_address}; use kvdb_rocksdb::Database; - use types::all::{Error, NodeAddress, ServiceConfiguration, ClusterConfiguration, ServerKeyId}; + use types::all::{Error, ServerKeyId}; use super::{DB_META_KEY_VERSION, CURRENT_VERSION, KeyStorage, PersistentKeyStorage, DocumentKeyShare, DocumentKeyShareVersion, CurrentSerializableDocumentKeyShare, upgrade_db, SerializableDocumentKeyShareV0, SerializableDocumentKeyShareV1, SerializableDocumentKeyShareV2, SerializableDocumentKeyShareVersionV2}; @@ -472,27 +467,6 @@ pub mod tests { #[test] fn persistent_key_storage() { let tempdir = TempDir::new("").unwrap(); - let config = ServiceConfiguration { - listener_address: None, - service_contract_address: None, - service_contract_srv_gen_address: None, - service_contract_srv_retr_address: None, - service_contract_doc_store_address: None, - service_contract_doc_sretr_address: None, - acl_check_enabled: true, - data_path: tempdir.path().display().to_string(), - cluster_config: ClusterConfiguration { - threads: 1, - listener_address: NodeAddress { - address: "0.0.0.0".to_owned(), - port: 8083, - }, - nodes: BTreeMap::new(), - allow_connecting_to_higher_nodes: false, - admin_public: None, - auto_migrate_enabled: false, - }, - }; let key1 = ServerKeyId::from(1); let value1 = DocumentKeyShare { @@ -526,7 +500,9 @@ pub mod tests { }; let key3 = ServerKeyId::from(3); - let key_storage = PersistentKeyStorage::new(&config).unwrap(); + let db = Database::open_default(&tempdir.path().display().to_string()).unwrap(); + + let key_storage = PersistentKeyStorage::new(Arc::new(db)).unwrap(); key_storage.insert(key1.clone(), value1.clone()).unwrap(); key_storage.insert(key2.clone(), value2.clone()).unwrap(); assert_eq!(key_storage.get(&key1), Ok(Some(value1.clone()))); @@ -534,7 +510,9 @@ pub mod tests { assert_eq!(key_storage.get(&key3), Ok(None)); drop(key_storage); - let key_storage = PersistentKeyStorage::new(&config).unwrap(); + let db = Database::open_default(&tempdir.path().display().to_string()).unwrap(); + + let key_storage = PersistentKeyStorage::new(Arc::new(db)).unwrap(); assert_eq!(key_storage.get(&key1), Ok(Some(value1))); assert_eq!(key_storage.get(&key2), Ok(Some(value2))); assert_eq!(key_storage.get(&key3), Ok(None)); @@ -563,7 +541,7 @@ pub mod tests { } // upgrade database - let db = upgrade_db(db).unwrap(); + let db = upgrade_db(Arc::new(db)).unwrap(); // check upgrade assert_eq!(db.get(None, DB_META_KEY_VERSION).unwrap().unwrap()[0], CURRENT_VERSION); @@ -606,7 +584,7 @@ pub mod tests { } // upgrade database - let db = upgrade_db(db).unwrap(); + let db = upgrade_db(Arc::new(db)).unwrap(); // check upgrade assert_eq!(db.get(None, DB_META_KEY_VERSION).unwrap().unwrap()[0], CURRENT_VERSION); @@ -654,7 +632,7 @@ pub mod tests { } // upgrade database - let db = upgrade_db(db).unwrap(); + let db = upgrade_db(Arc::new(db)).unwrap(); // check upgrade assert_eq!(db.get(None, DB_META_KEY_VERSION).unwrap().unwrap()[0], CURRENT_VERSION); diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index dc45f1af369..8e1278e425b 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -28,7 +28,6 @@ extern crate futures_cpupool; extern crate hyper; extern crate keccak_hash as hash; extern crate kvdb; -extern crate kvdb_rocksdb; extern crate parking_lot; extern crate rustc_hex; extern crate serde; @@ -54,6 +53,9 @@ extern crate lazy_static; #[macro_use] extern crate log; +#[cfg(test)] +extern crate kvdb_rocksdb; + mod key_server_cluster; mod types; mod helpers; @@ -69,6 +71,7 @@ mod listener; mod trusted_client; use std::sync::Arc; +use kvdb::KeyValueDB; use ethcore::client::Client; use ethcore::miner::Miner; use sync::SyncProvider; @@ -79,7 +82,7 @@ pub use traits::{NodeKeyPair, KeyServer}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; /// Start new key server instance -pub fn start(client: Arc, sync: Arc, miner: Arc, self_key_pair: Arc, config: ServiceConfiguration) -> Result, Error> { +pub fn start(client: Arc, sync: Arc, miner: Arc, self_key_pair: Arc, config: ServiceConfiguration, db: Arc) -> Result, Error> { let trusted_client = trusted_client::TrustedClient::new(self_key_pair.clone(), client.clone(), sync, miner); let acl_storage: Arc = if config.acl_check_enabled { acl_storage::OnChainAclStorage::new(trusted_client.clone())? @@ -89,7 +92,7 @@ pub fn start(client: Arc, sync: Arc, miner: Arc, se let key_server_set = key_server_set::OnChainKeyServerSet::new(trusted_client.clone(), self_key_pair.clone(), config.cluster_config.auto_migrate_enabled, config.cluster_config.nodes.clone())?; - let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(&config)?); + let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(db)?); let key_server = Arc::new(key_server::KeyServerImpl::new(&config.cluster_config, key_server_set.clone(), self_key_pair.clone(), acl_storage.clone(), key_storage.clone())?); let cluster = key_server.cluster(); let key_server: Arc = key_server; diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index 5e28415b188..b9940268144 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -91,8 +91,6 @@ pub struct ServiceConfiguration { pub service_contract_doc_sretr_address: Option, /// Is ACL check enabled. If false, everyone has access to all keys. Useful for tests only. pub acl_check_enabled: bool, - /// Data directory path for secret store - pub data_path: String, /// Cluster configuration. pub cluster_config: ClusterConfiguration, } diff --git a/util/migration/Cargo.toml b/util/migration-rocksdb/Cargo.toml similarity index 91% rename from util/migration/Cargo.toml rename to util/migration-rocksdb/Cargo.toml index d938822bacd..3f0b8e75204 100644 --- a/util/migration/Cargo.toml +++ b/util/migration-rocksdb/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "migration" +name = "migration-rocksdb" version = "0.1.0" authors = ["Parity Technologies "] diff --git a/util/migration/src/lib.rs b/util/migration-rocksdb/src/lib.rs similarity index 100% rename from util/migration/src/lib.rs rename to util/migration-rocksdb/src/lib.rs diff --git a/util/migration/tests/tests.rs b/util/migration-rocksdb/tests/tests.rs similarity index 99% rename from util/migration/tests/tests.rs rename to util/migration-rocksdb/tests/tests.rs index c1ff8228f87..85c48f12b67 100644 --- a/util/migration/tests/tests.rs +++ b/util/migration-rocksdb/tests/tests.rs @@ -22,7 +22,7 @@ extern crate macros; extern crate tempdir; extern crate kvdb_rocksdb; -extern crate migration; +extern crate migration_rocksdb as migration; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; From 89b90b84543f774949db6316a2d461388a81a799 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 14 Apr 2018 03:15:33 +0800 Subject: [PATCH 016/147] Use tokio::spawn in secret_store listener and fix Uri (#8373) * Directly wait for future to resolve in a threadpool * Ignore return value * Use path.starts_with instead of req_uri.is_absolute The later now means something else in hyper 0.11.. * Use tokio::spawn * typo: remove accidential unsafe impl --- secret_store/src/listener/http_listener.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index 7d4385ccc5b..bf293a44eb4 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -20,7 +20,7 @@ use hyper::{self, header, Chunk, Uri, Request as HttpRequest, Response as HttpRe use hyper::server::Http; use serde::Serialize; use serde_json; -use tokio::executor::current_thread; +use tokio; use tokio::net::TcpListener; use tokio::runtime::Runtime; use tokio_service::Service; @@ -104,9 +104,7 @@ impl KeyServerHttpListener { warn!("Key server handler error: {:?}", e); }); - // TODO: Change this to tokio::spawn once hyper is Send. - current_thread::spawn(serve); - future::ok(()) + tokio::spawn(serve) }); runtime.spawn(server); @@ -207,7 +205,7 @@ impl Service for KeyServerHttpHandler { type Request = HttpRequest; type Response = HttpResponse; type Error = hyper::Error; - type Future = Box>; + type Future = Box + Send>; fn call(&self, req: HttpRequest) -> Self::Future { if req.headers().has::() { @@ -222,7 +220,7 @@ impl Service for KeyServerHttpHandler { Box::new(req.body().concat2().map(move |body| { let path = req_uri.path().to_string(); - if req_uri.is_absolute() { + if path.starts_with("/") { this.process(req_method, req_uri, &path, &body) } else { warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri); From b7a0f3c1c8ef3bc0428e3ce1368f69d26b3654dc Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Sat, 14 Apr 2018 21:47:52 +0300 Subject: [PATCH 017/147] remove Tendermint extra_info due to seal inconsistencies (#8367) --- ethcore/src/engines/tendermint/mod.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index c9312e90435..14d1ebd5852 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -27,7 +27,7 @@ mod params; use std::sync::{Weak, Arc}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; -use std::collections::{HashSet, BTreeMap}; +use std::collections::HashSet; use hash::keccak; use ethereum_types::{H256, H520, U128, U256, Address}; use parking_lot::RwLock; @@ -449,17 +449,6 @@ impl Engine for Tendermint { fn maximum_uncle_age(&self) -> usize { 0 } - /// Additional engine-specific information for the user/developer concerning `header`. - fn extra_info(&self, header: &Header) -> BTreeMap { - let message = ConsensusMessage::new_proposal(header).expect("Invalid header."); - map![ - "signature".into() => message.signature.to_string(), - "height".into() => message.vote_step.height.to_string(), - "view".into() => message.vote_step.view.to_string(), - "block_hash".into() => message.block_hash.as_ref().map(ToString::to_string).unwrap_or("".into()) - ] - } - fn populate_from_parent(&self, header: &mut Header, parent: &Header) { // Chain scoring: total weight is sqrt(U256::max_value())*height - view let new_difficulty = U256::from(U128::max_value()) From 4619b301e650f91e6c8a79cd48317a176ee7693e Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 14 Apr 2018 21:35:58 +0200 Subject: [PATCH 018/147] More code refactoring to integrate Duration (#8322) * More code refactoring to integrate Duration * Fix typo * Fix tests * More test fix --- dapps/src/tests/helpers/fetch.rs | 6 ++-- ethcore/light/src/net/load_timer.rs | 30 +++++++++--------- ethcore/light/src/net/mod.rs | 24 +++++++-------- ethcore/light/src/net/request_credits.rs | 33 ++++++++++++-------- ethcore/service/src/service.rs | 9 +++--- ethcore/src/account_provider/mod.rs | 10 +++--- ethcore/src/engines/authority_round/mod.rs | 9 +++--- ethcore/src/engines/transition.rs | 3 +- ethcore/src/error.rs | 15 ++++++--- ethcore/src/verification/verification.rs | 18 +++++------ ethcore/sync/src/api.rs | 3 +- ethcore/sync/src/chain.rs | 36 +++++++++++----------- ethcore/sync/src/light_sync/mod.rs | 17 +++++----- local-store/src/lib.rs | 5 +-- parity/informant.rs | 2 +- parity/light_helpers/queue_cull.rs | 6 ++-- rpc/src/v1/impls/personal.rs | 5 +-- util/io/src/lib.rs | 6 ++-- util/io/src/service.rs | 20 ++++++------ util/network-devp2p/src/connection.rs | 5 +-- util/network-devp2p/src/handshake.rs | 3 +- util/network-devp2p/src/host.rs | 15 ++++----- util/network-devp2p/src/lib.rs | 3 +- util/network-devp2p/src/session.rs | 16 +++++----- util/network-devp2p/tests/tests.rs | 2 +- util/network/src/lib.rs | 15 ++++----- util/unexpected/src/lib.rs | 12 ++++++++ whisper/src/net/mod.rs | 4 +-- 28 files changed, 185 insertions(+), 147 deletions(-) diff --git a/dapps/src/tests/helpers/fetch.rs b/dapps/src/tests/helpers/fetch.rs index 146163a77f4..51c98db531d 100644 --- a/dapps/src/tests/helpers/fetch.rs +++ b/dapps/src/tests/helpers/fetch.rs @@ -34,8 +34,8 @@ impl FetchControl { } pub fn wait_for_requests(&self, len: usize) { - const MAX_TIMEOUT_MS: u64 = 5000; - const ATTEMPTS: u64 = 10; + const MAX_TIMEOUT: time::Duration = time::Duration::from_millis(5000); + const ATTEMPTS: u32 = 10; let mut attempts_left = ATTEMPTS; loop { let current = self.fetch.requested.lock().len(); @@ -50,7 +50,7 @@ impl FetchControl { } else { attempts_left -= 1; // Should we handle spurious timeouts better? - thread::park_timeout(time::Duration::from_millis(MAX_TIMEOUT_MS / ATTEMPTS)); + thread::park_timeout(MAX_TIMEOUT / ATTEMPTS); } } } diff --git a/ethcore/light/src/net/load_timer.rs b/ethcore/light/src/net/load_timer.rs index c6e524a4412..2846a57384b 100644 --- a/ethcore/light/src/net/load_timer.rs +++ b/ethcore/light/src/net/load_timer.rs @@ -48,11 +48,11 @@ pub trait SampleStore: Send + Sync { } // get a hardcoded, arbitrarily determined (but intended overestimate) -// of the time in nanoseconds to serve a request of the given kind. +// of the time it takes to serve a request of the given kind. // // TODO: seed this with empirical data. -fn hardcoded_serve_time(kind: Kind) -> u64 { - match kind { +fn hardcoded_serve_time(kind: Kind) -> Duration { + Duration::new(0, match kind { Kind::Headers => 500_000, Kind::HeaderProof => 500_000, Kind::TransactionIndex => 500_000, @@ -63,7 +63,7 @@ fn hardcoded_serve_time(kind: Kind) -> u64 { Kind::Code => 1_500_000, Kind::Execution => 250, // per gas. Kind::Signal => 500_000, - } + }) } /// A no-op store. @@ -114,10 +114,10 @@ impl LoadDistribution { } } - /// Calculate EMA of load in nanoseconds for a specific request kind. + /// Calculate EMA of load for a specific request kind. /// If there is no data for the given request kind, no EMA will be calculated, /// but a hardcoded time will be returned. - pub fn expected_time_ns(&self, kind: Kind) -> u64 { + pub fn expected_time(&self, kind: Kind) -> Duration { let samples = self.samples.read(); samples.get(&kind).and_then(|s| { if s.len() == 0 { return None } @@ -128,7 +128,9 @@ impl LoadDistribution { (alpha * c as f64) + ((1.0 - alpha) * a) }); - Some(ema as u64) + // TODO: use `Duration::from_nanos` once stable (https://github.com/rust-lang/rust/issues/46507) + let ema = ema as u64; + Some(Duration::new(ema / 1_000_000_000, (ema % 1_000_000_000) as u32)) }).unwrap_or_else(move || hardcoded_serve_time(kind)) } @@ -223,12 +225,12 @@ mod tests { #[test] fn hardcoded_before_data() { let dist = LoadDistribution::load(&NullStore); - assert_eq!(dist.expected_time_ns(Kind::Headers), hardcoded_serve_time(Kind::Headers)); + assert_eq!(dist.expected_time(Kind::Headers), hardcoded_serve_time(Kind::Headers)); dist.update(Kind::Headers, Duration::new(0, 100_000), 100); dist.end_period(&NullStore); - assert_eq!(dist.expected_time_ns(Kind::Headers), 1000); + assert_eq!(dist.expected_time(Kind::Headers), Duration::new(0, 1000)); } #[test] @@ -244,20 +246,20 @@ mod tests { sum += x; if i == 0 { continue } - let moving_average = dist.expected_time_ns(Kind::Headers); + let moving_average = dist.expected_time(Kind::Headers); // should be weighted below the maximum entry. - let arith_average = (sum as f64 / (i + 1) as f64) as u64; - assert!(moving_average < x as u64); + let arith_average = (sum as f64 / (i + 1) as f64) as u32; + assert!(moving_average < Duration::new(0, x)); // when there are only 2 entries, they should be equal due to choice of // ALPHA = 1/N. // otherwise, the weight should be below the arithmetic mean because the much // smaller previous values are discounted less. if i == 1 { - assert_eq!(moving_average, arith_average); + assert_eq!(moving_average, Duration::new(0, arith_average)); } else { - assert!(moving_average < arith_average) + assert!(moving_average < Duration::new(0, arith_average)) } } } diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index abdf91ae442..8299773230c 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -61,16 +61,16 @@ pub use self::load_timer::{SampleStore, FileStore}; pub use self::status::{Status, Capabilities, Announcement}; const TIMEOUT: TimerToken = 0; -const TIMEOUT_INTERVAL_MS: u64 = 1000; +const TIMEOUT_INTERVAL: Duration = Duration::from_secs(1); const TICK_TIMEOUT: TimerToken = 1; -const TICK_TIMEOUT_INTERVAL_MS: u64 = 5000; +const TICK_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5); const PROPAGATE_TIMEOUT: TimerToken = 2; -const PROPAGATE_TIMEOUT_INTERVAL_MS: u64 = 5000; +const PROPAGATE_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5); const RECALCULATE_COSTS_TIMEOUT: TimerToken = 3; -const RECALCULATE_COSTS_INTERVAL_MS: u64 = 60 * 60 * 1000; +const RECALCULATE_COSTS_INTERVAL: Duration = Duration::from_secs(60 * 60); // minimum interval between updates. const UPDATE_INTERVAL: Duration = Duration::from_millis(5000); @@ -369,9 +369,9 @@ impl LightProtocol { let sample_store = params.sample_store.unwrap_or_else(|| Box::new(NullStore)); let load_distribution = LoadDistribution::load(&*sample_store); let flow_params = FlowParams::from_request_times( - |kind| load_distribution.expected_time_ns(kind), + |kind| load_distribution.expected_time(kind), params.config.load_share, - params.config.max_stored_seconds, + Duration::from_secs(params.config.max_stored_seconds), ); LightProtocol { @@ -766,9 +766,9 @@ impl LightProtocol { self.load_distribution.end_period(&*self.sample_store); let new_params = Arc::new(FlowParams::from_request_times( - |kind| self.load_distribution.expected_time_ns(kind), + |kind| self.load_distribution.expected_time(kind), self.config.load_share, - self.config.max_stored_seconds, + Duration::from_secs(self.config.max_stored_seconds), )); *self.flow_params.write() = new_params.clone(); @@ -1080,13 +1080,13 @@ fn punish(peer: PeerId, io: &IoContext, e: Error) { impl NetworkProtocolHandler for LightProtocol { fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { - io.register_timer(TIMEOUT, TIMEOUT_INTERVAL_MS) + io.register_timer(TIMEOUT, TIMEOUT_INTERVAL) .expect("Error registering sync timer."); - io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL_MS) + io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL) .expect("Error registering sync timer."); - io.register_timer(PROPAGATE_TIMEOUT, PROPAGATE_TIMEOUT_INTERVAL_MS) + io.register_timer(PROPAGATE_TIMEOUT, PROPAGATE_TIMEOUT_INTERVAL) .expect("Error registering sync timer."); - io.register_timer(RECALCULATE_COSTS_TIMEOUT, RECALCULATE_COSTS_INTERVAL_MS) + io.register_timer(RECALCULATE_COSTS_TIMEOUT, RECALCULATE_COSTS_INTERVAL) .expect("Error registering request timer interval token."); } diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index c35a2922279..e1b7455ccca 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -235,23 +235,30 @@ impl FlowParams { /// Create new flow parameters from , /// proportion of total capacity which should be given to a peer, - /// and number of seconds of stored capacity a peer can accumulate. - pub fn from_request_times u64>( - request_time_ns: F, + /// and stored capacity a peer can accumulate. + pub fn from_request_times Duration>( + request_time: F, load_share: f64, - max_stored_seconds: u64 + max_stored: Duration ) -> Self { use request::Kind; let load_share = load_share.abs(); let recharge: u64 = 100_000_000; - let max = recharge.saturating_mul(max_stored_seconds); + let max = { + let sec = max_stored.as_secs().saturating_mul(recharge); + let nanos = (max_stored.subsec_nanos() as u64).saturating_mul(recharge) / 1_000_000_000; + sec + nanos + }; let cost_for_kind = |kind| { // how many requests we can handle per second - let ns = request_time_ns(kind); - let second_duration = 1_000_000_000f64 / ns as f64; + let rq_dur = request_time(kind); + let second_duration = { + let as_ns = rq_dur.as_secs() as f64 * 1_000_000_000f64 + rq_dur.subsec_nanos() as f64; + 1_000_000_000f64 / as_ns + }; // scale by share of the load given to this peer. let serve_per_second = second_duration * load_share; @@ -426,21 +433,21 @@ mod tests { #[test] fn scale_by_load_share_and_time() { let flow_params = FlowParams::from_request_times( - |_| 10_000, + |_| Duration::new(0, 10_000), 0.05, - 60, + Duration::from_secs(60), ); let flow_params2 = FlowParams::from_request_times( - |_| 10_000, + |_| Duration::new(0, 10_000), 0.1, - 60, + Duration::from_secs(60), ); let flow_params3 = FlowParams::from_request_times( - |_| 5_000, + |_| Duration::new(0, 5_000), 0.05, - 60, + Duration::from_secs(60), ); assert_eq!(flow_params2.costs, flow_params3.costs); diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index b57d613e3ba..b60d4194c90 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use std::path::Path; +use std::time::Duration; use ansi_term::Colour; use io::{IoContext, TimerToken, IoHandler, IoService, IoError}; @@ -180,13 +181,13 @@ struct ClientIoHandler { const CLIENT_TICK_TIMER: TimerToken = 0; const SNAPSHOT_TICK_TIMER: TimerToken = 1; -const CLIENT_TICK_MS: u64 = 5000; -const SNAPSHOT_TICK_MS: u64 = 10000; +const CLIENT_TICK: Duration = Duration::from_secs(5); +const SNAPSHOT_TICK: Duration = Duration::from_secs(10); impl IoHandler for ClientIoHandler { fn initialize(&self, io: &IoContext) { - io.register_timer(CLIENT_TICK_TIMER, CLIENT_TICK_MS).expect("Error registering client timer"); - io.register_timer(SNAPSHOT_TICK_TIMER, SNAPSHOT_TICK_MS).expect("Error registering snapshot timer"); + io.register_timer(CLIENT_TICK_TIMER, CLIENT_TICK).expect("Error registering client timer"); + io.register_timer(SNAPSHOT_TICK_TIMER, SNAPSHOT_TICK).expect("Error registering snapshot timer"); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 2edb42be1e9..9d6b814c6f6 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -638,8 +638,8 @@ impl AccountProvider { } /// Unlocks account temporarily with a timeout. - pub fn unlock_account_timed(&self, account: Address, password: String, duration_ms: u32) -> Result<(), Error> { - self.unlock_account(account, password, Unlock::Timed(Instant::now() + Duration::from_millis(duration_ms as u64))) + pub fn unlock_account_timed(&self, account: Address, password: String, duration: Duration) -> Result<(), Error> { + self.unlock_account(account, password, Unlock::Timed(Instant::now() + duration)) } /// Checks if given account is unlocked @@ -834,7 +834,7 @@ impl AccountProvider { #[cfg(test)] mod tests { use super::{AccountProvider, Unlock, DappId}; - use std::time::Instant; + use std::time::{Duration, Instant}; use ethstore::ethkey::{Generator, Random, Address}; use ethstore::{StoreAccountRef, Derivation}; use ethereum_types::H256; @@ -938,8 +938,8 @@ mod tests { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); - assert!(ap.unlock_account_timed(kp.address(), "test1".into(), 60000).is_err()); - assert!(ap.unlock_account_timed(kp.address(), "test".into(), 60000).is_ok()); + assert!(ap.unlock_account_timed(kp.address(), "test1".into(), Duration::from_secs(60)).is_err()); + assert!(ap.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60)).is_ok()); assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); ap.unlocked.write().get_mut(&StoreAccountRef::root(kp.address())).unwrap().unlock = Unlock::Timed(Instant::now()); assert!(ap.sign(kp.address(), None, Default::default()).is_err()); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index e3acc5eed9d..b8b9ab8b308 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -19,7 +19,7 @@ use std::fmt; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Weak, Arc}; -use std::time::{UNIX_EPOCH, Duration}; +use std::time::{UNIX_EPOCH, SystemTime, Duration}; use std::collections::{BTreeMap, HashSet}; use std::iter::FromIterator; @@ -536,6 +536,7 @@ fn verify_timestamp(step: &Step, header_step: usize) -> Result<(), BlockError> { // NOTE This error might be returned only in early stage of verification (Stage 1). // Returning it further won't recover the sync process. trace!(target: "engine", "verify_timestamp: block too early"); + let oob = oob.map(|n| SystemTime::now() + Duration::from_secs(n)); Err(BlockError::TemporarilyInvalid(oob).into()) }, Ok(_) => Ok(()), @@ -694,8 +695,8 @@ const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; impl IoHandler<()> for TransitionHandler { fn initialize(&self, io: &IoContext<()>) { if let Some(engine) = self.engine.upgrade() { - let remaining = engine.step.duration_remaining(); - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, remaining.as_millis()) + let remaining = engine.step.duration_remaining().as_millis(); + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining)) .unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e)) } } @@ -711,7 +712,7 @@ impl IoHandler<()> for TransitionHandler { } let next_run_at = engine.step.duration_remaining().as_millis() >> 2; - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, next_run_at) + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at)) .unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e)) } } diff --git a/ethcore/src/engines/transition.rs b/ethcore/src/engines/transition.rs index dc745b6e398..a0469b62498 100644 --- a/ethcore/src/engines/transition.rs +++ b/ethcore/src/engines/transition.rs @@ -51,8 +51,7 @@ impl TransitionHandler where S: Sync + Send + Clone { pub const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; fn set_timeout(io: &IoContext, timeout: Duration) { - let ms = timeout.as_secs() * 1_000 + timeout.subsec_nanos() as u64 / 1_000_000; - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, ms) + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, timeout) .unwrap_or_else(|e| warn!(target: "engine", "Failed to set consensus step timeout: {}.", e)) } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index defb301dcbe..4c8157a82f1 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -17,6 +17,7 @@ //! General error types for use in ethcore. use std::{fmt, error}; +use std::time::SystemTime; use kvdb; use ethereum_types::{H256, U256, Address, Bloom}; use util_error::UtilError; @@ -81,9 +82,9 @@ pub enum BlockError { /// Receipts trie root header field is invalid. InvalidReceiptsRoot(Mismatch), /// Timestamp header field is invalid. - InvalidTimestamp(OutOfBounds), + InvalidTimestamp(OutOfBounds), /// Timestamp header field is too far in future. - TemporarilyInvalid(OutOfBounds), + TemporarilyInvalid(OutOfBounds), /// Log bloom header field is invalid. InvalidLogBloom(Mismatch), /// Number field of header is invalid. @@ -125,8 +126,14 @@ impl fmt::Display for BlockError { InvalidSeal => "Block has invalid seal.".into(), InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob), InvalidReceiptsRoot(ref mis) => format!("Invalid receipts trie root in header: {}", mis), - InvalidTimestamp(ref oob) => format!("Invalid timestamp in header: {}", oob), - TemporarilyInvalid(ref oob) => format!("Future timestamp in header: {}", oob), + InvalidTimestamp(ref oob) => { + let oob = oob.map(|st| st.elapsed().unwrap_or_default().as_secs()); + format!("Invalid timestamp in header: {}", oob) + }, + TemporarilyInvalid(ref oob) => { + let oob = oob.map(|st| st.elapsed().unwrap_or_default().as_secs()); + format!("Future timestamp in header: {}", oob) + }, InvalidLogBloom(ref oob) => format!("Invalid log bloom in header: {}", oob), InvalidNumber(ref mis) => format!("Invalid number in header: {}", mis), RidiculousNumber(ref oob) => format!("Implausible block number. {}", oob), diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index e50eb79194d..5b0700bfd9c 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -22,7 +22,7 @@ //! 3. Final verification against the blockchain done before enactment. use std::collections::HashSet; -use std::time::{SystemTime, UNIX_EPOCH}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; use bytes::Bytes; use ethereum_types::H256; @@ -284,11 +284,10 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool) } if is_full { - const ACCEPTABLE_DRIFT_SECS: u64 = 15; - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default(); - let max_time = now.as_secs() + ACCEPTABLE_DRIFT_SECS; - let invalid_threshold = max_time + ACCEPTABLE_DRIFT_SECS * 9; - let timestamp = header.timestamp(); + const ACCEPTABLE_DRIFT: Duration = Duration::from_secs(15); + let max_time = SystemTime::now() + ACCEPTABLE_DRIFT; + let invalid_threshold = max_time + ACCEPTABLE_DRIFT * 9; + let timestamp = UNIX_EPOCH + Duration::from_secs(header.timestamp()); if timestamp > invalid_threshold { return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: timestamp }))) @@ -310,7 +309,9 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result let gas_limit_divisor = engine.params().gas_limit_bound_divisor; if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) { - return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() }))) + let min = SystemTime::now() + Duration::from_secs(parent.timestamp() + 1); + let found = SystemTime::now() + Duration::from_secs(header.timestamp()); + return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(min), found }))) } if header.number() != parent.number() + 1 { return Err(From::from(BlockError::InvalidNumber(Mismatch { expected: parent.number() + 1, found: header.number() }))); @@ -679,8 +680,7 @@ mod tests { header = good.clone(); header.set_timestamp(10); - check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), - InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() })); + check_fail_timestamp(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), false); header = good.clone(); header.set_timestamp(2450000000); diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index eeccb46112f..6270bcfd596 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeMap}; use std::io; +use std::time::Duration; use bytes::Bytes; use devp2p::{NetworkService, ConnectionFilter}; use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, ProtocolId, @@ -373,7 +374,7 @@ struct SyncProtocolHandler { impl NetworkProtocolHandler for SyncProtocolHandler { fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { if io.subprotocol_name() != WARP_SYNC_PROTOCOL_ID { - io.register_timer(0, 1000).expect("Error registering sync timer"); + io.register_timer(0, Duration::from_secs(1)).expect("Error registering sync timer"); } } diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index 44ab1971a99..014302d7feb 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -91,7 +91,7 @@ use std::sync::Arc; use std::collections::{HashSet, HashMap}; use std::cmp; -use std::time::Instant; +use std::time::{Duration, Instant}; use hash::keccak; use heapsize::HeapSizeOf; use ethereum_types::{H256, U256}; @@ -177,14 +177,14 @@ pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; -const WAIT_PEERS_TIMEOUT_SEC: u64 = 5; -const STATUS_TIMEOUT_SEC: u64 = 5; -const HEADERS_TIMEOUT_SEC: u64 = 15; -const BODIES_TIMEOUT_SEC: u64 = 20; -const RECEIPTS_TIMEOUT_SEC: u64 = 10; -const FORK_HEADER_TIMEOUT_SEC: u64 = 3; -const SNAPSHOT_MANIFEST_TIMEOUT_SEC: u64 = 5; -const SNAPSHOT_DATA_TIMEOUT_SEC: u64 = 120; +const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); +const STATUS_TIMEOUT: Duration = Duration::from_secs(5); +const HEADERS_TIMEOUT: Duration = Duration::from_secs(15); +const BODIES_TIMEOUT: Duration = Duration::from_secs(20); +const RECEIPTS_TIMEOUT: Duration = Duration::from_secs(10); +const FORK_HEADER_TIMEOUT: Duration = Duration::from_secs(3); +const SNAPSHOT_MANIFEST_TIMEOUT: Duration = Duration::from_secs(5); +const SNAPSHOT_DATA_TIMEOUT: Duration = Duration::from_secs(120); #[derive(Copy, Clone, Eq, PartialEq, Debug)] /// Sync state @@ -573,7 +573,7 @@ impl ChainSync { (best_hash, max_peers, snapshot_peers) }; - let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed().as_secs() > WAIT_PEERS_TIMEOUT_SEC); + let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed() > WAIT_PEERS_TIMEOUT); if let (Some(hash), Some(peers)) = (best_hash, best_hash.map_or(None, |h| snapshot_peers.get(&h))) { if max_peers >= SNAPSHOT_MIN_PEERS { @@ -1825,15 +1825,15 @@ impl ChainSync { let tick = Instant::now(); let mut aborting = Vec::new(); for (peer_id, peer) in &self.peers { - let elapsed = (tick - peer.ask_time).as_secs(); + let elapsed = tick - peer.ask_time; let timeout = match peer.asking { - PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT_SEC, - PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT_SEC, - PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT_SEC, + PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT, + PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT, + PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT, PeerAsking::Nothing => false, - PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT_SEC, - PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT_SEC, - PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT_SEC, + PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT, + PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT, + PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, }; if timeout { trace!(target:"sync", "Timeout {}", peer_id); @@ -1848,7 +1848,7 @@ impl ChainSync { // Check for handshake timeouts for (peer, &ask_time) in &self.handshaking_peers { let elapsed = (tick - ask_time) / 1_000_000_000; - if elapsed.as_secs() > STATUS_TIMEOUT_SEC { + if elapsed > STATUS_TIMEOUT { trace!(target:"sync", "Status timeout {}", peer); io.disconnect_peer(*peer); } diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index df76d25ccca..0f6660e179f 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -58,12 +58,12 @@ mod sync_round; #[cfg(test)] mod tests; -// Base number of milliseconds for the header request timeout. -const REQ_TIMEOUT_MILLISECS_BASE: u64 = 7000; -// Additional number of milliseconds for each requested header. +// Base value for the header request timeout. +const REQ_TIMEOUT_BASE: Duration = Duration::from_secs(7); +// Additional value for each requested header. // If we request N headers, then the timeout will be: -// REQ_TIMEOUT_MILLISECS_BASE + N * REQ_TIMEOUT_MILLISECS_PER_HEADER -const REQ_TIMEOUT_MILLISECS_PER_HEADER: u64 = 10; +// REQ_TIMEOUT_BASE + N * REQ_TIMEOUT_PER_HEADER +const REQ_TIMEOUT_PER_HEADER: Duration = Duration::from_millis(10); /// Peer chain info. #[derive(Debug, Clone, PartialEq, Eq)] @@ -585,11 +585,12 @@ impl LightSync { if requested_from.contains(peer) { continue } match ctx.request_from(*peer, request.clone()) { Ok(id) => { - let timeout_ms = REQ_TIMEOUT_MILLISECS_BASE + - req.max * REQ_TIMEOUT_MILLISECS_PER_HEADER; + assert!(req.max <= u32::max_value() as u64, + "requesting more than 2^32 headers at a time would overflow"); + let timeout = REQ_TIMEOUT_BASE + REQ_TIMEOUT_PER_HEADER * req.max as u32; self.pending_reqs.lock().insert(id.clone(), PendingReq { started: Instant::now(), - timeout: Duration::from_millis(timeout_ms), + timeout, }); requested_from.insert(peer.clone()); diff --git a/local-store/src/lib.rs b/local-store/src/lib.rs index 9120b8694a1..2ebc6a69ce2 100644 --- a/local-store/src/lib.rs +++ b/local-store/src/lib.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use std::fmt; +use std::time::Duration; use transaction::{ SignedTransaction, PendingTransaction, UnverifiedTransaction, @@ -50,7 +51,7 @@ extern crate kvdb_memorydb; const LOCAL_TRANSACTIONS_KEY: &'static [u8] = &*b"LOCAL_TXS"; const UPDATE_TIMER: ::io::TimerToken = 0; -const UPDATE_TIMEOUT_MS: u64 = 15 * 60 * 1000; // once every 15 minutes. +const UPDATE_TIMEOUT: Duration = Duration::from_secs(15 * 60); // once every 15 minutes. /// Errors which can occur while using the local data store. #[derive(Debug)] @@ -205,7 +206,7 @@ impl LocalDataStore { impl IoHandler for LocalDataStore { fn initialize(&self, io: &::io::IoContext) { - if let Err(e) = io.register_timer(UPDATE_TIMER, UPDATE_TIMEOUT_MS) { + if let Err(e) = io.register_timer(UPDATE_TIMER, UPDATE_TIMEOUT) { warn!(target: "local_store", "Error registering local store update timer: {}", e); } } diff --git a/parity/informant.rs b/parity/informant.rs index fddcadebd87..896e80ec53d 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -399,7 +399,7 @@ const INFO_TIMER: TimerToken = 0; impl IoHandler for Informant { fn initialize(&self, io: &IoContext) { - io.register_timer(INFO_TIMER, 5000).expect("Error registering timer"); + io.register_timer(INFO_TIMER, Duration::from_secs(5)).expect("Error registering timer"); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index e0725406199..b6be59e2ce3 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -35,10 +35,10 @@ use parking_lot::RwLock; // Attepmt to cull once every 10 minutes. const TOKEN: TimerToken = 1; -const TIMEOUT_MS: u64 = 1000 * 60 * 10; +const TIMEOUT: Duration = Duration::from_secs(60 * 10); // But make each attempt last only 9 minutes -const PURGE_TIMEOUT: Duration = Duration::from_millis(1000 * 60 * 9); +const PURGE_TIMEOUT: Duration = Duration::from_secs(60 * 9); /// Periodically culls the transaction queue of mined transactions. pub struct QueueCull { @@ -56,7 +56,7 @@ pub struct QueueCull { impl IoHandler for QueueCull { fn initialize(&self, io: &IoContext) { - io.register_timer(TOKEN, TIMEOUT_MS).expect("Error registering timer"); + io.register_timer(TOKEN, TIMEOUT).expect("Error registering timer"); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index c3560fe9df3..03495fd37f8 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -16,6 +16,7 @@ //! Account management (personal) rpc implementation use std::sync::Arc; +use std::time::Duration; use bytes::{Bytes, ToPretty}; use ethcore::account_provider::AccountProvider; @@ -130,8 +131,8 @@ impl Personal for PersonalClient { Some("Restart your client with --geth flag or use personal_sendTransaction instead."), )), (true, Some(0)) => store.unlock_account_permanently(account, account_pass), - (true, Some(d)) => store.unlock_account_timed(account, account_pass, d * 1000), - (true, None) => store.unlock_account_timed(account, account_pass, 300_000), + (true, Some(d)) => store.unlock_account_timed(account, account_pass, Duration::from_secs(d.into())), + (true, None) => store.unlock_account_timed(account, account_pass, Duration::from_secs(300)), }; match r { Ok(_) => Ok(true), diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index 22241a2f5d0..20b908ac91d 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -22,6 +22,7 @@ //! extern crate ethcore_io; //! use ethcore_io::*; //! use std::sync::Arc; +//! use std::time::Duration; //! //! struct MyHandler; //! @@ -32,7 +33,7 @@ //! //! impl IoHandler for MyHandler { //! fn initialize(&self, io: &IoContext) { -//! io.register_timer(0, 1000).unwrap(); +//! io.register_timer(0, Duration::from_secs(1)).unwrap(); //! } //! //! fn timeout(&self, _io: &IoContext, timer: TimerToken) { @@ -147,6 +148,7 @@ pub use service::TOKENS_PER_HANDLER; mod tests { use std::sync::Arc; + use std::time::Duration; use super::*; struct MyHandler; @@ -158,7 +160,7 @@ mod tests { impl IoHandler for MyHandler { fn initialize(&self, io: &IoContext) { - io.register_timer(0, 1000).unwrap(); + io.register_timer(0, Duration::from_secs(1)).unwrap(); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/util/io/src/service.rs b/util/io/src/service.rs index baa279cabdb..19f2d4b3bb5 100644 --- a/util/io/src/service.rs +++ b/util/io/src/service.rs @@ -54,7 +54,7 @@ pub enum IoMessage where Message: Send + Clone + Sized { AddTimer { handler_id: HandlerId, token: TimerToken, - delay: u64, + delay: Duration, once: bool, }, RemoveTimer { @@ -93,10 +93,10 @@ impl IoContext where Message: Send + Clone + Sync + 'static { } /// Register a new recurring IO timer. 'IoHandler::timeout' will be called with the token. - pub fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), IoError> { + pub fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { self.channel.send_io(IoMessage::AddTimer { - token: token, - delay: ms, + token, + delay, handler_id: self.handler, once: false, })?; @@ -104,10 +104,10 @@ impl IoContext where Message: Send + Clone + Sync + 'static { } /// Register a new IO timer once. 'IoHandler::timeout' will be called with the token. - pub fn register_timer_once(&self, token: TimerToken, ms: u64) -> Result<(), IoError> { + pub fn register_timer_once(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { self.channel.send_io(IoMessage::AddTimer { - token: token, - delay: ms, + token, + delay, handler_id: self.handler, once: true, })?; @@ -173,7 +173,7 @@ impl IoContext where Message: Send + Clone + Sync + 'static { #[derive(Clone)] struct UserTimer { - delay: u64, + delay: Duration, timeout: Timeout, once: bool, } @@ -252,7 +252,7 @@ impl Handler for IoManager where Message: Send + Clone + Sync self.timers.write().remove(&token_id); event_loop.clear_timeout(&timer.timeout); } else { - event_loop.timeout(token, Duration::from_millis(timer.delay)).expect("Error re-registering user timer"); + event_loop.timeout(token, timer.delay).expect("Error re-registering user timer"); } self.worker_channel.push(Work { work_type: WorkType::Timeout, token: token_id, handler: handler.clone(), handler_id: handler_index }); self.work_ready.notify_all(); @@ -283,7 +283,7 @@ impl Handler for IoManager where Message: Send + Clone + Sync }, IoMessage::AddTimer { handler_id, token, delay, once } => { let timer_id = token + handler_id * TOKENS_PER_HANDLER; - let timeout = event_loop.timeout(Token(timer_id), Duration::from_millis(delay)).expect("Error registering user timer"); + let timeout = event_loop.timeout(Token(timer_id), delay).expect("Error registering user timer"); self.timers.write().insert(timer_id, UserTimer { delay: delay, timeout: timeout, once: once }); }, IoMessage::RemoveTimer { handler_id, token } => { diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 4d775b215f0..12c38b3a245 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -17,6 +17,7 @@ use std::collections::VecDeque; use std::net::SocketAddr; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; +use std::time::Duration; use hash::{keccak, write_keccak}; use mio::{Token, Ready, PollOpt}; use mio::deprecated::{Handler, EventLoop, TryRead, TryWrite}; @@ -37,7 +38,7 @@ use crypto; use network::{Error, ErrorKind}; const ENCRYPTED_HEADER_LEN: usize = 32; -const RECIEVE_PAYLOAD_TIMEOUT: u64 = 30000; +const RECEIVE_PAYLOAD: Duration = Duration::from_secs(30); pub const MAX_PAYLOAD_SIZE: usize = (1 << 24) - 1; pub trait GenericSocket : Read + Write { @@ -447,7 +448,7 @@ impl EncryptedConnection { if let EncryptedConnectionState::Header = self.read_state { if let Some(data) = self.connection.readable()? { self.read_header(&data)?; - io.register_timer(self.connection.token, RECIEVE_PAYLOAD_TIMEOUT)?; + io.register_timer(self.connection.token, RECEIVE_PAYLOAD)?; } }; if let EncryptedConnectionState::Payload = self.read_state { diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 020b65477ba..d7818b64d95 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::time::Duration; use rand::random; use hash::write_keccak; use mio::tcp::*; @@ -73,7 +74,7 @@ pub struct Handshake { const V4_AUTH_PACKET_SIZE: usize = 307; const V4_ACK_PACKET_SIZE: usize = 210; -const HANDSHAKE_TIMEOUT: u64 = 5000; +const HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(5); const PROTOCOL_VERSION: u64 = 4; // Amount of bytes added when encrypting with encryptECIES. const ECIES_OVERHEAD: usize = 113; diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 7056c67f6cb..73ca2aca4bd 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -24,6 +24,7 @@ use std::cmp::{min, max}; use std::path::{Path, PathBuf}; use std::io::{Read, Write, self}; use std::fs; +use std::time::Duration; use ethkey::{KeyPair, Secret, Random, Generator}; use hash::keccak; use mio::*; @@ -67,13 +68,13 @@ const SYS_TIMER: TimerToken = LAST_SESSION + 1; // Timeouts // for IDLE TimerToken -const MAINTENANCE_TIMEOUT: u64 = 1000; +const MAINTENANCE_TIMEOUT: Duration = Duration::from_secs(1); // for DISCOVERY_REFRESH TimerToken -const DISCOVERY_REFRESH_TIMEOUT: u64 = 60_000; +const DISCOVERY_REFRESH_TIMEOUT: Duration = Duration::from_secs(60); // for DISCOVERY_ROUND TimerToken -const DISCOVERY_ROUND_TIMEOUT: u64 = 300; +const DISCOVERY_ROUND_TIMEOUT: Duration = Duration::from_millis(300); // for NODE_TABLE TimerToken -const NODE_TABLE_TIMEOUT: u64 = 300_000; +const NODE_TABLE_TIMEOUT: Duration = Duration::from_secs(300); #[derive(Debug, PartialEq, Eq)] /// Protocol info @@ -165,10 +166,10 @@ impl<'s> NetworkContextTrait for NetworkContext<'s> { self.session.as_ref().map_or(false, |s| s.lock().expired()) } - fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), Error> { + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error> { self.io.message(NetworkIoMessage::AddTimer { - token: token, - delay: ms, + token, + delay, protocol: self.protocol, }).unwrap_or_else(|e| warn!("Error sending network IO message: {:?}", e)); Ok(()) diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index f326ff4b1ee..8faf21e465c 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -24,12 +24,13 @@ //! use net::*; //! use devp2p::NetworkService; //! use std::sync::Arc; +//! use std::time::Duration; //! //! struct MyHandler; //! //! impl NetworkProtocolHandler for MyHandler { //! fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { -//! io.register_timer(0, 1000); +//! io.register_timer(0, Duration::from_secs(1)); //! } //! //! fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index 6353a90946f..c1e09a25252 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -34,8 +34,8 @@ use node_table::NodeId; use snappy; // Timeout must be less than (interval - 1). -const PING_TIMEOUT_SEC: Duration = Duration::from_secs(60); -const PING_INTERVAL_SEC: Duration = Duration::from_secs(120); +const PING_TIMEOUT: Duration = Duration::from_secs(60); +const PING_INTERVAL: Duration = Duration::from_secs(120); const MIN_PROTOCOL_VERSION: u32 = 4; const MIN_COMPRESSION_PROTOCOL_VERSION: u32 = 5; @@ -116,7 +116,7 @@ impl Session { protocol_version: 0, capabilities: Vec::new(), peer_capabilities: Vec::new(), - ping_ms: None, + ping: None, originated: originated, remote_address: "Handshake".to_owned(), local_address: local_addr, @@ -298,12 +298,12 @@ impl Session { return true; } let timed_out = if let Some(pong) = self.pong_time { - pong.duration_since(self.ping_time) > PING_TIMEOUT_SEC + pong.duration_since(self.ping_time) > PING_TIMEOUT } else { - self.ping_time.elapsed() > PING_TIMEOUT_SEC + self.ping_time.elapsed() > PING_TIMEOUT }; - if !timed_out && self.ping_time.elapsed() > PING_INTERVAL_SEC { + if !timed_out && self.ping_time.elapsed() > PING_INTERVAL { if let Err(e) = self.send_ping(io) { debug!("Error sending ping message: {:?}", e); } @@ -368,9 +368,7 @@ impl Session { PACKET_PONG => { let time = Instant::now(); self.pong_time = Some(time); - let ping_elapsed = time.duration_since(self.ping_time); - self.info.ping_ms = Some(ping_elapsed.as_secs() * 1_000 + - ping_elapsed.subsec_nanos() as u64 / 1_000_000); + self.info.ping = Some(time.duration_since(self.ping_time)); Ok(SessionData::Continue) }, PACKET_GET_PEERS => Ok(SessionData::None), //TODO; diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index 3aed1b9fc4f..4788e0d442a 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -71,7 +71,7 @@ impl TestProtocol { impl NetworkProtocolHandler for TestProtocol { fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { - io.register_timer(0, 10).unwrap(); + io.register_timer(0, Duration::from_millis(10)).unwrap(); } fn read(&self, _io: &NetworkContext, _peer: &PeerId, packet_id: u8, data: &[u8]) { diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 55c31dd2e64..1a0c88e4caf 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -37,6 +37,7 @@ use std::collections::HashMap; use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr}; use std::str::{self, FromStr}; use std::sync::Arc; +use std::time::Duration; use ipnetwork::{IpNetwork, IpNetworkError}; use io::IoChannel; use ethkey::Secret; @@ -74,8 +75,8 @@ pub enum NetworkIoMessage { protocol: ProtocolId, /// Timer token. token: TimerToken, - /// Timer delay in milliseconds. - delay: u64, + /// Timer delay. + delay: Duration, }, /// Initliaze public interface. InitPublicInterface, @@ -100,8 +101,8 @@ pub struct SessionInfo { pub capabilities: Vec, /// Peer protocol capabilities pub peer_capabilities: Vec, - /// Peer ping delay in milliseconds - pub ping_ms: Option, + /// Peer ping delay + pub ping: Option, /// True if this session was originated by us. pub originated: bool, /// Remote endpoint address of the session @@ -271,7 +272,7 @@ pub trait NetworkContext { fn is_expired(&self) -> bool; /// Register a new IO timer. 'IoHandler::timeout' will be called with the token. - fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), Error>; + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error>; /// Returns peer identification string fn peer_client_version(&self, peer: PeerId) -> String; @@ -315,8 +316,8 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { (**self).is_expired() } - fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), Error> { - (**self).register_timer(token, ms) + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error> { + (**self).register_timer(token, delay) } fn peer_client_version(&self, peer: PeerId) -> String { diff --git a/util/unexpected/src/lib.rs b/util/unexpected/src/lib.rs index e34b2326cf3..4cf8448bd49 100644 --- a/util/unexpected/src/lib.rs +++ b/util/unexpected/src/lib.rs @@ -44,6 +44,18 @@ pub struct OutOfBounds { pub found: T, } +impl OutOfBounds { + pub fn map(self, map: F) -> OutOfBounds + where F: Fn(T) -> U + { + OutOfBounds { + min: self.min.map(&map), + max: self.max.map(&map), + found: map(self.found), + } + } +} + impl fmt::Display for OutOfBounds { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let msg = match (self.min.as_ref(), self.max.as_ref()) { diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index 28f3fee55a2..dd5e345bcde 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -36,7 +36,7 @@ mod tests; // how often periodic relays are. when messages are imported // we directly broadcast. const RALLY_TOKEN: TimerToken = 1; -const RALLY_TIMEOUT_MS: u64 = 2500; +const RALLY_TIMEOUT: Duration = Duration::from_millis(2500); /// Current protocol version. pub const PROTOCOL_VERSION: usize = 6; @@ -685,7 +685,7 @@ impl Network { impl ::network::NetworkProtocolHandler for Network { fn initialize(&self, io: &NetworkContext, host_info: &HostInfo) { // set up broadcast timer (< 1s) - io.register_timer(RALLY_TOKEN, RALLY_TIMEOUT_MS) + io.register_timer(RALLY_TOKEN, RALLY_TIMEOUT) .expect("Failed to initialize message rally timer"); *self.node_key.write() = host_info.id().clone(); From d03dce496cd746eca68579eca2e34d372531647c Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 16 Apr 2018 13:02:23 +0300 Subject: [PATCH 019/147] tokio-core v0.1.16 -> v0.1.17 (#8408) --- Cargo.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 402327b2e20..e78a947eaae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -786,7 +786,7 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -823,7 +823,7 @@ dependencies = [ "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1045,7 +1045,7 @@ dependencies = [ "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1217,7 +1217,7 @@ dependencies = [ "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1233,7 +1233,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-rustls 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1260,7 +1260,7 @@ dependencies = [ "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1390,7 +1390,7 @@ dependencies = [ "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2119,7 +2119,7 @@ name = "parity-reactor" version = "0.1.0" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2215,7 +2215,7 @@ dependencies = [ "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes)", "tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3189,7 +3189,7 @@ dependencies = [ [[package]] name = "tokio-core" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3198,11 +3198,11 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3231,7 +3231,7 @@ dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3247,7 +3247,7 @@ dependencies = [ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3272,7 +3272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3364,7 +3364,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3963,7 +3963,7 @@ dependencies = [ "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" "checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" -"checksum tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "799492ccba3d8ed5e41f2520a7cfd504cb65bbfe5fbbbd0012e335ae5f188051" +"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" "checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a" "checksum tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes)" = "" From bcd4ee9a34291aaf2bb2b54c2a67ad7862ccbbe8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 16 Apr 2018 14:52:12 +0100 Subject: [PATCH 020/147] Replace legacy Rlp with UntrustedRlp and use in ethcore rlp views (#8316) * WIP * Replace Rlp with UntrustedRlp in views, explicity unwrap with expect First pass to get it to compile. Need to figure out whether to do this or to propogate Errors upstream, which would require many more changes to dependent code. If we do this way we are assuming that the views are always used in a context where the rlp is trusted to be valid e.g. when reading from our own DB. So need to fid out whether views are used with data received from an untrusted (e.g. extrernal peer). * Remove original Rlp impl, rename UntrustedRlp -> Rlp * Create rlp views with view! macro to record debug info Views are assumed to be over valid rlp, so if there is a decoding error we record where the view was created in the first place and report it in the expect * Use $crate in view! macro to avoid import, fix tests * Expect valid rlp in decode functions for now * Replace spaces with tabs in new file * Add doc tests for creating views with macro * Update rlp docs to reflect removing of UntrustedRlp * Replace UntrustedRlp usages in private-tx merge --- ethcore/light/src/cht.rs | 4 +- ethcore/light/src/client/header_chain.rs | 6 +- ethcore/light/src/net/mod.rs | 20 +- ethcore/light/src/net/request_credits.rs | 4 +- ethcore/light/src/net/status.rs | 30 +- ethcore/light/src/net/tests/mod.rs | 8 +- ethcore/light/src/on_demand/request.rs | 4 +- ethcore/light/src/types/request/mod.rs | 36 +- ethcore/private-tx/src/lib.rs | 6 +- ethcore/src/block.rs | 14 +- ethcore/src/blockchain/blockchain.rs | 32 +- ethcore/src/blockchain/generator.rs | 2 +- ethcore/src/client/client.rs | 10 +- ethcore/src/client/test_client.rs | 14 +- ethcore/src/encoded.rs | 18 +- ethcore/src/engines/authority_round/mod.rs | 18 +- ethcore/src/engines/basic_authority.rs | 4 +- ethcore/src/engines/epoch.rs | 6 +- ethcore/src/engines/tendermint/message.rs | 18 +- ethcore/src/engines/tendermint/mod.rs | 11 +- .../engines/validator_set/safe_contract.rs | 10 +- ethcore/src/ethereum/ethash.rs | 6 +- ethcore/src/ethereum/mod.rs | 4 +- ethcore/src/header.rs | 6 +- ethcore/src/json_tests/transaction.rs | 4 +- ethcore/src/lib.rs | 4 +- ethcore/src/snapshot/account.rs | 18 +- ethcore/src/snapshot/block.rs | 10 +- ethcore/src/snapshot/consensus/authority.rs | 6 +- ethcore/src/snapshot/consensus/work.rs | 6 +- ethcore/src/snapshot/io.rs | 4 +- ethcore/src/snapshot/mod.rs | 6 +- ethcore/src/spec/spec.rs | 2 +- ethcore/src/test_helpers.rs | 2 +- ethcore/src/tests/client.rs | 12 +- ethcore/src/tests/trace.rs | 4 +- ethcore/src/trace/types/error.rs | 4 +- ethcore/src/trace/types/flat.rs | 4 +- ethcore/src/trace/types/trace.rs | 10 +- ethcore/src/verification/queue/kind.rs | 2 +- ethcore/src/verification/queue/mod.rs | 6 +- ethcore/src/verification/verification.rs | 28 +- ethcore/src/views/block.rs | 59 +- ethcore/src/views/body.rs | 56 +- ethcore/src/views/header.rs | 42 +- ethcore/src/views/mod.rs | 14 + ethcore/src/views/transaction.rs | 35 +- ethcore/src/views/view_rlp.rs | 130 +++++ ethcore/sync/src/block_sync.rs | 12 +- ethcore/sync/src/blocks.rs | 25 +- ethcore/sync/src/chain.rs | 96 ++-- ethcore/sync/src/lib.rs | 1 + ethcore/transaction/src/transaction.rs | 6 +- ethcore/types/src/receipt.rs | 4 +- ethcore/types/src/snapshot_manifest.rs | 4 +- ethcore/vm/src/call_type.rs | 4 +- local-store/src/lib.rs | 4 +- parity/blockchain.rs | 2 +- rpc/src/lib.rs | 1 + rpc/src/v1/impls/eth.rs | 4 +- rpc/src/v1/impls/light/eth.rs | 4 +- rpc/src/v1/impls/private.rs | 6 +- rpc/src/v1/impls/signer.rs | 4 +- rpc/src/v1/impls/traces.rs | 4 +- rpc/src/v1/tests/eth.rs | 2 +- util/journaldb/src/overlaydb.rs | 4 +- util/journaldb/src/overlayrecentdb.rs | 4 +- util/journaldb/src/util.rs | 6 +- util/network-devp2p/src/connection.rs | 4 +- util/network-devp2p/src/discovery.rs | 16 +- util/network-devp2p/src/handshake.rs | 6 +- util/network-devp2p/src/node_table.rs | 4 +- util/network-devp2p/src/session.rs | 8 +- util/network/src/lib.rs | 4 +- util/patricia_trie/src/node.rs | 6 +- util/patricia_trie/src/triedbmut.rs | 4 +- util/rlp/src/impls.rs | 20 +- util/rlp/src/lib.rs | 14 +- util/rlp/src/rlpin.rs | 533 +++++++++++------- util/rlp/src/traits.rs | 4 +- util/rlp/src/untrusted_rlp.rs | 406 ------------- util/rlp/tests/tests.rs | 18 +- util/rlp_compress/src/lib.rs | 8 +- util/rlp_derive/src/de.rs | 4 +- whisper/src/message.rs | 18 +- whisper/src/net/mod.rs | 12 +- 86 files changed, 967 insertions(+), 1078 deletions(-) create mode 100644 ethcore/src/views/view_rlp.rs delete mode 100644 util/rlp/src/untrusted_rlp.rs diff --git a/ethcore/light/src/cht.rs b/ethcore/light/src/cht.rs index 6f5ebf808e8..ffb7841f45a 100644 --- a/ethcore/light/src/cht.rs +++ b/ethcore/light/src/cht.rs @@ -26,7 +26,7 @@ use hashdb::HashDB; use memorydb::MemoryDB; use bytes::Bytes; use trie::{self, TrieMut, TrieDBMut, Trie, TrieDB, Recorder}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; // encode a key. macro_rules! key { @@ -150,7 +150,7 @@ pub fn check_proof(proof: &[Bytes], num: u64, root: H256) -> Option<(H256, U256) let res = match TrieDB::new(&db, &root) { Err(_) => return None, Ok(trie) => trie.get_with(&key!(num), |val: &[u8]| { - let rlp = UntrustedRlp::new(val); + let rlp = Rlp::new(val); rlp.val_at::(0) .and_then(|h| rlp.val_at::(1).map(|td| (h, td))) .ok() diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 84b7916eef8..7bd13a6c098 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -41,7 +41,7 @@ use ethcore::engines::epoch::{ PendingTransition as PendingEpochTransition }; -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; use plain_hasher::H256FastMap; @@ -125,7 +125,7 @@ impl Encodable for Entry { } impl Decodable for Entry { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let mut candidates = SmallVec::<[Candidate; 3]>::new(); for item in rlp.iter() { @@ -186,7 +186,7 @@ fn encode_canonical_transition(header: &Header, proof: &[u8]) -> Vec { // decode last canonical transition entry. fn decode_canonical_transition(t: &[u8]) -> Result<(Header, &[u8]), DecoderError> { - let rlp = UntrustedRlp::new(t); + let rlp = Rlp::new(t); Ok((rlp.val_at(0)?, rlp.at(1)?.data()?)) } diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 8299773230c..d58d90fac45 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -22,7 +22,7 @@ use transaction::UnverifiedTransaction; use io::TimerToken; use network::{HostInfo, NetworkProtocolHandler, NetworkContext, PeerId}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; use kvdb::DBValue; use parking_lot::{Mutex, RwLock}; @@ -528,7 +528,7 @@ impl LightProtocol { // - check whether peer exists // - check whether request was made // - check whether request kinds match - fn pre_verify_response(&self, peer: &PeerId, raw: &UntrustedRlp) -> Result { + fn pre_verify_response(&self, peer: &PeerId, raw: &Rlp) -> Result { let req_id = ReqId(raw.val_at(0)?); let cur_credits: U256 = raw.val_at(1)?; @@ -572,7 +572,7 @@ impl LightProtocol { /// Packet data is _untrusted_, which means that invalid data won't lead to /// issues. pub fn handle_packet(&self, io: &IoContext, peer: &PeerId, packet_id: u8, data: &[u8]) { - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); trace!(target: "pip", "Incoming packet {} from peer {}", packet_id, peer); @@ -794,7 +794,7 @@ impl LightProtocol { impl LightProtocol { // Handle status message from peer. - fn status(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { + fn status(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> { let pending = match self.pending_peers.write().remove(peer) { Some(pending) => pending, None => { @@ -855,7 +855,7 @@ impl LightProtocol { } // Handle an announcement. - fn announcement(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { + fn announcement(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> { if !self.peers.read().contains_key(peer) { debug!(target: "pip", "Ignoring announcement from unknown peer"); return Ok(()) @@ -900,7 +900,7 @@ impl LightProtocol { } // Receive requests from a peer. - fn request(&self, peer_id: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + fn request(&self, peer_id: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> { // the maximum amount of requests we'll fill in a single packet. const MAX_REQUESTS: usize = 256; @@ -968,7 +968,7 @@ impl LightProtocol { } // handle a packet with responses. - fn response(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + fn response(&self, peer: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> { let (req_id, responses) = { let id_guard = self.pre_verify_response(peer, &raw)?; let responses: Vec = raw.list_at(2)?; @@ -987,7 +987,7 @@ impl LightProtocol { } // handle an update of request credits parameters. - fn update_credits(&self, peer_id: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + fn update_credits(&self, peer_id: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> { let peers = self.peers.read(); let peer = peers.get(peer_id).ok_or(Error::UnknownPeer)?; @@ -1022,7 +1022,7 @@ impl LightProtocol { } // handle an acknowledgement of request credits update. - fn acknowledge_update(&self, peer_id: &PeerId, _io: &IoContext, _raw: UntrustedRlp) -> Result<(), Error> { + fn acknowledge_update(&self, peer_id: &PeerId, _io: &IoContext, _raw: Rlp) -> Result<(), Error> { let peers = self.peers.read(); let peer = peers.get(peer_id).ok_or(Error::UnknownPeer)?; let mut peer = peer.lock(); @@ -1041,7 +1041,7 @@ impl LightProtocol { } // Receive a set of transactions to relay. - fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { + fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> { const MAX_TRANSACTIONS: usize = 256; let txs: Vec<_> = data.iter() diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index e1b7455ccca..abe609dabbd 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -29,7 +29,7 @@ use request::{self, Request}; use super::error::Error; -use rlp::{UntrustedRlp, RlpStream, Decodable, Encodable, DecoderError}; +use rlp::{Rlp, RlpStream, Decodable, Encodable, DecoderError}; use ethereum_types::U256; use std::time::{Duration, Instant}; @@ -162,7 +162,7 @@ impl Encodable for CostTable { } impl Decodable for CostTable { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let base = rlp.val_at(0)?; let mut headers = None; diff --git a/ethcore/light/src/net/status.rs b/ethcore/light/src/net/status.rs index 0f811bbe408..c9ee3d760f0 100644 --- a/ethcore/light/src/net/status.rs +++ b/ethcore/light/src/net/status.rs @@ -16,7 +16,7 @@ //! Peer status and capabilities. -use rlp::{DecoderError, Encodable, Decodable, RlpStream, UntrustedRlp}; +use rlp::{DecoderError, Encodable, Decodable, RlpStream, Rlp}; use ethereum_types::{H256, U256}; use super::request_credits::FlowParams; @@ -85,7 +85,7 @@ impl Key { // helper for decoding key-value pairs in the handshake or an announcement. struct Parser<'a> { pos: usize, - rlp: UntrustedRlp<'a>, + rlp: Rlp<'a>, } impl<'a> Parser<'a> { @@ -97,7 +97,7 @@ impl<'a> Parser<'a> { // expect a specific next key, and get the value's RLP. // if the key isn't found, the position isn't advanced. - fn expect_raw(&mut self, key: Key) -> Result, DecoderError> { + fn expect_raw(&mut self, key: Key) -> Result, DecoderError> { trace!(target: "les", "Expecting key {}", key.as_str()); let pre_pos = self.pos; if let Some((k, val)) = self.get_next()? { @@ -109,7 +109,7 @@ impl<'a> Parser<'a> { } // get the next key and value RLP. - fn get_next(&mut self) -> Result)>, DecoderError> { + fn get_next(&mut self) -> Result)>, DecoderError> { while self.pos < self.rlp.item_count()? { let pair = self.rlp.at(self.pos)?; let k: String = pair.val_at(0)?; @@ -208,7 +208,7 @@ impl Capabilities { /// - chain status /// - serving capabilities /// - request credit parameters -pub fn parse_handshake(rlp: UntrustedRlp) -> Result<(Status, Capabilities, Option), DecoderError> { +pub fn parse_handshake(rlp: Rlp) -> Result<(Status, Capabilities, Option), DecoderError> { let mut parser = Parser { pos: 0, rlp: rlp, @@ -304,7 +304,7 @@ pub struct Announcement { } /// Parse an announcement. -pub fn parse_announcement(rlp: UntrustedRlp) -> Result { +pub fn parse_announcement(rlp: Rlp) -> Result { let mut last_key = None; let mut announcement = Announcement { @@ -374,7 +374,7 @@ mod tests { use super::*; use super::super::request_credits::FlowParams; use ethereum_types::{U256, H256}; - use rlp::{RlpStream, UntrustedRlp}; + use rlp::{RlpStream, Rlp}; #[test] fn full_handshake() { @@ -404,7 +404,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, Some(&flow_params)); let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&handshake)).unwrap(); + = parse_handshake(Rlp::new(&handshake)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); @@ -439,7 +439,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, Some(&flow_params)); let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&handshake)).unwrap(); + = parse_handshake(Rlp::new(&handshake)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); @@ -473,7 +473,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, Some(&flow_params)); let interleaved = { - let handshake = UntrustedRlp::new(&handshake); + let handshake = Rlp::new(&handshake); let mut stream = RlpStream::new_list(handshake.item_count().unwrap_or(0) * 3); for item in handshake.iter() { @@ -489,7 +489,7 @@ mod tests { }; let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&interleaved)).unwrap(); + = parse_handshake(Rlp::new(&interleaved)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); @@ -510,7 +510,7 @@ mod tests { }; let serialized = write_announcement(&announcement); - let read = parse_announcement(UntrustedRlp::new(&serialized)).unwrap(); + let read = parse_announcement(Rlp::new(&serialized)).unwrap(); assert_eq!(read, announcement); } @@ -529,7 +529,7 @@ mod tests { .append_raw(&encode_flag(Key::ServeHeaders), 1); let out = stream.drain(); - assert!(parse_announcement(UntrustedRlp::new(&out)).is_err()); + assert!(parse_announcement(Rlp::new(&out)).is_err()); let mut stream = RlpStream::new_list(6); stream @@ -541,7 +541,7 @@ mod tests { .append_raw(&encode_pair(Key::ServeStateSince, &44u64), 1); let out = stream.drain(); - assert!(parse_announcement(UntrustedRlp::new(&out)).is_ok()); + assert!(parse_announcement(Rlp::new(&out)).is_ok()); } #[test] @@ -566,7 +566,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, None); let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&handshake)).unwrap(); + = parse_handshake(Rlp::new(&handshake)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index 397576ae427..3c04c0ffba6 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -31,7 +31,7 @@ use provider::Provider; use request; use request::*; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use ethereum_types::{H256, U256, Address}; use std::sync::Arc; @@ -688,7 +688,7 @@ fn id_guard() { stream.begin_list(2).append(&125usize).append(&3usize); let packet = stream.out(); - assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_err()); + assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_err()); } // next, do an unexpected response. @@ -699,7 +699,7 @@ fn id_guard() { stream.begin_list(0); let packet = stream.out(); - assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_err()); + assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_err()); } // lastly, do a valid (but empty) response. @@ -710,7 +710,7 @@ fn id_guard() { stream.begin_list(0); let packet = stream.out(); - assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_ok()); + assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_ok()); } let peers = proto.peers.read(); diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 8b184cc1d89..18a309ae96b 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -30,7 +30,7 @@ use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY, KECCAK_EMPTY_LIST_RLP, keccak}; use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256, Address}; use parking_lot::Mutex; use hashdb::HashDB; @@ -831,7 +831,7 @@ impl Account { match TrieDB::new(&db, &state_root).and_then(|t| t.get(&keccak(&self.address)))? { Some(val) => { - let rlp = UntrustedRlp::new(&val); + let rlp = Rlp::new(&val); Ok(Some(BasicAccount { nonce: rlp.val_at(0)?, balance: rlp.val_at(1)?, diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index bd68c6a0a20..8d911d3f555 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -16,7 +16,7 @@ //! Light protocol request types. -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::H256; mod batch; @@ -148,7 +148,7 @@ impl From for Field { } impl Decodable for Field { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.val_at::(0)? { 0 => Ok(Field::Scalar(rlp.val_at::(1)?)), 1 => Ok({ @@ -224,7 +224,7 @@ impl From for HashOrNumber { } impl Decodable for HashOrNumber { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.as_val::().map(HashOrNumber::Hash) .or_else(|_| rlp.as_val().map(HashOrNumber::Number)) } @@ -331,7 +331,7 @@ impl Request { } impl Decodable for Request { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.val_at::(0)? { Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)), Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)), @@ -493,7 +493,7 @@ pub enum Kind { } impl Decodable for Kind { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.as_val::()? { 0 => Ok(Kind::Headers), 1 => Ok(Kind::HeaderProof), @@ -578,7 +578,7 @@ impl Response { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.val_at::(0)? { Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)), Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)), @@ -673,7 +673,7 @@ pub trait ResponseLike { pub mod header { use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output}; use ethcore::encoded; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; /// Potentially incomplete headers request. #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] @@ -754,7 +754,7 @@ pub mod header { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use ethcore::header::Header as FullHeader; let mut headers = Vec::new(); @@ -785,7 +785,7 @@ pub mod header { /// Request and response for header proofs. pub mod header_proof { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::{H256, U256}; use bytes::Bytes; @@ -859,7 +859,7 @@ pub mod header_proof { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Response { proof: rlp.list_at(0)?, hash: rlp.val_at(1)?, @@ -1027,7 +1027,7 @@ pub mod block_receipts { pub mod block_body { use super::{Field, NoSuchOutput, OutputKind, Output}; use ethcore::encoded; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::H256; /// Potentially incomplete block body request. @@ -1092,7 +1092,7 @@ pub mod block_body { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use ethcore::header::Header as FullHeader; use transaction::UnverifiedTransaction; @@ -1411,7 +1411,7 @@ pub mod contract_code { pub mod execution { use super::{Field, NoSuchOutput, OutputKind, Output}; use transaction::Action; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::{H256, U256, Address}; use kvdb::DBValue; use bytes::Bytes; @@ -1508,7 +1508,7 @@ pub mod execution { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let mut items = Vec::new(); for raw_item in rlp.iter() { let mut item = DBValue::new(); @@ -1536,7 +1536,7 @@ pub mod execution { /// A request for epoch signal data. pub mod epoch_signal { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::H256; use bytes::Bytes; @@ -1548,7 +1548,7 @@ pub mod epoch_signal { } impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Incomplete { block_hash: rlp.val_at(0)?, }) @@ -1617,7 +1617,7 @@ pub mod epoch_signal { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Response { signal: rlp.as_val()?, @@ -1891,7 +1891,7 @@ mod tests { stream.append(&100usize).append_list(&reqs); let out = stream.out(); - let rlp = UntrustedRlp::new(&out); + let rlp = Rlp::new(&out); assert_eq!(rlp.val_at::(0).unwrap(), 100usize); assert_eq!(rlp.list_at::(1).unwrap(), reqs); } diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index e28dd7c3314..80510938cff 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -238,14 +238,14 @@ impl Provider where { fn extract_original_transaction(&self, private: PrivateTransaction, contract: &Address) -> Result { let encrypted_transaction = private.encrypted; let transaction_bytes = self.decrypt(contract, &encrypted_transaction)?; - let original_transaction: UnverifiedTransaction = UntrustedRlp::new(&transaction_bytes).as_val()?; + let original_transaction: UnverifiedTransaction = Rlp::new(&transaction_bytes).as_val()?; Ok(original_transaction) } /// Process received private transaction pub fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { trace!("Private transaction received"); - let private_tx: PrivateTransaction = UntrustedRlp::new(rlp).as_val()?; + let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?; let contract = private_tx.contract; let contract_validators = self.get_validators(BlockId::Latest, &contract)?; @@ -356,7 +356,7 @@ impl Provider where { /// Add signed private transaction into the store /// Creates corresponding public transaction if last required singature collected and sends it to the chain pub fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { - let tx: SignedPrivateTransaction = UntrustedRlp::new(rlp).as_val()?; + let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?; trace!("Signature for private transaction received: {:?}", tx); let private_hash = tx.private_transaction_hash(); let desc = match self.transactions_for_signing.lock().get(&private_hash) { diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 4cbc0bac9f8..e3622c293df 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -22,7 +22,7 @@ use std::collections::HashSet; use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; use triehash::ordered_trie_root; -use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError, encode_list}; +use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list}; use ethereum_types::{H256, U256, Address, Bloom}; use bytes::Bytes; use unexpected::{Mismatch, OutOfBounds}; @@ -54,7 +54,7 @@ pub struct Block { impl Block { /// Returns true if the given bytes form a valid encoding of a block in RLP. pub fn is_good(b: &[u8]) -> bool { - UntrustedRlp::new(b).as_val::().is_ok() + Rlp::new(b).as_val::().is_ok() } /// Get the RLP-encoding of the block with the seal. @@ -68,7 +68,7 @@ impl Block { } impl Decodable for Block { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.as_raw().len() != rlp.payload_info()?.total() { return Err(DecoderError::RlpIsTooBig); } @@ -622,7 +622,7 @@ pub fn enact_verified( // Remove state root from transaction receipts to make them EIP-98 compatible. strip_receipts: bool, ) -> Result { - let view = BlockView::new(&block.bytes); + let view = view!(BlockView, &block.bytes); enact( block.header, @@ -664,7 +664,7 @@ mod tests { last_hashes: Arc, factories: Factories, ) -> Result { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header(); let transactions: Result, Error> = block .transactions() @@ -715,7 +715,7 @@ mod tests { last_hashes: Arc, factories: Factories, ) -> Result { - let header = BlockView::new(block_bytes).header_view(); + let header = view!(BlockView, block_bytes).header_view(); Ok(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)?.seal(engine, header.seal())?) } @@ -781,7 +781,7 @@ mod tests { let bytes = e.rlp_bytes(); assert_eq!(bytes, orig_bytes); - let uncles = BlockView::new(&bytes).uncles(); + let uncles = view!(BlockView, &bytes).uncles(); assert_eq!(uncles[1].extra_data(), b"uncle2"); let db = e.drain(); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 5dffc9ec371..6ad8bf8111a 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -25,11 +25,11 @@ use heapsize::HeapSizeOf; use ethereum_types::{H256, Bloom, U256}; use parking_lot::{Mutex, RwLock}; use bytes::Bytes; -use rlp::{Rlp, RlpStream}; +use rlp::RlpStream; use rlp_compress::{compress, decompress, blocks_swapper}; use header::*; use transaction::*; -use views::*; +use views::{BlockView, HeaderView}; use log_entry::{LogEntry, LocalizedLogEntry}; use receipt::Receipt; use blooms::{BloomGroup, GroupPosition}; @@ -231,13 +231,7 @@ impl BlockProvider for BlockChain { fn block(&self, hash: &H256) -> Option { let header = self.block_header_data(hash)?; let body = self.block_body(hash)?; - - let mut block = RlpStream::new_list(3); - let body_rlp = body.rlp(); - block.append_raw(header.rlp().as_raw(), 1); - block.append_raw(body_rlp.at(0).as_raw(), 1); - block.append_raw(body_rlp.at(1).as_raw(), 1); - Some(encoded::Block::new(block.out())) + Some(encoded::Block::new_from_header_and_body(&header.view(), &body.view())) } /// Get block header data @@ -499,7 +493,7 @@ impl BlockChain { None => { // best block does not exist // we need to insert genesis into the cache - let block = BlockView::new(genesis); + let block = view!(BlockView, genesis); let header = block.header_view(); let hash = block.hash(); @@ -701,7 +695,7 @@ impl BlockChain { /// Supply a dummy parent total difficulty when the parent block may not be in the chain. /// Returns true if the block is disconnected. pub fn insert_unordered_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, parent_td: Option, is_best: bool, is_ancient: bool) -> bool { - let block = BlockView::new(bytes); + let block = view!(BlockView, bytes); let header = block.header_view(); let hash = header.hash(); @@ -898,7 +892,7 @@ impl BlockChain { /// If the block is already known, does nothing. pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec) -> ImportRoute { // create views onto rlp - let block = BlockView::new(bytes); + let block = view!(BlockView, bytes); let header = block.header_view(); let hash = header.hash(); @@ -1138,7 +1132,7 @@ impl BlockChain { /// This function returns modified block hashes. fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let mut block_hashes = HashMap::new(); - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header_view(); let number = header.number(); @@ -1165,7 +1159,7 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); @@ -1197,7 +1191,7 @@ impl BlockChain { /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap> { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let transaction_hashes = block.transaction_hashes(); match info.location { @@ -1265,7 +1259,7 @@ impl BlockChain { /// to bloom location in database (BlocksBloomLocation). /// fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header_view(); let log_blooms = match info.location { @@ -1384,9 +1378,9 @@ impl BlockChain { /// Create a block body from a block. pub fn block_to_body(block: &[u8]) -> Bytes { let mut body = RlpStream::new_list(2); - let block_rlp = Rlp::new(block); - body.append_raw(block_rlp.at(1).as_raw(), 1); - body.append_raw(block_rlp.at(2).as_raw(), 1); + let block_view = view!(BlockView, block); + body.append_raw(block_view.transactions_rlp().as_raw(), 1); + body.append_raw(block_view.uncles_rlp().as_raw(), 1); body.out() } diff --git a/ethcore/src/blockchain/generator.rs b/ethcore/src/blockchain/generator.rs index 5f990a4d980..e767f2211c3 100644 --- a/ethcore/src/blockchain/generator.rs +++ b/ethcore/src/blockchain/generator.rs @@ -41,7 +41,7 @@ impl Block { #[inline] pub fn hash(&self) -> H256 { - BlockView::new(&self.encoded()).header_view().hash() + view!(BlockView, &self.encoded()).header_view().hash() } #[inline] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index fb3f07e41e1..d2b63b6cdb5 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -62,7 +62,7 @@ use ethcore_miner::pool::VerifiedTransaction; use parking_lot::{Mutex, RwLock}; use rand::OsRng; use receipt::{Receipt, LocalizedReceipt}; -use rlp::UntrustedRlp; +use rlp::Rlp; use snapshot::{self, io as snapshot_io}; use spec::Spec; use state_db::StateDB; @@ -446,7 +446,7 @@ impl Importer { /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. fn import_old_block(&self, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { - let block = BlockView::new(&block_bytes); + let block = view!(BlockView, &block_bytes); let header = block.header(); let receipts = ::rlp::decode_list(&receipts_bytes); let hash = header.hash(); @@ -514,7 +514,7 @@ impl Importer { let receipts = block.receipts().to_owned(); let traces = block.traces().clone().drain(); - assert_eq!(header.hash(), BlockView::new(block_data).header_view().hash()); + assert_eq!(header.hash(), view!(BlockView, block_data).header_view().hash()); //let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new)); @@ -988,7 +988,7 @@ impl Client { let txs: Vec = transactions .iter() - .filter_map(|bytes| UntrustedRlp::new(bytes).as_val().ok()) + .filter_map(|bytes| Rlp::new(bytes).as_val().ok()) .collect(); self.notify(|notify| { @@ -1423,7 +1423,7 @@ impl ImportBlock for Client { fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { { // check block order - let header = BlockView::new(&block_bytes).header_view(); + let header = view!(BlockView, &block_bytes).header_view(); if self.chain.read().is_known(&header.hash()) { return Err(BlockImportError::Import(ImportError::AlreadyInChain)); } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 02067afd002..c2e06009b64 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -29,7 +29,7 @@ use journaldb; use kvdb::DBValue; use kvdb_memorydb; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use ethkey::{Generator, Random}; use ethcore_miner::pool::VerifiedTransaction; use transaction::{self, Transaction, LocalizedTransaction, SignedTransaction, Action}; @@ -471,7 +471,7 @@ impl ChainInfo for TestBlockChainClient { impl BlockInfo for TestBlockChainClient { fn block_header(&self, id: BlockId) -> Option { self.block_hash(id) - .and_then(|hash| self.blocks.read().get(&hash).map(|r| BlockView::new(r).header_rlp().as_raw().to_vec())) + .and_then(|hash| self.blocks.read().get(&hash).map(|r| view!(BlockView, r).header_rlp().as_raw().to_vec())) .map(encoded::Header::new) } @@ -513,7 +513,7 @@ impl RegistryInfo for TestBlockChainClient { impl ImportBlock for TestBlockChainClient { fn import_block(&self, b: Bytes) -> Result { - let header = BlockView::new(&b).header(); + let header = view!(BlockView, &b).header(); let h = header.hash(); let number: usize = header.number() as usize; if number > self.blocks.read().len() { @@ -522,7 +522,7 @@ impl ImportBlock for TestBlockChainClient { if number > 0 { match self.blocks.read().get(header.parent_hash()) { Some(parent) => { - let parent = BlockView::new(parent).header(); + let parent = view!(BlockView, parent).header(); if parent.number() != (header.number() - 1) { panic!("Unexpected block parent"); } @@ -547,7 +547,7 @@ impl ImportBlock for TestBlockChainClient { while n > 0 && self.numbers.read()[&n] != parent_hash { *self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone(); n -= 1; - parent_hash = BlockView::new(&self.blocks.read()[&parent_hash]).header().parent_hash().clone(); + parent_hash = view!(BlockView, &self.blocks.read()[&parent_hash]).header().parent_hash().clone(); } } } @@ -692,7 +692,7 @@ impl BlockChainClient for TestBlockChainClient { fn block_body(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| { - let block = BlockView::new(r); + let block = view!(BlockView, r); let mut stream = RlpStream::new_list(2); stream.append_raw(block.transactions_rlp().as_raw(), 1); stream.append_raw(block.uncles_rlp().as_raw(), 1); @@ -811,7 +811,7 @@ impl BlockChainClient for TestBlockChainClient { fn queue_transactions(&self, transactions: Vec, _peer_id: usize) { // import right here - let txs = transactions.into_iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect(); + let txs = transactions.into_iter().filter_map(|bytes| Rlp::new(&bytes).as_val().ok()).collect(); self.miner.import_external_transactions(self, txs); } diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 5d3d3160631..1f627666a90 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -26,12 +26,12 @@ use block::Block as FullBlock; use header::{BlockNumber, Header as FullHeader}; use transaction::UnverifiedTransaction; -use views; use hash::keccak; use heapsize::HeapSizeOf; use ethereum_types::{H256, Bloom, U256, Address}; use rlp::{Rlp, RlpStream}; +use views::{self, BlockView, HeaderView, BodyView}; /// Owning header view. #[derive(Debug, Clone, PartialEq, Eq)] @@ -52,7 +52,7 @@ impl Header { /// Get a borrowed header view onto the data. #[inline] - pub fn view(&self) -> views::HeaderView { views::HeaderView::new(&self.0) } + pub fn view(&self) -> HeaderView { view!(HeaderView, &self.0) } /// Get the rlp of the header. #[inline] @@ -125,7 +125,7 @@ impl Body { /// Get a borrowed view of the data within. #[inline] - pub fn view(&self) -> views::BodyView { views::BodyView::new(&self.0) } + pub fn view(&self) -> BodyView { view!(BodyView, &self.0) } /// Fully decode this block body. pub fn decode(&self) -> (Vec, Vec) { @@ -145,7 +145,7 @@ impl Body { // forwarders to borrowed view. impl Body { /// Get raw rlp of transactions - pub fn transactions_rlp(&self) -> Rlp { self.view().transactions_rlp() } + pub fn transactions_rlp(&self) -> Rlp { self.view().transactions_rlp().rlp } /// Get a vector of all transactions. pub fn transactions(&self) -> Vec { self.view().transactions() } @@ -160,7 +160,7 @@ impl Body { pub fn transaction_hashes(&self) -> Vec { self.view().transaction_hashes() } /// Get raw rlp of uncle headers - pub fn uncles_rlp(&self) -> Rlp { self.view().uncles_rlp() } + pub fn uncles_rlp(&self) -> Rlp { self.view().uncles_rlp().rlp } /// Decode uncle headers. pub fn uncles(&self) -> Vec { self.view().uncles() } @@ -198,20 +198,20 @@ impl Block { /// Get a borrowed view of the whole block. #[inline] - pub fn view(&self) -> views::BlockView { views::BlockView::new(&self.0) } + pub fn view(&self) -> BlockView { view!(BlockView, &self.0) } /// Get a borrowed view of the block header. #[inline] - pub fn header_view(&self) -> views::HeaderView { self.view().header_view() } + pub fn header_view(&self) -> HeaderView { self.view().header_view() } /// Decode to a full block. pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0) } /// Decode the header. - pub fn decode_header(&self) -> FullHeader { self.rlp().val_at(0) } + pub fn decode_header(&self) -> FullHeader { self.view().rlp().val_at(0) } /// Clone the encoded header. - pub fn header(&self) -> Header { Header(self.rlp().at(0).as_raw().to_vec()) } + pub fn header(&self) -> Header { Header(self.view().rlp().at(0).as_raw().to_vec()) } /// Get the rlp of this block. #[inline] diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index b8b9ab8b308..013445ba35f 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -41,7 +41,7 @@ use self::finality::RollingFinality; use ethkey::{self, Signature}; use io::{IoContext, IoHandler, TimerToken, IoService}; use itertools::{self, Itertools}; -use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; +use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, Rlp}; use ethereum_types::{H256, H520, Address, U128, U256}; use parking_lot::{Mutex, RwLock}; use unexpected::{Mismatch, OutOfBounds}; @@ -325,7 +325,7 @@ impl Encodable for EmptyStep { } impl Decodable for EmptyStep { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let signature = rlp.val_at(0)?; let empty_step_rlp = rlp.at(1)?; @@ -366,7 +366,7 @@ impl Encodable for SealedEmptyStep { } impl Decodable for SealedEmptyStep { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let signature = rlp.val_at(0)?; let step = rlp.val_at(1)?; @@ -415,7 +415,7 @@ impl super::EpochVerifier for EpochVerifier { let mut finality_checker = RollingFinality::blank(self.subchain_validators.clone().into_inner()); let mut finalized = Vec::new(); - let headers: Vec

= UntrustedRlp::new(proof).as_list().ok()?; + let headers: Vec
= Rlp::new(proof).as_list().ok()?; { let mut push_header = |parent_header: &Header, header: Option<&Header>| { @@ -479,13 +479,13 @@ fn header_expected_seal_fields(header: &Header, empty_steps_transition: u64) -> fn header_step(header: &Header, empty_steps_transition: u64) -> Result { let expected_seal_fields = header_expected_seal_fields(header, empty_steps_transition); - UntrustedRlp::new(&header.seal().get(0).expect( + Rlp::new(&header.seal().get(0).expect( &format!("was either checked with verify_block_basic or is genesis; has {} fields; qed (Make sure the spec file has a correct genesis seal)", expected_seal_fields))).as_val() } fn header_signature(header: &Header, empty_steps_transition: u64) -> Result { let expected_seal_fields = header_expected_seal_fields(header, empty_steps_transition); - UntrustedRlp::new(&header.seal().get(1).expect( + Rlp::new(&header.seal().get(1).expect( &format!("was checked with verify_block_basic; has {} fields; qed", expected_seal_fields))).as_val::().map(Into::into) } @@ -498,7 +498,7 @@ fn header_empty_steps_raw(header: &Header) -> &[u8] { // extracts the empty steps from the header seal. should only be called when there are 3 fields in the seal // (i.e. header.number() >= self.empty_steps_transition). fn header_empty_steps(header: &Header) -> Result, ::rlp::DecoderError> { - let empty_steps = UntrustedRlp::new(header_empty_steps_raw(header)).as_list::()?; + let empty_steps = Rlp::new(header_empty_steps_raw(header)).as_list::()?; Ok(empty_steps.into_iter().map(|s| EmptyStep::from_sealed(s, header.parent_hash())).collect()) } @@ -575,7 +575,7 @@ fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof: } fn destructure_proofs(combined: &[u8]) -> Result<(BlockNumber, &[u8], &[u8]), Error> { - let rlp = UntrustedRlp::new(combined); + let rlp = Rlp::new(combined); Ok(( rlp.at(0)?.as_val()?, rlp.at(1)?.data()?, @@ -801,7 +801,7 @@ impl Engine for AuthorityRound { EngineError::MalformedMessage(format!("{:?}", x)) } - let rlp = UntrustedRlp::new(rlp); + let rlp = Rlp::new(rlp); let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;; if empty_step.verify(&*self.validators).unwrap_or(false) { diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 768cde3d5ee..bbefddccb74 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -57,10 +57,10 @@ impl super::EpochVerifier for EpochVerifier { } fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Error> { - use rlp::UntrustedRlp; + use rlp::Rlp; // Check if the signature belongs to a validator, can depend on parent state. - let sig = UntrustedRlp::new(&header.seal()[0]).as_val::()?; + let sig = Rlp::new(&header.seal()[0]).as_val::()?; let signer = ethkey::public_to_address(ðkey::recover(&sig.into(), &header.bare_hash())?); if *header.author() != signer { diff --git a/ethcore/src/engines/epoch.rs b/ethcore/src/engines/epoch.rs index dffc822cbf8..6975e8898b1 100644 --- a/ethcore/src/engines/epoch.rs +++ b/ethcore/src/engines/epoch.rs @@ -18,7 +18,7 @@ use ethereum_types::H256; -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; /// A full epoch transition. #[derive(Debug, Clone)] @@ -41,7 +41,7 @@ impl Encodable for Transition { } impl Decodable for Transition { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Transition { block_hash: rlp.val_at(0)?, block_number: rlp.val_at(1)?, @@ -64,7 +64,7 @@ impl Encodable for PendingTransition { } impl Decodable for PendingTransition { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(PendingTransition { proof: rlp.as_val()?, }) diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index eac08df9bc6..17b79a80b8c 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -23,7 +23,7 @@ use bytes::Bytes; use super::{Height, View, BlockHash, Step}; use error::Error; use header::Header; -use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; +use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError}; use ethkey::{recover, public_to_address}; use super::super::vote_collector::Message; @@ -61,12 +61,12 @@ impl VoteStep { /// Header consensus view. pub fn consensus_view(header: &Header) -> Result { let view_rlp = header.seal().get(0).expect("seal passed basic verification; seal has 3 fields; qed"); - UntrustedRlp::new(view_rlp.as_slice()).as_val() + Rlp::new(view_rlp.as_slice()).as_val() } /// Proposal signature. pub fn proposal_signature(header: &Header) -> Result { - UntrustedRlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val() + Rlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val() } impl Message for ConsensusMessage { @@ -100,7 +100,7 @@ impl ConsensusMessage { pub fn verify(&self) -> Result { let full_rlp = ::rlp::encode(self); - let block_info = UntrustedRlp::new(&full_rlp).at(1)?; + let block_info = Rlp::new(&full_rlp).at(1)?; let public_key = recover(&self.signature.into(), &keccak(block_info.as_raw()))?; Ok(public_to_address(&public_key)) } @@ -142,7 +142,7 @@ impl Step { } impl Decodable for Step { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.as_val()? { 0u8 => Ok(Step::Propose), 1 => Ok(Step::Prevote), @@ -160,7 +160,7 @@ impl Encodable for Step { /// (signature, (height, view, step, block_hash)) impl Decodable for ConsensusMessage { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let m = rlp.at(1)?; let block_message: H256 = m.val_at(3)?; Ok(ConsensusMessage { @@ -234,7 +234,7 @@ mod tests { }; let raw_rlp = ::rlp::encode(&message).into_vec(); let rlp = Rlp::new(&raw_rlp); - assert_eq!(message, rlp.as_val()); + assert_eq!(Ok(message), rlp.as_val()); let message = ConsensusMessage { signature: H520::default(), @@ -247,7 +247,7 @@ mod tests { }; let raw_rlp = ::rlp::encode(&message); let rlp = Rlp::new(&raw_rlp); - assert_eq!(message, rlp.as_val()); + assert_eq!(Ok(message), rlp.as_val()); } #[test] @@ -260,7 +260,7 @@ mod tests { let raw_rlp = message_full_rlp(&tap.sign(addr, None, keccak(&mi)).unwrap().into(), &mi); - let rlp = UntrustedRlp::new(&raw_rlp); + let rlp = Rlp::new(&raw_rlp); let message: ConsensusMessage = rlp.as_val().unwrap(); match message.verify() { Ok(a) if a == addr => {}, _ => panic!(), }; } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 14d1ebd5852..5021ef9865a 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -36,7 +36,7 @@ use client::EngineClient; use bytes::Bytes; use error::{Error, BlockError}; use header::{Header, BlockNumber}; -use rlp::UntrustedRlp; +use rlp::Rlp; use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; use block::*; @@ -118,7 +118,7 @@ impl super::EpochVerifier for EpochVerifier let mut addresses = HashSet::new(); let ref header_signatures_field = header.seal().get(2).ok_or(BlockError::InvalidSeal)?; - for rlp in UntrustedRlp::new(header_signatures_field).iter() { + for rlp in Rlp::new(header_signatures_field).iter() { let signature: H520 = rlp.as_val()?; let address = (self.recover)(&signature.into(), &message)?; @@ -154,7 +154,7 @@ fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof: } fn destructure_proofs(combined: &[u8]) -> Result<(BlockNumber, &[u8], &[u8]), Error> { - let rlp = UntrustedRlp::new(combined); + let rlp = Rlp::new(combined); Ok(( rlp.at(0)?.as_val()?, rlp.at(1)?.data()?, @@ -503,7 +503,8 @@ impl Engine for Tendermint { fn fmt_err(x: T) -> EngineError { EngineError::MalformedMessage(format!("{:?}", x)) } - let rlp = UntrustedRlp::new(rlp); + + let rlp = Rlp::new(rlp); let message: ConsensusMessage = rlp.as_val().map_err(fmt_err)?; if !self.votes.is_old_or_known(&message) { let msg_hash = keccak(rlp.at(1).map_err(fmt_err)?.as_raw()); @@ -595,7 +596,7 @@ impl Engine for Tendermint { let precommit_hash = message_hash(vote_step.clone(), header.bare_hash()); let ref signatures_field = header.seal().get(2).expect("block went through verify_block_basic; block has .seal_fields() fields; qed"); let mut origins = HashSet::new(); - for rlp in UntrustedRlp::new(signatures_field).iter() { + for rlp in Rlp::new(signatures_field).iter() { let precommit = ConsensusMessage { signature: rlp.as_val()?, block_hash: Some(header.bare_hash()), diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 5c73cb28d14..f132a0bf9d1 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -25,7 +25,7 @@ use parking_lot::RwLock; use bytes::Bytes; use memory_cache::MemoryLruCache; use unexpected::Mismatch; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use kvdb::DBValue; use client::EngineClient; @@ -63,7 +63,7 @@ impl ::engines::StateDependentProof for StateProof { } fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> { - let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof)) + let (header, state_items) = decode_first_proof(&Rlp::new(proof)) .map_err(|e| format!("proof incorrectly encoded: {}", e))?; if &header != &self.header { return Err("wrong header in proof".into()); @@ -145,7 +145,7 @@ fn check_first_proof(machine: &EthereumMachine, provider: &validator_set::Valida }).map_err(|err| err.to_string()) } -fn decode_first_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec), ::error::Error> { +fn decode_first_proof(rlp: &Rlp) -> Result<(Header, Vec), ::error::Error> { let header = rlp.val_at(0)?; let state_items = rlp.at(1)?.iter().map(|x| { let mut val = DBValue::new(); @@ -165,7 +165,7 @@ fn encode_proof(header: &Header, receipts: &[Receipt]) -> Bytes { stream.drain().into_vec() } -fn decode_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec), ::error::Error> { +fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec), ::error::Error> { Ok((rlp.val_at(0)?, rlp.list_at(1)?)) } @@ -357,7 +357,7 @@ impl ValidatorSet for ValidatorSafeContract { fn epoch_set(&self, first: bool, machine: &EthereumMachine, _number: ::header::BlockNumber, proof: &[u8]) -> Result<(SimpleList, Option), ::error::Error> { - let rlp = UntrustedRlp::new(proof); + let rlp = Rlp::new(proof); if first { trace!(target: "engine", "Recovering initial epoch set"); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 41ab777d4a7..7d43395286f 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::UntrustedRlp; +use rlp::Rlp; use machine::EthereumMachine; /// Number of blocks in an ethash snapshot. @@ -59,8 +59,8 @@ impl Seal { ).into()); } - let mix_hash = UntrustedRlp::new(seal[0].as_ref()).as_val::()?; - let nonce = UntrustedRlp::new(seal[1].as_ref()).as_val::()?; + let mix_hash = Rlp::new(seal[0].as_ref()).as_val::()?; + let nonce = Rlp::new(seal[1].as_ref()).as_val::()?; let seal = Seal { mix_hash, nonce, diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 71cf2e86af0..5cf64626868 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -174,7 +174,7 @@ mod tests { assert_eq!(morden.state_root(), "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".into()); let genesis = morden.genesis_block(); - assert_eq!(BlockView::new(&genesis).header_view().hash(), "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303".into()); + assert_eq!(view!(BlockView, &genesis).header_view().hash(), "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303".into()); let _ = morden.engine; } @@ -185,7 +185,7 @@ mod tests { assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into()); let genesis = frontier.genesis_block(); - assert_eq!(BlockView::new(&genesis).header_view().hash(), "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3".into()); + assert_eq!(view!(BlockView, &genesis).header_view().hash(), "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3".into()); let _ = frontier.engine; } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 50529c72011..a31aa029b31 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -21,7 +21,7 @@ use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak}; use heapsize::HeapSizeOf; use ethereum_types::{H256, U256, Address, Bloom}; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable}; +use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable}; pub use types::BlockNumber; @@ -177,7 +177,7 @@ impl Header { /// Get the seal field with RLP-decoded values as bytes. pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(&'a self) -> Result { self.seal.iter().map(|rlp| { - UntrustedRlp::new(rlp).data() + Rlp::new(rlp).data() }).collect() } @@ -327,7 +327,7 @@ fn change_field(hash: &mut Option, field: &mut T, value: T) where T: Pa impl Decodable for Header { - fn decode(r: &UntrustedRlp) -> Result { + fn decode(r: &Rlp) -> Result { let mut blockheader = Header { parent_hash: r.val_at(0)?, uncles_hash: r.val_at(1)?, diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index b7445c51ad3..1be4900b126 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -17,7 +17,7 @@ use super::test_common::*; use evm; use ethjson; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::{Action, UnverifiedTransaction, SignedTransaction}; fn do_json_test(json_data: &[u8]) -> Vec { @@ -40,7 +40,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { let allow_unsigned = number.map_or(false, |n| n >= 3_000_000); let rlp: Vec = test.rlp.into(); - let res = UntrustedRlp::new(&rlp) + let res = Rlp::new(&rlp) .as_val() .map_err(::error::Error::from) .and_then(|t: UnverifiedTransaction| { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 1b0a1e35461..65be24dec0c 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -127,6 +127,9 @@ extern crate evm; pub extern crate ethstore; +#[macro_use] +pub mod views; + #[cfg(test)] extern crate kvdb_rocksdb; @@ -152,7 +155,6 @@ pub mod state_db; pub mod test_helpers; pub mod trace; pub mod verification; -pub mod views; mod cache_manager; mod blooms; diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 222875b842f..6c9e0f3d6e8 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -25,7 +25,7 @@ use ethereum_types::{H256, U256}; use hashdb::HashDB; use bytes::Bytes; use trie::{TrieDB, Trie}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use std::collections::HashSet; @@ -148,7 +148,7 @@ pub fn to_fat_rlps(account_hash: &H256, acc: &BasicAccount, acct_db: &AccountDB, // if it exists. pub fn from_fat_rlp( acct_db: &mut AccountDBMut, - rlp: UntrustedRlp, + rlp: Rlp, mut storage_root: H256, ) -> Result<(BasicAccount, Option), Error> { use trie::{TrieDBMut, TrieMut}; @@ -217,7 +217,7 @@ mod tests { use ethereum_types::{H256, Address}; use hashdb::HashDB; use kvdb::DBValue; - use rlp::UntrustedRlp; + use rlp::Rlp; use std::collections::HashSet; @@ -239,7 +239,7 @@ mod tests { assert_eq!(::rlp::decode::(&thin_rlp), account); let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); - let fat_rlp = UntrustedRlp::new(&fat_rlps[0]).at(1).unwrap(); + let fat_rlp = Rlp::new(&fat_rlps[0]).at(1).unwrap(); assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account); } @@ -264,7 +264,7 @@ mod tests { assert_eq!(::rlp::decode::(&thin_rlp), account); let fat_rlp = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); - let fat_rlp = UntrustedRlp::new(&fat_rlp[0]).at(1).unwrap(); + let fat_rlp = Rlp::new(&fat_rlp[0]).at(1).unwrap(); assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account); } @@ -292,7 +292,7 @@ mod tests { let mut root = KECCAK_NULL_RLP; let mut restored_account = None; for rlp in fat_rlps { - let fat_rlp = UntrustedRlp::new(&rlp).at(1).unwrap(); + let fat_rlp = Rlp::new(&rlp).at(1).unwrap(); restored_account = Some(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, root).unwrap().0); root = restored_account.as_ref().unwrap().storage_root.clone(); } @@ -336,8 +336,8 @@ mod tests { let fat_rlp2 = to_fat_rlps(&keccak(&addr2), &account2, &AccountDB::new(db.as_hashdb(), &addr2), &mut used_code, usize::max_value(), usize::max_value()).unwrap(); assert_eq!(used_code.len(), 1); - let fat_rlp1 = UntrustedRlp::new(&fat_rlp1[0]).at(1).unwrap(); - let fat_rlp2 = UntrustedRlp::new(&fat_rlp2[0]).at(1).unwrap(); + let fat_rlp1 = Rlp::new(&fat_rlp1[0]).at(1).unwrap(); + let fat_rlp2 = Rlp::new(&fat_rlp2[0]).at(1).unwrap(); let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2, H256::zero()).unwrap(); assert!(maybe_code.is_none()); @@ -351,6 +351,6 @@ mod tests { #[test] fn encoding_empty_acc() { let mut db = get_temp_state_db(); - assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None)); + assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), Rlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None)); } } diff --git a/ethcore/src/snapshot/block.rs b/ethcore/src/snapshot/block.rs index aa946fd703d..a47c504d8f5 100644 --- a/ethcore/src/snapshot/block.rs +++ b/ethcore/src/snapshot/block.rs @@ -21,7 +21,7 @@ use header::Header; use hash::keccak; use views::BlockView; -use rlp::{DecoderError, RlpStream, UntrustedRlp}; +use rlp::{DecoderError, RlpStream, Rlp}; use ethereum_types::H256; use bytes::Bytes; use triehash::ordered_trie_root; @@ -89,7 +89,7 @@ impl AbridgedBlock { /// /// Will fail if contains invalid rlp. pub fn to_block(&self, parent_hash: H256, number: u64, receipts_root: H256) -> Result { - let rlp = UntrustedRlp::new(&self.rlp); + let rlp = Rlp::new(&self.rlp); let mut header: Header = Default::default(); header.set_parent_hash(parent_hash); @@ -151,7 +151,7 @@ mod tests { let receipts_root = b.header.receipts_root().clone(); let encoded = encode_block(&b); - let abridged = AbridgedBlock::from_block_view(&BlockView::new(&encoded)); + let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded)); assert_eq!(abridged.to_block(H256::new(), 0, receipts_root).unwrap(), b); } @@ -162,7 +162,7 @@ mod tests { let receipts_root = b.header.receipts_root().clone(); let encoded = encode_block(&b); - let abridged = AbridgedBlock::from_block_view(&BlockView::new(&encoded)); + let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded)); assert_eq!(abridged.to_block(H256::new(), 2, receipts_root).unwrap(), b); } @@ -198,7 +198,7 @@ mod tests { let encoded = encode_block(&b); - let abridged = AbridgedBlock::from_block_view(&BlockView::new(&encoded[..])); + let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded[..])); assert_eq!(abridged.to_block(H256::new(), 0, receipts_root).unwrap(), b); } } diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index d3184a08101..474f5d350c1 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -33,7 +33,7 @@ use receipt::Receipt; use snapshot::{Error, ManifestData}; use itertools::{Position, Itertools}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; use kvdb::KeyValueDB; use bytes::Bytes; @@ -182,7 +182,7 @@ impl ChunkRebuilder { fn verify_transition( &mut self, last_verifier: &mut Option>>, - transition_rlp: UntrustedRlp, + transition_rlp: Rlp, engine: &EthEngine, ) -> Result { use engines::ConstructedVerifier; @@ -242,7 +242,7 @@ impl Rebuilder for ChunkRebuilder { engine: &EthEngine, abort_flag: &AtomicBool, ) -> Result<(), ::error::Error> { - let rlp = UntrustedRlp::new(chunk); + let rlp = Rlp::new(chunk); let is_last_chunk: bool = rlp.val_at(0)?; let num_items = rlp.item_count()?; diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index 7f90e327c06..5414ed59634 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -33,7 +33,7 @@ use snapshot::block::AbridgedBlock; use ethereum_types::H256; use kvdb::KeyValueDB; use bytes::Bytes; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use rand::OsRng; /// Snapshot creation and restoration for PoW chains. @@ -225,7 +225,7 @@ impl Rebuilder for PowRebuilder { use ethereum_types::U256; use triehash::ordered_trie_root; - let rlp = UntrustedRlp::new(chunk); + let rlp = Rlp::new(chunk); let item_count = rlp.item_count()?; let num_blocks = (item_count - 3) as u64; @@ -284,7 +284,7 @@ impl Rebuilder for PowRebuilder { self.db.write_buffered(batch); self.chain.commit(); - parent_hash = BlockView::new(&block_bytes).hash(); + parent_hash = view!(BlockView, &block_bytes).hash(); cur_number += 1; } diff --git a/ethcore/src/snapshot/io.rs b/ethcore/src/snapshot/io.rs index 7e38177ea52..84faa19b485 100644 --- a/ethcore/src/snapshot/io.rs +++ b/ethcore/src/snapshot/io.rs @@ -27,7 +27,7 @@ use std::path::{Path, PathBuf}; use bytes::Bytes; use ethereum_types::H256; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use super::ManifestData; @@ -238,7 +238,7 @@ impl PackedReader { file.seek(SeekFrom::Start(manifest_off))?; file.read_exact(&mut manifest_buf)?; - let rlp = UntrustedRlp::new(&manifest_buf); + let rlp = Rlp::new(&manifest_buf); let (start, version) = if rlp.item_count()? == 5 { (0, 1) diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 6b751bf2c48..fbf0c5ca5ec 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -39,7 +39,7 @@ use parking_lot::Mutex; use journaldb::{self, Algorithm, JournalDB}; use kvdb::KeyValueDB; use trie::{TrieDB, TrieDBMut, Trie, TrieMut}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use bloom_journal::Bloom; use self::io::SnapshotWriter; @@ -327,7 +327,7 @@ impl StateRebuilder { /// Feed an uncompressed state chunk into the rebuilder. pub fn feed(&mut self, chunk: &[u8], flag: &AtomicBool) -> Result<(), ::error::Error> { - let rlp = UntrustedRlp::new(chunk); + let rlp = Rlp::new(chunk); let empty_rlp = StateAccount::new_basic(U256::zero(), U256::zero()).rlp(); let mut pairs = Vec::with_capacity(rlp.item_count()?); @@ -415,7 +415,7 @@ struct RebuiltStatus { // returns a status detailing newly-loaded code and accounts missing code. fn rebuild_accounts( db: &mut HashDB, - account_fat_rlps: UntrustedRlp, + account_fat_rlps: Rlp, out_chunk: &mut [(H256, Bytes)], known_code: &HashMap, known_storage_roots: &mut HashMap, diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index ec1b5edf3da..c1fda86672a 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -913,7 +913,7 @@ mod tests { ); let genesis = test_spec.genesis_block(); assert_eq!( - BlockView::new(&genesis).header_view().hash(), + view!(BlockView, &genesis).header_view().hash(), "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303".into() ); } diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 692f029c86f..32b8beab830 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -171,7 +171,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun panic!("error importing block which is valid by definition: {:?}", e); } - last_header = BlockView::new(&b.rlp_bytes()).header(); + last_header = view!(BlockView, &b.rlp_bytes()).header(); db = b.drain(); } client.flush_queue(); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index fc5f84bfaed..0b8200e938a 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -141,7 +141,7 @@ fn query_bad_block() { fn returns_chain_info() { let dummy_block = get_good_dummy_block(); let client = get_test_client_with_blocks(vec![dummy_block.clone()]); - let block = BlockView::new(&dummy_block); + let block = view!(BlockView, &dummy_block); let info = client.chain_info(); assert_eq!(info.best_block_hash, block.header().hash()); } @@ -178,12 +178,12 @@ fn returns_logs_with_limit() { fn returns_block_body() { let dummy_block = get_good_dummy_block(); let client = get_test_client_with_blocks(vec![dummy_block.clone()]); - let block = BlockView::new(&dummy_block); + let block = view!(BlockView, &dummy_block); let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap(); let body = body.rlp(); - assert_eq!(body.item_count(), 2); - assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]); - assert_eq!(body.at(1).as_raw()[..], block.rlp().at(2).as_raw()[..]); + assert_eq!(body.item_count().unwrap(), 2); + assert_eq!(body.at(0).unwrap().as_raw()[..], block.rlp().at(1).as_raw()[..]); + assert_eq!(body.at(1).unwrap().as_raw()[..], block.rlp().at(2).as_raw()[..]); } #[test] @@ -259,7 +259,7 @@ fn can_mine() { let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).close(); - assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().hash()); + assert_eq!(*b.block().header().parent_hash(), view!(BlockView, &dummy_blocks[0]).header_view().hash()); } #[test] diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 1626e828ccd..72d0d473716 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -97,7 +97,7 @@ fn can_trace_block_and_uncle_reward() { panic!("error importing block which is valid by definition: {:?}", e); } - last_header = BlockView::new(&root_block.rlp_bytes()).header(); + last_header = view!(BlockView, &root_block.rlp_bytes()).header(); let root_header = last_header.clone(); db = root_block.drain(); @@ -125,7 +125,7 @@ fn can_trace_block_and_uncle_reward() { panic!("error importing block which is valid by definition: {:?}", e); } - last_header = BlockView::new(&parent_block.rlp_bytes()).header(); + last_header = view!(BlockView,&parent_block.rlp_bytes()).header(); db = parent_block.drain(); last_hashes.push(last_header.hash()); diff --git a/ethcore/src/trace/types/error.rs b/ethcore/src/trace/types/error.rs index 70a3c315ad6..f2fa192d331 100644 --- a/ethcore/src/trace/types/error.rs +++ b/ethcore/src/trace/types/error.rs @@ -17,7 +17,7 @@ //! Trace errors. use std::fmt; -use rlp::{Encodable, RlpStream, Decodable, DecoderError, UntrustedRlp}; +use rlp::{Encodable, RlpStream, Decodable, DecoderError, Rlp}; use vm::Error as VmError; /// Trace evm errors. @@ -115,7 +115,7 @@ impl Encodable for Error { } impl Decodable for Error { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use self::Error::*; let value: u8 = rlp.as_val()?; match value { diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index e3f66e170bf..e2746ca7f7d 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -17,7 +17,7 @@ //! Flat trace module use std::collections::VecDeque; -use rlp::{UntrustedRlp, RlpStream, Decodable, Encodable, DecoderError}; +use rlp::{Rlp, RlpStream, Decodable, Encodable, DecoderError}; use heapsize::HeapSizeOf; use ethereum_types::Bloom; use super::trace::{Action, Res}; @@ -63,7 +63,7 @@ impl Encodable for FlatTrace { } impl Decodable for FlatTrace { - fn decode(d: &UntrustedRlp) -> Result { + fn decode(d: &Rlp) -> Result { let v: Vec = d.list_at(3)?; let res = FlatTrace { action: d.val_at(0)?, diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index e6db17603d6..06f24efac38 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -18,7 +18,7 @@ use ethereum_types::{U256, Address, Bloom, BloomInput}; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable}; +use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable}; use vm::ActionParams; use evm::CallType; @@ -154,7 +154,7 @@ impl Encodable for RewardType { } impl Decodable for RewardType { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.as_val().and_then(|v| Ok(match v { 0u32 => RewardType::Block, 1 => RewardType::Uncle, @@ -191,7 +191,7 @@ impl Encodable for Reward { } impl Decodable for Reward { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let res = Reward { author: rlp.val_at(0)?, value: rlp.val_at(1)?, @@ -263,7 +263,7 @@ impl Encodable for Action { } impl Decodable for Action { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let action_type: u8 = rlp.val_at(0)?; match action_type { 0 => rlp.val_at(1).map(Action::Call), @@ -334,7 +334,7 @@ impl Encodable for Res { } impl Decodable for Res { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let action_type: u8 = rlp.val_at(0)?; match action_type { 0 => rlp.val_at(1).map(Res::Call), diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index 898435eb260..223de30f758 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -122,7 +122,7 @@ pub mod blocks { pub fn new(bytes: Bytes) -> Self { use views::BlockView; - let header = BlockView::new(&bytes).header(); + let header = view!(BlockView, &bytes).header(); Unverified { header: header, bytes: bytes, diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index b6e60d042ae..d50bd1cb34c 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -733,7 +733,7 @@ mod tests { use super::kind::blocks::Unverified; use test_helpers::{get_good_dummy_block_seq, get_good_dummy_block}; use error::*; - use views::*; + use views::BlockView; // create a test block queue. // auto_scaling enables verifier adjustment. @@ -785,7 +785,7 @@ mod tests { fn returns_total_difficulty() { let queue = get_test_queue(false); let block = get_good_dummy_block(); - let hash = BlockView::new(&block).header().hash().clone(); + let hash = view!(BlockView, &block).header().hash().clone(); if let Err(e) = queue.import(Unverified::new(block)) { panic!("error importing block that is valid by definition({:?})", e); } @@ -801,7 +801,7 @@ mod tests { fn returns_ok_for_drained_duplicates() { let queue = get_test_queue(false); let block = get_good_dummy_block(); - let hash = BlockView::new(&block).header().hash().clone(); + let hash = view!(BlockView, &block).header().hash().clone(); if let Err(e) = queue.import(Unverified::new(block)) { panic!("error importing block that is valid by definition({:?})", e); } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 5b0700bfd9c..d0bfcc0c7cb 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -28,7 +28,7 @@ use bytes::Bytes; use ethereum_types::H256; use hash::keccak; use heapsize::HeapSizeOf; -use rlp::UntrustedRlp; +use rlp::Rlp; use triehash::ordered_trie_root; use unexpected::{Mismatch, OutOfBounds}; @@ -63,13 +63,13 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &EthEngine) -> verify_header_params(&header, engine, true)?; verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash())?; engine.verify_block_basic(&header)?; - for u in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { + for u in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { let u = u?; verify_header_params(&u, engine, false)?; engine.verify_block_basic(&u)?; } - for t in UntrustedRlp::new(bytes).at(1)?.iter().map(|rlp| rlp.as_val::()) { + for t in Rlp::new(bytes).at(1)?.iter().map(|rlp| rlp.as_val::()) { engine.verify_transaction_basic(&t?, &header)?; } Ok(()) @@ -81,7 +81,7 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &EthEngine) -> pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine, check_seal: bool) -> Result { if check_seal { engine.verify_block_unordered(&header)?; - for u in UntrustedRlp::new(&bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { + for u in Rlp::new(&bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { engine.verify_block_unordered(&u?)?; } } @@ -91,7 +91,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine, Some((engine.params().nonce_cap_increment * header.number()).into()) } else { None }; { - let v = BlockView::new(&bytes); + let v = view!(BlockView, &bytes); for t in v.transactions() { let t = engine.verify_transaction_unordered(t, &header)?; if let Some(max_nonce) = nonce_cap { @@ -145,7 +145,7 @@ pub fn verify_block_family(header: &Header, parent: } fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> { - let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?; + let num_uncles = Rlp::new(bytes).at(2)?.item_count()?; let max_uncles = engine.maximum_uncle_count(header.number()); if num_uncles != 0 { if num_uncles > max_uncles { @@ -174,7 +174,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth } let mut verified = HashSet::new(); - for uncle in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { + for uncle in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { let uncle = uncle?; if excluded.contains(&uncle.hash()) { return Err(From::from(BlockError::UncleInChain(uncle.hash()))) @@ -333,7 +333,7 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result /// Verify block data against header: transactions root and uncles hash. fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), Error> { - let block = UntrustedRlp::new(block); + let block = Rlp::new(block); let tx = block.at(1)?; let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw())); if expected_root != transactions_root { @@ -408,8 +408,8 @@ mod tests { } pub fn insert(&mut self, bytes: Bytes) { - let number = BlockView::new(&bytes).header_view().number(); - let hash = BlockView::new(&bytes).header_view().hash(); + let number = view!(BlockView, &bytes).header_view().number(); + let hash = view!(BlockView, &bytes).header_view().hash(); self.blocks.insert(hash.clone(), bytes); self.numbers.insert(number, hash.clone()); } @@ -448,7 +448,7 @@ mod tests { /// Get the familial details concerning a block. fn block_details(&self, hash: &H256) -> Option { self.blocks.get(hash).map(|bytes| { - let header = BlockView::new(bytes).header(); + let header = view!(BlockView, bytes).header(); BlockDetails { number: header.number(), total_difficulty: header.difficulty().clone(), @@ -482,12 +482,12 @@ mod tests { } fn basic_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> { - let header = BlockView::new(bytes).header(); + let header = view!(BlockView, bytes).header(); verify_block_basic(&header, bytes, engine) } fn family_test(bytes: &[u8], engine: &EthEngine, bc: &BC) -> Result<(), Error> where BC: BlockProvider { - let view = BlockView::new(bytes); + let view = view!(BlockView, bytes); let header = view.header(); let transactions: Vec<_> = view.transactions() .into_iter() @@ -514,7 +514,7 @@ mod tests { } fn unordered_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> { - let header = BlockView::new(bytes).header(); + let header = view!(BlockView, bytes).header(); verify_block_unordered(header, bytes.to_vec(), engine, false)?; Ok(()) } diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index f6bb92873c5..f610504d85f 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -20,25 +20,34 @@ use bytes::Bytes; use ethereum_types::H256; use hash::keccak; use header::Header; -use rlp::Rlp; use transaction::{UnverifiedTransaction, LocalizedTransaction}; use views::{TransactionView, HeaderView}; +use super::ViewRlp; /// View onto block rlp. pub struct BlockView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } -impl<'a> BlockView<'a> { - /// Creates new view onto block from raw bytes. - pub fn new(bytes: &'a [u8]) -> BlockView<'a> { - BlockView { - rlp: Rlp::new(bytes) - } - } +impl<'a> BlockView<'a> { /// Creates new view onto block from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> { + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{BlockView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let block_view = view!(BlockView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> BlockView<'a> { BlockView { rlp: rlp } @@ -50,7 +59,7 @@ impl<'a> BlockView<'a> { } /// Return reference to underlaying rlp. - pub fn rlp(&self) -> &Rlp<'a> { + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } @@ -60,13 +69,13 @@ impl<'a> BlockView<'a> { } /// Return header rlp. - pub fn header_rlp(&self) -> Rlp { + pub fn header_rlp(&self) -> ViewRlp<'a> { self.rlp.at(0) } /// Create new header view obto block head rlp. pub fn header_view(&self) -> HeaderView<'a> { - HeaderView::new_from_rlp(self.rlp.at(0)) + HeaderView::new(self.header_rlp()) } /// Return List of transactions in given block. @@ -92,28 +101,28 @@ impl<'a> BlockView<'a> { } /// Return the raw rlp for the transactions in the given block. - pub fn transactions_rlp(&self) -> Rlp<'a> { + pub fn transactions_rlp(&self) -> ViewRlp<'a> { self.rlp.at(1) } /// Return number of transactions in given block, without deserializing them. pub fn transactions_count(&self) -> usize { - self.rlp.at(1).iter().count() + self.transactions_rlp().iter().count() } /// Return List of transactions in given block. pub fn transaction_views(&self) -> Vec> { - self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect() + self.transactions_rlp().iter().map(TransactionView::new).collect() } /// Return transaction hashes. pub fn transaction_hashes(&self) -> Vec { - self.rlp.at(1).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.transactions_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Returns transaction at given index without deserializing unnecessary data. pub fn transaction_at(&self, index: usize) -> Option { - self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val()) + self.transactions_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Returns localized transaction at given index. @@ -131,7 +140,7 @@ impl<'a> BlockView<'a> { } /// Returns raw rlp for the uncles in the given block - pub fn uncles_rlp(&self) -> Rlp<'a> { + pub fn uncles_rlp(&self) -> ViewRlp<'a> { self.rlp.at(2) } @@ -142,27 +151,27 @@ impl<'a> BlockView<'a> { /// Return number of uncles in given block, without deserializing them. pub fn uncles_count(&self) -> usize { - self.rlp.at(2).iter().count() + self.uncles_rlp().iter().count() } /// Return List of transactions in given block. pub fn uncle_views(&self) -> Vec> { - self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect() + self.uncles_rlp().iter().map(HeaderView::new).collect() } /// Return list of uncle hashes of given block. pub fn uncle_hashes(&self) -> Vec { - self.rlp.at(2).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.uncles_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Return nth uncle. pub fn uncle_at(&self, index: usize) -> Option
{ - self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Return nth uncle rlp. pub fn uncle_rlp_at(&self, index: usize) -> Option { - self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) } } @@ -176,7 +185,7 @@ mod tests { // that's rlp of block created with ethash engine. let rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap(); - let view = BlockView::new(&rlp); + let view = view!(BlockView, &rlp); assert_eq!(view.hash(), "2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259".into()); assert_eq!(view.transactions_count(), 1); assert_eq!(view.uncles_count(), 0); diff --git a/ethcore/src/views/body.rs b/ethcore/src/views/body.rs index d23f1a1d774..d2864b97259 100644 --- a/ethcore/src/views/body.rs +++ b/ethcore/src/views/body.rs @@ -20,32 +20,40 @@ use bytes::Bytes; use ethereum_types::H256; use hash::keccak; use header::{Header, BlockNumber}; -use rlp::Rlp; use transaction::{LocalizedTransaction, UnverifiedTransaction}; use views::{TransactionView, HeaderView}; +use super::ViewRlp; /// View onto block rlp. pub struct BodyView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } impl<'a> BodyView<'a> { - /// Creates new view onto block from raw bytes. - pub fn new(bytes: &'a [u8]) -> BodyView<'a> { - BodyView { - rlp: Rlp::new(bytes) - } - } - - /// Creates new view onto block from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> BodyView<'a> { + /// Creates new view onto block body from rlp. + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{BodyView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let body_view = view!(BodyView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> BodyView<'a> { BodyView { rlp: rlp } } /// Return reference to underlaying rlp. - pub fn rlp(&self) -> &Rlp<'a> { + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } @@ -69,27 +77,27 @@ impl<'a> BodyView<'a> { } /// Return the raw rlp for the transactions in the given block. - pub fn transactions_rlp(&self) -> Rlp<'a> { + pub fn transactions_rlp(&self) -> ViewRlp<'a> { self.rlp.at(0) } /// Return number of transactions in given block, without deserializing them. pub fn transactions_count(&self) -> usize { - self.rlp.at(0).item_count() + self.transactions_rlp().item_count() } /// Return List of transactions in given block. pub fn transaction_views(&self) -> Vec> { - self.rlp.at(0).iter().map(TransactionView::new_from_rlp).collect() + self.transactions_rlp().iter().map(TransactionView::new).collect() } /// Return transaction hashes. pub fn transaction_hashes(&self) -> Vec { - self.rlp.at(0).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.transactions_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Returns transaction at given index without deserializing unnecessary data. pub fn transaction_at(&self, index: usize) -> Option { - self.rlp.at(0).iter().nth(index).map(|rlp| rlp.as_val()) + self.transactions_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Returns localized transaction at given index. @@ -104,7 +112,7 @@ impl<'a> BodyView<'a> { } /// Returns raw rlp for the uncles in the given block - pub fn uncles_rlp(&self) -> Rlp<'a> { + pub fn uncles_rlp(&self) -> ViewRlp<'a> { self.rlp.at(1) } @@ -115,27 +123,27 @@ impl<'a> BodyView<'a> { /// Return number of uncles in given block, without deserializing them. pub fn uncles_count(&self) -> usize { - self.rlp.at(1).item_count() + self.uncles_rlp().item_count() } /// Return List of transactions in given block. pub fn uncle_views(&self) -> Vec> { - self.rlp.at(1).iter().map(HeaderView::new_from_rlp).collect() + self.uncles_rlp().iter().map(HeaderView::new).collect() } /// Return list of uncle hashes of given block. pub fn uncle_hashes(&self) -> Vec { - self.rlp.at(1).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.uncles_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Return nth uncle. pub fn uncle_at(&self, index: usize) -> Option
{ - self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Return nth uncle rlp. pub fn uncle_rlp_at(&self, index: usize) -> Option { - self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) } } @@ -150,7 +158,7 @@ mod tests { // that's rlp of block created with ethash engine. let rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap(); let body = BlockChain::block_to_body(&rlp); - let view = BodyView::new(&body); + let view = view!(BodyView, &body); assert_eq!(view.transactions_count(), 1); assert_eq!(view.uncles_count(), 0); } diff --git a/ethcore/src/views/header.rs b/ethcore/src/views/header.rs index cce4eee8281..8d407f0a1bb 100644 --- a/ethcore/src/views/header.rs +++ b/ethcore/src/views/header.rs @@ -20,35 +20,44 @@ use bytes::Bytes; use ethereum_types::{H256, Bloom, U256, Address}; use hash::keccak; use header::BlockNumber; -use rlp::{self, Rlp}; +use rlp::{self}; +use super::ViewRlp; /// View onto block header rlp. pub struct HeaderView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } impl<'a> HeaderView<'a> { - /// Creates new view onto header from raw bytes. - pub fn new(bytes: &'a [u8]) -> HeaderView<'a> { + /// Creates a new Header view from valid ViewRlp + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{HeaderView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let tx_view = view!(HeaderView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> HeaderView<'a> { HeaderView { - rlp: Rlp::new(bytes) - } - } - - /// Creates new view onto header from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> HeaderView<'a> { - HeaderView { - rlp: rlp + rlp } } /// Returns header hash. pub fn hash(&self) -> H256 { - keccak(self.rlp.as_raw()) + keccak(self.rlp.rlp.as_raw()) } /// Returns raw rlp. - pub fn rlp(&self) -> &Rlp<'a> { &self.rlp } + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } /// Returns parent hash. pub fn parent_hash(&self) -> H256 { self.rlp.val_at(0) } @@ -102,9 +111,10 @@ impl<'a> HeaderView<'a> { pub fn decode_seal(&self) -> Result, rlp::DecoderError> { let seal = self.seal(); seal.into_iter() - .map(|s| rlp::UntrustedRlp::new(&s).data().map(|x| x.to_vec())) + .map(|s| rlp::Rlp::new(&s).data().map(|x| x.to_vec())) .collect() } + } #[cfg(test)] @@ -120,7 +130,7 @@ mod tests { let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap(); let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap(); - let view = HeaderView::new(&rlp); + let view = view!(HeaderView, &rlp); assert_eq!(view.hash(), "2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259".into()); assert_eq!(view.parent_hash(), "d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7".into()); assert_eq!(view.uncles_hash(), "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".into()); diff --git a/ethcore/src/views/mod.rs b/ethcore/src/views/mod.rs index 5d3cc8cdccd..b9cbad88891 100644 --- a/ethcore/src/views/mod.rs +++ b/ethcore/src/views/mod.rs @@ -16,12 +16,26 @@ //! Block oriented views onto rlp. +#[macro_use] +mod view_rlp; mod block; mod body; mod header; mod transaction; +pub use self::view_rlp::ViewRlp; pub use self::block::BlockView; pub use self::body::BodyView; pub use self::header::HeaderView; pub use self::transaction::TransactionView; + +#[cfg(test)] +mod tests { + use super::HeaderView; + + #[test] + #[should_panic(expected="View rlp is trusted and should be valid. Constructed in ethcore/src/views/mod.rs on line 39: RlpExpectedToBeList")] + fn should_include_file_line_number_in_panic_for_invalid_rlp() { + let _ = view!(HeaderView, &[]).parent_hash(); + } +} \ No newline at end of file diff --git a/ethcore/src/views/transaction.rs b/ethcore/src/views/transaction.rs index 92bd49c2768..5607482b309 100644 --- a/ethcore/src/views/transaction.rs +++ b/ethcore/src/views/transaction.rs @@ -18,30 +18,39 @@ use bytes::Bytes; use ethereum_types::{H256, U256}; use hash::keccak; -use rlp::Rlp; +// use rlp::{Rlp, Decodable}; +use super::ViewRlp; /// View onto transaction rlp. pub struct TransactionView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } impl<'a> TransactionView<'a> { - /// Creates new view onto block from raw bytes. - pub fn new(bytes: &'a [u8]) -> TransactionView<'a> { - TransactionView { - rlp: Rlp::new(bytes) - } - } - - /// Creates new view onto block from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> TransactionView<'a> { + /// Creates new view onto valid transaction rlp. + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{TransactionView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let tx_view = view!(TransactionView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> TransactionView<'a> { TransactionView { rlp: rlp } } /// Return reference to underlaying rlp. - pub fn rlp(&self) -> &Rlp<'a> { + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } @@ -84,7 +93,7 @@ mod tests { fn test_transaction_view() { let rlp = "f87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804".from_hex().unwrap(); - let view = TransactionView::new(&rlp); + let view = view!(TransactionView, &rlp); assert_eq!(view.nonce(), 0.into()); assert_eq!(view.gas_price(), 1.into()); assert_eq!(view.gas(), 0x61a8.into()); diff --git a/ethcore/src/views/view_rlp.rs b/ethcore/src/views/view_rlp.rs new file mode 100644 index 00000000000..6afdb3af8c0 --- /dev/null +++ b/ethcore/src/views/view_rlp.rs @@ -0,0 +1,130 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Wrapper for view rlp expected to be valid with debug info + +use rlp::{Rlp, Decodable, DecoderError}; + +/// Wrapper for trusted rlp, which is expected to be valid, for use in views +/// When created with view!, records the file and line where it was created for debugging +pub struct ViewRlp<'a> { + /// Wrapped Rlp, expected to be valid + pub rlp: Rlp<'a>, + file: &'a str, + line: u32, +} + +impl<'a, 'view> ViewRlp<'a> where 'a : 'view { + #[doc(hidden)] + pub fn new(bytes: &'a [u8], file: &'a str, line: u32) -> Self { + ViewRlp { + rlp: Rlp::new(bytes), + file, + line + } + } + + /// Returns a new instance replacing existing rlp with new rlp, maintaining debug info + fn new_from_rlp(&self, rlp: Rlp<'a>) -> Self { + ViewRlp { + rlp, + file: self.file, + line: self.line + } + } + + fn maybe_at(&self, index: usize) -> Option> { + self.rlp.at(index) + .map(|rlp| self.new_from_rlp(rlp)) + .ok() + } + + fn expect_valid_rlp(&self, r: Result) -> T { + r.expect(&format!("View rlp is trusted and should be valid. Constructed in {} on line {}", self.file, self.line)) + } + + /// Returns rlp at the given index, panics if no rlp at that index + pub fn at(&self, index: usize) -> ViewRlp<'a> { + let rlp = self.expect_valid_rlp(self.rlp.at(index)); + self.new_from_rlp(rlp) + } + + /// Returns an iterator over all rlp values + pub fn iter(&'view self) -> ViewRlpIterator<'a, 'view> { + self.into_iter() + } + + /// Returns decoded value of this rlp, panics if rlp not valid + pub fn as_val(&self) -> T where T: Decodable { + self.expect_valid_rlp(self.rlp.as_val()) + } + + /// Returns decoded value at the given index, panics not present or valid at that index + pub fn val_at(&self, index: usize) -> T where T : Decodable { + self.expect_valid_rlp(self.rlp.val_at(index)) + } + + /// Returns decoded list of values, panics if rlp is invalid + pub fn list_at(&self, index: usize) -> Vec where T: Decodable { + self.expect_valid_rlp(self.rlp.list_at(index)) + } + + /// Returns the number of items in the rlp, panics if it is not a list of rlp values + pub fn item_count(&self) -> usize { + self.expect_valid_rlp(self.rlp.item_count()) + } + + /// Returns raw rlp bytes + pub fn as_raw(&'view self) -> &'a [u8] { + self.rlp.as_raw() + } +} + +/// Iterator over rlp-slice list elements. +pub struct ViewRlpIterator<'a, 'view> where 'a: 'view { + rlp: &'view ViewRlp<'a>, + index: usize, +} + +impl<'a, 'view> IntoIterator for &'view ViewRlp<'a> where 'a: 'view { + type Item = ViewRlp<'a>; + type IntoIter = ViewRlpIterator<'a, 'view>; + + fn into_iter(self) -> Self::IntoIter { + ViewRlpIterator { + rlp: self, + index: 0, + } + } +} + +impl<'a, 'view> Iterator for ViewRlpIterator<'a, 'view> { + type Item = ViewRlp<'a>; + + fn next(&mut self) -> Option> { + let index = self.index; + let result = self.rlp.maybe_at(index); + self.index += 1; + result + } +} + +#[macro_export] +macro_rules! view { + ($view: ident, $bytes: expr) => { + $view::new($crate::views::ViewRlp::new($bytes, file!(), line!())) + }; +} \ No newline at end of file diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index 5cf81b2e86d..f7626b0efd9 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -22,8 +22,8 @@ use std::collections::{HashSet, VecDeque}; use std::cmp; use heapsize::HeapSizeOf; use ethereum_types::H256; -use rlp::UntrustedRlp; -use ethcore::views::{BlockView}; +use rlp::Rlp; +use ethcore::views::BlockView; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockStatus, BlockId, BlockImportError}; use ethcore::block::Block; @@ -216,7 +216,7 @@ impl BlockDownloader { } /// Add new block headers. - pub fn import_headers(&mut self, io: &mut SyncIo, r: &UntrustedRlp, expected_hash: Option) -> Result { + pub fn import_headers(&mut self, io: &mut SyncIo, r: &Rlp, expected_hash: Option) -> Result { let item_count = r.item_count().unwrap_or(0); if self.state == State::Idle { trace!(target: "sync", "Ignored unexpected block headers"); @@ -316,7 +316,7 @@ impl BlockDownloader { } /// Called by peer once it has new block bodies - pub fn import_bodies(&mut self, _io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), BlockDownloaderImportError> { + pub fn import_bodies(&mut self, _io: &mut SyncIo, r: &Rlp) -> Result<(), BlockDownloaderImportError> { let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); @@ -342,7 +342,7 @@ impl BlockDownloader { } /// Called by peer once it has new block bodies - pub fn import_receipts(&mut self, _io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), BlockDownloaderImportError> { + pub fn import_receipts(&mut self, _io: &mut SyncIo, r: &Rlp) -> Result<(), BlockDownloaderImportError> { let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); @@ -478,7 +478,7 @@ impl BlockDownloader { let block = block_and_receipts.block; let receipts = block_and_receipts.receipts; let (h, number, parent) = { - let header = BlockView::new(&block).header_view(); + let header = view!(BlockView, &block).header_view(); (header.hash(), header.number(), header.parent_hash()) }; diff --git a/ethcore/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs index 37aa579ef99..321c783b4db 100644 --- a/ethcore/sync/src/blocks.rs +++ b/ethcore/sync/src/blocks.rs @@ -22,7 +22,7 @@ use heapsize::HeapSizeOf; use ethereum_types::H256; use triehash::ordered_trie_root; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Rlp, RlpStream, DecoderError}; use network; use ethcore::encoded::Block; use ethcore::views::{HeaderView, BodyView}; @@ -292,8 +292,9 @@ impl BlockCollection { } for block in blocks { - let body = BodyView::new(block.body.as_ref().expect("blocks contains only full blocks; qed")); - let block_view = Block::new_from_header_and_body(&HeaderView::new(&block.header), &body); + let body = view!(BodyView, block.body.as_ref().expect("blocks contains only full blocks; qed")); + let header = view!(HeaderView, &block.header); + let block_view = Block::new_from_header_and_body(&header, &body); drained.push(BlockAndReceipts { block: block_view.rlp().as_raw().to_vec(), receipts: block.receipts.clone(), @@ -340,7 +341,7 @@ impl BlockCollection { fn insert_body(&mut self, b: Bytes) -> Result<(), network::Error> { let header_id = { - let body = UntrustedRlp::new(&b); + let body = Rlp::new(&b); let tx = body.at(0)?; let tx_root = ordered_trie_root(tx.iter().map(|r| r.as_raw())); let uncles = keccak(body.at(1)?.as_raw()); @@ -375,7 +376,7 @@ impl BlockCollection { fn insert_receipt(&mut self, r: Bytes) -> Result<(), network::Error> { let receipt_root = { - let receipts = UntrustedRlp::new(&r); + let receipts = Rlp::new(&r); ordered_trie_root(receipts.iter().map(|r| r.as_raw())) }; self.downloading_receipts.remove(&receipt_root); @@ -403,7 +404,7 @@ impl BlockCollection { } fn insert_header(&mut self, header: Bytes) -> Result { - let info: BlockHeader = UntrustedRlp::new(&header).as_val()?; + let info: BlockHeader = Rlp::new(&header).as_val()?; let hash = info.hash(); if self.blocks.contains_key(&hash) { return Ok(hash); @@ -525,8 +526,8 @@ mod test { let blocks: Vec<_> = (0..nblocks) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner()) .collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); bc.reset_to(heads); assert!(!bc.is_empty()); @@ -580,8 +581,8 @@ mod test { let blocks: Vec<_> = (0..nblocks) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner()) .collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); bc.reset_to(heads); @@ -604,8 +605,8 @@ mod test { let blocks: Vec<_> = (0..nblocks) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner()) .collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); bc.reset_to(heads); diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index 014302d7feb..bc8e35ed492 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -98,7 +98,7 @@ use ethereum_types::{H256, U256}; use plain_hasher::H256FastMap; use parking_lot::RwLock; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, DecoderError, Encodable}; +use rlp::{Rlp, RlpStream, DecoderError, Encodable}; use network::{self, PeerId, PacketId}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo}; @@ -632,7 +632,7 @@ impl ChainSync { } /// Called by peer to report status - fn on_peer_status(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_status(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { self.handshaking_peers.remove(&peer_id); let protocol_version: u8 = r.val_at(0)?; let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer_id) != 0; @@ -702,7 +702,7 @@ impl ChainSync { } /// Called by peer once it has new block headers during sync - fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { let confirmed = match self.peers.get_mut(&peer_id) { Some(ref mut peer) if peer.asking == PeerAsking::ForkHeader => { peer.asking = PeerAsking::Nothing; @@ -803,7 +803,7 @@ impl ChainSync { } /// Called by peer once it has new block bodies - fn on_peer_block_bodies(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_bodies(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { self.clear_peer_download(peer_id); let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); if !self.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { @@ -857,7 +857,7 @@ impl ChainSync { } /// Called by peer once it has new block receipts - fn on_peer_block_receipts(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_receipts(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { self.clear_peer_download(peer_id); let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); if !self.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { @@ -911,7 +911,7 @@ impl ChainSync { } /// Called by peer once it has new block bodies - fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id); return Ok(()); @@ -978,7 +978,7 @@ impl ChainSync { } /// Handles `NewHashes` packet. Initiates headers download for any unknown hashes. - fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id); return Ok(()); @@ -1053,7 +1053,7 @@ impl ChainSync { } /// Called when snapshot manifest is downloaded from a peer. - fn on_snapshot_manifest(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_snapshot_manifest(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring snapshot manifest from unconfirmed peer {}", peer_id); return Ok(()); @@ -1097,7 +1097,7 @@ impl ChainSync { } /// Called when snapshot data is downloaded from a peer. - fn on_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring snapshot data from unconfirmed peer {}", peer_id); return Ok(()); @@ -1501,7 +1501,7 @@ impl ChainSync { } /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { // Accept transactions only when fully synced if !io.is_chain_queue_empty() || (self.state != SyncState::Idle && self.state != SyncState::NewBlocks) { trace!(target: "sync", "{} Ignoring transactions while syncing", peer_id); @@ -1555,7 +1555,7 @@ impl ChainSync { } /// Respond to GetBlockHeaders request - fn return_block_headers(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_block_headers(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { // Packet layout: // [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ] let max_headers: usize = r.val_at(1)?; @@ -1628,7 +1628,7 @@ impl ChainSync { } /// Respond to GetBlockBodies request - fn return_block_bodies(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_block_bodies(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let mut count = r.item_count().unwrap_or(0); if count == 0 { debug!(target: "sync", "Empty GetBlockBodies request, ignoring."); @@ -1650,7 +1650,7 @@ impl ChainSync { } /// Respond to GetNodeData request - fn return_node_data(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_node_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let mut count = r.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetNodeData: {} entries", peer_id, count); if count == 0 { @@ -1674,7 +1674,7 @@ impl ChainSync { Ok(Some((NODE_DATA_PACKET, rlp))) } - fn return_receipts(io: &SyncIo, rlp: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_receipts(io: &SyncIo, rlp: &Rlp, peer_id: PeerId) -> RlpResponseResult { let mut count = rlp.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetReceipts: {} entries", peer_id, count); if count == 0 { @@ -1699,7 +1699,7 @@ impl ChainSync { } /// Respond to GetSnapshotManifest request - fn return_snapshot_manifest(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let count = r.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); if count != 0 { @@ -1722,7 +1722,7 @@ impl ChainSync { } /// Respond to GetSnapshotData request - fn return_snapshot_data(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let hash: H256 = r.val_at(0)?; trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); let rlp = match io.snapshot_service().chunk(hash) { @@ -1739,8 +1739,8 @@ impl ChainSync { Ok(Some((SNAPSHOT_DATA_PACKET, rlp))) } - fn return_rlp(io: &mut SyncIo, rlp: &UntrustedRlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> - where FRlp : Fn(&SyncIo, &UntrustedRlp, PeerId) -> RlpResponseResult, + fn return_rlp(io: &mut SyncIo, rlp: &Rlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> + where FRlp : Fn(&SyncIo, &Rlp, PeerId) -> RlpResponseResult, FError : FnOnce(network::Error) -> String { let response = rlp_func(io, rlp, peer); @@ -1757,7 +1757,7 @@ impl ChainSync { /// Dispatch incoming requests and responses pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); let result = match packet_id { GET_BLOCK_BODIES_PACKET => ChainSync::return_rlp(io, &rlp, peer, ChainSync::return_block_bodies, @@ -1798,7 +1798,7 @@ impl ChainSync { debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); return; } - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); let result = match packet_id { STATUS_PACKET => self.on_peer_status(io, peer, &rlp), TRANSACTIONS_PACKET => self.on_peer_transactions(io, peer, &rlp), @@ -2233,7 +2233,7 @@ impl ChainSync { } /// Called when peer sends us new consensus packet - fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { trace!(target: "sync", "Received consensus packet from {:?}", peer_id); io.chain().queue_consensus_message(r.as_raw().to_vec()); Ok(()) @@ -2249,7 +2249,7 @@ impl ChainSync { } /// Called when peer sends us new private transaction packet - fn on_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); return Ok(()); @@ -2273,7 +2273,7 @@ impl ChainSync { } /// Called when peer sends us signed private transaction packet - fn on_signed_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_signed_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); return Ok(()); @@ -2324,7 +2324,7 @@ mod tests { use ethereum_types::{H256, U256, Address}; use parking_lot::RwLock; use bytes::Bytes; - use rlp::{Rlp, RlpStream, UntrustedRlp}; + use rlp::{Rlp, RlpStream}; use super::*; use ::SyncConfig; use super::{PeerInfo, PeerAsking}; @@ -2421,7 +2421,7 @@ mod tests { let ss = TestSnapshotService::new(); let io = TestIo::new(&mut client, &ss, &queue, None); - let result = ChainSync::return_receipts(&io, &UntrustedRlp::new(&[0xc0]), 0); + let result = ChainSync::return_receipts(&io, &Rlp::new(&[0xc0]), 0); assert!(result.is_ok()); } @@ -2442,7 +2442,7 @@ mod tests { let receipts_request = receipt_list.out(); // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_receipts(&io, &UntrustedRlp::new(&receipts_request.clone()), 0); + let result = ChainSync::return_receipts(&io, &Rlp::new(&receipts_request.clone()), 0); assert!(result.is_ok()); let rlp_result = result.unwrap(); @@ -2484,41 +2484,41 @@ mod tests { client.add_blocks(100, EachBlockWith::Nothing); let blocks: Vec<_> = (0 .. 100) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let io = TestIo::new(&mut client, &ss, &queue, None); let unknown: H256 = H256::new(); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); assert!(to_header_vec(result).is_empty()); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); assert!(to_header_vec(result).is_empty()); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(2, 1, 0, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(2, 1, 0, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(50, 3, 5, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(50, 3, 5, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); } @@ -2537,7 +2537,7 @@ mod tests { let node_request = node_list.out(); // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_node_data(&io, &UntrustedRlp::new(&node_request.clone()), 0); + let result = ChainSync::return_node_data(&io, &Rlp::new(&node_request.clone()), 0); assert!(result.is_ok()); let rlp_result = result.unwrap(); @@ -2546,7 +2546,7 @@ mod tests { // the length of one rlp-encoded hashe let rlp = rlp_result.unwrap().1.out(); let rlp = Rlp::new(&rlp); - assert_eq!(1, rlp.item_count()); + assert_eq!(Ok(1), rlp.item_count()); io.sender = Some(2usize); @@ -2891,7 +2891,7 @@ mod tests { return None; } - let rlp = UntrustedRlp::new(&*p.data); + let rlp = Rlp::new(&*p.data); let item_count = rlp.item_count().unwrap_or(0); if item_count != 1 { return None; @@ -2918,7 +2918,7 @@ mod tests { let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); - let block = UntrustedRlp::new(&block_data); + let block = Rlp::new(&block_data); let result = sync.on_peer_new_block(&mut io, 0, &block); @@ -2937,7 +2937,7 @@ mod tests { let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); - let block = UntrustedRlp::new(&block_data); + let block = Rlp::new(&block_data); let result = sync.on_peer_new_block(&mut io, 0, &block); @@ -2954,7 +2954,7 @@ mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); let empty_data = vec![]; - let block = UntrustedRlp::new(&empty_data); + let block = Rlp::new(&empty_data); let result = sync.on_peer_new_block(&mut io, 0, &block); @@ -2971,7 +2971,7 @@ mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); let hashes_data = get_dummy_hashes(); - let hashes_rlp = UntrustedRlp::new(&hashes_data); + let hashes_rlp = Rlp::new(&hashes_data); let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); @@ -2988,7 +2988,7 @@ mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); let empty_hashes_data = vec![]; - let hashes_rlp = UntrustedRlp::new(&empty_hashes_data); + let hashes_rlp = Rlp::new(&empty_hashes_data); let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); @@ -3011,7 +3011,7 @@ mod tests { sync.propagate_new_hashes(&chain_info, &mut io, &peers); let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(data)); + let result = sync.on_peer_new_hashes(&mut io, 0, &Rlp::new(data)); assert!(result.is_ok()); } @@ -3031,7 +3031,7 @@ mod tests { sync.propagate_blocks(&chain_info, &mut io, &[], &peers); let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(data)); + let result = sync.on_peer_new_block(&mut io, 0, &Rlp::new(data)); assert!(result.is_ok()); } diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index a6e0c7db24c..bf3b475fc6f 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -26,6 +26,7 @@ extern crate ethcore_network_devp2p as devp2p; extern crate ethcore_bytes as bytes; extern crate ethcore_io as io; extern crate ethcore_transaction as transaction; +#[macro_use] extern crate ethcore; extern crate ethereum_types; extern crate env_logger; diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 6e8e78cc48b..571dec3faeb 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -24,7 +24,7 @@ use ethkey::{self, Signature, Secret, Public, recover, public_to_address}; use evm::Schedule; use hash::keccak; use heapsize::HeapSizeOf; -use rlp::{self, RlpStream, UntrustedRlp, DecoderError, Encodable}; +use rlp::{self, RlpStream, Rlp, DecoderError, Encodable}; type Bytes = Vec; type BlockNumber = u64; @@ -50,7 +50,7 @@ impl Default for Action { } impl rlp::Decodable for Action { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.is_empty() { Ok(Action::Create) } else { @@ -291,7 +291,7 @@ impl Deref for UnverifiedTransaction { } impl rlp::Decodable for UnverifiedTransaction { - fn decode(d: &UntrustedRlp) -> Result { + fn decode(d: &Rlp) -> Result { if d.item_count()? != 9 { return Err(DecoderError::RlpIncorrectListLen); } diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index 8aee9936536..c1defbc151f 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -18,7 +18,7 @@ use ethereum_types::{H256, U256, Address, Bloom}; use heapsize::HeapSizeOf; -use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; +use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError}; use {BlockNumber}; use log_entry::{LogEntry, LocalizedLogEntry}; @@ -81,7 +81,7 @@ impl Encodable for Receipt { } impl Decodable for Receipt { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.item_count()? == 3 { Ok(Receipt { outcome: TransactionOutcome::Unknown, diff --git a/ethcore/types/src/snapshot_manifest.rs b/ethcore/types/src/snapshot_manifest.rs index 7f41f9994d7..c59402023a8 100644 --- a/ethcore/types/src/snapshot_manifest.rs +++ b/ethcore/types/src/snapshot_manifest.rs @@ -17,7 +17,7 @@ //! Snapshot manifest type definition use ethereum_types::H256; -use rlp::{UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Rlp, RlpStream, DecoderError}; use bytes::Bytes; /// Manifest data. @@ -53,7 +53,7 @@ impl ManifestData { /// Try to restore manifest data from raw bytes, interpreted as RLP. pub fn from_rlp(raw: &[u8]) -> Result { - let decoder = UntrustedRlp::new(raw); + let decoder = Rlp::new(raw); let (start, version) = if decoder.item_count()? == 5 { (0, 1) } else { diff --git a/ethcore/vm/src/call_type.rs b/ethcore/vm/src/call_type.rs index 08a004053f0..83260825f3c 100644 --- a/ethcore/vm/src/call_type.rs +++ b/ethcore/vm/src/call_type.rs @@ -1,6 +1,6 @@ //! EVM call types. -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; /// The type of the call-like instruction. #[derive(Debug, PartialEq, Clone)] @@ -31,7 +31,7 @@ impl Encodable for CallType { } impl Decodable for CallType { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.as_val().and_then(|v| Ok(match v { 0u32 => CallType::None, 1 => CallType::Call, diff --git a/local-store/src/lib.rs b/local-store/src/lib.rs index 2ebc6a69ce2..078dff36ed8 100644 --- a/local-store/src/lib.rs +++ b/local-store/src/lib.rs @@ -26,7 +26,7 @@ use transaction::{ }; use ethcore::client::ClientIoMessage; use io::IoHandler; -use rlp::UntrustedRlp; +use rlp::Rlp; use kvdb::KeyValueDB; extern crate ethcore; @@ -103,7 +103,7 @@ struct TransactionEntry { impl TransactionEntry { fn into_pending(self) -> Option { - let tx: UnverifiedTransaction = match UntrustedRlp::new(&self.rlp_bytes).as_val() { + let tx: UnverifiedTransaction = match Rlp::new(&self.rlp_bytes).as_val() { Err(e) => { warn!(target: "local_store", "Invalid persistent transaction stored: {}", e); return None diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 586313ab416..439f13ba393 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -247,7 +247,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { let do_import = |bytes: Vec| { while client.queue_info().is_full() { sleep(Duration::from_secs(1)); } - let header: ::ethcore::header::Header = ::rlp::UntrustedRlp::new(&bytes).val_at(0) + let header: ::ethcore::header::Header = ::rlp::Rlp::new(&bytes).val_at(0) .map_err(|e| format!("Bad block: {}", e))?; if client.best_block_header().number() >= header.number() { return Ok(()) } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 9d97c3c992c..7b5cc36447c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -44,6 +44,7 @@ extern crate jsonrpc_ipc_server as ipc; extern crate jsonrpc_pubsub; extern crate ethash; +#[cfg_attr(test, macro_use)] extern crate ethcore; extern crate ethcore_bytes as bytes; extern crate ethcore_crypto as crypto; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 37f918466e8..c894f16dfc4 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -20,7 +20,7 @@ use std::thread; use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH}; use std::sync::Arc; -use rlp::{self, UntrustedRlp}; +use rlp::{self, Rlp}; use ethereum_types::{U256, H64, H160, H256, Address}; use parking_lot::Mutex; @@ -813,7 +813,7 @@ impl Eth for EthClient< } fn send_raw_transaction(&self, raw: Bytes) -> Result { - UntrustedRlp::new(&raw.into_vec()).as_val() + Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction)) .and_then(|signed_transaction| { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 73e041abac3..eeef12da6e6 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -36,7 +36,7 @@ use sync::LightSync; use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; use ethereum_types::U256; use parking_lot::{RwLock, Mutex}; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::SignedTransaction; use v1::impls::eth_filter::Filterable; @@ -373,7 +373,7 @@ impl Eth for EthClient { fn send_raw_transaction(&self, raw: Bytes) -> Result { let best_header = self.client.best_block_header().decode(); - UntrustedRlp::new(&raw.into_vec()).as_val() + Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| { self.client.engine().verify_transaction_basic(&tx, &best_header) diff --git a/rpc/src/v1/impls/private.rs b/rpc/src/v1/impls/private.rs index bf797d5a589..ab5866e4a75 100644 --- a/rpc/src/v1/impls/private.rs +++ b/rpc/src/v1/impls/private.rs @@ -18,7 +18,7 @@ use std::sync::Arc; -use rlp::UntrustedRlp; +use rlp::Rlp; use ethcore_private_tx::Provider as PrivateTransactionManager; use ethereum_types::Address; @@ -56,7 +56,7 @@ impl Private for PrivateClient { type Metadata = Metadata; fn send_transaction(&self, request: Bytes) -> Result { - let signed_transaction = UntrustedRlp::new(&request.into_vec()).as_val() + let signed_transaction = Rlp::new(&request.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))?; let client = self.unwrap_manager()?; @@ -65,7 +65,7 @@ impl Private for PrivateClient { } fn compose_deployment_transaction(&self, block_number: BlockNumber, request: Bytes, validators: Vec, gas_price: U256) -> Result { - let signed_transaction = UntrustedRlp::new(&request.into_vec()).as_val() + let signed_transaction = Rlp::new(&request.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))?; let client = self.unwrap_manager()?; diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index ce3f13b9767..2e8d41c4ace 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -22,7 +22,7 @@ use ethcore::account_provider::AccountProvider; use ethkey; use parity_reactor::Remote; use parking_lot::Mutex; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::{SignedTransaction, PendingTransaction}; use jsonrpc_core::{Result, BoxFuture, Error}; @@ -127,7 +127,7 @@ impl SignerClient { fn verify_transaction(bytes: Bytes, request: FilledTransactionRequest, process: F) -> Result where F: FnOnce(PendingTransaction) -> Result, { - let signed_transaction = UntrustedRlp::new(&bytes.0).as_val().map_err(errors::rlp)?; + let signed_transaction = Rlp::new(&bytes.0).as_val().map_err(errors::rlp)?; let signed_transaction = SignedTransaction::new(signed_transaction).map_err(|e| errors::invalid_params("Invalid signature.", e))?; let sender = signed_transaction.sender(); diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 06df83b752b..bf4dc83beb1 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId}; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::SignedTransaction; use jsonrpc_core::Result; @@ -139,7 +139,7 @@ impl Traces for TracesClient where fn raw_transaction(&self, raw_transaction: Bytes, flags: TraceOptions, block: Trailing) -> Result { let block = block.unwrap_or_default(); - let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?; + let tx = Rlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?; let signed = SignedTransaction::new(tx).map_err(errors::transaction)?; let id = match block { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 6aacbc865d7..4b83710bc02 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -411,7 +411,7 @@ fn verify_transaction_counts(name: String, chain: BlockChain) { let tester = EthTester::from_chain(&chain); let mut id = 1; - for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| BlockView::new(b)) { + for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| view!(BlockView, b)) { let count = b.transactions_count(); let hash = b.hash(); diff --git a/util/journaldb/src/overlaydb.rs b/util/journaldb/src/overlaydb.rs index 6ff1b97e8be..fa7ff04596e 100644 --- a/util/journaldb/src/overlaydb.rs +++ b/util/journaldb/src/overlaydb.rs @@ -21,7 +21,7 @@ use std::collections::HashMap; use std::collections::hash_map::Entry; use error::{Result, BaseDataError}; use ethereum_types::H256; -use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode}; +use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode}; use hashdb::*; use memorydb::*; use kvdb::{KeyValueDB, DBTransaction}; @@ -64,7 +64,7 @@ impl Encodable for Payload { } impl Decodable for Payload { - fn decode(rlp: &UntrustedRlp) -> ::std::result::Result { + fn decode(rlp: &Rlp) -> ::std::result::Result { let payload = Payload { count: rlp.val_at(0)?, value: DBValue::from_slice(rlp.at(1)?.data()?), diff --git a/util/journaldb/src/overlayrecentdb.rs b/util/journaldb/src/overlayrecentdb.rs index 9ac8a4e294f..fdc178350e6 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -21,7 +21,7 @@ use std::collections::hash_map::Entry; use std::sync::Arc; use parking_lot::RwLock; use heapsize::HeapSizeOf; -use rlp::{UntrustedRlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable}; +use rlp::{Rlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable}; use hashdb::*; use memorydb::*; use super::{DB_PREFIX_LEN, LATEST_ERA_KEY}; @@ -78,7 +78,7 @@ struct DatabaseValue { } impl Decodable for DatabaseValue { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let id = rlp.val_at(0)?; let inserts = rlp.at(1)?.iter().map(|r| { let k = r.val_at(0)?; diff --git a/util/journaldb/src/util.rs b/util/journaldb/src/util.rs index 52dbad7e1da..e99be458e58 100644 --- a/util/journaldb/src/util.rs +++ b/util/journaldb/src/util.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use ethereum_types::H256; -use rlp::{RlpStream, Encodable, UntrustedRlp, DecoderError}; +use rlp::{RlpStream, Encodable, Rlp, DecoderError}; const PADDING : [u8; 10] = [ 0u8; 10 ]; @@ -34,13 +34,13 @@ impl Encodable for DatabaseKey { } pub struct DatabaseValueView<'a> { - rlp: UntrustedRlp<'a>, + rlp: Rlp<'a>, } impl<'a> DatabaseValueView<'a> { pub fn from_rlp(data: &'a [u8]) -> Self { DatabaseValueView { - rlp: UntrustedRlp::new(data), + rlp: Rlp::new(data), } } diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 12c38b3a245..2b390baf75e 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -24,7 +24,7 @@ use mio::deprecated::{Handler, EventLoop, TryRead, TryWrite}; use mio::tcp::*; use ethereum_types::{H128, H256, H512}; use ethcore_bytes::*; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use std::io::{self, Cursor, Read, Write}; use io::{IoContext, StreamToken}; use handshake::Handshake; @@ -391,7 +391,7 @@ impl EncryptedConnection { self.decoder.decrypt(&mut RefReadBuffer::new(&header[0..16]), &mut RefWriteBuffer::new(&mut hdec), false).expect("Invalid length or padding"); let length = ((((hdec[0] as u32) << 8) + (hdec[1] as u32)) << 8) + (hdec[2] as u32); - let header_rlp = UntrustedRlp::new(&hdec[3..6]); + let header_rlp = Rlp::new(&hdec[3..6]); let protocol_id = header_rlp.val_at::(0)?; self.payload_len = length as usize; diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index 2828b8f19fd..f14cd5ba6fd 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -25,7 +25,7 @@ use mio::deprecated::{Handler, EventLoop}; use mio::udp::*; use hash::keccak; use ethereum_types::{H256, H520}; -use rlp::{UntrustedRlp, RlpStream, encode_list}; +use rlp::{Rlp, RlpStream, encode_list}; use node_table::*; use network::{Error, ErrorKind}; use io::{StreamToken, IoContext}; @@ -259,7 +259,7 @@ impl Discovery { fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) -> Result<(), Error> { let mut rlp = RlpStream::new(); rlp.append_raw(&[packet_id], 1); - let source = UntrustedRlp::new(payload); + let source = Rlp::new(payload); rlp.begin_list(source.item_count()? + 1); for i in 0 .. source.item_count()? { rlp.append_raw(source.at(i)?.as_raw(), 1); @@ -382,7 +382,7 @@ impl Discovery { let node_id = recover(&signature.into(), &keccak(signed))?; let packet_id = signed[0]; - let rlp = UntrustedRlp::new(&signed[1..]); + let rlp = Rlp::new(&signed[1..]); match packet_id { PACKET_PING => self.on_ping(&rlp, &node_id, &from, &hash_signed), PACKET_PONG => self.on_pong(&rlp, &node_id, &from), @@ -409,7 +409,7 @@ impl Discovery { entry.endpoint.is_allowed(&self.ip_filter) && entry.id != self.id } - fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr, echo_hash: &[u8]) -> Result, Error> { + fn on_ping(&mut self, rlp: &Rlp, node: &NodeId, from: &SocketAddr, echo_hash: &[u8]) -> Result, Error> { trace!(target: "discovery", "Got Ping from {:?}", &from); let source = NodeEndpoint::from_rlp(&rlp.at(1)?)?; let dest = NodeEndpoint::from_rlp(&rlp.at(2)?)?; @@ -433,7 +433,7 @@ impl Discovery { Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) } - fn on_pong(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, Error> { + fn on_pong(&mut self, rlp: &Rlp, node: &NodeId, from: &SocketAddr) -> Result, Error> { trace!(target: "discovery", "Got Pong from {:?}", &from); // TODO: validate pong packet in rlp.val_at(1) let dest = NodeEndpoint::from_rlp(&rlp.at(0)?)?; @@ -448,7 +448,7 @@ impl Discovery { Ok(None) } - fn on_find_node(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { + fn on_find_node(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { trace!(target: "discovery", "Got FindNode from {:?}", &from); let target: NodeId = rlp.val_at(0)?; let timestamp: u64 = rlp.val_at(1)?; @@ -481,7 +481,7 @@ impl Discovery { packets.collect() } - fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { + fn on_neighbours(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { // TODO: validate packet let mut added = HashMap::new(); trace!(target: "discovery", "Got {} Neighbours from {:?}", rlp.at(0)?.item_count()?, &from); @@ -725,7 +725,7 @@ mod tests { discovery2.on_packet(&ping_data.payload, ep1.address.clone()).ok(); let pong_data = discovery2.send_queue.pop_front().unwrap(); let data = &pong_data.payload[(32 + 65)..]; - let rlp = UntrustedRlp::new(&data[1..]); + let rlp = Rlp::new(&data[1..]); assert_eq!(ping_data.payload[0..32], rlp.val_at::>(1).unwrap()[..]) } } diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index d7818b64d95..37c39eb618e 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -20,7 +20,7 @@ use hash::write_keccak; use mio::tcp::*; use ethereum_types::{H256, H520}; use ethcore_bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use connection::{Connection}; use node_table::NodeId; use io::{IoContext, StreamToken}; @@ -205,7 +205,7 @@ impl Handshake { trace!(target: "network", "Received EIP8 handshake auth from {:?}", self.connection.remote_addr_str()); self.auth_cipher.extend_from_slice(data); let auth = ecies::decrypt(secret, &self.auth_cipher[0..2], &self.auth_cipher[2..])?; - let rlp = UntrustedRlp::new(&auth); + let rlp = Rlp::new(&auth); let signature: H520 = rlp.val_at(0)?; let remote_public: Public = rlp.val_at(1)?; let remote_nonce: H256 = rlp.val_at(2)?; @@ -248,7 +248,7 @@ impl Handshake { trace!(target: "network", "Received EIP8 handshake auth from {:?}", self.connection.remote_addr_str()); self.ack_cipher.extend_from_slice(data); let ack = ecies::decrypt(secret, &self.ack_cipher[0..2], &self.ack_cipher[2..])?; - let rlp = UntrustedRlp::new(&ack); + let rlp = Rlp::new(&ack); self.remote_ephemeral = rlp.val_at(0)?; self.remote_nonce = rlp.val_at(1)?; self.remote_version = rlp.val_at(2)?; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 470bf5cde0f..fd18c10a12c 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -22,7 +22,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::{fs, mem, slice}; use ethereum_types::H512; -use rlp::{UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Rlp, RlpStream, DecoderError}; use network::{Error, ErrorKind, AllowIP, IpFilter}; use discovery::{TableUpdates, NodeEntry}; use ip_utils::*; @@ -66,7 +66,7 @@ impl NodeEndpoint { } } - pub fn from_rlp(rlp: &UntrustedRlp) -> Result { + pub fn from_rlp(rlp: &Rlp) -> Result { let tcp_port = rlp.val_at::(2)?; let udp_port = rlp.val_at::(1)?; let addr_bytes = rlp.at(0)?.data()?; diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index c1e09a25252..47eb2cf7283 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -23,7 +23,7 @@ use mio::*; use mio::deprecated::{Handler, EventLoop}; use mio::tcp::*; use ethereum_types::H256; -use rlp::{UntrustedRlp, RlpStream, EMPTY_LIST_RLP}; +use rlp::{Rlp, RlpStream, EMPTY_LIST_RLP}; use connection::{EncryptedConnection, Packet, Connection, MAX_PAYLOAD_SIZE}; use handshake::Handshake; use io::{IoContext, StreamToken}; @@ -349,12 +349,12 @@ impl Session { }; match packet_id { PACKET_HELLO => { - let rlp = UntrustedRlp::new(&data); //TODO: validate rlp expected size + let rlp = Rlp::new(&data); //TODO: validate rlp expected size self.read_hello(io, &rlp, host)?; Ok(SessionData::Ready) }, PACKET_DISCONNECT => { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let reason: u8 = rlp.val_at(0)?; if self.had_hello { debug!(target:"network", "Disconnected: {}: {:?}", self.token(), DisconnectReason::from_u8(reason)); @@ -419,7 +419,7 @@ impl Session { self.send(io, &rlp.drain()) } - fn read_hello(&mut self, io: &IoContext, rlp: &UntrustedRlp, host: &HostInfo) -> Result<(), Error> + fn read_hello(&mut self, io: &IoContext, rlp: &Rlp, host: &HostInfo) -> Result<(), Error> where Message: Send + Sync + Clone { let protocol = rlp.val_at::(0)?; let client_version = rlp.val_at::(1)?; diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 1a0c88e4caf..5077a953d48 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -42,7 +42,7 @@ use ipnetwork::{IpNetwork, IpNetworkError}; use io::IoChannel; use ethkey::Secret; use ethereum_types::{H256, H512}; -use rlp::{Decodable, DecoderError, UntrustedRlp}; +use rlp::{Decodable, DecoderError, Rlp}; /// Protocol handler level packet id pub type PacketId = u8; @@ -118,7 +118,7 @@ pub struct PeerCapabilityInfo { } impl Decodable for PeerCapabilityInfo { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let p: Vec = rlp.val_at(0)?; if p.len() != 3 { return Err(DecoderError::Custom("Invalid subprotocol string length. Should be 3")); diff --git a/util/patricia_trie/src/node.rs b/util/patricia_trie/src/node.rs index 47807940fee..0b99acded34 100644 --- a/util/patricia_trie/src/node.rs +++ b/util/patricia_trie/src/node.rs @@ -19,7 +19,7 @@ use elastic_array::ElasticArray36; use nibbleslice::NibbleSlice; use nibblevec::NibbleVec; use bytes::*; -use rlp::{UntrustedRlp, RlpStream, Prototype, DecoderError}; +use rlp::{Rlp, RlpStream, Prototype, DecoderError}; use hashdb::DBValue; /// Partial node key type. @@ -41,7 +41,7 @@ pub enum Node<'a> { impl<'a> Node<'a> { /// Decode the `node_rlp` and return the Node. pub fn decoded(node_rlp: &'a [u8]) -> Result { - let r = UntrustedRlp::new(node_rlp); + let r = Rlp::new(node_rlp); match r.prototype()? { // either leaf or extension - decode first item with NibbleSlice::??? // and use is_leaf return to figure out which. @@ -105,7 +105,7 @@ impl<'a> Node<'a> { } pub fn try_decode_hash(node_data: &[u8]) -> Option { - let r = UntrustedRlp::new(node_data); + let r = Rlp::new(node_data); if r.is_data() && r.size() == 32 { Some(r.as_val().expect("Hash is the correct size of 32 bytes; qed")) } else { diff --git a/util/patricia_trie/src/triedbmut.rs b/util/patricia_trie/src/triedbmut.rs index 98215de012f..b8d919deea2 100644 --- a/util/patricia_trie/src/triedbmut.rs +++ b/util/patricia_trie/src/triedbmut.rs @@ -24,7 +24,7 @@ use super::node::NodeKey; use hashdb::HashDB; use bytes::ToPretty; use nibbleslice::NibbleSlice; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use hashdb::DBValue; use std::collections::{HashSet, VecDeque}; @@ -107,7 +107,7 @@ impl Node { RlpNode::Branch(ref children_rlp, val) => { let mut child = |i| { let raw = children_rlp[i]; - let child_rlp = UntrustedRlp::new(raw); + let child_rlp = Rlp::new(raw); if !child_rlp.is_empty() { Some(Self::inline_or_hash(raw, db, storage)) } else { diff --git a/util/rlp/src/impls.rs b/util/rlp/src/impls.rs index 7cb6572fec9..573f2c0781e 100644 --- a/util/rlp/src/impls.rs +++ b/util/rlp/src/impls.rs @@ -11,7 +11,7 @@ use byteorder::{ByteOrder, BigEndian}; use bigint::{U128, U256, H64, H128, H160, H256, H512, H520, Bloom}; use traits::{Encodable, Decodable}; use stream::RlpStream; -use {UntrustedRlp, DecoderError}; +use {Rlp, DecoderError}; pub fn decode_usize(bytes: &[u8]) -> Result { match bytes.len() { @@ -41,7 +41,7 @@ impl Encodable for bool { } impl Decodable for bool { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match bytes.len() { 0 => Ok(false), @@ -65,7 +65,7 @@ impl Encodable for Vec { } impl Decodable for Vec { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { Ok(bytes.to_vec()) }) @@ -87,7 +87,7 @@ impl Encodable for Option where T: Encodable { } impl Decodable for Option where T: Decodable { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let items = rlp.item_count()?; match items { 1 => rlp.val_at(0).map(Some), @@ -108,7 +108,7 @@ impl Encodable for u8 { } impl Decodable for u8 { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match bytes.len() { 1 if bytes[0] != 0 => Ok(bytes[0]), @@ -136,7 +136,7 @@ macro_rules! impl_encodable_for_u { macro_rules! impl_decodable_for_u { ($name: ident) => { impl Decodable for $name { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match bytes.len() { 0 | 1 => u8::decode(rlp).map(|v| v as $name), @@ -174,7 +174,7 @@ impl Encodable for usize { } impl Decodable for usize { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { u64::decode(rlp).map(|value| value as usize) } } @@ -192,7 +192,7 @@ macro_rules! impl_encodable_for_hash { macro_rules! impl_decodable_for_hash { ($name: ident, $size: expr) => { impl Decodable for $name { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$size) { cmp::Ordering::Less => Err(DecoderError::RlpIsTooShort), cmp::Ordering::Greater => Err(DecoderError::RlpIsTooBig), @@ -239,7 +239,7 @@ macro_rules! impl_encodable_for_uint { macro_rules! impl_decodable_for_uint { ($name: ident, $size: expr) => { impl Decodable for $name { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { if !bytes.is_empty() && bytes[0] == 0 { Err(DecoderError::RlpInvalidIndirection) @@ -273,7 +273,7 @@ impl Encodable for String { } impl Decodable for String { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match str::from_utf8(bytes) { Ok(s) => Ok(s.to_owned()), diff --git a/util/rlp/src/lib.rs b/util/rlp/src/lib.rs index a5889a4efc2..a6754e22de9 100644 --- a/util/rlp/src/lib.rs +++ b/util/rlp/src/lib.rs @@ -27,12 +27,6 @@ //! * You encode a big set of data. //! //!### Use `Rlp` when: -//! * You are working on trusted data (not corrupted). -//! * You want to get view onto rlp-slice. -//! * You don't want to decode whole rlp at once. -//! -//!### Use `UntrustedRlp` when: -//! * You are working on untrusted data (~corrupted). //! * You need to handle data corruption errors. //! * You are working on input data. //! * You want to get view onto rlp-slice. @@ -46,7 +40,6 @@ extern crate rustc_hex; mod traits; mod error; mod rlpin; -mod untrusted_rlp; mod stream; mod impls; @@ -55,8 +48,7 @@ use elastic_array::ElasticArray1024; pub use error::DecoderError; pub use traits::{Decodable, Encodable}; -pub use untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; -pub use rlpin::{Rlp, RlpIterator}; +pub use rlpin::{Rlp, RlpIterator, PayloadInfo, Prototype}; pub use stream::RlpStream; /// The RLP encoded empty data (used to mean "null value"). @@ -77,12 +69,12 @@ pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; /// ``` pub fn decode(bytes: &[u8]) -> T where T: Decodable { let rlp = Rlp::new(bytes); - rlp.as_val() + rlp.as_val().expect("trusted rlp should be valid") } pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable { let rlp = Rlp::new(bytes); - rlp.as_list() + rlp.as_list().expect("trusted rlp should be valid") } /// Shortcut function to encode structure into rlp. diff --git a/util/rlp/src/rlpin.rs b/util/rlp/src/rlpin.rs index c9679591308..a55b4f79071 100644 --- a/util/rlp/src/rlpin.rs +++ b/util/rlp/src/rlpin.rs @@ -6,246 +6,295 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::cell::Cell; use std::fmt; -use {UntrustedRlp, PayloadInfo, Prototype, Decodable}; +use rustc_hex::ToHex; +use impls::decode_usize; +use {Decodable, DecoderError}; -impl<'a> From> for Rlp<'a> { - fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { - Rlp { rlp: rlp } +/// rlp offset +#[derive(Copy, Clone, Debug)] +struct OffsetCache { + index: usize, + offset: usize, +} + +impl OffsetCache { + fn new(index: usize, offset: usize) -> OffsetCache { + OffsetCache { + index: index, + offset: offset, + } + } +} + +#[derive(Debug)] +/// RLP prototype +pub enum Prototype { + /// Empty + Null, + /// Value + Data(usize), + /// List + List(usize), +} + +/// Stores basic information about item +pub struct PayloadInfo { + /// Header length in bytes + pub header_len: usize, + /// Value length in bytes + pub value_len: usize, +} + +fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result { + let header_len = 1 + len_of_len; + match header_bytes.get(1) { + Some(&0) => return Err(DecoderError::RlpDataLenWithZeroPrefix), + None => return Err(DecoderError::RlpIsTooShort), + _ => (), } + if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); } + let value_len = decode_usize(&header_bytes[1..header_len])?; + Ok(PayloadInfo::new(header_len, value_len)) } -/// Data-oriented view onto trusted rlp-slice. +impl PayloadInfo { + fn new(header_len: usize, value_len: usize) -> PayloadInfo { + PayloadInfo { + header_len: header_len, + value_len: value_len, + } + } + + /// Total size of the RLP. + pub fn total(&self) -> usize { self.header_len + self.value_len } + + /// Create a new object from the given bytes RLP. The bytes + pub fn from(header_bytes: &[u8]) -> Result { + match header_bytes.first().cloned() { + None => Err(DecoderError::RlpIsTooShort), + Some(0...0x7f) => Ok(PayloadInfo::new(0, 1)), + Some(l @ 0x80...0xb7) => Ok(PayloadInfo::new(1, l as usize - 0x80)), + Some(l @ 0xb8...0xbf) => { + let len_of_len = l as usize - 0xb7; + calculate_payload_info(header_bytes, len_of_len) + } + Some(l @ 0xc0...0xf7) => Ok(PayloadInfo::new(1, l as usize - 0xc0)), + Some(l @ 0xf8...0xff) => { + let len_of_len = l as usize - 0xf7; + calculate_payload_info(header_bytes, len_of_len) + }, + // we cant reach this place, but rust requires _ to be implemented + _ => { unreachable!(); } + } + } +} + +/// Data-oriented view onto rlp-slice. +/// +/// This is an immutable structure. No operations change it. /// -/// Unlikely to `UntrustedRlp` doesn't bother you with error -/// handling. It assumes that you know what you are doing. +/// Should be used in places where, error handling is required, +/// eg. on input #[derive(Debug)] pub struct Rlp<'a> { - rlp: UntrustedRlp<'a> + bytes: &'a [u8], + offset_cache: Cell, + count_cache: Cell>, +} + +impl<'a> Clone for Rlp<'a> { + fn clone(&self) -> Rlp<'a> { + Rlp { + bytes: self.bytes, + offset_cache: self.offset_cache.clone(), + count_cache: self.count_cache.clone(), + } + } } impl<'a> fmt::Display for Rlp<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "{}", self.rlp) + match self.prototype() { + Ok(Prototype::Null) => write!(f, "null"), + Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex()), + Ok(Prototype::List(len)) => { + write!(f, "[")?; + for i in 0..len-1 { + write!(f, "{}, ", self.at(i).unwrap())?; + } + write!(f, "{}", self.at(len - 1).unwrap())?; + write!(f, "]") + }, + Err(err) => write!(f, "{:?}", err) + } } } impl<'a, 'view> Rlp<'a> where 'a: 'view { - /// Create a new instance of `Rlp` pub fn new(bytes: &'a [u8]) -> Rlp<'a> { Rlp { - rlp: UntrustedRlp::new(bytes) + bytes: bytes, + offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), + count_cache: Cell::new(None) } } - /// The raw data of the RLP as slice. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog = rlp.at(1).as_raw(); - /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']); - /// } - /// ``` pub fn as_raw(&'view self) -> &'a [u8] { - self.rlp.as_raw() - } - - /// Get the prototype of the RLP. - pub fn prototype(&self) -> Prototype { - self.rlp.prototype().unwrap() - } - - /// Get payload info. - pub fn payload_info(&self) -> PayloadInfo { - self.rlp.payload_info().unwrap() - } - - /// Get underlieing data. - pub fn data(&'view self) -> &'a [u8] { - self.rlp.data().unwrap() - } - - /// Returns number of RLP items. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.item_count(), 2); - /// let view = rlp.at(1); - /// assert_eq!(view.item_count(), 0); - /// } - /// ``` - pub fn item_count(&self) -> usize { - self.rlp.item_count().unwrap_or(0) - } - - /// Returns the number of bytes in the data, or zero if it isn't data. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.size(), 0); - /// let view = rlp.at(1); - /// assert_eq!(view.size(), 3); - /// } - /// ``` + self.bytes + } + + pub fn prototype(&self) -> Result { + // optimize? && return appropriate errors + if self.is_data() { + Ok(Prototype::Data(self.size())) + } else if self.is_list() { + self.item_count().map(Prototype::List) + } else { + Ok(Prototype::Null) + } + } + + pub fn payload_info(&self) -> Result { + BasicDecoder::payload_info(self.bytes) + } + + pub fn data(&'view self) -> Result<&'a [u8], DecoderError> { + let pi = BasicDecoder::payload_info(self.bytes)?; + Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) + } + + pub fn item_count(&self) -> Result { + match self.is_list() { + true => match self.count_cache.get() { + Some(c) => Ok(c), + None => { + let c = self.iter().count(); + self.count_cache.set(Some(c)); + Ok(c) + } + }, + false => Err(DecoderError::RlpExpectedToBeList), + } + } + pub fn size(&self) -> usize { - self.rlp.size() - } - - /// Get view onto RLP-slice at index. - /// - /// Caches offset to given index, so access to successive - /// slices is faster. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog: String = rlp.at(1).as_val(); - /// assert_eq!(dog, "dog".to_string()); - /// } - /// ``` - pub fn at(&'view self, index: usize) -> Rlp<'a> { - From::from(self.rlp.at(index).unwrap()) - } - - /// No value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_null()); - /// } - /// ``` + match self.is_data() { + // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. + true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0), + false => 0 + } + } + + pub fn at(&'view self, index: usize) -> Result, DecoderError> { + if !self.is_list() { + return Err(DecoderError::RlpExpectedToBeList); + } + + // move to cached position if its index is less or equal to + // current search index, otherwise move to beginning of list + let c = self.offset_cache.get(); + let (mut bytes, to_skip) = match c.index <= index { + true => (Rlp::consume(self.bytes, c.offset)?, index - c.index), + false => (self.consume_list_payload()?, index), + }; + + // skip up to x items + bytes = Rlp::consume_items(bytes, to_skip)?; + + // update the cache + self.offset_cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len())); + + // construct new rlp + let found = BasicDecoder::payload_info(bytes)?; + Ok(Rlp::new(&bytes[0..found.header_len + found.value_len])) + } + pub fn is_null(&self) -> bool { - self.rlp.is_null() - } - - /// Contains a zero-length string or zero-length list. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc0]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_empty()); - /// } - /// ``` + self.bytes.len() == 0 + } + pub fn is_empty(&self) -> bool { - self.rlp.is_empty() - } - - /// List value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_list()); - /// } - /// ``` + !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) + } + pub fn is_list(&self) -> bool { - self.rlp.is_list() - } - - /// String value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.at(1).is_data()); - /// } - /// ``` + !self.is_null() && self.bytes[0] >= 0xc0 + } + pub fn is_data(&self) -> bool { - self.rlp.is_data() - } - - /// Int value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc1, 0x10]; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.is_int(), false); - /// assert_eq!(rlp.at(0).is_int(), true); - /// } - /// ``` + !self.is_null() && self.bytes[0] < 0xc0 + } + pub fn is_int(&self) -> bool { - self.rlp.is_int() - } - - /// Get iterator over rlp-slices - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let strings: Vec = rlp.iter().map(| i | i.as_val()).collect(); - /// } - /// ``` + if self.is_null() { + return false; + } + + match self.bytes[0] { + 0...0x80 => true, + 0x81...0xb7 => self.bytes[1] != 0, + b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0, + _ => false + } + } + pub fn iter(&'view self) -> RlpIterator<'a, 'view> { self.into_iter() } - /// Decode data into an object - pub fn as_val(&self) -> T where T: Decodable { - self.rlp.as_val().expect("Unexpected rlp error") + pub fn as_val(&self) -> Result where T: Decodable { + T::decode(self) } - pub fn as_list(&self) -> Vec where T: Decodable { + pub fn as_list(&self) -> Result, DecoderError> where T: Decodable { self.iter().map(|rlp| rlp.as_val()).collect() } - /// Decode data at given list index into an object - pub fn val_at(&self, index: usize) -> T where T: Decodable { - self.at(index).as_val() + pub fn val_at(&self, index: usize) -> Result where T: Decodable { + self.at(index)?.as_val() + } + + pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable { + self.at(index)?.as_list() } - pub fn list_at(&self, index: usize) -> Vec where T: Decodable { - self.at(index).as_list() + pub fn decoder(&self) -> BasicDecoder { + BasicDecoder::new(self.clone()) + } + + /// consumes first found prefix + fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> { + let item = BasicDecoder::payload_info(self.bytes)?; + let bytes = Rlp::consume(self.bytes, item.header_len)?; + Ok(bytes) + } + + /// consumes fixed number of items + fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> { + let mut result = bytes; + for _ in 0..items { + let i = BasicDecoder::payload_info(result)?; + result = Rlp::consume(result, i.header_len + i.value_len)?; + } + Ok(result) + } + + + /// consumes slice prefix of length `len` + fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { + match bytes.len() >= len { + true => Ok(&bytes[len..]), + false => Err(DecoderError::RlpIsTooShort), + } } } -/// Iterator over trusted rlp-slice list elements. +/// Iterator over rlp-slice list elements. pub struct RlpIterator<'a, 'view> where 'a: 'view { rlp: &'view Rlp<'a>, - index: usize + index: usize, } impl<'a, 'view> IntoIterator for &'view Rlp<'a> where 'a: 'view { @@ -265,19 +314,93 @@ impl<'a, 'view> Iterator for RlpIterator<'a, 'view> { fn next(&mut self) -> Option> { let index = self.index; - let result = self.rlp.rlp.at(index).ok().map(From::from); + let result = self.rlp.at(index).ok(); self.index += 1; result } } -#[test] -fn break_it() { - use rustc_hex::FromHex; - use bigint::U256; +pub struct BasicDecoder<'a> { + rlp: Rlp<'a> +} + +impl<'a> BasicDecoder<'a> { + pub fn new(rlp: Rlp<'a>) -> BasicDecoder<'a> { + BasicDecoder { + rlp: rlp + } + } + + /// Return first item info. + fn payload_info(bytes: &[u8]) -> Result { + let item = PayloadInfo::from(bytes)?; + match item.header_len.checked_add(item.value_len) { + Some(x) if x <= bytes.len() => Ok(item), + _ => Err(DecoderError::RlpIsTooShort), + } + } + + pub fn decode_value(&self, f: F) -> Result + where F: Fn(&[u8]) -> Result { + + let bytes = self.rlp.as_raw(); + + match bytes.first().cloned() { + // RLP is too short. + None => Err(DecoderError::RlpIsTooShort), + // Single byte value. + Some(l @ 0...0x7f) => Ok(f(&[l])?), + // 0-55 bytes + Some(l @ 0x80...0xb7) => { + let last_index_of = 1 + l as usize - 0x80; + if bytes.len() < last_index_of { + return Err(DecoderError::RlpInconsistentLengthAndData); + } + let d = &bytes[1..last_index_of]; + if l == 0x81 && d[0] < 0x80 { + return Err(DecoderError::RlpInvalidIndirection); + } + Ok(f(d)?) + }, + // Longer than 55 bytes. + Some(l @ 0xb8...0xbf) => { + let len_of_len = l as usize - 0xb7; + let begin_of_value = 1 as usize + len_of_len; + if bytes.len() < begin_of_value { + return Err(DecoderError::RlpInconsistentLengthAndData); + } + let len = decode_usize(&bytes[1..begin_of_value])?; + + let last_index_of_value = begin_of_value.checked_add(len) + .ok_or(DecoderError::RlpInvalidLength)?; + if bytes.len() < last_index_of_value { + return Err(DecoderError::RlpInconsistentLengthAndData); + } + Ok(f(&bytes[begin_of_value..last_index_of_value])?) + } + // We are reading value, not a list! + _ => Err(DecoderError::RlpExpectedToBeData) + } + } +} + +#[cfg(test)] +mod tests { + use {Rlp, DecoderError}; - let h: Vec = FromHex::from_hex("f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap(); - let r: Rlp = Rlp::new(&h); - let u: U256 = r.val_at(1); - assert_eq!(format!("{}", u), "19526463837540678066"); + #[test] + fn test_rlp_display() { + use rustc_hex::FromHex; + let data = "f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".from_hex().unwrap(); + let rlp = Rlp::new(&data); + assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); + } + + #[test] + fn length_overflow() { + let bs = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; + let rlp = Rlp::new(&bs); + let res: Result = rlp.as_val(); + assert_eq!(Err(DecoderError::RlpInvalidLength), res); + } } diff --git a/util/rlp/src/traits.rs b/util/rlp/src/traits.rs index 193d0bf84ad..1596009e75f 100644 --- a/util/rlp/src/traits.rs +++ b/util/rlp/src/traits.rs @@ -8,12 +8,12 @@ //! Common RLP traits use elastic_array::ElasticArray1024; -use {DecoderError, UntrustedRlp, RlpStream}; +use {DecoderError, Rlp, RlpStream}; /// RLP decodable trait pub trait Decodable: Sized { /// Decode a value from RLP bytes - fn decode(rlp: &UntrustedRlp) -> Result; + fn decode(rlp: &Rlp) -> Result; } /// Structure encodable to RLP diff --git a/util/rlp/src/untrusted_rlp.rs b/util/rlp/src/untrusted_rlp.rs deleted file mode 100644 index 7f95ce2efed..00000000000 --- a/util/rlp/src/untrusted_rlp.rs +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cell::Cell; -use std::fmt; -use rustc_hex::ToHex; -use impls::decode_usize; -use {Decodable, DecoderError}; - -/// rlp offset -#[derive(Copy, Clone, Debug)] -struct OffsetCache { - index: usize, - offset: usize, -} - -impl OffsetCache { - fn new(index: usize, offset: usize) -> OffsetCache { - OffsetCache { - index: index, - offset: offset, - } - } -} - -#[derive(Debug)] -/// RLP prototype -pub enum Prototype { - /// Empty - Null, - /// Value - Data(usize), - /// List - List(usize), -} - -/// Stores basic information about item -pub struct PayloadInfo { - /// Header length in bytes - pub header_len: usize, - /// Value length in bytes - pub value_len: usize, -} - -fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result { - let header_len = 1 + len_of_len; - match header_bytes.get(1) { - Some(&0) => return Err(DecoderError::RlpDataLenWithZeroPrefix), - None => return Err(DecoderError::RlpIsTooShort), - _ => (), - } - if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); } - let value_len = decode_usize(&header_bytes[1..header_len])?; - Ok(PayloadInfo::new(header_len, value_len)) -} - -impl PayloadInfo { - fn new(header_len: usize, value_len: usize) -> PayloadInfo { - PayloadInfo { - header_len: header_len, - value_len: value_len, - } - } - - /// Total size of the RLP. - pub fn total(&self) -> usize { self.header_len + self.value_len } - - /// Create a new object from the given bytes RLP. The bytes - pub fn from(header_bytes: &[u8]) -> Result { - match header_bytes.first().cloned() { - None => Err(DecoderError::RlpIsTooShort), - Some(0...0x7f) => Ok(PayloadInfo::new(0, 1)), - Some(l @ 0x80...0xb7) => Ok(PayloadInfo::new(1, l as usize - 0x80)), - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - calculate_payload_info(header_bytes, len_of_len) - } - Some(l @ 0xc0...0xf7) => Ok(PayloadInfo::new(1, l as usize - 0xc0)), - Some(l @ 0xf8...0xff) => { - let len_of_len = l as usize - 0xf7; - calculate_payload_info(header_bytes, len_of_len) - }, - // we cant reach this place, but rust requires _ to be implemented - _ => { unreachable!(); } - } - } -} - -/// Data-oriented view onto rlp-slice. -/// -/// This is an immutable structure. No operations change it. -/// -/// Should be used in places where, error handling is required, -/// eg. on input -#[derive(Debug)] -pub struct UntrustedRlp<'a> { - bytes: &'a [u8], - offset_cache: Cell, - count_cache: Cell>, -} - -impl<'a> Clone for UntrustedRlp<'a> { - fn clone(&self) -> UntrustedRlp<'a> { - UntrustedRlp { - bytes: self.bytes, - offset_cache: self.offset_cache.clone(), - count_cache: self.count_cache.clone(), - } - } -} - -impl<'a> fmt::Display for UntrustedRlp<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.prototype() { - Ok(Prototype::Null) => write!(f, "null"), - Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex()), - Ok(Prototype::List(len)) => { - write!(f, "[")?; - for i in 0..len-1 { - write!(f, "{}, ", self.at(i).unwrap())?; - } - write!(f, "{}", self.at(len - 1).unwrap())?; - write!(f, "]") - }, - Err(err) => write!(f, "{:?}", err) - } - } -} - -impl<'a, 'view> UntrustedRlp<'a> where 'a: 'view { - pub fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> { - UntrustedRlp { - bytes: bytes, - offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), - count_cache: Cell::new(None) - } - } - - pub fn as_raw(&'view self) -> &'a [u8] { - self.bytes - } - - pub fn prototype(&self) -> Result { - // optimize? && return appropriate errors - if self.is_data() { - Ok(Prototype::Data(self.size())) - } else if self.is_list() { - self.item_count().map(Prototype::List) - } else { - Ok(Prototype::Null) - } - } - - pub fn payload_info(&self) -> Result { - BasicDecoder::payload_info(self.bytes) - } - - pub fn data(&'view self) -> Result<&'a [u8], DecoderError> { - let pi = BasicDecoder::payload_info(self.bytes)?; - Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) - } - - pub fn item_count(&self) -> Result { - match self.is_list() { - true => match self.count_cache.get() { - Some(c) => Ok(c), - None => { - let c = self.iter().count(); - self.count_cache.set(Some(c)); - Ok(c) - } - }, - false => Err(DecoderError::RlpExpectedToBeList), - } - } - - pub fn size(&self) -> usize { - match self.is_data() { - // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. - true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0), - false => 0 - } - } - - pub fn at(&'view self, index: usize) -> Result, DecoderError> { - if !self.is_list() { - return Err(DecoderError::RlpExpectedToBeList); - } - - // move to cached position if its index is less or equal to - // current search index, otherwise move to beginning of list - let c = self.offset_cache.get(); - let (mut bytes, to_skip) = match c.index <= index { - true => (UntrustedRlp::consume(self.bytes, c.offset)?, index - c.index), - false => (self.consume_list_payload()?, index), - }; - - // skip up to x items - bytes = UntrustedRlp::consume_items(bytes, to_skip)?; - - // update the cache - self.offset_cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len())); - - // construct new rlp - let found = BasicDecoder::payload_info(bytes)?; - Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len])) - } - - pub fn is_null(&self) -> bool { - self.bytes.len() == 0 - } - - pub fn is_empty(&self) -> bool { - !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) - } - - pub fn is_list(&self) -> bool { - !self.is_null() && self.bytes[0] >= 0xc0 - } - - pub fn is_data(&self) -> bool { - !self.is_null() && self.bytes[0] < 0xc0 - } - - pub fn is_int(&self) -> bool { - if self.is_null() { - return false; - } - - match self.bytes[0] { - 0...0x80 => true, - 0x81...0xb7 => self.bytes[1] != 0, - b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0, - _ => false - } - } - - pub fn iter(&'view self) -> UntrustedRlpIterator<'a, 'view> { - self.into_iter() - } - - pub fn as_val(&self) -> Result where T: Decodable { - T::decode(self) - } - - pub fn as_list(&self) -> Result, DecoderError> where T: Decodable { - self.iter().map(|rlp| rlp.as_val()).collect() - } - - pub fn val_at(&self, index: usize) -> Result where T: Decodable { - self.at(index)?.as_val() - } - - pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable { - self.at(index)?.as_list() - } - - pub fn decoder(&self) -> BasicDecoder { - BasicDecoder::new(self.clone()) - } - - /// consumes first found prefix - fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> { - let item = BasicDecoder::payload_info(self.bytes)?; - let bytes = UntrustedRlp::consume(self.bytes, item.header_len)?; - Ok(bytes) - } - - /// consumes fixed number of items - fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> { - let mut result = bytes; - for _ in 0..items { - let i = BasicDecoder::payload_info(result)?; - result = UntrustedRlp::consume(result, i.header_len + i.value_len)?; - } - Ok(result) - } - - - /// consumes slice prefix of length `len` - fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { - match bytes.len() >= len { - true => Ok(&bytes[len..]), - false => Err(DecoderError::RlpIsTooShort), - } - } -} - -/// Iterator over rlp-slice list elements. -pub struct UntrustedRlpIterator<'a, 'view> where 'a: 'view { - rlp: &'view UntrustedRlp<'a>, - index: usize, -} - -impl<'a, 'view> IntoIterator for &'view UntrustedRlp<'a> where 'a: 'view { - type Item = UntrustedRlp<'a>; - type IntoIter = UntrustedRlpIterator<'a, 'view>; - - fn into_iter(self) -> Self::IntoIter { - UntrustedRlpIterator { - rlp: self, - index: 0, - } - } -} - -impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> { - type Item = UntrustedRlp<'a>; - - fn next(&mut self) -> Option> { - let index = self.index; - let result = self.rlp.at(index).ok(); - self.index += 1; - result - } -} - -pub struct BasicDecoder<'a> { - rlp: UntrustedRlp<'a> -} - -impl<'a> BasicDecoder<'a> { - pub fn new(rlp: UntrustedRlp<'a>) -> BasicDecoder<'a> { - BasicDecoder { - rlp: rlp - } - } - - /// Return first item info. - fn payload_info(bytes: &[u8]) -> Result { - let item = PayloadInfo::from(bytes)?; - match item.header_len.checked_add(item.value_len) { - Some(x) if x <= bytes.len() => Ok(item), - _ => Err(DecoderError::RlpIsTooShort), - } - } - - pub fn decode_value(&self, f: F) -> Result - where F: Fn(&[u8]) -> Result { - - let bytes = self.rlp.as_raw(); - - match bytes.first().cloned() { - // RLP is too short. - None => Err(DecoderError::RlpIsTooShort), - // Single byte value. - Some(l @ 0...0x7f) => Ok(f(&[l])?), - // 0-55 bytes - Some(l @ 0x80...0xb7) => { - let last_index_of = 1 + l as usize - 0x80; - if bytes.len() < last_index_of { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - let d = &bytes[1..last_index_of]; - if l == 0x81 && d[0] < 0x80 { - return Err(DecoderError::RlpInvalidIndirection); - } - Ok(f(d)?) - }, - // Longer than 55 bytes. - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - let begin_of_value = 1 as usize + len_of_len; - if bytes.len() < begin_of_value { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - let len = decode_usize(&bytes[1..begin_of_value])?; - - let last_index_of_value = begin_of_value.checked_add(len) - .ok_or(DecoderError::RlpInvalidLength)?; - if bytes.len() < last_index_of_value { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - Ok(f(&bytes[begin_of_value..last_index_of_value])?) - } - // We are reading value, not a list! - _ => Err(DecoderError::RlpExpectedToBeData) - } - } -} - -#[cfg(test)] -mod tests { - use {UntrustedRlp, DecoderError}; - - #[test] - fn test_rlp_display() { - use rustc_hex::FromHex; - let data = "f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".from_hex().unwrap(); - let rlp = UntrustedRlp::new(&data); - assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); - } - - #[test] - fn length_overflow() { - let bs = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; - let rlp = UntrustedRlp::new(&bs); - let res: Result = rlp.as_val(); - assert_eq!(Err(DecoderError::RlpInvalidLength), res); - } -} diff --git a/util/rlp/tests/tests.rs b/util/rlp/tests/tests.rs index 03151c5bf78..6ff426a7739 100644 --- a/util/rlp/tests/tests.rs +++ b/util/rlp/tests/tests.rs @@ -11,13 +11,13 @@ extern crate rlp; use std::{fmt, cmp}; use bigint::{U256, H160}; -use rlp::{Encodable, Decodable, UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Encodable, Decodable, Rlp, RlpStream, DecoderError}; #[test] fn rlp_at() { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); assert!(rlp.is_list()); let animals: Vec = rlp.as_list().unwrap(); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); @@ -43,7 +43,7 @@ fn rlp_at() { fn rlp_at_err() { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o']; { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); assert!(rlp.is_list()); let cat_err = rlp.at(0).unwrap_err(); @@ -58,7 +58,7 @@ fn rlp_at_err() { fn rlp_iter() { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let mut iter = rlp.iter(); let cat = iter.next().unwrap(); @@ -337,7 +337,7 @@ fn decode_untrusted_vector_str() { fn test_rlp_data_length_check() { let data = vec![0x84, b'c', b'a', b't']; - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); @@ -351,7 +351,7 @@ fn test_rlp_long_data_length_check() data.push(b'c'); } - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); @@ -365,7 +365,7 @@ fn test_the_exact_long_string() data.push(b'c'); } - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert!(as_val.is_ok()); @@ -379,7 +379,7 @@ fn test_rlp_2bytes_data_length_check() data.push(b'c'); } - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); @@ -396,7 +396,7 @@ fn test_rlp_nested_empty_list_encode() { #[test] fn test_rlp_list_length_overflow() { let data: Vec = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00]; - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.val_at(0); assert_eq!(Err(DecoderError::RlpIsTooShort), as_val); } diff --git a/util/rlp_compress/src/lib.rs b/util/rlp_compress/src/lib.rs index 89c5e832834..b895e1ce1ac 100644 --- a/util/rlp_compress/src/lib.rs +++ b/util/rlp_compress/src/lib.rs @@ -16,7 +16,7 @@ mod common; use std::cmp; use std::collections::HashMap; use elastic_array::ElasticArray1024; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use common::{SNAPSHOT_SWAPPER, BLOCKS_SWAPPER}; pub fn snapshot_swapper() -> &'static Swapper<'static> { @@ -41,7 +41,7 @@ pub trait Decompressor { /// Call this function to compress rlp. pub fn compress(c: &[u8], swapper: &Compressor) -> ElasticArray1024 { - let rlp = UntrustedRlp::new(c); + let rlp = Rlp::new(c); if rlp.is_data() { ElasticArray1024::from_slice(swapper.compressed(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw())) } else { @@ -51,7 +51,7 @@ pub fn compress(c: &[u8], swapper: &Compressor) -> ElasticArray1024 { /// Call this function to decompress rlp. pub fn decompress(c: &[u8], swapper: &Decompressor) -> ElasticArray1024 { - let rlp = UntrustedRlp::new(c); + let rlp = Rlp::new(c); if rlp.is_data() { ElasticArray1024::from_slice(swapper.decompressed(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw())) } else { @@ -59,7 +59,7 @@ pub fn decompress(c: &[u8], swapper: &Decompressor) -> ElasticArray1024 { } } -fn map_rlp ElasticArray1024>(rlp: &UntrustedRlp, f: F) -> ElasticArray1024 { +fn map_rlp ElasticArray1024>(rlp: &Rlp, f: F) -> ElasticArray1024 { let mut stream = RlpStream::new_list(rlp.item_count().unwrap_or_default()); for subrlp in rlp.iter() { stream.append_raw(&f(&subrlp), 1); diff --git a/util/rlp_derive/src/de.rs b/util/rlp_derive/src/de.rs index 7432d3e2e83..dac4e34cdb3 100644 --- a/util/rlp_derive/src/de.rs +++ b/util/rlp_derive/src/de.rs @@ -35,7 +35,7 @@ pub fn impl_decodable(ast: &syn::DeriveInput) -> quote::Tokens { let dummy_const: syn::Ident = format!("_IMPL_RLP_DECODABLE_FOR_{}", name).into(); let impl_block = quote! { impl rlp::Decodable for #name { - fn decode(rlp: &rlp::UntrustedRlp) -> Result { + fn decode(rlp: &rlp::Rlp) -> Result { let result = #name { #(#stmts)* }; @@ -75,7 +75,7 @@ pub fn impl_decodable_wrapper(ast: &syn::DeriveInput) -> quote::Tokens { let dummy_const: syn::Ident = format!("_IMPL_RLP_DECODABLE_FOR_{}", name).into(); let impl_block = quote! { impl rlp::Decodable for #name { - fn decode(rlp: &rlp::UntrustedRlp) -> Result { + fn decode(rlp: &rlp::Rlp) -> Result { let result = #name { #stmt }; diff --git a/whisper/src/message.rs b/whisper/src/message.rs index 126acebd25a..fbf2faf3fdf 100644 --- a/whisper/src/message.rs +++ b/whisper/src/message.rs @@ -20,7 +20,7 @@ use std::fmt; use std::time::{self, SystemTime, Duration, Instant}; use ethereum_types::{H256, H512}; -use rlp::{self, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{self, DecoderError, RlpStream, Rlp}; use smallvec::SmallVec; use tiny_keccak::{keccak256, Keccak}; @@ -85,7 +85,7 @@ impl rlp::Encodable for Topic { } impl rlp::Decodable for Topic { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use std::cmp; rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&4) { @@ -145,7 +145,7 @@ fn append_topics<'a>(s: &'a mut RlpStream, topics: &[Topic]) -> &'a mut RlpStrea } } -fn decode_topics(rlp: UntrustedRlp) -> Result, DecoderError> { +fn decode_topics(rlp: Rlp) -> Result, DecoderError> { if rlp.is_list() { rlp.iter().map(|r| r.as_val::()).collect() } else { @@ -212,7 +212,7 @@ impl rlp::Encodable for Envelope { } impl rlp::Decodable for Envelope { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.item_count()? != 5 { return Err(DecoderError::RlpIncorrectListLen) } Ok(Envelope { @@ -332,7 +332,7 @@ impl Message { } /// Decode message from RLP and check for validity against system time. - pub fn decode(rlp: UntrustedRlp, now: SystemTime) -> Result { + pub fn decode(rlp: Rlp, now: SystemTime) -> Result { let envelope: Envelope = rlp.as_val()?; let encoded_size = rlp.as_raw().len(); let hash = H256(keccak256(rlp.as_raw())); @@ -418,7 +418,7 @@ impl Message { mod tests { use super::*; use std::time::{self, Duration, SystemTime}; - use rlp::UntrustedRlp; + use rlp::Rlp; use smallvec::SmallVec; fn unix_time(x: u64) -> SystemTime { @@ -481,7 +481,7 @@ mod tests { for i in 0..30 { let now = unix_time(100_000 - i); - Message::decode(UntrustedRlp::new(&*encoded), now).unwrap(); + Message::decode(Rlp::new(&*encoded), now).unwrap(); } } @@ -499,7 +499,7 @@ mod tests { let encoded = ::rlp::encode(&envelope); let now = unix_time(100_000 - 1_000); - Message::decode(UntrustedRlp::new(&*encoded), now).unwrap(); + Message::decode(Rlp::new(&*encoded), now).unwrap(); } #[test] @@ -516,6 +516,6 @@ mod tests { let encoded = ::rlp::encode(&envelope); let now = unix_time(95_000); - Message::decode(UntrustedRlp::new(&*encoded), now).unwrap(); + Message::decode(Rlp::new(&*encoded), now).unwrap(); } } diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index dd5e345bcde..fc6138cf1dd 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -26,7 +26,7 @@ use ethereum_types::{H256, H512}; use network::{self, HostInfo, NetworkContext, NodeId, PeerId, ProtocolId, TimerToken}; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock}; -use rlp::{DecoderError, RlpStream, UntrustedRlp}; +use rlp::{DecoderError, RlpStream, Rlp}; use message::{Message, Error as MessageError}; @@ -506,7 +506,7 @@ impl Network { } // handle status packet from peer. - fn on_status(&self, peer: &PeerId, _status: UntrustedRlp) + fn on_status(&self, peer: &PeerId, _status: Rlp) -> Result<(), Error> { let peers = self.peers.read(); @@ -523,7 +523,7 @@ impl Network { } } - fn on_messages(&self, peer: &PeerId, message_packet: UntrustedRlp) + fn on_messages(&self, peer: &PeerId, message_packet: Rlp) -> Result<(), Error> { let mut messages_vec = { @@ -568,7 +568,7 @@ impl Network { Ok(()) } - fn on_pow_requirement(&self, peer: &PeerId, requirement: UntrustedRlp) + fn on_pow_requirement(&self, peer: &PeerId, requirement: Rlp) -> Result<(), Error> { use byteorder::{ByteOrder, BigEndian}; @@ -604,7 +604,7 @@ impl Network { Ok(()) } - fn on_topic_filter(&self, peer: &PeerId, filter: UntrustedRlp) + fn on_topic_filter(&self, peer: &PeerId, filter: Rlp) -> Result<(), Error> { let peers = self.peers.read(); @@ -661,7 +661,7 @@ impl Network { } fn on_packet(&self, io: &C, peer: &PeerId, packet_id: u8, data: &[u8]) { - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); let res = match packet_id { packet::STATUS => self.on_status(peer, rlp), packet::MESSAGES => self.on_messages(peer, rlp), From 7ce99cfe7b5bf031ef9c25268ca0266b18108fa5 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 02:14:42 +0800 Subject: [PATCH 021/147] Fix TODO comments (#8413) --- rpc/src/v1/types/block.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index d9c1b247c34..2b3a085ca55 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -55,8 +55,7 @@ pub struct Block { pub uncles_hash: H256, /// Authors address pub author: H160, - // TODO: get rid of this one - /// ? + /// Alias of `author` pub miner: H160, /// State root hash #[serde(rename="stateRoot")] From d0a903c1d1c3d60a794169c5f080ac66729fbdc4 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 19 Apr 2018 10:53:14 +0200 Subject: [PATCH 022/147] update zip to 0.3 (#8381) * update zip to 0.3 * enable zip deflate feature --- Cargo.lock | 62 ++++++++++++++++++++++++++++++++++++------------ dapps/Cargo.toml | 2 +- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e78a947eaae..def760f7b57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,8 @@ +[[package]] +name = "adler32" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aho-corasick" version = "0.6.4" @@ -168,6 +173,11 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.1" @@ -250,6 +260,14 @@ dependencies = [ "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam" version = "0.3.2" @@ -1062,11 +1080,11 @@ dependencies = [ [[package]] name = "flate2" -version = "0.2.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1654,12 +1672,23 @@ dependencies = [ ] [[package]] -name = "miniz-sys" -version = "0.1.10" +name = "miniz_oxide" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide_c_api" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1714,12 +1743,11 @@ dependencies = [ [[package]] name = "msdos_time" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2019,7 +2047,7 @@ dependencies = [ "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3723,16 +3751,17 @@ dependencies = [ [[package]] name = "zip" -version = "0.1.19" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] +"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" @@ -3754,6 +3783,7 @@ dependencies = [ "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" "checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" @@ -3761,6 +3791,7 @@ dependencies = [ "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" +"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" @@ -3790,7 +3821,7 @@ dependencies = [ "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" -"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423" +"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" @@ -3846,12 +3877,13 @@ dependencies = [ "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" "checksum mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e3d709ffbb330e1566dc2f2a3c9b58a5ad4a381f740b810cd305dc3f089bc160" "checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae" -"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" +"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398" +"checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" "checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "" "checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "65ba9d75bcea84e07812618fedf284a64776c2f2ea0cad6bca7f69739695a958" +"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" "checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" @@ -4012,4 +4044,4 @@ dependencies = [ "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9cfb54ca6b8f17d2377219ce485b134d53561b77e1393c7ea416f543a527431" -"checksum zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c0deac03fc7d43abcf19f2c2db6bd9289f9ea3d31f350e26eb0ed8b4117983c1" +"checksum zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "10931e278527cea65682696481e6d840371d581079df529ebfee186e0eaad719" diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index fdd497763f1..8e35b213e06 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -22,7 +22,7 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" unicase = "1.4" -zip = { version = "0.1", default-features = false } +zip = { version = "0.3", default-features = false, features = ["deflate"] } itertools = "0.5" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } From a08069c508ba69d156d2b2f0d567aa6c97a80a02 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 19 Apr 2018 17:24:19 +0800 Subject: [PATCH 023/147] typo, docs parity_chainId: empty string -> None (#8434) --- rpc/src/v1/traits/parity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 165cf63d677..83d8b19811c 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -178,7 +178,7 @@ build_rpc_trait! { fn mode(&self) -> Result; /// Returns the chain ID used for transaction signing at the - /// current best block. An empty string is returned if not + /// current best block. None is returned if not /// available. #[rpc(name = "parity_chainId")] fn chain_id(&self) -> Result>; From b00912708837e8e617f30f526d3ba607aa5507d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 19 Apr 2018 11:25:15 +0200 Subject: [PATCH 024/147] Fix receipts stripping. (#8414) --- ethcore/src/block.rs | 28 ++++++++++++++++++---------- ethcore/src/client/client.rs | 13 ++++++++++--- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index e3622c293df..d9f3d27afb0 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -491,6 +491,24 @@ impl ClosedBlock { } impl LockedBlock { + + /// Removes outcomes from receipts and updates the receipt root. + /// + /// This is done after the block is enacted for historical reasons. + /// We allow inconsistency in receipts for some chains if `validate_receipts_transition` + /// is set to non-zero value, so the check only happens if we detect + /// unmatching root first and then fall back to striped receipts. + pub fn strip_receipts_outcomes(&mut self) { + for receipt in &mut self.block.receipts { + receipt.outcome = TransactionOutcome::Unknown; + } + self.block.header.set_receipts_root( + ordered_trie_root(self.block.receipts.iter().map(|r| r.rlp_bytes())) + ); + // compute hash and cache it. + self.block.header.compute_hash(); + } + /// Get the hash of the header without seal arguments. pub fn hash(&self) -> H256 { self.header().bare_hash() } @@ -570,7 +588,6 @@ fn enact( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, - strip_receipts: bool, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { @@ -600,12 +617,6 @@ fn enact( b.push_uncle(u)?; } - if strip_receipts { - for receipt in &mut b.block.receipts { - receipt.outcome = TransactionOutcome::Unknown; - } - } - Ok(b.close_and_lock()) } @@ -619,8 +630,6 @@ pub fn enact_verified( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, - // Remove state root from transaction receipts to make them EIP-98 compatible. - strip_receipts: bool, ) -> Result { let view = view!(BlockView, &block.bytes); @@ -635,7 +644,6 @@ pub fn enact_verified( last_hashes, factories, is_epoch_begin, - strip_receipts, ) } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d2b63b6cdb5..bb7f5894b8c 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -415,7 +415,6 @@ impl Importer { let db = client.state_db.read().boxed_clone_canon(header.parent_hash()); let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some(); - let strip_receipts = header.number() < engine.params().validate_receipts_transition; let enact_result = enact_verified( block, engine, @@ -425,13 +424,21 @@ impl Importer { last_hashes, client.factories.clone(), is_epoch_begin, - strip_receipts, ); - let locked_block = enact_result.map_err(|e| { + let mut locked_block = enact_result.map_err(|e| { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); })?; + // Strip receipts for blocks before validate_receipts_transition, + // if the expected receipts root header does not match. + // (i.e. allow inconsistency in receipts outcome before the transition block) + if header.number() < engine.params().validate_receipts_transition + && header.receipts_root() != locked_block.block().header().receipts_root() + { + locked_block.strip_receipts_outcomes(); + } + // Final Verification if let Err(e) = self.verifier.verify_block_final(&header, locked_block.block().header()) { warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); From 9ca84a825f900f01f67820771b580e3082596f8f Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Thu, 19 Apr 2018 11:26:55 +0200 Subject: [PATCH 025/147] Changelogs for 1.9.6 and 1.10.1 (#8411) * Add changelog for 1.9.6 * Add Changelog for 1.10.1 --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ docs/CHANGELOG-1.9.md | 27 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0f438696b6..2f42b781888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,44 @@ +## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) + +Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. + +The full list of included changes: + +- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350)) + - Bump beta to 1.10.1 + - Unflag critical release +- Backports ([#8346](https://github.com/paritytech/parity/pull/8346)) + - Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) + - Warp-only sync with warp-after [blocknumber] flag. + - Fix tests. + - Fix configuration tests. + - Rename to warp barrier. + - Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) + - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) + - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) + - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) + - Include suicided accounts in state diff + - Shorten form match -> if let + - Test suicide trace diff in State + - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) + - Replace_home for password_files, reserved_peers and log_file + - Typo: arg_log_file is Option + - Enable UI by default, but only display info page. + - Fix test. + - Fix naming and remove old todo. + - Change "wallet" with "browser UI" +- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205)) + - Change name Wallet -> UI + - Make warning bold +- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132)) +- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220)) + - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) + - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203)) +- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181)) + - Updated jsonrpc to include latest backports + - Update dependencies. + ## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22) This is the Parity 1.10.0-beta release! Cool! diff --git a/docs/CHANGELOG-1.9.md b/docs/CHANGELOG-1.9.md index ddb7e9cee1c..0351d611353 100644 --- a/docs/CHANGELOG-1.9.md +++ b/docs/CHANGELOG-1.9.md @@ -1,3 +1,30 @@ +## Parity [v1.9.6](https://github.com/paritytech/parity/releases/tag/v1.9.6) (2018-04-16) + +Parity 1.9.6 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Bump app_dirs, fixes [#8315](https://github.com/paritytech/parity/issues/8315) ([#8355](https://github.com/paritytech/parity/pull/8355)) +- Fix Cargo lock +- Backports ([#8352](https://github.com/paritytech/parity/pull/8352)) + - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) + - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) + - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) + - Include suicided accounts in state diff + - Shorten form match -> if let + - Test suicide trace diff in State + - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) + - Replace_home for password_files, reserved_peers and log_file + - Typo: arg_log_file is Option + - Bump version in util/version +- Bump stable to 1.9.6 ([#8348](https://github.com/paritytech/parity/pull/8348)) +- WASM libraries bump ([#8219](https://github.com/paritytech/parity/pull/8219)) + - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) + - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Updated jsonrpc to include latest backports (1.9) ([#8182](https://github.com/paritytech/parity/pull/8182)) + - Updated jsonrpc to include latest backports (1.9) + - Update dependencies. + ## Parity [v1.9.5](https://github.com/paritytech/parity/releases/tag/v1.9.5) (2018-03-21) Parity 1.9.5 is a bug-fix release to improve performance and stability. This release marks the 1.9 track _stable_. From 23a7dbaf70422a121de16f040700015774425ec8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 19 Apr 2018 10:52:54 +0100 Subject: [PATCH 026/147] Move ethcore::Error to error_chain (#8386) * WIP * Convert Ethcore error to use error_chain * Use error_chain for ImportError and BlockImportError * Fix error pattern matches for error_chain in miner * Implement explicit From for AccountsError * Fix pattern matches for ErrorKinds * Handle ethcore error_chain in light client * Explicitly define Result type to avoid shadowing * Fix remaining Error pattern matches * Fix tab space formatting * Helps if the tests compile * Fix error chain matching after merge --- Cargo.lock | 2 + ethcore/Cargo.toml | 1 + ethcore/light/Cargo.toml | 1 + ethcore/light/src/client/header_chain.rs | 15 +- ethcore/light/src/lib.rs | 2 + ethcore/src/client/client.rs | 10 +- ethcore/src/client/mod.rs | 2 +- ethcore/src/engines/authority_round/mod.rs | 8 +- ethcore/src/engines/mod.rs | 8 +- ethcore/src/engines/tendermint/mod.rs | 18 +- ethcore/src/error.rs | 311 ++++++++------------ ethcore/src/ethereum/ethash.rs | 18 +- ethcore/src/executed.rs | 8 +- ethcore/src/lib.rs | 6 + ethcore/src/miner/miner.rs | 16 +- ethcore/src/snapshot/tests/proof_of_work.rs | 4 +- ethcore/src/snapshot/tests/state.rs | 4 +- ethcore/src/verification/queue/kind.rs | 4 +- ethcore/src/verification/queue/mod.rs | 10 +- ethcore/src/verification/verification.rs | 9 +- ethcore/sync/src/block_sync.rs | 14 +- ethcore/sync/src/chain.rs | 8 +- ethcore/sync/src/light_sync/mod.rs | 6 +- ethcore/transaction/src/error.rs | 8 +- ethkey/src/error.rs | 8 +- parity/blockchain.rs | 6 +- rpc/src/v1/helpers/errors.rs | 10 +- 27 files changed, 246 insertions(+), 271 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index def760f7b57..72c163e4d86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,6 +512,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -613,6 +614,7 @@ name = "ethcore-light" version = "1.11.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-io 1.11.0", diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 69166297581..c9db7cf9f68 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -20,6 +20,7 @@ fetch = { path = "../util/fetch" } hashdb = { path = "../util/hashdb" } memorydb = { path = "../util/memorydb" } patricia-trie = { path = "../util/patricia_trie" } +error-chain = { version = "0.11", default-features = false } ethcore-io = { path = "../util/io" } ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index 9de1ceb9e7a..ba76dc3b104 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -35,6 +35,7 @@ keccak-hash = { path = "../../util/hash" } triehash = { path = "../../util/triehash" } kvdb = { path = "../../util/kvdb" } memory-cache = { path = "../../util/memory_cache" } +error-chain = { version = "0.11", default-features = false } [dev-dependencies] kvdb-memorydb = { path = "../../util/kvdb-memorydb" } diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 7bd13a6c098..abcb04c3662 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -31,7 +31,7 @@ use std::sync::Arc; use cht; use ethcore::block_status::BlockStatus; -use ethcore::error::{Error, BlockImportError, BlockError}; +use ethcore::error::{Error, ErrorKind, BlockImportError, BlockImportErrorKind, BlockError}; use ethcore::encoded; use ethcore::header::Header; use ethcore::ids::BlockId; @@ -260,7 +260,7 @@ impl HeaderChain { let best_block = { let era = match candidates.get(&curr.best_num) { Some(era) => era, - None => return Err(Error::Database("Database corrupt: highest block referenced but no data.".into())), + None => bail!(ErrorKind::Database("Database corrupt: highest block referenced but no data.".into())), }; let best = &era.candidates[0]; @@ -332,8 +332,7 @@ impl HeaderChain { // instantiate genesis epoch data if it doesn't exist. if let None = chain.db.get(col, LAST_CANONICAL_TRANSITION)? { - let genesis_data = spec.genesis_epoch_data() - .map_err(|s| Error::Database(s.into()))?; + let genesis_data = spec.genesis_epoch_data()?; { let mut batch = chain.db.transaction(); @@ -411,7 +410,7 @@ impl HeaderChain { .and_then(|entry| entry.candidates.iter().find(|c| c.hash == parent_hash)) .map(|c| c.total_difficulty) .ok_or_else(|| BlockError::UnknownParent(parent_hash)) - .map_err(BlockImportError::Block)? + .map_err(BlockImportErrorKind::Block)? }; parent_td + *header.difficulty() @@ -580,7 +579,7 @@ impl HeaderChain { } else { let msg = format!("header of block #{} not found in DB ; database in an \ inconsistent state", h_num); - return Err(Error::Database(msg.into())); + bail!(ErrorKind::Database(msg.into())); }; let decoded = header.decode(); @@ -590,7 +589,7 @@ impl HeaderChain { .ok_or_else(|| { let msg = format!("entry for era #{} not found in DB ; database \ in an inconsistent state", h_num); - Error::Database(msg.into()) + ErrorKind::Database(msg.into()) })?; ::rlp::decode(&bytes) }; @@ -600,7 +599,7 @@ impl HeaderChain { .ok_or_else(|| { let msg = "no candidate matching block found in DB ; database in an \ inconsistent state"; - Error::Database(msg.into()) + ErrorKind::Database(msg.into()) })? .total_difficulty; diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index 1ffe0079c18..9723854b8d5 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -80,6 +80,8 @@ extern crate keccak_hash as hash; extern crate triehash; extern crate kvdb; extern crate memory_cache; +#[macro_use] +extern crate error_chain; #[cfg(test)] extern crate kvdb_memorydb; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index bb7f5894b8c..6ec318a03f9 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -49,7 +49,7 @@ use client::{ }; use encoded; use engines::{EthEngine, EpochTransition}; -use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; +use error::{ImportErrorKind, BlockImportErrorKind, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use vm::{EnvInfo, LastHashes}; use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; @@ -1417,11 +1417,11 @@ impl ImportBlock for Client { { if self.chain.read().is_known(&unverified.hash()) { - return Err(BlockImportError::Import(ImportError::AlreadyInChain)); + bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } let status = self.block_status(BlockId::Hash(unverified.parent_hash())); if status == BlockStatus::Unknown || status == BlockStatus::Pending { - return Err(BlockImportError::Block(BlockError::UnknownParent(unverified.parent_hash()))); + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash()))); } } Ok(self.importer.block_queue.import(unverified)?) @@ -1432,11 +1432,11 @@ impl ImportBlock for Client { // check block order let header = view!(BlockView, &block_bytes).header_view(); if self.chain.read().is_known(&header.hash()) { - return Err(BlockImportError::Import(ImportError::AlreadyInChain)); + bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } let status = self.block_status(BlockId::Hash(header.parent_hash())); if status == BlockStatus::Unknown || status == BlockStatus::Pending { - return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash()))); + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(header.parent_hash()))); } } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 8f6b624a5ed..1e4ccba585f 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -48,7 +48,7 @@ pub use types::call_analytics::CallAnalytics; pub use executive::{Executed, Executive, TransactOptions}; pub use vm::{LastHashes, EnvInfo}; -pub use error::{BlockImportError, TransactionImportError}; +pub use error::{BlockImportError, BlockImportErrorKind, TransactionImportError}; pub use verification::VerifierType; mod traits; diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 013445ba35f..387dafd50a4 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1339,7 +1339,7 @@ mod tests { use transaction::{Action, Transaction}; use engines::{Seal, Engine, EngineError, EthEngine}; use engines::validator_set::TestSet; - use error::Error; + use error::{Error, ErrorKind}; use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep}; #[test] @@ -1842,7 +1842,7 @@ mod tests { ]); assert!(match engine.verify_block_family(&header, &parent_header) { - Err(Error::Engine(EngineError::InsufficientProof(ref s))) + Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _)) if s.contains("invalid step") => true, _ => false, }); @@ -1856,7 +1856,7 @@ mod tests { ]); assert!(match engine.verify_block_family(&header, &parent_header) { - Err(Error::Engine(EngineError::InsufficientProof(ref s))) + Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _)) if s.contains("invalid empty step proof") => true, _ => false, }); @@ -1871,7 +1871,7 @@ mod tests { ]); assert!(match engine.verify_block_family(&header, &parent_header) { - Err(Error::Engine(EngineError::InsufficientProof(ref s))) + Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _)) if s.contains("invalid empty step proof") => true, _ => false, }); diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 4d22bd1f76a..3412c483678 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -37,7 +37,7 @@ pub use self::tendermint::Tendermint; use std::sync::{Weak, Arc}; use std::collections::{BTreeMap, HashMap}; -use std::fmt; +use std::{fmt, error}; use self::epoch::PendingTransition; @@ -102,6 +102,12 @@ impl fmt::Display for EngineError { } } +impl error::Error for EngineError { + fn description(&self) -> &str { + "Engine error" + } +} + /// Seal type. #[derive(Debug, PartialEq, Eq)] pub enum Seal { diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 5021ef9865a..289beaad0cc 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -768,7 +768,7 @@ mod tests { use ethereum_types::Address; use bytes::Bytes; use block::*; - use error::{Error, BlockError}; + use error::{Error, ErrorKind, BlockError}; use header::Header; use client::ChainInfo; use miner::MinerService; @@ -855,7 +855,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidSealArity(_)), _)) => {}, Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -885,7 +885,7 @@ mod tests { header.set_seal(seal); // Bad proposer. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::NotProposer(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::NotProposer(_)), _)) => {}, _ => panic!(), } @@ -895,7 +895,7 @@ mod tests { header.set_seal(seal); // Not authority. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::NotAuthorized(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::NotAuthorized(_)), _)) => {}, _ => panic!(), }; engine.stop(); @@ -925,7 +925,7 @@ mod tests { // One good signature is not enough. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::BadSealFieldSize(_)), _)) => {}, _ => panic!(), } @@ -945,7 +945,7 @@ mod tests { // One good and one bad signature. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::NotAuthorized(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::NotAuthorized(_)), _)) => {}, _ => panic!(), }; engine.stop(); @@ -1092,7 +1092,7 @@ mod tests { } else if *s == signature0 { Ok(voter) } else { - Err(Error::Ethkey(EthkeyError::InvalidSignature)) + Err(ErrorKind::Ethkey(EthkeyError::InvalidSignature).into()) } } }, @@ -1100,7 +1100,7 @@ mod tests { // One good signature is not enough. match epoch_verifier.verify_light(&header) { - Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::BadSealFieldSize(_)), _)) => {}, _ => panic!(), } @@ -1117,7 +1117,7 @@ mod tests { // One good and one bad signature. match epoch_verifier.verify_light(&header) { - Err(Error::Ethkey(EthkeyError::InvalidSignature)) => {}, + Err(Error(ErrorKind::Ethkey(EthkeyError::InvalidSignature), _)) => {}, _ => panic!(), }; diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 4c8157a82f1..b68bf355347 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -20,7 +20,7 @@ use std::{fmt, error}; use std::time::SystemTime; use kvdb; use ethereum_types::{H256, U256, Address, Bloom}; -use util_error::UtilError; +use util_error::{self, UtilError}; use snappy::InvalidInput; use unexpected::{Mismatch, OutOfBounds}; use trie::TrieError; @@ -147,45 +147,66 @@ impl fmt::Display for BlockError { } } -#[derive(Debug, Clone, Copy, PartialEq)] -/// Import to the block queue result -pub enum ImportError { - /// Already in the block chain. - AlreadyInChain, - /// Already in the block queue. - AlreadyQueued, - /// Already marked as bad from a previous import (could mean parent is bad). - KnownBad, +impl error::Error for BlockError { + fn description(&self) -> &str { + "Block error" + } } -impl fmt::Display for ImportError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg = match *self { - ImportError::AlreadyInChain => "block already in chain", - ImportError::AlreadyQueued => "block already in the block queue", - ImportError::KnownBad => "block known to be bad", - }; +error_chain! { + types { + ImportError, ImportErrorKind, ImportErrorResultExt, ImportErrorResult; + } + + errors { + #[doc = "Already in the block chain."] + AlreadyInChain { + description("Block already in chain") + display("Block already in chain") + } + + #[doc = "Already in the block queue"] + AlreadyQueued { + description("block already in the block queue") + display("block already in the block queue") + } - f.write_fmt(format_args!("Block import error ({})", msg)) + #[doc = "Already marked as bad from a previous import (could mean parent is bad)."] + KnownBad { + description("block known to be bad") + display("block known to be bad") + } } } -/// Error dedicated to import block function -#[derive(Debug)] -pub enum BlockImportError { - /// Import error - Import(ImportError), - /// Block error - Block(BlockError), - /// Other error - Other(String), + +error_chain! { + types { + BlockImportError, BlockImportErrorKind, BlockImportErrorResultExt; + } + + links { + Import(ImportError, ImportErrorKind) #[doc = "Import error"]; + } + + foreign_links { + Block(BlockError) #[doc = "Block error"]; + } + + errors { + #[doc = "Other error"] + Other(err: String) { + description("Other error") + display("Other error {}", err) + } + } } impl From for BlockImportError { fn from(e: Error) -> Self { match e { - Error::Block(block_error) => BlockImportError::Block(block_error), - Error::Import(import_error) => BlockImportError::Import(import_error), - _ => BlockImportError::Other(format!("other block import error: {:?}", e)), + Error(ErrorKind::Block(block_error), _) => BlockImportErrorKind::Block(block_error).into(), + Error(ErrorKind::Import(import_error), _) => BlockImportErrorKind::Import(import_error.into()).into(), + _ => BlockImportErrorKind::Other(format!("other block import error: {:?}", e)).into(), } } } @@ -202,203 +223,121 @@ pub enum TransactionImportError { impl From for TransactionImportError { fn from(e: Error) -> Self { match e { - Error::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error), + Error(ErrorKind::Transaction(transaction_error), _) => TransactionImportError::Transaction(transaction_error), _ => TransactionImportError::Other(format!("other block import error: {:?}", e)), } } } -#[derive(Debug)] -/// General error type which should be capable of representing all errors in ethcore. -pub enum Error { - /// Client configuration error. - Client(ClientError), - /// Database error. - Database(kvdb::Error), - /// Error concerning a utility. - Util(UtilError), - /// Error concerning block processing. - Block(BlockError), - /// Unknown engine given. - UnknownEngineName(String), - /// Error concerning EVM code execution. - Execution(ExecutionError), - /// Error concerning transaction processing. - Transaction(TransactionError), - /// Error concerning block import. - Import(ImportError), - /// PoW hash is invalid or out of date. - PowHashInvalid, - /// The value of the nonce or mishash is invalid. - PowInvalid, - /// Error concerning TrieDBs - Trie(TrieError), - /// Io crate error. - Io(IoError), - /// Standard io error. - StdIo(::std::io::Error), - /// Snappy error. - Snappy(InvalidInput), - /// Snapshot error. - Snapshot(SnapshotError), - /// Consensus vote error. - Engine(EngineError), - /// Ethkey error. - Ethkey(EthkeyError), - /// Account Provider error. - AccountProvider(AccountsError), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Client(ref err) => err.fmt(f), - Error::Database(ref err) => err.fmt(f), - Error::Util(ref err) => err.fmt(f), - Error::Io(ref err) => err.fmt(f), - Error::Block(ref err) => err.fmt(f), - Error::Execution(ref err) => err.fmt(f), - Error::Transaction(ref err) => err.fmt(f), - Error::Import(ref err) => err.fmt(f), - Error::UnknownEngineName(ref name) => - f.write_fmt(format_args!("Unknown engine name ({})", name)), - Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."), - Error::PowInvalid => f.write_str("Invalid nonce or mishash"), - Error::Trie(ref err) => err.fmt(f), - Error::StdIo(ref err) => err.fmt(f), - Error::Snappy(ref err) => err.fmt(f), - Error::Snapshot(ref err) => err.fmt(f), - Error::Engine(ref err) => err.fmt(f), - Error::Ethkey(ref err) => err.fmt(f), - Error::AccountProvider(ref err) => err.fmt(f), - } +error_chain! { + types { + Error, ErrorKind, ErrorResultExt, EthcoreResult; } -} -impl error::Error for Error { - fn description(&self) -> &str { - // improve description - "ethcore error" + links { + Database(kvdb::Error, kvdb::ErrorKind) #[doc = "Database error."]; + Util(UtilError, util_error::ErrorKind) #[doc = "Error concerning a utility"]; + Import(ImportError, ImportErrorKind) #[doc = "Error concerning block import." ]; } -} - -/// Result of import block operation. -pub type ImportResult = Result; - -impl From for Error { - fn from(err: ClientError) -> Error { - match err { - ClientError::Trie(err) => Error::Trie(err), - _ => Error::Client(err) - } + + foreign_links { + Io(IoError) #[doc = "Io create error"]; + StdIo(::std::io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; + Trie(TrieError) #[doc = "Error concerning TrieDBs."]; + Execution(ExecutionError) #[doc = "Error concerning EVM code execution."]; + Block(BlockError) #[doc = "Error concerning block processing."]; + Transaction(TransactionError) #[doc = "Error concerning transaction processing."]; + Snappy(InvalidInput) #[doc = "Snappy error."]; + Engine(EngineError) #[doc = "Consensus vote error."]; + Ethkey(EthkeyError) #[doc = "Ethkey error."]; } -} -impl From for Error { - fn from(err: kvdb::Error) -> Error { - Error::Database(err) - } -} + errors { + #[doc = "Client configuration error."] + Client(err: ClientError) { + description("Client configuration error.") + display("Client configuration error {}", err) + } -impl From for Error { - fn from(err: TransactionError) -> Error { - Error::Transaction(err) - } -} + #[doc = "Snapshot error."] + Snapshot(err: SnapshotError) { + description("Snapshot error.") + display("Snapshot error {}", err) + } -impl From for Error { - fn from(err: ImportError) -> Error { - Error::Import(err) - } -} + #[doc = "Account Provider error"] + AccountProvider(err: AccountsError) { + description("Accounts Provider error") + display("Accounts Provider error {}", err) + } -impl From for Error { - fn from(err: BlockError) -> Error { - Error::Block(err) - } -} + #[doc = "PoW hash is invalid or out of date."] + PowHashInvalid { + description("PoW hash is invalid or out of date.") + display("PoW hash is invalid or out of date.") + } + + #[doc = "The value of the nonce or mishash is invalid."] + PowInvalid { + description("The value of the nonce or mishash is invalid.") + display("The value of the nonce or mishash is invalid.") + } -impl From for Error { - fn from(err: ExecutionError) -> Error { - Error::Execution(err) + #[doc = "Unknown engine given"] + UnknownEngineName(name: String) { + description("Unknown engine name") + display("Unknown engine name ({})", name) + } } } -impl From<::rlp::DecoderError> for Error { - fn from(err: ::rlp::DecoderError) -> Error { - Error::Util(UtilError::from(err)) - } -} -impl From for Error { - fn from(err: UtilError) -> Error { - Error::Util(err) - } -} +/// Result of import block operation. +pub type ImportResult = EthcoreResult; -impl From for Error { - fn from(err: IoError) -> Error { - Error::Io(err) +impl From for Error { + fn from(err: ClientError) -> Error { + match err { + ClientError::Trie(err) => ErrorKind::Trie(err).into(), + _ => ErrorKind::Client(err).into() + } } } -impl From for Error { - fn from(err: TrieError) -> Error { - Error::Trie(err) - } -} +impl From for Error { + fn from(err: AccountsError) -> Error { + ErrorKind::AccountProvider(err).into() + } +} -impl From<::std::io::Error> for Error { - fn from(err: ::std::io::Error) -> Error { - Error::StdIo(err) +impl From<::rlp::DecoderError> for Error { + fn from(err: ::rlp::DecoderError) -> Error { + UtilError::from(err).into() } } impl From for Error { fn from(err: BlockImportError) -> Error { match err { - BlockImportError::Block(e) => Error::Block(e), - BlockImportError::Import(e) => Error::Import(e), - BlockImportError::Other(s) => Error::Util(UtilError::from(s)), + BlockImportError(BlockImportErrorKind::Block(e), _) => ErrorKind::Block(e).into(), + BlockImportError(BlockImportErrorKind::Import(e), _) => ErrorKind::Import(e).into(), + BlockImportError(BlockImportErrorKind::Other(s), _) => UtilError::from(s).into(), + _ => ErrorKind::Msg(format!("other block import error: {:?}", err)).into(), } } } -impl From<::snappy::InvalidInput> for Error { - fn from(err: ::snappy::InvalidInput) -> Error { - Error::Snappy(err) - } -} - impl From for Error { fn from(err: SnapshotError) -> Error { match err { - SnapshotError::Io(err) => Error::StdIo(err), - SnapshotError::Trie(err) => Error::Trie(err), + SnapshotError::Io(err) => ErrorKind::StdIo(err).into(), + SnapshotError::Trie(err) => ErrorKind::Trie(err).into(), SnapshotError::Decoder(err) => err.into(), - other => Error::Snapshot(other), + other => ErrorKind::Snapshot(other).into(), } } } -impl From for Error { - fn from(err: EngineError) -> Error { - Error::Engine(err) - } -} - -impl From for Error { - fn from(err: EthkeyError) -> Error { - Error::Ethkey(err) - } -} - -impl From for Error { - fn from(err: AccountsError) -> Error { - Error::AccountProvider(err) - } -} - impl From> for Error where Error: From { fn from(err: Box) -> Error { Error::from(*err) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 7d43395286f..09e9caf727b 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -488,7 +488,7 @@ mod tests { use ethereum_types::{H64, H256, U256, Address}; use block::*; use test_helpers::get_temp_state_db; - use error::{BlockError, Error}; + use error::{BlockError, Error, ErrorKind}; use header::Header; use spec::Spec; use engines::Engine; @@ -640,7 +640,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidSealArity(_)), _)) => {}, Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -655,7 +655,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::DifficultyOutOfBounds(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::DifficultyOutOfBounds(_)), _)) => {}, Err(_) => { panic!("should be block difficulty error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -671,7 +671,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidProofOfWork(_)), _)) => {}, Err(_) => { panic!("should be invalid proof of work error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -685,7 +685,7 @@ mod tests { let verify_result = engine.verify_block_unordered(&header); match verify_result { - Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidSealArity(_)), _)) => {}, Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -710,7 +710,7 @@ mod tests { let verify_result = engine.verify_block_unordered(&header); match verify_result { - Err(Error::Block(BlockError::MismatchedH256SealElement(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::MismatchedH256SealElement(_)), _)) => {}, Err(_) => { panic!("should be invalid 256-bit seal fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -726,7 +726,7 @@ mod tests { let verify_result = engine.verify_block_unordered(&header); match verify_result { - Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidProofOfWork(_)), _)) => {}, Err(_) => { panic!("should be invalid proof-of-work fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -741,7 +741,7 @@ mod tests { let verify_result = engine.verify_block_family(&header, &parent_header); match verify_result { - Err(Error::Block(BlockError::RidiculousNumber(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::RidiculousNumber(_)), _)) => {}, Err(_) => { panic!("should be invalid block number fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -758,7 +758,7 @@ mod tests { let verify_result = engine.verify_block_family(&header, &parent_header); match verify_result { - Err(Error::Block(BlockError::InvalidDifficulty(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidDifficulty(_)), _)) => {}, Err(_) => { panic!("should be invalid difficulty fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } diff --git a/ethcore/src/executed.rs b/ethcore/src/executed.rs index a7872093264..9ffd673154d 100644 --- a/ethcore/src/executed.rs +++ b/ethcore/src/executed.rs @@ -24,7 +24,7 @@ use trace::{VMTrace, FlatTrace}; use log_entry::LogEntry; use state_diff::StateDiff; -use std::fmt; +use std::{fmt, error}; /// Transaction execution receipt. #[derive(Debug, PartialEq, Clone)] @@ -148,6 +148,12 @@ impl fmt::Display for ExecutionError { } } +impl error::Error for ExecutionError { + fn description(&self) -> &str { + "Transaction execution error" + } +} + /// Result of executing the transaction. #[derive(PartialEq, Debug, Clone)] pub enum CallError { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 65be24dec0c..9bb2e94c1cc 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -54,6 +54,10 @@ //! cargo build --release //! ``` +// Recursion limit required because of +// error_chain foreign_links. +#![recursion_limit="128"] + extern crate bloomchain; extern crate bn; extern crate byteorder; @@ -112,6 +116,8 @@ extern crate ethabi_derive; #[macro_use] extern crate ethabi_contract; #[macro_use] +extern crate error_chain; +#[macro_use] extern crate log; #[macro_use] extern crate lazy_static; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index e344ee6b12c..76a011343fb 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use ansi_term::Colour; use bytes::Bytes; use engines::{EthEngine, Seal}; -use error::{Error, ExecutionError}; +use error::{Error, ErrorKind, ExecutionError}; use ethcore_miner::gas_pricer::GasPricer; use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy}; use ethcore_miner::work_notify::NotifyWork; @@ -393,7 +393,7 @@ impl Miner { // Re-verify transaction again vs current state. let result = client.verify_signed(&transaction) - .map_err(Error::Transaction) + .map_err(|e| e.into()) .and_then(|_| { open_block.push_transaction(transaction, None) }); @@ -411,7 +411,7 @@ impl Miner { debug!(target: "miner", "Adding tx {:?} took {} ms", hash, took_ms(&took)); match result { - Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) => { + Err(Error(ErrorKind::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas }), _)) => { debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?})", hash, gas_limit, gas_used, gas); // Penalize transaction if it's above current gas limit @@ -436,12 +436,12 @@ impl Miner { }, // Invalid nonce error can happen only if previous transaction is skipped because of gas limit. // If there is errornous state of transaction queue it will be fixed when next block is imported. - Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) => { + Err(Error(ErrorKind::Execution(ExecutionError::InvalidNonce { expected, got }), _)) => { debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got); }, // already have transaction - ignore - Err(Error::Transaction(transaction::Error::AlreadyImported)) => {}, - Err(Error::Transaction(transaction::Error::NotAllowed)) => { + Err(Error(ErrorKind::Transaction(transaction::Error::AlreadyImported), _)) => {}, + Err(Error(ErrorKind::Transaction(transaction::Error::NotAllowed), _)) => { not_allowed_transactions.insert(hash); debug!(target: "miner", "Skipping non-allowed transaction for sender {:?}", hash); }, @@ -981,11 +981,11 @@ impl miner::MinerService for Miner { trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal); b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { warn!(target: "miner", "Mined solution rejected: {}", e); - Err(Error::PowInvalid) + Err(ErrorKind::PowInvalid.into()) }) } else { warn!(target: "miner", "Submitted solution rejected: Block unknown or out of date."); - Err(Error::PowHashInvalid) + Err(ErrorKind::PowHashInvalid.into()) }; result.and_then(|sealed| { diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index e41b61e6e06..ae1805e85bd 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use std::sync::atomic::AtomicBool; use tempdir::TempDir; -use error::Error; +use error::{Error, ErrorKind}; use blockchain::generator::{BlockGenerator, BlockBuilder}; use blockchain::BlockChain; @@ -141,7 +141,7 @@ fn checks_flag() { let mut rebuilder = SNAPSHOT_MODE.rebuilder(chain, db.clone(), &manifest).unwrap(); match rebuilder.feed(&chunk, engine.as_ref(), &AtomicBool::new(false)) { - Err(Error::Snapshot(SnapshotError::RestorationAborted)) => {} + Err(Error(ErrorKind::Snapshot(SnapshotError::RestorationAborted), _)) => {} _ => panic!("Wrong result on abort flag set") } } diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index f61c799933c..f17fa7dde5a 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -26,7 +26,7 @@ use snapshot::{chunk_state, Error as SnapshotError, Progress, StateRebuilder}; use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; use super::helpers::{compare_dbs, StateProducer}; -use error::Error; +use error::{Error, ErrorKind}; use rand::{XorShiftRng, SeedableRng}; use ethereum_types::H256; @@ -189,7 +189,7 @@ fn checks_flag() { let chunk = ::snappy::decompress(&raw).unwrap(); match rebuilder.feed(&chunk, &flag) { - Err(Error::Snapshot(SnapshotError::RestorationAborted)) => {}, + Err(Error(ErrorKind::Snapshot(SnapshotError::RestorationAborted), _)) => {}, _ => panic!("unexpected result when feeding with flag off"), } } diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index 223de30f758..7007da5be1f 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -69,7 +69,7 @@ pub mod blocks { use super::{Kind, BlockLike}; use engines::EthEngine; - use error::{Error, BlockError}; + use error::{Error, ErrorKind, BlockError}; use header::Header; use verification::{PreverifiedBlock, verify_block_basic, verify_block_unordered}; @@ -88,7 +88,7 @@ pub mod blocks { fn create(input: Self::Input, engine: &EthEngine) -> Result { match verify_block_basic(&input.header, &input.bytes, engine) { Ok(()) => Ok(input), - Err(Error::Block(BlockError::TemporarilyInvalid(oob))) => { + Err(Error(ErrorKind::Block(BlockError::TemporarilyInvalid(oob)), _)) => { debug!(target: "client", "Block received too early {}: {:?}", input.hash(), oob); Err(BlockError::TemporarilyInvalid(oob).into()) }, diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index d50bd1cb34c..ca633b0f3de 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -472,17 +472,17 @@ impl VerificationQueue { let h = input.hash(); { if self.processing.read().contains_key(&h) { - return Err(ImportError::AlreadyQueued.into()); + bail!(ErrorKind::Import(ImportErrorKind::AlreadyQueued)); } let mut bad = self.verification.bad.lock(); if bad.contains(&h) { - return Err(ImportError::KnownBad.into()); + bail!(ErrorKind::Import(ImportErrorKind::KnownBad)); } if bad.contains(&input.parent_hash()) { bad.insert(h.clone()); - return Err(ImportError::KnownBad.into()); + bail!(ErrorKind::Import(ImportErrorKind::KnownBad)); } } @@ -502,7 +502,7 @@ impl VerificationQueue { Err(err) => { match err { // Don't mark future blocks as bad. - Error::Block(BlockError::TemporarilyInvalid(_)) => {}, + Error(ErrorKind::Block(BlockError::TemporarilyInvalid(_)), _) => {}, _ => { self.verification.bad.lock().insert(h.clone()); } @@ -773,7 +773,7 @@ mod tests { match duplicate_import { Err(e) => { match e { - Error::Import(ImportError::AlreadyQueued) => {}, + Error(ErrorKind::Import(ImportErrorKind::AlreadyQueued), _) => {}, _ => { panic!("must return AlreadyQueued error"); } } } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index d0bfcc0c7cb..814a12aadfe 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -358,6 +358,7 @@ mod tests { use hash::keccak; use engines::EthEngine; use error::BlockError::*; + use error::ErrorKind; use ethkey::{Random, Generator}; use spec::{CommonParams, Spec}; use test_helpers::{create_test_block_with_data, create_test_block}; @@ -372,7 +373,7 @@ mod tests { fn check_fail(result: Result<(), Error>, e: BlockError) { match result { - Err(Error::Block(ref error)) if *error == e => (), + Err(Error(ErrorKind::Block(ref error), _)) if *error == e => (), Err(other) => panic!("Block verification failed.\nExpected: {:?}\nGot: {:?}", e, other), Ok(_) => panic!("Block verification failed.\nExpected: {:?}\nGot: Ok", e), } @@ -381,8 +382,8 @@ mod tests { fn check_fail_timestamp(result: Result<(), Error>, temp: bool) { let name = if temp { "TemporarilyInvalid" } else { "InvalidTimestamp" }; match result { - Err(Error::Block(BlockError::InvalidTimestamp(_))) if !temp => (), - Err(Error::Block(BlockError::TemporarilyInvalid(_))) if temp => (), + Err(Error(ErrorKind::Block(BlockError::InvalidTimestamp(_)), _)) if !temp => (), + Err(Error(ErrorKind::Block(BlockError::TemporarilyInvalid(_)), _)) if temp => (), Err(other) => panic!("Block verification failed.\nExpected: {}\nGot: {:?}", name, other), Ok(_) => panic!("Block verification failed.\nExpected: {}\nGot: Ok", name), } @@ -716,7 +717,7 @@ mod tests { header.set_gas_limit(0.into()); header.set_difficulty("0000000000000000000000000000000000000000000000000000000000020000".parse::().unwrap()); match family_test(&create_test_block(&header), engine, &bc) { - Err(Error::Block(InvalidGasLimit(_))) => {}, + Err(Error(ErrorKind::Block(InvalidGasLimit(_)), _)) => {}, Err(_) => { panic!("should be invalid difficulty fail"); }, _ => { panic!("Should be error, got Ok"); }, } diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index f7626b0efd9..4a5acae526b 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -25,9 +25,9 @@ use ethereum_types::H256; use rlp::Rlp; use ethcore::views::BlockView; use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockStatus, BlockId, BlockImportError}; +use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind}; use ethcore::block::Block; -use ethcore::error::{ImportError, BlockError}; +use ethcore::error::{ImportErrorKind, BlockError}; use sync_io::SyncIo; use blocks::BlockCollection; @@ -502,11 +502,11 @@ impl BlockDownloader { }; match result { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!(target: "sync", "Block already in chain {:?}", h); self.block_imported(&h, number, &parent); }, - Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { trace!(target: "sync", "Block already queued {:?}", h); self.block_imported(&h, number, &parent); }, @@ -515,14 +515,14 @@ impl BlockDownloader { imported.insert(h.clone()); self.block_imported(&h, number, &parent); }, - Err(BlockImportError::Block(BlockError::UnknownParent(_))) if allow_out_of_order => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(_)), _)) if allow_out_of_order => { break; }, - Err(BlockImportError::Block(BlockError::UnknownParent(_))) => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(_)), _)) => { trace!(target: "sync", "Unknown new block parent, restarting sync"); break; }, - Err(BlockImportError::Block(BlockError::TemporarilyInvalid(_))) => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::TemporarilyInvalid(_)), _)) => { debug!(target: "sync", "Block temporarily invalid, restarting sync"); break; }, diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index bc8e35ed492..eaab13b6f4b 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -101,7 +101,7 @@ use bytes::Bytes; use rlp::{Rlp, RlpStream, DecoderError, Encodable}; use network::{self, PeerId, PacketId}; use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo}; +use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockImportErrorKind, BlockQueueInfo}; use ethcore::error::*; use ethcore::snapshot::{ManifestData, RestorationStatus}; use transaction::SignedTransaction; @@ -943,10 +943,10 @@ impl ChainSync { return Ok(()); } match io.chain().import_block(block_rlp.as_raw().to_vec()) { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!(target: "sync", "New block already in chain {:?}", h); }, - Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { @@ -955,7 +955,7 @@ impl ChainSync { self.new_blocks.mark_as_known(&header.hash(), header.number()); trace!(target: "sync", "New block queued {:?} ({})", h, header.number()); }, - Err(BlockImportError::Block(BlockError::UnknownParent(p))) => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => { unknown = true; trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); }, diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index 0f6660e179f..9fa669817ae 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -427,7 +427,7 @@ impl LightSync { // handles request dispatch, block import, state machine transitions, and timeouts. fn maintain_sync(&self, ctx: &BasicContext) { - use ethcore::error::{BlockImportError, ImportError}; + use ethcore::error::{BlockImportError, BlockImportErrorKind, ImportErrorKind}; const DRAIN_AMOUNT: usize = 128; @@ -457,10 +457,10 @@ impl LightSync { for header in sink.drain(..) { match client.queue_header(header) { Ok(_) => {} - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!(target: "sync", "Block already in chain. Continuing."); }, - Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { trace!(target: "sync", "Block already queued. Continuing."); }, Err(e) => { diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index 4578b88acd0..e38dc3ac675 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; +use std::{fmt, error}; use ethereum_types::U256; use ethkey; @@ -112,3 +112,9 @@ impl fmt::Display for Error { } } +impl error::Error for Error { + fn description(&self) -> &str { + "Transaction error" + } +} + diff --git a/ethkey/src/error.rs b/ethkey/src/error.rs index 0ac2d221a9d..c7faf677880 100644 --- a/ethkey/src/error.rs +++ b/ethkey/src/error.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; +use std::{fmt, error}; #[derive(Debug)] /// Crypto error @@ -51,6 +51,12 @@ impl fmt::Display for Error { } } +impl error::Error for Error { + fn description(&self) -> &str { + "Crypto error" + } +} + impl Into for Error { fn into(self) -> String { format!("{}", self) diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 439f13ba393..f9c2f8ba378 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -27,7 +27,7 @@ use bytes::ToPretty; use rlp::PayloadInfo; use ethcore::account_provider::AccountProvider; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock}; -use ethcore::error::ImportError; +use ethcore::error::{ImportErrorKind, BlockImportErrorKind}; use ethcore::miner::Miner; use ethcore::verification::queue::VerifierSettings; use ethcore_service::ClientService; @@ -257,7 +257,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { } match client.import_header(header) { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!("Skipping block already in chain."); } Err(e) => { @@ -428,7 +428,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { let do_import = |bytes| { while client.queue_info().is_full() { sleep(Duration::from_secs(1)); } match client.import_block(bytes) { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!("Skipping block already in chain."); } Err(e) => { diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index aa660efc9c9..4e5fa2fb72d 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -19,7 +19,7 @@ use std::fmt; use ethcore::account_provider::{SignError as AccountError}; -use ethcore::error::{Error as EthcoreError, CallError}; +use ethcore::error::{Error as EthcoreError, ErrorKind, CallError}; use jsonrpc_core::{futures, Error, ErrorCode, Value}; use rlp::DecoderError; use transaction::Error as TransactionError; @@ -306,10 +306,10 @@ pub fn private_message_block_id_not_supported() -> Error { } } -pub fn transaction_message(error: TransactionError) -> String { +pub fn transaction_message(error: &TransactionError) -> String { use self::TransactionError::*; - match error { + match *error { AlreadyImported => "Transaction with the same hash was already imported.".into(), Old => "Transaction nonce is too low. Try incrementing the nonce.".into(), TooCheapToReplace => { @@ -330,7 +330,7 @@ pub fn transaction_message(error: TransactionError) -> String { GasLimitExceeded { limit, got } => { format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) }, - InvalidSignature(sig) => format!("Invalid signature: {}", sig), + InvalidSignature(ref sig) => format!("Invalid signature: {}", sig), InvalidChainId => "Invalid chain id.".into(), InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), SenderBanned => "Sender is banned in local queue.".into(), @@ -342,7 +342,7 @@ pub fn transaction_message(error: TransactionError) -> String { pub fn transaction>(error: T) -> Error { let error = error.into(); - if let EthcoreError::Transaction(e) = error { + if let ErrorKind::Transaction(ref e) = *error.kind() { Error { code: ErrorCode::ServerError(codes::TRANSACTION_ERROR), message: transaction_message(e), From e53f33b5cfdcbf181d8477f286c2c4ee4812fb47 Mon Sep 17 00:00:00 2001 From: lihuafeng <31607114+EighteenZi@users.noreply.github.com> Date: Thu, 19 Apr 2018 19:16:04 +0800 Subject: [PATCH 027/147] remove From::from. (#8390) * Some tiny modifications. 1. fix some typo in the comment. 2. sort the order of methods in 'impl state::Backend for StateDB` * Remove the clone of code_cache, as it has been done in clone_basic. * remove From::from. It seems not necessary. --- ethcore/src/executive.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) mode change 100644 => 100755 ethcore/src/executive.rs diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs old mode 100644 new mode 100755 index a97ee37081a..142086beb92 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -237,27 +237,27 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let base_gas_required = U256::from(t.gas_required(&schedule)); if t.gas < base_gas_required { - return Err(From::from(ExecutionError::NotEnoughBaseGas { required: base_gas_required, got: t.gas })); + return Err(ExecutionError::NotEnoughBaseGas { required: base_gas_required, got: t.gas }); } if !t.is_unsigned() && check_nonce && schedule.kill_dust != CleanDustMode::Off && !self.state.exists(&sender)? { - return Err(From::from(ExecutionError::SenderMustExist)); + return Err(ExecutionError::SenderMustExist); } let init_gas = t.gas - base_gas_required; // validate transaction nonce if check_nonce && t.nonce != nonce { - return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); + return Err(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }); } // validate if transaction fits into given block if self.info.gas_used + t.gas > self.info.gas_limit { - return Err(From::from(ExecutionError::BlockGasLimitReached { + return Err(ExecutionError::BlockGasLimitReached { gas_limit: self.info.gas_limit, gas_used: self.info.gas_used, gas: t.gas - })); + }); } // TODO: we might need bigints here, or at least check overflows. @@ -268,7 +268,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { // avoid unaffordable transactions let balance512 = U512::from(balance); if balance512 < total_cost { - return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: balance512 })); + return Err(ExecutionError::NotEnoughCash { required: total_cost, got: balance512 }); } let mut substate = Substate::new(); From 8088ebed011c7e7b19028eb2b55003ee6913ae65 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 20 Apr 2018 16:38:30 +0800 Subject: [PATCH 028/147] Use forked app_dirs crate for reverted Windows dir behavior (#8438) * Remove unused appdirs dependency in CLI * Use forked app_dirs crate for reverted Windows dir behavior --- Cargo.lock | 7 +++---- Cargo.toml | 1 - parity/main.rs | 1 - util/dir/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72c163e4d86..fd372304603 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,7 +19,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "app_dirs" version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/paritytech/app-dirs-rs#0b37f9481ce29e9d5174ad185bca695b206368eb" dependencies = [ "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -379,7 +379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "dir" version = "0.1.0" dependencies = [ - "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", ] @@ -1943,7 +1943,6 @@ name = "parity" version = "1.11.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)", @@ -3766,7 +3765,7 @@ dependencies = [ "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" -"checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" +"checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" diff --git a/Cargo.toml b/Cargo.toml index 9daf4fb5586..4237bf545ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,6 @@ toml = "0.4" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -app_dirs = "1.2.1" futures = "0.1" futures-cpupool = "0.1" fdlimit = "0.1" diff --git a/parity/main.rs b/parity/main.rs index 24b53ae2c92..705cf777e7b 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -19,7 +19,6 @@ #![warn(missing_docs)] extern crate ansi_term; -extern crate app_dirs; extern crate ctrlc; extern crate docopt; #[macro_use] diff --git a/util/dir/Cargo.toml b/util/dir/Cargo.toml index 5963833a7ef..e1a13401a25 100644 --- a/util/dir/Cargo.toml +++ b/util/dir/Cargo.toml @@ -6,4 +6,4 @@ authors = ["Parity Technologies "] [dependencies] ethereum-types = "0.3" journaldb = { path = "../journaldb" } -app_dirs = "1.2.1" +app_dirs = { git = "https://github.com/paritytech/app-dirs-rs" } From 7e9466ae8318791ada68103f3275e114580ffbc1 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 20 Apr 2018 18:22:19 +0800 Subject: [PATCH 029/147] Permission fix (#8441) --- ethcore/src/account_provider/mod.rs | 0 ethcore/src/executive.rs | 0 ethcore/src/state/account.rs | 0 ethcore/src/state/mod.rs | 0 ethcore/src/state_db.rs | 0 ethstore/Cargo.toml | 0 ethstore/src/account/crypto.rs | 0 ethstore/src/account/mod.rs | 0 ethstore/src/account/safe_account.rs | 0 ethstore/src/accounts_dir/disk.rs | 0 ethstore/src/accounts_dir/mod.rs | 0 ethstore/src/accounts_dir/vault.rs | 0 ethstore/src/error.rs | 0 ethstore/src/ethstore.rs | 0 ethstore/src/json/vault_file.rs | 0 ethstore/src/json/vault_key_file.rs | 0 ethstore/src/lib.rs | 0 ethstore/src/secret_store.rs | 0 ethstore/tests/api.rs | 0 ethstore/tests/util/transient_dir.rs | 0 20 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 ethcore/src/account_provider/mod.rs mode change 100755 => 100644 ethcore/src/executive.rs mode change 100755 => 100644 ethcore/src/state/account.rs mode change 100755 => 100644 ethcore/src/state/mod.rs mode change 100755 => 100644 ethcore/src/state_db.rs mode change 100755 => 100644 ethstore/Cargo.toml mode change 100755 => 100644 ethstore/src/account/crypto.rs mode change 100755 => 100644 ethstore/src/account/mod.rs mode change 100755 => 100644 ethstore/src/account/safe_account.rs mode change 100755 => 100644 ethstore/src/accounts_dir/disk.rs mode change 100755 => 100644 ethstore/src/accounts_dir/mod.rs mode change 100755 => 100644 ethstore/src/accounts_dir/vault.rs mode change 100755 => 100644 ethstore/src/error.rs mode change 100755 => 100644 ethstore/src/ethstore.rs mode change 100755 => 100644 ethstore/src/json/vault_file.rs mode change 100755 => 100644 ethstore/src/json/vault_key_file.rs mode change 100755 => 100644 ethstore/src/lib.rs mode change 100755 => 100644 ethstore/src/secret_store.rs mode change 100755 => 100644 ethstore/tests/api.rs mode change 100755 => 100644 ethstore/tests/util/transient_dir.rs diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs old mode 100755 new mode 100644 diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml old mode 100755 new mode 100644 diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/account/mod.rs b/ethstore/src/account/mod.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/accounts_dir/disk.rs b/ethstore/src/accounts_dir/disk.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/accounts_dir/mod.rs b/ethstore/src/accounts_dir/mod.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/accounts_dir/vault.rs b/ethstore/src/accounts_dir/vault.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/error.rs b/ethstore/src/error.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/json/vault_file.rs b/ethstore/src/json/vault_file.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/json/vault_key_file.rs b/ethstore/src/json/vault_key_file.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs old mode 100755 new mode 100644 diff --git a/ethstore/tests/api.rs b/ethstore/tests/api.rs old mode 100755 new mode 100644 diff --git a/ethstore/tests/util/transient_dir.rs b/ethstore/tests/util/transient_dir.rs old mode 100755 new mode 100644 From 47103c4553d4ed301fea521833b235326c9eae4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 20 Apr 2018 11:32:00 +0100 Subject: [PATCH 030/147] Block reward contract (#8419) * engine: add block reward contract abi and helper client * aura: add support for block reward contract * engine: test block reward contract client * aura: test block reward contract * engine + aura: add missing docs * engine: share SystemCall type alias * aura: add transition for block reward contract * engine: fix example block reward contract source link and bytecode --- Cargo.lock | 18 +- ...authority_round_block_reward_contract.json | 61 ++++++ ethcore/res/contracts/block_reward.json | 29 +++ ethcore/src/engines/authority_round/mod.rs | 117 ++++++++++- ethcore/src/engines/block_reward.rs | 184 ++++++++++++++++++ ethcore/src/engines/mod.rs | 6 +- ethcore/src/engines/validator_set/mod.rs | 4 +- ethcore/src/spec/spec.rs | 7 + json/src/spec/authority_round.rs | 8 + 9 files changed, 412 insertions(+), 22 deletions(-) create mode 100644 ethcore/res/authority_round_block_reward_contract.json create mode 100644 ethcore/res/contracts/block_reward.json create mode 100644 ethcore/src/engines/block_reward.rs diff --git a/Cargo.lock b/Cargo.lock index fd372304603..547c3c88bdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,7 +462,7 @@ dependencies = [ [[package]] name = "ethabi-contract" -version = "5.0.3" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -514,7 +514,7 @@ dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-bloom-journal 0.1.0", @@ -745,7 +745,7 @@ version = "1.0.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", @@ -780,7 +780,7 @@ version = "1.0.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", @@ -1786,7 +1786,7 @@ name = "node-filter" version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-io 1.11.0", @@ -2084,7 +2084,7 @@ name = "parity-hash-fetch" version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2305,7 +2305,7 @@ name = "parity-updater" version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", @@ -2708,7 +2708,7 @@ name = "registrar" version = "0.0.1" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -3815,7 +3815,7 @@ dependencies = [ "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "" "checksum ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05e33a914b94b763f0a92333e4e5c95c095563f06ef7d6b295b3d3c2cf31e21f" -"checksum ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca2263c24359e827348ac99aa1f2e28ba5bab0d6c0b83941fa252de8a9e9c073" +"checksum ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "210c9e21d164c15b6ef64fe601e0e12a3c84a031d5ef558e38463e53edbd22ed" "checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" "checksum ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3ae691a36ce5d25b433e63128ce5579f4a18457b6a9c849832b2c9e0fec92a" diff --git a/ethcore/res/authority_round_block_reward_contract.json b/ethcore/res/authority_round_block_reward_contract.json new file mode 100644 index 00000000000..e008de117f7 --- /dev/null +++ b/ethcore/res/authority_round_block_reward_contract.json @@ -0,0 +1,61 @@ +{ + "name": "TestAuthorityRoundBlockRewardContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "list": [ + "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e", + "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1" + ] + }, + "immediateTransitions": true, + "emptyStepsTransition": "1", + "maximumEmptySteps": "2", + "blockRewardContractAddress": "0x0000000000000000000000000000000000000042" + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "eip140Transition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0" + }, + "genesis": { + "seal": { + "authorityRound": { + "step": "0x0", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, + "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }, + "0000000000000000000000000000000000000042": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029" + } + } +} diff --git a/ethcore/res/contracts/block_reward.json b/ethcore/res/contracts/block_reward.json new file mode 100644 index 00000000000..9209967f3ac --- /dev/null +++ b/ethcore/res/contracts/block_reward.json @@ -0,0 +1,29 @@ +[ + { + "constant": false, + "inputs": [ + { + "name": "benefactors", + "type": "address[]" + }, + { + "name": "kind", + "type": "uint16[]" + } + ], + "name": "reward", + "outputs": [ + { + "name": "", + "type": "address[]" + }, + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 387dafd50a4..4807d6c3fbb 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -27,6 +27,8 @@ use account_provider::AccountProvider; use block::*; use client::EngineClient; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; +use engines::block_reward; +use engines::block_reward::{BlockRewardContract, RewardKind}; use error::{Error, BlockError}; use ethjson; use machine::{AuxiliaryData, Call, EthereumMachine}; @@ -68,6 +70,10 @@ pub struct AuthorityRoundParams { pub immediate_transitions: bool, /// Block reward in base units. pub block_reward: U256, + /// Block reward contract transition block. + pub block_reward_contract_transition: u64, + /// Block reward contract. + pub block_reward_contract: Option, /// Number of accepted uncles transition block. pub maximum_uncle_count_transition: u64, /// Number of accepted uncles. @@ -95,6 +101,8 @@ impl From for AuthorityRoundParams { validate_step_transition: p.validate_step_transition.map_or(0, Into::into), immediate_transitions: p.immediate_transitions.unwrap_or(false), block_reward: p.block_reward.map_or_else(Default::default, Into::into), + block_reward_contract_transition: p.block_reward_contract_transition.map_or(0, Into::into), + block_reward_contract: p.block_reward_contract_address.map(BlockRewardContract::new), maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into), maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into), empty_steps_transition: p.empty_steps_transition.map_or(u64::max_value(), |n| ::std::cmp::max(n.into(), 1)), @@ -388,6 +396,8 @@ pub struct AuthorityRound { epoch_manager: Mutex, immediate_transitions: bool, block_reward: U256, + block_reward_contract_transition: u64, + block_reward_contract: Option, maximum_uncle_count_transition: u64, maximum_uncle_count: usize, empty_steps_transition: u64, @@ -620,6 +630,8 @@ impl AuthorityRound { epoch_manager: Mutex::new(EpochManager::blank()), immediate_transitions: our_params.immediate_transitions, block_reward: our_params.block_reward, + block_reward_contract_transition: our_params.block_reward_contract_transition, + block_reward_contract: our_params.block_reward_contract, maximum_uncle_count_transition: our_params.maximum_uncle_count_transition, maximum_uncle_count: our_params.maximum_uncle_count, empty_steps_transition: our_params.empty_steps_transition, @@ -970,9 +982,7 @@ impl Engine for AuthorityRound { /// Apply the block reward on finalisation of the block. fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { - use parity_machine::WithBalances; - - let mut rewards = Vec::new(); + let mut benefactors = Vec::new(); if block.header().number() >= self.empty_steps_transition { let empty_steps = if block.header().seal().is_empty() { // this is a new block, calculate rewards based on the empty steps messages we have accumulated @@ -998,17 +1008,33 @@ impl Engine for AuthorityRound { for empty_step in empty_steps { let author = empty_step.author()?; - rewards.push((author, self.block_reward)); + benefactors.push((author, RewardKind::EmptyStep)); } } let author = *block.header().author(); - rewards.push((author, self.block_reward)); + benefactors.push((author, RewardKind::Author)); + + let rewards = match self.block_reward_contract { + Some(ref c) if block.header().number() >= self.block_reward_contract_transition => { + let mut call = |to, data| { + let result = self.machine.execute_as_system( + block, + to, + U256::max_value(), // unbounded gas? maybe make configurable. + Some(data), + ); + result.map_err(|e| format!("{}", e)) + }; - for &(ref author, ref block_reward) in rewards.iter() { - self.machine.add_balance(block, author, block_reward)?; - } - self.machine.note_rewards(block, &rewards, &[]) + c.reward(&benefactors, &mut call)? + }, + _ => { + benefactors.into_iter().map(|(author, _)| (author, self.block_reward)).collect() + }, + }; + + block_reward::apply_block_rewards(&rewards, block, &self.machine) } /// Check the number of seal fields. @@ -1521,6 +1547,8 @@ mod tests { empty_steps_transition: u64::max_value(), maximum_empty_steps: 0, block_reward: Default::default(), + block_reward_contract_transition: 0, + block_reward_contract: Default::default(), }; let aura = { @@ -1563,6 +1591,8 @@ mod tests { empty_steps_transition: u64::max_value(), maximum_empty_steps: 0, block_reward: Default::default(), + block_reward_contract_transition: 0, + block_reward_contract: Default::default(), }; let aura = { @@ -1617,6 +1647,8 @@ mod tests { empty_steps_transition: u64::max_value(), maximum_empty_steps: 0, block_reward: Default::default(), + block_reward_contract_transition: 0, + block_reward_contract: Default::default(), }; let mut c_params = ::spec::CommonParams::default(); @@ -1894,4 +1926,71 @@ mod tests { _ => false, }); } + + #[test] + fn block_reward_contract() { + let spec = Spec::new_test_round_block_reward_contract(); + let tap = Arc::new(AccountProvider::transient_provider()); + + let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap(); + + 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 client = generate_dummy_client_with_spec_and_accounts( + Spec::new_test_round_block_reward_contract, + None, + ); + engine.register_client(Arc::downgrade(&client) as _); + + // step 2 + 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(); + + // since the block is empty it isn't sealed and we generate empty steps + engine.set_signer(tap.clone(), addr1, "1".into()); + assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None); + engine.step(); + + // step 3 + // the signer of the accumulated empty step message should be rewarded + let b2 = OpenBlock::new( + engine, + Default::default(), + false, + db2, + &genesis_header, + last_hashes.clone(), + addr1, + (3141562.into(), 31415620.into()), + vec![], + false, + ).unwrap(); + let addr1_balance = b2.block().state().balance(&addr1).unwrap(); + + // after closing the block `addr1` should be reward twice, one for the included empty step + // message and another for block creation + let b2 = b2.close_and_lock(); + + // the contract rewards (1000 + kind) for each benefactor/reward kind + assert_eq!( + b2.block().state().balance(&addr1).unwrap(), + addr1_balance + (1000 + 0).into() + (1000 + 2).into(), + ) + } } diff --git a/ethcore/src/engines/block_reward.rs b/ethcore/src/engines/block_reward.rs new file mode 100644 index 00000000000..510a5255f5f --- /dev/null +++ b/ethcore/src/engines/block_reward.rs @@ -0,0 +1,184 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use ethabi; +use ethabi::ParamType; +use ethereum_types::{H160, Address, U256}; + +use block::ExecutedBlock; +use error::Error; +use machine::EthereumMachine; +use super::SystemCall; + +use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json"); + +/// The kind of block reward. +/// Depending on the consensus engine the allocated block reward might have +/// different semantics which could lead e.g. to different reward values. +#[repr(u8)] +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum RewardKind { + /// Reward attributed to the block author. + Author = 0, + /// Reward attributed to the block uncle(s). + Uncle = 1, + /// Reward attributed to the author(s) of empty step(s) included in the block (AuthorityRound engine). + EmptyStep = 2, +} + +impl From for u16 { + fn from(reward_kind: RewardKind) -> Self { + reward_kind as u16 + } +} + +/// A client for the block reward contract. +pub struct BlockRewardContract { + /// Address of the contract. + address: Address, + block_reward_contract: block_reward_contract::BlockReward, +} + +impl BlockRewardContract { + /// Create a new block reward contract client targeting the given address. + pub fn new(address: Address) -> BlockRewardContract { + BlockRewardContract { + address, + block_reward_contract: block_reward_contract::BlockReward::default(), + } + } + + /// Calls the block reward contract with the given benefactors list (and associated reward kind) + /// and returns the reward allocation (address - value). The block reward contract *must* be + /// called by the system address so the `caller` must ensure that (e.g. using + /// `machine.execute_as_system`). + pub fn reward( + &self, + benefactors: &[(Address, RewardKind)], + caller: &mut SystemCall, + ) -> Result, Error> { + let reward = self.block_reward_contract.functions().reward(); + + let input = reward.input( + benefactors.iter().map(|&(address, _)| H160::from(address)), + benefactors.iter().map(|&(_, ref reward_kind)| u16::from(*reward_kind)), + ); + + let output = caller(self.address, input) + .map_err(Into::into) + .map_err(::engines::EngineError::FailedSystemCall)?; + + // since this is a non-constant call we can't use ethabi's function output + // deserialization, sadness ensues. + let types = &[ + ParamType::Array(Box::new(ParamType::Address)), + ParamType::Array(Box::new(ParamType::Uint(256))), + ]; + + let tokens = ethabi::decode(types, &output) + .map_err(|err| err.to_string()) + .map_err(::engines::EngineError::FailedSystemCall)?; + + assert!(tokens.len() == 2); + + let addresses = tokens[0].clone().to_array().expect("type checked by ethabi::decode; qed"); + let rewards = tokens[1].clone().to_array().expect("type checked by ethabi::decode; qed"); + + if addresses.len() != rewards.len() { + return Err(::engines::EngineError::FailedSystemCall( + "invalid data returned by reward contract: both arrays must have the same size".into() + ).into()); + } + + let addresses = addresses.into_iter().map(|t| t.to_address().expect("type checked by ethabi::decode; qed")); + let rewards = rewards.into_iter().map(|t| t.to_uint().expect("type checked by ethabi::decode; qed")); + + Ok(addresses.zip(rewards).collect()) + } +} + +/// Applies the given block rewards, i.e. adds the given balance to each benefactors' address. +/// If tracing is enabled the operations are recorded. +pub fn apply_block_rewards(rewards: &[(Address, U256)], block: &mut ExecutedBlock, machine: &EthereumMachine) -> Result<(), Error> { + use parity_machine::WithBalances; + + for &(ref author, ref block_reward) in rewards { + machine.add_balance(block, author, block_reward)?; + } + + machine.note_rewards(block, &rewards, &[]) +} + +#[cfg(test)] +mod test { + use client::PrepareOpenBlock; + use ethereum_types::U256; + use spec::Spec; + use test_helpers::generate_dummy_client_with_spec_and_accounts; + + use super::{BlockRewardContract, RewardKind}; + + #[test] + fn block_reward_contract() { + let client = generate_dummy_client_with_spec_and_accounts( + Spec::new_test_round_block_reward_contract, + None, + ); + + let machine = Spec::new_test_machine(); + + // the spec has a block reward contract defined at the given address + let block_reward_contract = BlockRewardContract::new( + "0000000000000000000000000000000000000042".into(), + ); + + let mut call = |to, data| { + let mut block = client.prepare_open_block( + "0000000000000000000000000000000000000001".into(), + (3141562.into(), 31415620.into()), + vec![], + ); + + let result = machine.execute_as_system( + block.block_mut(), + to, + U256::max_value(), + Some(data), + ); + + result.map_err(|e| format!("{}", e)) + }; + + // if no benefactors are given no rewards are attributed + assert!(block_reward_contract.reward(&vec![], &mut call).unwrap().is_empty()); + + // the contract rewards (1000 + kind) for each benefactor + let benefactors = vec![ + ("0000000000000000000000000000000000000033".into(), RewardKind::Author), + ("0000000000000000000000000000000000000034".into(), RewardKind::Uncle), + ("0000000000000000000000000000000000000035".into(), RewardKind::EmptyStep), + ]; + + let rewards = block_reward_contract.reward(&benefactors, &mut call).unwrap(); + let expected = vec![ + ("0000000000000000000000000000000000000033".into(), U256::from(1000)), + ("0000000000000000000000000000000000000034".into(), U256::from(1000 + 1)), + ("0000000000000000000000000000000000000035".into(), U256::from(1000 + 2)), + ]; + + assert_eq!(expected, rewards); + } +} diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 3412c483678..8556879f95a 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -18,6 +18,7 @@ mod authority_round; mod basic_authority; +mod block_reward; mod instant_seal; mod null_engine; mod signer; @@ -56,7 +57,7 @@ use ethereum_types::{H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; use bytes::Bytes; -/// Default EIP-210 contrat code. +/// Default EIP-210 contract code. /// As defined in https://github.com/ethereum/EIPs/pull/210 pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b"; @@ -119,6 +120,9 @@ pub enum Seal { None, } +/// A system-calling closure. Enacts calls on a block's state from the system address. +pub type SystemCall<'a> = FnMut(Address, Vec) -> Result, String> + 'a; + /// Type alias for a function we can get headers by hash through. pub type Headers<'a, H> = Fn(H256) -> Option + 'a; diff --git a/ethcore/src/engines/validator_set/mod.rs b/ethcore/src/engines/validator_set/mod.rs index de2164f918f..d439c69c2e5 100644 --- a/ethcore/src/engines/validator_set/mod.rs +++ b/ethcore/src/engines/validator_set/mod.rs @@ -38,9 +38,7 @@ pub use self::simple_list::SimpleList; use self::contract::ValidatorContract; use self::safe_contract::ValidatorSafeContract; use self::multi::Multi; - -/// A system-calling closure. Enacts calls on a block's state from the system address. -pub type SystemCall<'a> = FnMut(Address, Bytes) -> Result + 'a; +use super::SystemCall; /// Creates a validator set from spec. pub fn new_validator_set(spec: ValidatorSpec) -> Box { diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index c1fda86672a..7f6d650dd4f 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -848,6 +848,13 @@ impl Spec { load_bundled!("authority_round_empty_steps") } + /// Create a new Spec with AuthorityRound consensus (with empty steps) using a block reward + /// contract. The contract source code can be found at: + /// https://github.com/parity-contracts/block-reward/blob/daf7d44383b6cdb11cb6b953b018648e2b027cfb/contracts/ExampleBlockReward.sol + pub fn new_test_round_block_reward_contract() -> Self { + load_bundled!("authority_round_block_reward_contract") + } + /// Create a new Spec with Tendermint consensus which does internal sealing (not requiring /// work). /// Account keccak("0") and keccak("1") are a authorities. diff --git a/json/src/spec/authority_round.rs b/json/src/spec/authority_round.rs index 4dea4f09899..4ef9368362c 100644 --- a/json/src/spec/authority_round.rs +++ b/json/src/spec/authority_round.rs @@ -16,6 +16,7 @@ //! Authority params deserialization. +use ethereum_types::Address; use uint::Uint; use super::ValidatorSet; @@ -43,6 +44,13 @@ pub struct AuthorityRoundParams { /// Reward per block in wei. #[serde(rename="blockReward")] pub block_reward: Option, + /// Block at which the block reward contract should start being used. + #[serde(rename="blockRewardContractTransition")] + pub block_reward_contract_transition: Option, + /// Block reward contract address (setting the block reward contract + /// overrides the static block reward definition). + #[serde(rename="blockRewardContractAddress")] + pub block_reward_contract_address: Option
, /// Block at which maximum uncle count should be considered. #[serde(rename="maximumUncleCountTransition")] pub maximum_uncle_count_transition: Option, From a855ab976f9fb385acbac5c19987dc0fdfc5ed8c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 20 Apr 2018 18:32:25 +0800 Subject: [PATCH 031/147] Improve VM executor stack size estimation rules (#8439) * Improve VM executor stack size estimation rules * typo: docs add "(Debug build)" comment * Fix an off by one typo and set minimal stack size This avoids the case if `depth_threshold == max_depth`. Usually setting stack size to zero will just rebound it to platform minimal stack size, but we set it here just in case. * Use saturating_sub to avoid potential overflow --- ethcore/src/executive.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 142086beb92..cded6358e8f 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -34,10 +34,21 @@ use transaction::{Action, SignedTransaction}; use crossbeam; pub use executed::{Executed, ExecutionResult}; -/// Roughly estimate what stack size each level of evm depth will use -/// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132) -/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp` -const STACK_SIZE_PER_DEPTH: usize = 24*1024; +#[cfg(debug_assertions)] +/// Roughly estimate what stack size each level of evm depth will use. (Debug build) +const STACK_SIZE_PER_DEPTH: usize = 128 * 1024; + +#[cfg(not(debug_assertions))] +/// Roughly estimate what stack size each level of evm depth will use. +const STACK_SIZE_PER_DEPTH: usize = 24 * 1024; + +#[cfg(debug_assertions)] +/// Entry stack overhead prior to execution. (Debug build) +const STACK_SIZE_ENTRY_OVERHEAD: usize = 100 * 1024; + +#[cfg(not(debug_assertions))] +/// Entry stack overhead prior to execution. +const STACK_SIZE_ENTRY_OVERHEAD: usize = 20 * 1024; /// Returns new address created from address, nonce, and code hash pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option) { @@ -332,12 +343,12 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { tracer: &mut T, vm_tracer: &mut V ) -> vm::Result where T: Tracer, V: VMTracer { - - let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH); + let local_stack_size = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get()); + let depth_threshold = local_stack_size.saturating_sub(STACK_SIZE_ENTRY_OVERHEAD) / STACK_SIZE_PER_DEPTH; let static_call = params.call_type == CallType::StaticCall; // Ordinary execution - keep VM in same thread - if (self.depth + 1) % depth_threshold != 0 { + if self.depth != depth_threshold { let vm_factory = self.state.vm_factory(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); @@ -345,17 +356,15 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { return vm.exec(params, &mut ext).finalize(ext); } - // Start in new thread to reset stack - // TODO [todr] No thread builder yet, so we need to reset once for a while - // https://github.com/aturon/crossbeam/issues/16 + // Start in new thread with stack size needed up to max depth crossbeam::scope(|scope| { let vm_factory = self.state.vm_factory(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); - scope.spawn(move || { + scope.builder().stack_size(::std::cmp::max(schedule.max_depth.saturating_sub(depth_threshold) * STACK_SIZE_PER_DEPTH, local_stack_size)).spawn(move || { let mut vm = vm_factory.create(¶ms, &schedule); vm.exec(params, &mut ext).finalize(ext) - }) + }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() } From 18815ba8c08cc8471e539f475331070fe5205d37 Mon Sep 17 00:00:00 2001 From: Anton Gavrilov Date: Fri, 20 Apr 2018 15:45:53 +0200 Subject: [PATCH 032/147] Private transactions processing error handling (#8431) * Integration test for private transaction returned * Do not interrupt verification in case of errors * Helpers use specified * Review comments fixed --- Cargo.lock | 1 + ethcore/private-tx/src/lib.rs | 11 +- ethcore/sync/Cargo.toml | 1 + ethcore/sync/src/lib.rs | 1 + ethcore/sync/src/res/private_spec.json | 30 +++++ ethcore/sync/src/tests/consensus.rs | 4 +- ethcore/sync/src/tests/helpers.rs | 42 +------ ethcore/sync/src/tests/mod.rs | 1 + ethcore/sync/src/tests/private.rs | 150 +++++++++++++++++++++++++ 9 files changed, 193 insertions(+), 48 deletions(-) create mode 100644 ethcore/sync/src/res/private_spec.json create mode 100644 ethcore/sync/src/tests/private.rs diff --git a/Cargo.lock b/Cargo.lock index 547c3c88bdc..ae38937ba8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -858,6 +858,7 @@ dependencies = [ "ethcore-light 1.11.0", "ethcore-network 1.11.0", "ethcore-network-devp2p 1.11.0", + "ethcore-private-tx 1.0.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 80510938cff..12028ddf121 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -306,11 +306,6 @@ impl Provider where { /// Retrieve and verify the first available private transaction for every sender /// /// TODO [ToDr] It seems that: - /// 1. This method will fail on any error without removing invalid transaction. - /// 2. It means that the transaction will be stuck there forever and we will never be able to make any progress. - /// - /// It might be more sensible to `drain()` transactions from the queue instead and process all of them, - /// possibly printing some errors in case of failures. /// The 3 methods `ready_transaction,get_descriptor,remove` are always used in conjuction so most likely /// can be replaced with a single `drain()` method instead. /// Thanks to this we also don't really need to lock the entire verification for the time of execution. @@ -339,13 +334,11 @@ impl Provider where { trace!("Sending signature for private transaction: {:?}", signed_private_transaction); self.broadcast_signed_private_transaction(signed_private_transaction.rlp_bytes().into_vec()); } else { - trace!("Incorrect type of action for the transaction"); - bail!(ErrorKind::BadTransactonType); + warn!("Incorrect type of action for the transaction"); } }, Err(e) => { - trace!("Cannot retrieve descriptor for transaction with error {:?}", e); - bail!(e); + warn!("Cannot retrieve descriptor for transaction with error {:?}", e); } } verification_queue.remove_private_transaction(&transaction_hash); diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index a09f161e2a9..6930baa101b 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -35,3 +35,4 @@ ipnetwork = "0.12.6" [dev-dependencies] ethkey = { path = "../../ethkey" } kvdb-memorydb = { path = "../../util/kvdb-memorydb" } +ethcore-private-tx = { path = "../private-tx" } diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index bf3b475fc6f..a3e24bdb823 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -46,6 +46,7 @@ extern crate ethcore_light as light; #[cfg(test)] extern crate ethkey; #[cfg(test)] extern crate kvdb_memorydb; #[cfg(test)] extern crate rustc_hex; +#[cfg(test)] extern crate ethcore_private_tx; #[macro_use] extern crate macros; diff --git a/ethcore/sync/src/res/private_spec.json b/ethcore/sync/src/res/private_spec.json new file mode 100644 index 00000000000..f93d754a611 --- /dev/null +++ b/ethcore/sync/src/res/private_spec.json @@ -0,0 +1,30 @@ +{ + "name": "PrivateTransactions", + "engine": { + "instantSeal": null + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x11" + }, + "genesis": { + "seal": { + "generic": "0x0" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x989680" + }, + "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 } } } } + } +} \ No newline at end of file diff --git a/ethcore/sync/src/tests/consensus.rs b/ethcore/sync/src/tests/consensus.rs index 287a61916a4..8825bad2c8c 100644 --- a/ethcore/sync/src/tests/consensus.rs +++ b/ethcore/sync/src/tests/consensus.rs @@ -48,7 +48,7 @@ fn authority_round() { ap.insert_account(s1.secret().clone(), "").unwrap(); let chain_id = Spec::new_test_round().chain_id(); - let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap), false); + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap)); let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them gets lucky to produce a block. @@ -135,7 +135,7 @@ fn tendermint() { ap.insert_account(s1.secret().clone(), "").unwrap(); let chain_id = Spec::new_test_tendermint().chain_id(); - let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap), false); + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap)); let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them issues a proposal. diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 54b62c79a07..086dc503bba 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -33,7 +33,7 @@ use io::{IoChannel, IoContext, IoHandler}; use api::WARP_SYNC_PROTOCOL_ID; use chain::{ChainSync, ETH_PROTOCOL_VERSION_63, PAR_PROTOCOL_VERSION_3}; use SyncConfig; -use private_tx::{NoopPrivateTxHandler, PrivateTxHandler, SimplePrivateTxHandler}; +use private_tx::SimplePrivateTxHandler; pub trait FlushingBlockChainClient: BlockChainClient { fn flush(&self) {} @@ -210,7 +210,7 @@ pub struct EthPeer where C: FlushingBlockChainClient { pub snapshot_service: Arc, pub sync: RwLock, pub queue: RwLock>, - pub private_tx_handler: Arc, + pub private_tx_handler: Arc, pub io_queue: RwLock>, new_blocks_queue: RwLock>, } @@ -335,7 +335,7 @@ impl TestNet> { for _ in 0..n { let chain = TestBlockChainClient::new(); let ss = Arc::new(TestSnapshotService::new()); - let private_tx_handler = Arc::new(NoopPrivateTxHandler); + let private_tx_handler = Arc::new(SimplePrivateTxHandler::default()); let sync = ChainSync::new(config.clone(), &chain, private_tx_handler.clone()); net.peers.push(Arc::new(EthPeer { sync: RwLock::new(sync), @@ -362,8 +362,7 @@ impl TestNet> { n: usize, config: SyncConfig, spec_factory: F, - accounts: Option>, - private_tx_handler: bool, + accounts: Option> ) -> Self where F: Fn() -> Spec { @@ -373,11 +372,7 @@ impl TestNet> { disconnect_events: Vec::new(), }; for _ in 0..n { - if private_tx_handler { - net.add_peer_with_private_config(config.clone(), spec_factory(), accounts.clone()); - } else { - net.add_peer(config.clone(), spec_factory(), accounts.clone()); - } + net.add_peer_with_private_config(config.clone(), spec_factory(), accounts.clone()); } net } @@ -410,33 +405,6 @@ impl TestNet> { //private_provider.add_notify(peer.clone()); self.peers.push(peer); } - - pub fn add_peer(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { - let miner = Arc::new(Miner::new_for_tests(&spec, accounts)); - let client = EthcoreClient::new( - ClientConfig::default(), - &spec, - Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), - miner.clone(), - IoChannel::disconnected(), - ).unwrap(); - - let ss = Arc::new(TestSnapshotService::new()); - let private_tx_handler = Arc::new(NoopPrivateTxHandler); - let sync = ChainSync::new(config, &*client, private_tx_handler.clone()); - let peer = Arc::new(EthPeer { - sync: RwLock::new(sync), - snapshot_service: ss, - queue: RwLock::new(VecDeque::new()), - chain: client, - miner, - private_tx_handler, - io_queue: RwLock::new(VecDeque::new()), - new_blocks_queue: RwLock::new(VecDeque::new()), - }); - peer.chain.add_notify(peer.clone()); - self.peers.push(peer); - } } impl

TestNet

where P: Peer { diff --git a/ethcore/sync/src/tests/mod.rs b/ethcore/sync/src/tests/mod.rs index 8b9059fc135..eb01108286b 100644 --- a/ethcore/sync/src/tests/mod.rs +++ b/ethcore/sync/src/tests/mod.rs @@ -18,6 +18,7 @@ pub mod helpers; pub mod snapshot; mod chain; mod consensus; +mod private; #[cfg(feature = "ipc")] mod rpc; diff --git a/ethcore/sync/src/tests/private.rs b/ethcore/sync/src/tests/private.rs new file mode 100644 index 00000000000..a9e8718e5e7 --- /dev/null +++ b/ethcore/sync/src/tests/private.rs @@ -0,0 +1,150 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use hash::keccak; +use io::{IoHandler, IoChannel}; +use ethcore::client::{BlockChainClient, BlockId, ClientIoMessage}; +use ethcore::spec::Spec; +use ethcore::miner::MinerService; +use ethcore::CreateContractAddress; +use transaction::{Transaction, Action}; +use ethcore::executive::{contract_address}; +use ethcore::test_helpers::{push_block_with_transactions}; +use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor}; +use ethcore::account_provider::AccountProvider; +use ethkey::{KeyPair}; +use tests::helpers::{TestNet, TestIoHandler}; +use rustc_hex::FromHex; +use SyncConfig; + +fn seal_spec() -> Spec { + let spec_data = include_str!("../res/private_spec.json"); + Spec::load(&::std::env::temp_dir(), spec_data.as_bytes()).unwrap() +} + +#[test] +fn send_private_transaction() { + // Setup two clients + let s0 = KeyPair::from_secret_slice(&keccak("1")).unwrap(); + let s1 = KeyPair::from_secret_slice(&keccak("0")).unwrap(); + let ap = Arc::new(AccountProvider::transient_provider()); + ap.insert_account(s0.secret().clone(), "").unwrap(); + ap.insert_account(s1.secret().clone(), "").unwrap(); + + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), seal_spec, Some(ap.clone())); + let client0 = net.peer(0).chain.clone(); + let client1 = net.peer(1).chain.clone(); + let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); + let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); + + net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".to_owned())).unwrap(); + net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); + net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); + net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler0))); + net.peer(1).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1))); + + let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &s0.address(), &0.into(), &[]); + let chain_id = client0.signing_chain_id(); + + // Exhange statuses + net.sync(); + + // Setup private providers + let validator_config = ProviderConfig{ + validator_accounts: vec![s1.address()], + signer_account: None, + passwords: vec!["".into()], + }; + + let signer_config = ProviderConfig{ + validator_accounts: Vec::new(), + signer_account: Some(s0.address()), + passwords: vec!["".into()], + }; + + let pm0 = Arc::new(Provider::new( + client0.clone(), + net.peer(0).miner.clone(), + ap.clone(), + Box::new(NoopEncryptor::default()), + signer_config, + IoChannel::to_handler(Arc::downgrade(&io_handler0)), + ).unwrap()); + pm0.add_notify(net.peers[0].clone()); + + let pm1 = Arc::new(Provider::new( + client1.clone(), + net.peer(1).miner.clone(), + ap.clone(), + Box::new(NoopEncryptor::default()), + validator_config, + IoChannel::to_handler(Arc::downgrade(&io_handler1)), + ).unwrap()); + pm1.add_notify(net.peers[1].clone()); + + // Create and deploy contract + let private_contract_test = "6060604052341561000f57600080fd5b60d88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146046578063bc64b76d14607457600080fd5b3415605057600080fd5b60566098565b60405180826000191660001916815260200191505060405180910390f35b3415607e57600080fd5b6096600480803560001916906020019091905050609e565b005b60005481565b8060008160001916905550505600a165627a7a723058206acbdf4b15ca4c2d43e1b1879b830451a34f1e9d02ff1f2f394d8d857e79d2080029".from_hex().unwrap(); + let mut private_create_tx = Transaction::default(); + private_create_tx.action = Action::Create; + private_create_tx.data = private_contract_test; + private_create_tx.gas = 200000.into(); + let private_create_tx_signed = private_create_tx.sign(&s0.secret(), None); + let validators = vec![s1.address()]; + let (public_tx, _) = pm0.public_creation_transaction(BlockId::Latest, &private_create_tx_signed, &validators, 0.into()).unwrap(); + let public_tx = public_tx.sign(&s0.secret(), chain_id); + + let public_tx_copy = public_tx.clone(); + push_block_with_transactions(&client0, &[public_tx]); + push_block_with_transactions(&client1, &[public_tx_copy]); + + net.sync(); + + //Create private transaction for modifying state + let mut private_tx = Transaction::default(); + private_tx.action = Action::Call(address.clone()); + private_tx.data = "bc64b76d2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); //setX(42) + private_tx.gas = 120000.into(); + private_tx.nonce = 1.into(); + let private_tx = private_tx.sign(&s0.secret(), None); + assert!(pm0.create_private_transaction(private_tx).is_ok()); + + //send private transaction message to validator + net.sync(); + + let validator_handler = net.peer(1).private_tx_handler.clone(); + let received_private_transactions = validator_handler.txs.lock().clone(); + assert_eq!(received_private_transactions.len(), 1); + + //process received private transaction message + let private_transaction = received_private_transactions[0].clone(); + assert!(pm1.import_private_transaction(&private_transaction).is_ok()); + assert!(pm1.on_private_transaction_queued().is_ok()); + + //send signed response + net.sync(); + + let sender_handler = net.peer(0).private_tx_handler.clone(); + let received_signed_private_transactions = sender_handler.signed_txs.lock().clone(); + assert_eq!(received_signed_private_transactions.len(), 1); + + //process signed response + let signed_private_transaction = received_signed_private_transactions[0].clone(); + assert!(pm0.import_signed_private_transaction(&signed_private_transaction).is_ok()); + let local_transactions = net.peer(0).miner.local_transactions(); + assert_eq!(local_transactions.len(), 1); +} \ No newline at end of file From 7df760c4afbbd1af41b7ccc29b528e7040beabbe Mon Sep 17 00:00:00 2001 From: Nikita Chebykin Date: Fri, 20 Apr 2018 15:46:08 +0200 Subject: [PATCH 033/147] Update Cargo hidapi-rs dependency (#8447) --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ae38937ba8e..408a1c22769 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1210,7 +1210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hidapi" version = "0.3.1" -source = "git+https://github.com/paritytech/hidapi-rs#e77ea09c98f29ea8855dd9cd9461125a28ca9125" +source = "git+https://github.com/paritytech/hidapi-rs#70ec4bd1b755ec5dd32ad2be0c8345864147c8bc" dependencies = [ "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", From 36781067d6f0e7f342837ac77ff5f118c7131639 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Sat, 21 Apr 2018 11:24:51 +0200 Subject: [PATCH 034/147] Allow 32 bit pipelines to fail (#8454) * Disable 32bit tragets for gitlab * Rename linux pipelines --- .gitlab-ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f3a8a3f0c1e..3a04125e577 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ cache: paths: - target/ untracked: true -linux-stable: +linux-ubuntu: stage: build image: parity/rust:gitlab-ci only: @@ -31,7 +31,7 @@ linux-stable: paths: - parity.zip name: "stable-x86_64-unknown-linux-gnu_parity" -linux-stable-debian: +linux-debian: stage: build image: parity/rust-debian:gitlab-ci only: @@ -80,6 +80,7 @@ linux-i686: paths: - parity.zip name: "i686-unknown-linux-gnu" + allow_failure: true linux-armv7: stage: build image: parity/rust-armv7:gitlab-ci @@ -96,6 +97,7 @@ linux-armv7: paths: - parity.zip name: "armv7_unknown_linux_gnueabihf_parity" + allow_failure: true linux-arm: stage: build image: parity/rust-arm:gitlab-ci @@ -112,6 +114,7 @@ linux-arm: paths: - parity.zip name: "arm-unknown-linux-gnueabihf_parity" + allow_failure: true linux-aarch64: stage: build image: parity/rust-arm64:gitlab-ci From a50672a14998b2aed0cc5a522b917e113ac6240e Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Sat, 21 Apr 2018 12:27:39 +0300 Subject: [PATCH 035/147] Update wasmi (#8452) --- Cargo.lock | 6 +++--- ethcore/wasm/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 408a1c22769..2b5807fe502 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3627,12 +3627,12 @@ dependencies = [ "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", "pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", - "wasmi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmi" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4033,7 +4033,7 @@ dependencies = [ "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasmi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26b20dbeb7caee04597a5d2c93e2b3e64872c6ea2af732d7ad49dbec44067c35" +"checksum wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb" "checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2" "checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index 2b8075f7413..a39e6ee5292 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -12,4 +12,4 @@ libc = "0.2" pwasm-utils = "0.1" vm = { path = "../vm" } ethcore-logger = { path = "../../logger" } -wasmi = { version = "0.1.2", features = ["opt-in-32bit"] } +wasmi = { version = "0.1.3", features = ["opt-in-32bit"] } From d8383576c15317bfd55ef16aea972012a100ff97 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 21 Apr 2018 17:41:09 +0800 Subject: [PATCH 036/147] Return error in case eth_call returns VM errors (#8448) * Add VMError generator * Return executed exceptions in eth_call --- rpc/src/v1/helpers/errors.rs | 16 ++++++++++++++++ rpc/src/v1/impls/eth.rs | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 4e5fa2fb72d..acff796646e 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -24,6 +24,7 @@ use jsonrpc_core::{futures, Error, ErrorCode, Value}; use rlp::DecoderError; use transaction::Error as TransactionError; use ethcore_private_tx::Error as PrivateTransactionError; +use vm::Error as VMError; mod codes { // NOTE [ToDr] Codes from [-32099, -32000] @@ -375,6 +376,21 @@ pub fn call(error: CallError) -> Error { } } +pub fn vm(error: &VMError, output: &[u8]) -> Error { + use rustc_hex::ToHex; + + let data = match error { + &VMError::Reverted => format!("{} 0x{}", VMError::Reverted, output.to_hex()), + error => format!("{}", error), + }; + + Error { + code: ErrorCode::ServerError(codes::EXECUTION_ERROR), + message: "VM execution error.".into(), + data: Some(Value::String(data)), + } +} + pub fn unknown_block() -> Error { Error { code: ErrorCode::InvalidParams, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index c894f16dfc4..a7ff4916dee 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -859,8 +859,14 @@ impl Eth for EthClient< let result = self.client.call(&signed, Default::default(), &mut state, &header); Box::new(future::done(result - .map(|b| b.output.into()) .map_err(errors::call) + .and_then(|executed| { + match executed.exception { + Some(ref exception) => Err(errors::vm(exception, &executed.output)), + None => Ok(executed) + } + }) + .map(|b| b.output.into()) )) } From 32129b68f450385cd21a1ae91c5d91321e803b86 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Sat, 21 Apr 2018 12:54:48 +0200 Subject: [PATCH 037/147] ParityShell::open `Return result` (#8377) * start * add error handling for winapi * fix typo * fix warnings and windows errors * formatting * Address review comments --- parity/main.rs | 2 +- parity/run.rs | 5 ++--- parity/url.rs | 52 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 705cf777e7b..6774a83864c 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -231,7 +231,7 @@ fn take_spec_name_override() -> Option { #[cfg(windows)] fn global_cleanup() { // We need to cleanup all sockets before spawning another Parity process. This makes shure everything is cleaned up. - // The loop is required because of internal refernce counter for winsock dll. We don't know how many crates we use do + // The loop is required because of internal reference counter for winsock dll. We don't know how many crates we use do // initialize it. There's at least 2 now. for _ in 0.. 10 { unsafe { ::winapi::um::winsock2::WSACleanup(); } diff --git a/parity/run.rs b/parity/run.rs index 6ccd4caf562..f07f67caa83 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -145,7 +145,7 @@ pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, l let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; // Open a browser - url::open(&token.url); + url::open(&token.url).map_err(|e| format!("{}", e))?; // Print a message println!("{}", token.message); Ok(()) @@ -157,10 +157,9 @@ pub fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfigur } let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); - url::open(&url); + url::open(&url).map_err(|e| format!("{}", e))?; Ok(()) } - // node info fetcher for the local store. struct FullNodeInfo { miner: Option>, // TODO: only TXQ needed, just use that after decoupling. diff --git a/parity/url.rs b/parity/url.rs index 4189ae24184..41c4e545831 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -16,33 +16,67 @@ //! Cross-platform open url in default browser +use std; +use std::os::raw::c_int; + +#[allow(unused)] +pub enum Error { + ProcessError(std::io::Error), + WindowsShellExecute(c_int), +} + +impl From for Error { + fn from(err: std::io::Error) -> Self { + Error::ProcessError(err) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match *self { + Error::ProcessError(ref e) => write!(f, "{}", e), + Error::WindowsShellExecute(e) => write!(f, "WindowsShellExecute error: {}", e), + } + } +} + #[cfg(windows)] -pub fn open(url: &str) { +pub fn open(url: &str) -> Result<(), Error> { use std::ffi::CString; use std::ptr; use winapi::um::shellapi::ShellExecuteA; use winapi::um::winuser::SW_SHOWNORMAL as Normal; - unsafe { + const WINDOWS_SHELL_EXECUTE_SUCCESS: c_int = 32; + + let h_instance = unsafe { ShellExecuteA(ptr::null_mut(), CString::new("open").unwrap().as_ptr(), CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), ptr::null(), ptr::null(), - Normal); + Normal) as c_int + }; + + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx + // `ShellExecute` returns a value greater than 32 on success + if h_instance > WINDOWS_SHELL_EXECUTE_SUCCESS { + Ok(()) + } else { + Err(Error::WindowsShellExecute(h_instance)) } } #[cfg(any(target_os="macos", target_os="freebsd"))] -pub fn open(url: &str) { - use std; - let _ = std::process::Command::new("open").arg(url).spawn(); +pub fn open(url: &str) -> Result<(), Error> { + let _ = std::process::Command::new("open").arg(url).spawn()?; + Ok(()) } #[cfg(target_os="linux")] -pub fn open(url: &str) { - use std; - let _ = std::process::Command::new("xdg-open").arg(url).spawn(); +pub fn open(url: &str) -> Result<(), Error> { + let _ = std::process::Command::new("xdg-open").arg(url).spawn()?; + Ok(()) } #[cfg(target_os="android")] From ee4921211ab5aa5b59155abb700430d05fa19a62 Mon Sep 17 00:00:00 2001 From: "Denis S. Soldatov aka General-Beck" Date: Mon, 23 Apr 2018 16:36:08 +0300 Subject: [PATCH 038/147] fix docker build (#8462) --- docker/hub/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/hub/Dockerfile b/docker/hub/Dockerfile index 70d7277800c..71655036e03 100644 --- a/docker/hub/Dockerfile +++ b/docker/hub/Dockerfile @@ -59,7 +59,7 @@ cd /build&&git clone https://github.com/paritytech/parity && \ binutils \ file \ pkg-config \ - dpkg-dev \ + dpkg-dev &&\ rm -rf /var/lib/apt/lists/* # setup ENTRYPOINT EXPOSE 8080 8545 8180 From 596200b6f9e78c737390ba08697050a70bdb9016 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Mon, 23 Apr 2018 15:36:20 +0200 Subject: [PATCH 039/147] Add changelog for 1.9.7 and 1.10.2 (#8460) * Add changelog for 1.9.7 * Add Changelog for 1.10.2 * Apply proper markdown * Run a spellchecker :) * Be pedantic about the 32-bit pipelines :) --- CHANGELOG.md | 25 +++++++++++++++++++++++++ docs/CHANGELOG-1.9.md | 26 ++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f42b781888..6272c32a7e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24) + +Parity 1.10.2 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455)) + - Update Parity beta to 1.10.2 + - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) + - Disable 32-bit targets for Gitlab + - Rename Linux pipelines + - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) + - Fix Cargo.lock +- Backports ([#8450](https://github.com/paritytech/parity/pull/8450)) + - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) + - Remove unused app_dirs dependency in CLI + - Use forked app_dirs crate for reverted Windows dir behavior + - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) + - Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) + - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) + - Improve VM executor stack size estimation rules + - Typo: docs add "(Debug build)" comment + - Fix an off by one typo and set minimal stack size + - Use saturating_sub to avoid potential overflow + ## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. diff --git a/docs/CHANGELOG-1.9.md b/docs/CHANGELOG-1.9.md index 0351d611353..133c93c4770 100644 --- a/docs/CHANGELOG-1.9.md +++ b/docs/CHANGELOG-1.9.md @@ -1,3 +1,29 @@ +## Parity [v1.9.7](https://github.com/paritytech/parity/releases/tag/v1.9.7) (2018-04-23) + +Parity 1.9.7 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Update Parity stable to 1.9.7 + Backports ([#8456](https://github.com/paritytech/parity/pull/8456)) + - Update Parity stable to 1.9.7 + - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) + - Disable 32-bit targets for Gitlab + - Rename Linux pipelines + - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) + - Revert Cargo lock update from master + - Fix Cargo.lock +- Backports ([#8449](https://github.com/paritytech/parity/pull/8449)) + - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) + - Remove unused app_dirs dependency in CLI + - Use forked app_dirs crate for reverted Windows dir behavior + - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) + - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) + - Improve VM executor stack size estimation rules + - Typo: docs add "(Debug build)" comment + - Fix an off by one typo and set minimal stack size + - Use saturating_sub to avoid potential overflow + - Upgrade crossbeam to 0.3 + ## Parity [v1.9.6](https://github.com/paritytech/parity/releases/tag/v1.9.6) (2018-04-16) Parity 1.9.6 is a bug-fix release to improve performance and stability. From 1b48864bdc1db2797fa79512acbd31796af4d0e0 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 24 Apr 2018 15:25:27 +0300 Subject: [PATCH 040/147] fix typos in vm description comment (#8446) --- json/src/vm/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/src/vm/vm.rs b/json/src/vm/vm.rs index c7e33b609a7..8cc01e3bac2 100644 --- a/json/src/vm/vm.rs +++ b/json/src/vm/vm.rs @@ -22,7 +22,7 @@ use hash::H256; use blockchain::State; use vm::{Transaction, Call, Env}; -/// Reporesents vm execution environment before and after exeuction of transaction. +/// Represents vm execution environment before and after execution of transaction. #[derive(Debug, PartialEq, Deserialize)] pub struct Vm { /// Contract calls made internaly by executed transaction. From c1a534b17ea5d562238c05aa4c791a2e333eea8b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 25 Apr 2018 16:00:58 +0800 Subject: [PATCH 041/147] Use rename_all for RichBlock and RichHeader serialization (#8471) * typo: fix a resolved TODO comment * Use rename_all instead of individual renames --- rpc/src/v1/types/block.rs | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 2b3a085ca55..486e3b9c140 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -44,11 +44,11 @@ impl Serialize for BlockTransactions { /// Block representation #[derive(Debug, Serialize)] +#[serde(rename_all="camelCase")] pub struct Block { /// Hash of the block pub hash: Option, /// Hash of the parent - #[serde(rename="parentHash")] pub parent_hash: H256, /// Hash of the uncles #[serde(rename="sha3Uncles")] @@ -58,37 +58,28 @@ pub struct Block { /// Alias of `author` pub miner: H160, /// State root hash - #[serde(rename="stateRoot")] pub state_root: H256, /// Transactions root hash - #[serde(rename="transactionsRoot")] pub transactions_root: H256, /// Transactions receipts root hash - #[serde(rename="receiptsRoot")] pub receipts_root: H256, /// Block number pub number: Option, /// Gas Used - #[serde(rename="gasUsed")] pub gas_used: U256, /// Gas Limit - #[serde(rename="gasLimit")] pub gas_limit: U256, /// Extra data - #[serde(rename="extraData")] pub extra_data: Bytes, /// Logs bloom - #[serde(rename="logsBloom")] pub logs_bloom: Option, /// Timestamp pub timestamp: U256, /// Difficulty pub difficulty: U256, /// Total difficulty - #[serde(rename="totalDifficulty")] pub total_difficulty: Option, /// Seal fields - #[serde(rename="sealFields")] pub seal_fields: Vec, /// Uncles' hashes pub uncles: Vec, @@ -100,49 +91,40 @@ pub struct Block { /// Block header representation. #[derive(Debug, Clone, Serialize, PartialEq, Eq)] +#[serde(rename_all="camelCase")] pub struct Header { /// Hash of the block pub hash: Option, /// Hash of the parent - #[serde(rename="parentHash")] pub parent_hash: H256, /// Hash of the uncles #[serde(rename="sha3Uncles")] pub uncles_hash: H256, /// Authors address pub author: H160, - // TODO: get rid of this one - /// ? + /// Alias of `author` pub miner: H160, /// State root hash - #[serde(rename="stateRoot")] pub state_root: H256, /// Transactions root hash - #[serde(rename="transactionsRoot")] pub transactions_root: H256, /// Transactions receipts root hash - #[serde(rename="receiptsRoot")] pub receipts_root: H256, /// Block number pub number: Option, /// Gas Used - #[serde(rename="gasUsed")] pub gas_used: U256, /// Gas Limit - #[serde(rename="gasLimit")] pub gas_limit: U256, /// Extra data - #[serde(rename="extraData")] pub extra_data: Bytes, /// Logs bloom - #[serde(rename="logsBloom")] pub logs_bloom: H2048, /// Timestamp pub timestamp: U256, /// Difficulty pub difficulty: U256, /// Seal fields - #[serde(rename="sealFields")] pub seal_fields: Vec, /// Size in bytes pub size: Option, From eb9fcbe0dde7de31342ba08c090a99643ca711a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 25 Apr 2018 15:39:46 +0200 Subject: [PATCH 042/147] Don't require write lock when fetching status. (#8481) --- ethcore/sync/src/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 6270bcfd596..c66a1c6a625 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -318,7 +318,7 @@ impl EthSync { impl SyncProvider for EthSync { /// Get sync status fn status(&self) -> EthSyncStatus { - self.eth_handler.sync.write().status() + self.eth_handler.sync.read().status() } /// Get sync peers From e54666b7ba4734eadda2cceb80ca99477757d805 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 25 Apr 2018 16:25:43 +0200 Subject: [PATCH 043/147] Bump master to 1.12 (#8477) * Bump master to 1.12 * Bump crates to 1.12 * Bump mac installer version to 1.12 * Update Gitlab scripts --- .gitlab-ci.yml | 2 +- Cargo.lock | 216 ++++++++++++++++----------------- Cargo.toml | 2 +- dapps/Cargo.toml | 2 +- dapps/ui/Cargo.toml | 2 +- devtools/Cargo.toml | 2 +- ethash/Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- ethcore/light/Cargo.toml | 2 +- ethcore/node_filter/Cargo.toml | 2 +- ethcore/stratum/Cargo.toml | 2 +- ethcore/sync/Cargo.toml | 2 +- hash-fetch/Cargo.toml | 2 +- hw/Cargo.toml | 2 +- ipfs/Cargo.toml | 2 +- logger/Cargo.toml | 2 +- mac/Parity.pkgproj | 2 +- mac/Parity/Info.plist | 2 +- miner/Cargo.toml | 2 +- nsis/installer.nsi | 2 +- price-info/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- scripts/gitlab-build.sh | 2 +- transaction-pool/Cargo.toml | 2 +- updater/Cargo.toml | 2 +- util/io/Cargo.toml | 2 +- util/network-devp2p/Cargo.toml | 2 +- util/network/Cargo.toml | 2 +- util/version/Cargo.toml | 4 +- 29 files changed, 137 insertions(+), 137 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3a04125e577..2c216496f67 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -188,7 +188,7 @@ docker-build: before_script: - docker info script: - - if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi + - if [ "$CI_BUILD_REF_NAME" == "master" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi - echo "Tag:" $DOCKER_TAG - docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity - scripts/docker-build.sh $DOCKER_TAG diff --git a/Cargo.lock b/Cargo.lock index 2b5807fe502..bb7936297e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -478,7 +478,7 @@ dependencies = [ [[package]] name = "ethash" -version = "1.11.0" +version = "1.12.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -504,7 +504,7 @@ dependencies = [ [[package]] name = "ethcore" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "bloomchain 0.2.0", @@ -516,13 +516,13 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 1.11.0", + "ethash 1.12.0", "ethcore-bloom-journal 0.1.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", - "ethcore-stratum 1.11.0", + "ethcore-io 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", + "ethcore-stratum 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", @@ -530,7 +530,7 @@ dependencies = [ "ethstore 0.2.0", "evm 0.1.0", "fetch 0.1.0", - "hardware-wallet 1.11.0", + "hardware-wallet 1.12.0", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -596,11 +596,11 @@ dependencies = [ [[package]] name = "ethcore-devtools" -version = "1.11.0" +version = "1.12.0" [[package]] name = "ethcore-io" -version = "1.11.0" +version = "1.12.0" dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -611,14 +611,14 @@ dependencies = [ [[package]] name = "ethcore-light" -version = "1.11.0" +version = "1.12.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-network 1.11.0", + "ethcore-io 1.12.0", + "ethcore-network 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -648,7 +648,7 @@ dependencies = [ [[package]] name = "ethcore-logger" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -663,12 +663,12 @@ dependencies = [ [[package]] name = "ethcore-miner" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 1.11.0", + "ethash 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -682,21 +682,21 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "price-info 1.11.0", + "price-info 1.12.0", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", - "transaction-pool 1.11.0", + "transaction-pool 1.12.0", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ethcore-network" -version = "1.11.0" +version = "1.12.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", - "ethcore-io 1.11.0", + "ethcore-io 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -706,16 +706,16 @@ dependencies = [ [[package]] name = "ethcore-network-devp2p" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-io 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-network 1.11.0", + "ethcore-io 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-network 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -747,12 +747,12 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-io 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", + "ethcore-io 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", @@ -782,11 +782,11 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-logger 1.11.0", - "ethcore-sync 1.11.0", + "ethcore-logger 1.12.0", + "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -819,10 +819,10 @@ version = "0.1.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", - "ethcore-io 1.11.0", + "ethcore 1.12.0", + "ethcore-io 1.12.0", "ethcore-private-tx 1.0.0", - "ethcore-sync 1.11.0", + "ethcore-sync 1.12.0", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -832,10 +832,10 @@ dependencies = [ [[package]] name = "ethcore-stratum" -version = "1.11.0" +version = "1.12.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -849,15 +849,15 @@ dependencies = [ [[package]] name = "ethcore-sync" -version = "1.11.0" +version = "1.12.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-light 1.11.0", - "ethcore-network 1.11.0", - "ethcore-network-devp2p 1.11.0", + "ethcore-io 1.12.0", + "ethcore-light 1.12.0", + "ethcore-network 1.12.0", + "ethcore-network-devp2p 1.12.0", "ethcore-private-tx 1.0.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1024,7 +1024,7 @@ name = "evmbin" version = "0.1.0" dependencies = [ "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1165,7 +1165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hardware-wallet" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -1330,7 +1330,7 @@ name = "journaldb" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1784,14 +1784,14 @@ dependencies = [ [[package]] name = "node-filter" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", - "ethcore-io 1.11.0", - "ethcore-network-devp2p 1.11.0", + "ethcore 1.12.0", + "ethcore-io 1.12.0", + "ethcore-network-devp2p 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1941,7 +1941,7 @@ dependencies = [ [[package]] name = "parity" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1951,18 +1951,18 @@ dependencies = [ "dir 0.1.0", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-light 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", - "ethcore-network 1.11.0", + "ethcore-io 1.12.0", + "ethcore-light 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", + "ethcore-network 1.12.0", "ethcore-private-tx 1.0.0", "ethcore-secretstore 1.0.0", "ethcore-service 0.1.0", - "ethcore-stratum 1.11.0", - "ethcore-sync 1.11.0", + "ethcore-stratum 1.12.0", + "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -1979,20 +1979,20 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", "migration-rocksdb 0.1.0", - "node-filter 1.11.0", + "node-filter 1.12.0", "node-health 0.1.0", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", - "parity-dapps 1.11.0", - "parity-hash-fetch 1.11.0", - "parity-ipfs-api 1.11.0", + "parity-dapps 1.12.0", + "parity-hash-fetch 1.12.0", + "parity-ipfs-api 1.12.0", "parity-local-store 0.1.0", "parity-reactor 0.1.0", - "parity-rpc 1.11.0", + "parity-rpc 1.12.0", "parity-rpc-client 1.4.0", - "parity-updater 1.11.0", - "parity-version 1.11.0", + "parity-updater 1.12.0", + "parity-version 1.12.0", "parity-whisper 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "path 0.1.0", @@ -2017,12 +2017,12 @@ dependencies = [ [[package]] name = "parity-dapps" -version = "1.11.0" +version = "1.12.0" dependencies = [ "base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethcore-devtools 1.11.0", + "ethcore-devtools 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2036,11 +2036,11 @@ dependencies = [ "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", "node-health 0.1.0", "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-hash-fetch 1.11.0", + "parity-hash-fetch 1.12.0", "parity-reactor 0.1.0", - "parity-ui 1.11.0", + "parity-ui 1.12.0", "parity-ui-deprecation 1.10.0", - "parity-version 1.11.0", + "parity-version 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "registrar 0.0.1", @@ -2082,7 +2082,7 @@ dependencies = [ [[package]] name = "parity-hash-fetch" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2107,10 +2107,10 @@ dependencies = [ [[package]] name = "parity-ipfs-api" -version = "1.11.0" +version = "1.12.0" dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2124,8 +2124,8 @@ dependencies = [ name = "parity-local-store" version = "0.1.0" dependencies = [ - "ethcore 1.11.0", - "ethcore-io 1.11.0", + "ethcore 1.12.0", + "ethcore-io 1.12.0", "ethcore-transaction 0.1.0", "ethkey 0.3.0", "kvdb 0.1.0", @@ -2154,22 +2154,22 @@ dependencies = [ [[package]] name = "parity-rpc" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 1.11.0", - "ethcore 1.11.0", + "ethash 1.12.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-devtools 1.11.0", - "ethcore-io 1.11.0", - "ethcore-light 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", - "ethcore-network 1.11.0", + "ethcore-devtools 1.12.0", + "ethcore-io 1.12.0", + "ethcore-light 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", + "ethcore-network 1.12.0", "ethcore-private-tx 1.0.0", - "ethcore-sync 1.11.0", + "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", @@ -2179,7 +2179,7 @@ dependencies = [ "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "hardware-wallet 1.11.0", + "hardware-wallet 1.12.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2195,8 +2195,8 @@ dependencies = [ "node-health 0.1.0", "order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", - "parity-updater 1.11.0", - "parity-version 1.11.0", + "parity-updater 1.12.0", + "parity-version 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2212,7 +2212,7 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "transaction-pool 1.11.0", + "transaction-pool 1.12.0", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -2227,7 +2227,7 @@ dependencies = [ "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-rpc 1.11.0", + "parity-rpc 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2253,7 +2253,7 @@ dependencies = [ [[package]] name = "parity-ui" -version = "1.11.0" +version = "1.12.0" dependencies = [ "parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)", "parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)", @@ -2303,21 +2303,21 @@ dependencies = [ [[package]] name = "parity-updater" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-sync 1.11.0", + "ethcore-sync 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-hash-fetch 1.11.0", - "parity-version 1.11.0", + "parity-hash-fetch 1.12.0", + "parity-version 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "path 0.1.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2328,7 +2328,7 @@ dependencies = [ [[package]] name = "parity-version" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethcore-bytes 0.1.0", "rlp 0.2.1", @@ -2355,7 +2355,7 @@ dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", - "ethcore-network 1.11.0", + "ethcore-network 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2418,7 +2418,7 @@ version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "keccak-hash 0.1.0", @@ -2493,7 +2493,7 @@ dependencies = [ [[package]] name = "price-info" -version = "1.11.0" +version = "1.12.0" dependencies = [ "fake-fetch 0.0.1", "fetch 0.1.0", @@ -2573,7 +2573,7 @@ name = "pwasm-run-test" version = "0.1.0" dependencies = [ "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2802,7 +2802,7 @@ version = "1.4.0" dependencies = [ "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-rpc 1.11.0", + "parity-rpc 1.12.0", "parity-rpc-client 1.4.0", "rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3415,7 +3415,7 @@ dependencies = [ [[package]] name = "transaction-pool" -version = "1.11.0" +version = "1.12.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3620,7 +3620,7 @@ name = "wasm" version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3663,9 +3663,9 @@ name = "whisper-cli" version = "0.1.0" dependencies = [ "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", - "ethcore-network 1.11.0", - "ethcore-network-devp2p 1.11.0", + "ethcore-logger 1.12.0", + "ethcore-network 1.12.0", + "ethcore-network-devp2p 1.12.0", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", diff --git a/Cargo.toml b/Cargo.toml index 4237bf545ff..a611458e653 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ description = "Parity Ethereum client" name = "parity" # NOTE Make sure to update util/version/Cargo.toml as well -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 8e35b213e06..a7ce5a54893 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity Dapps crate" name = "parity-dapps" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/dapps/ui/Cargo.toml b/dapps/ui/Cargo.toml index e7f409b1c1c..acb7a91735f 100644 --- a/dapps/ui/Cargo.toml +++ b/dapps/ui/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore Parity UI" homepage = "http://parity.io" license = "GPL-3.0" name = "parity-ui" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [build-dependencies] diff --git a/devtools/Cargo.toml b/devtools/Cargo.toml index d5e275a3adb..71eeaa2ddd0 100644 --- a/devtools/Cargo.toml +++ b/devtools/Cargo.toml @@ -3,5 +3,5 @@ description = "Ethcore development/test/build tools" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-devtools" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 91f1ce56f70..4bb1b50470e 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ethash" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [lib] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index c9db7cf9f68..147d9484c70 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index ba76dc3b104..3853ad910ff 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -3,7 +3,7 @@ description = "Parity Light Client Implementation" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-light" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index a726448bd1c..25b5ec59f4e 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -3,7 +3,7 @@ description = "Parity smart network connections" homepage = "http://parity.io" license = "GPL-3.0" name = "node-filter" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ethcore/stratum/Cargo.toml b/ethcore/stratum/Cargo.toml index de65a470c66..bf967df504a 100644 --- a/ethcore/stratum/Cargo.toml +++ b/ethcore/stratum/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore stratum lib" name = "ethcore-stratum" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index 6930baa101b..d2d060e686f 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore blockchain sync" name = "ethcore-sync" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/hash-fetch/Cargo.toml b/hash-fetch/Cargo.toml index 6a735fe37e0..d4f46a121e8 100644 --- a/hash-fetch/Cargo.toml +++ b/hash-fetch/Cargo.toml @@ -3,7 +3,7 @@ description = "Fetching hash-addressed content." homepage = "http://parity.io" license = "GPL-3.0" name = "parity-hash-fetch" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/hw/Cargo.toml b/hw/Cargo.toml index 778fb26e069..9a717e4bd3c 100644 --- a/hw/Cargo.toml +++ b/hw/Cargo.toml @@ -3,7 +3,7 @@ description = "Hardware wallet support." homepage = "http://parity.io" license = "GPL-3.0" name = "hardware-wallet" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ipfs/Cargo.toml b/ipfs/Cargo.toml index 15bd173c2ff..9c7b5f3b003 100644 --- a/ipfs/Cargo.toml +++ b/ipfs/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity IPFS-compatible API" name = "parity-ipfs-api" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/logger/Cargo.toml b/logger/Cargo.toml index 368d860fd44..a1f793769c5 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Log implementation for Parity" name = "ethcore-logger" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/mac/Parity.pkgproj b/mac/Parity.pkgproj index e5229f927a3..36b8921ee2f 100755 --- a/mac/Parity.pkgproj +++ b/mac/Parity.pkgproj @@ -462,7 +462,7 @@ OVERWRITE_PERMISSIONS VERSION - 1.11.0 + 1.12.0 UUID 2DCD5B81-7BAF-4DA1-9251-6274B089FD36 diff --git a/mac/Parity/Info.plist b/mac/Parity/Info.plist index 2cc7e67b83e..e0bdc21e695 100644 --- a/mac/Parity/Info.plist +++ b/mac/Parity/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.11 + 1.12 CFBundleVersion 1 LSApplicationCategoryType diff --git a/miner/Cargo.toml b/miner/Cargo.toml index cf8eb0cdd8b..95dd888dc9a 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -3,7 +3,7 @@ description = "Parity Miner interface." name = "ethcore-miner" homepage = "http://parity.io" license = "GPL-3.0" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/nsis/installer.nsi b/nsis/installer.nsi index 01155723401..c1f4033312c 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -9,7 +9,7 @@ !define COMPANYNAME "Parity Technologies" !define DESCRIPTION "Fast, light, robust Ethereum implementation" !define VERSIONMAJOR 1 -!define VERSIONMINOR 11 +!define VERSIONMINOR 12 !define VERSIONBUILD 0 !define ARGS "" !define FIRST_START_ARGS "--mode=passive ui" diff --git a/price-info/Cargo.toml b/price-info/Cargo.toml index 8dd497be9a1..948f09983ba 100644 --- a/price-info/Cargo.toml +++ b/price-info/Cargo.toml @@ -3,7 +3,7 @@ description = "Fetch current ETH price" homepage = "http://parity.io" license = "GPL-3.0" name = "price-info" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index d35a64af9d0..b8eb5254629 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity JSON-RPC servers." name = "parity-rpc" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/scripts/gitlab-build.sh b/scripts/gitlab-build.sh index a2a084adc9b..5f353a63da3 100755 --- a/scripts/gitlab-build.sh +++ b/scripts/gitlab-build.sh @@ -313,7 +313,7 @@ case $BUILD_PLATFORM in snapcraft clean echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image" sed -i 's/git/'"$VER"'/g' snap/snapcraft.yaml - if [[ "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.10* ]]; + if [[ "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.11* ]]; then sed -i -e 's/grade: devel/grade: stable/' snap/snapcraft.yaml; fi diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index fd191929937..b8630781123 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Generic transaction pool." name = "transaction-pool" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/updater/Cargo.toml b/updater/Cargo.toml index 9e7733bc46e..d76db6ec0ea 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity Updater Service." name = "parity-updater" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/util/io/Cargo.toml b/util/io/Cargo.toml index dca0426d509..8538863d03e 100644 --- a/util/io/Cargo.toml +++ b/util/io/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore IO library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-io" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 74edf83ad5d..a8207ca615b 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -3,7 +3,7 @@ description = "DevP2P implementation of the ethcore network library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-network-devp2p" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/util/network/Cargo.toml b/util/network/Cargo.toml index f98cd9e93ca..f7131da0388 100644 --- a/util/network/Cargo.toml +++ b/util/network/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore network library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-network" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/util/version/Cargo.toml b/util/version/Cargo.toml index 1cc0dc6d2c2..297211b2bd0 100644 --- a/util/version/Cargo.toml +++ b/util/version/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "parity-version" # NOTE: this value is used for Parity version string (via env CARGO_PKG_VERSION) -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] build = "build.rs" @@ -13,7 +13,7 @@ build = "build.rs" track = "nightly" # Indicates a critical release in this track (i.e. consensus issue) -critical = true +critical = false # Latest supported fork blocks for various networks. Used ONLY by auto-updater. [package.metadata.forks] From 74f04825dbbbd0fa4d2ec18e20f997bafa002345 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 25 Apr 2018 16:25:57 +0200 Subject: [PATCH 044/147] Fix snap builds (#8483) --- scripts/gitlab-build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/gitlab-build.sh b/scripts/gitlab-build.sh index 5f353a63da3..89fa2a08541 100755 --- a/scripts/gitlab-build.sh +++ b/scripts/gitlab-build.sh @@ -309,6 +309,7 @@ case $BUILD_PLATFORM in x86_64-unknown-snap-gnu) ARC="amd64" EXT="snap" + apt update apt install -y expect zip rhash snapcraft clean echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image" From c7a02e5d94f29d681ece4ca0973d9b1470d44300 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 25 Apr 2018 16:27:22 +0200 Subject: [PATCH 045/147] Update hardcodedSync for Ethereum, Kovan, and Ropsten (#8489) --- ethcore/res/ethereum/foundation.json | 111 +- ethcore/res/ethereum/kovan.json | 3422 ++++++++++++++++++++++++++ ethcore/res/ethereum/ropsten.json | 1522 ++++++++++++ 3 files changed, 5052 insertions(+), 3 deletions(-) diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 53322e6ffec..4438718711a 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -174,8 +174,8 @@ "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544" }, "hardcodedSync": { - "header": "f90219a061d694007fbaca6e23e73e29c8c6a60099abc740ab7e27ae3cd1b9c6a47efef7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347945a0b54d5dc17e0aadc383d2db43b0a0d3e029c4ca0a2f1bdabc1a72737de1c22a76cacc8fc162366904f759a99db7d6d19efee3090a0ac5f5b236e8977928a2ce43c7569ea5a74919643cb0b06d7540407b1ea1298f0a04356ddc5d77c83923a6541260308be167386e0969a608a017770c9e38091cfcab90100a00010002001009080011010141088000004000080081100000a002023000002204204801204084000c000010008000000000880080020c0000440200460000290005010c01c80800080004800100406003380000400402040000028084002a80087000008090a00200100544020019580022000000306100a0080100084020006809000e80000010000254810002000000a240050014200002002c10809202030006422022000203012000241089300080400000009001021020200012410348500028290230408100302000000058c0000020c08c20480081040020260004008481000080000800010010060020000e00020002140100a8988000004400201870b9af4a66df8038350a8018379d54483799eba845ab0426d984554482e45544846414e532e4f52472d3231323134313232a05eeccc80302d8fecca48a47be03654b5a41b5e5f296f271f910ebae631124f518890074810024c6c2b", - "totalDifficulty": "3144406426008470895785", + "header": "f90216a03b798fd7d7c51f61fdbe7a08d6d2257eea4501c12dfc5442146b85837c0da51fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea674fdde714fd979de3edf0f56aa9716b898ec8a0a2df7c321f2a532f63cdaf4e234227dd067f3782787db2ac892e875a8cb6842fa0c3a3f2c96c938633c7a99531a3876d544dbb8d5fac06879bea8e3cc5b6ece09da0221863f4a4fa6ca8dc7b6eed0eaefea36a5069f06ba9a61e78b87b634b5e4409b9010000a02080204012000000004100800000c0a08040041160000000740200200148000000000104011040800081808000102001180000000a80000011401020002c14008402000000100014400e20082080400000aa004100000000d10e8a0026180020882008200400a548000000201010088080000c0020800000001004046200600000052004020001800400800400420001800084002c1200040088028840004604020820400000264000005808500400410451c0808020140380c02014000440000002010422080800000240000000048a80072140000400409020020220810010020018008021800280a05008020000400000000044178000008000044410870b075e7ebe9d268353f001837a11f88379cd17845adfefa59565746865726d696e652d6177732d61736961312d32a0c92755fe5da24ea52d89783e387d88e1c2e24ac202641dd9906fc704a88979d28818d4dcc0009d0541", + "totalDifficulty": "3828700463149109414955", "CHTs": [ "0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc", "0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11", @@ -2757,7 +2757,112 @@ "0x568f44291c13efc908db42d2473bc91ebb16e062e9b4368bcb770a3033d67741", "0xe5ecad510448855ff0aafb92a8c7aa54aca0fb390bec3c14ad5d2ba200380aec", "0xa40aa7655c1458b76c04ea5934ae171fb01c72c8c375bb61a0c27b0ebd70f21f", - "0x770ad5107ac47fd983979b016553ca8f340a13e2647b9140e65c980dcf349cff" + "0x770ad5107ac47fd983979b016553ca8f340a13e2647b9140e65c980dcf349cff", + "0xfd074cacab08d2d5f113669672632ab0e94e03bfbbe17fc3de27a30e9f0e8327", + "0x2063bf5ce8eed483242157113534b314296deb123cb33083cb0cce04db610c9a", + "0x9dfb8274e842fd3cb7d73506e64adacc39eb12ebd8a972b7101385ac4eb5b12c", + "0x8294c3d4892cb0bcba9acdd31d53af5bfc97daf124f08d903297da8bbb28cdfe", + "0x9dc2d04fe197009f24ebd4a0c95a0b91d4ff0093387b61569af993fa91edb3fa", + "0xe88e256abdc6447b1f141c2fcf2c46721d9717a9fcb302513c93ed6e31b7c11c", + "0xd2ad4ca6091f6ae6c323b6565522c208a839e36958a1675e5e9b48b13068e7c8", + "0xb168169f2643b8cdbec58f3f94d7889af37117a35389726563ac770f5205faab", + "0x09f32b423ca728b8fd04f9872325c0e2a4c9b1eb36fab49b31ae51254c69ebab", + "0x0b47f8f28a3242c9ca705fd11949e648f190053de023366f98e6c736eb2f0de1", + "0x870a8067623b35b5f0146ec95047869357617fe3773a8285a622c18d44963f9f", + "0xd14e05d8f3238294ffd8885c1f1710f64f2d8eb3d3b4e8a921f7f5c94a0a6288", + "0xf9cdef6ffacbea7692e9fef3de1b778bd11399492486dca0209b27bd474eb04a", + "0x5dc41201eaa00957d070c68bb289fc00eb31b7e5fff52f0603d52d27a40abf81", + "0xae3a53054ff4e3e5562795b45777e1e3e82abeed84e2fab748af50aace8bc8e2", + "0x93fd6f9af3b1efd27487477edccd690b19902300a4eebd34cb0d9b2e60b3cccf", + "0xbe475a9dc045e70ac8218e5a65450edf026d70f3f814162251f83a88098245c2", + "0x20566435d247cc1e7d0d81e143c01b6649fa1fd3cd5a9f97738e6045b29460c5", + "0xb37273228fe8b0c1679bb2dab7176ee1282400daddaaeb0db415c716f5dd1f71", + "0x494bb2cea59fc43629b0f8be3fba9ee5b52948c72fd1f1c94d31600756bfb675", + "0xc690eb3d8e65d5efc211def8fe8f198e42c0321000b8998a6ab218d897d593a5", + "0x26821d73690b9d1bdd9594c92b086291474cd365bd41f7de5edc49dfc29c26df", + "0x026a57937338c9e168d254f99dc9dbe3fb41508049ac1a5b6d7df868e2935e6c", + "0x50dc451812556bd69244f3728c6a17e958b2fa125248103942ac94142610bcc7", + "0x0ffe7ea32c3ef43049d8041a16bd3381ba89b1439dc5329e839546aa01a64726", + "0xab1e06f13dbaed341fc9e33ef387ebbe187787ccd8961a47560f7e02617a06db", + "0x8b72166b0d16ebfd9c3156f5972e3778e16b3d7edf3decd4b6efbc779990ca3c", + "0x149de0dcdbe03bf6d0ae9ccc989a074a4cf2e78311ce8cb6dee3856c2a374caa", + "0x42147f5960814dc31cc38b692089e6d1d53b85cc85a69e4cc01954dc61c268a6", + "0x1460ceccff1ac00f3e126383c3102c424b75c2abeb973d0baa8bec8e7bdda692", + "0xdbbbf28a5d25c832c5f625868dea79a481dce880d5145f4119d3e9eb32356a6b", + "0xd8e5b32a88bdb502fbd62888b9906a0c7955ccaaad1ead31636572a07fe7419b", + "0xdbc42abbec7d223666da11767d9862cd1458f91b5bf2f6499da4ae5bff281888", + "0xc3138499753f545de139238bdc8cd4cbad254c6b87bf0eb37dc1fe7a85168e79", + "0x42be700f627bb081543ab289fcd01235bedea5e33a9779d6d14744685f5a652a", + "0x8660e4130c98f6a8024c1b587dd24ebe402126d4d9a2adf610c62bf033b749c5", + "0xdab926bab8c4ff9e492f992b5696e8f7e3ba3ce77e49fe0e2ca36d3efc8791b6", + "0x0e3911bcf379fd57014bee6a1f796b884c62f2392cf6e8ac5a145126e4622b88", + "0xbd52346714664eeb7b4034bc6a54804824bdd40d9e5bdbae9375a302926babe6", + "0x641e58eaeb404f7a40b9c4be686c26721563b310f7624a654185a60374c1512e", + "0xfa07b0f7b970413ae5085f042224861bb1bc5f2f6ad72a44c3681d47a817c0a9", + "0x70cf3fffa7e27f03d5cbb1664bbd0e1315dfc43df76f1b0e3dce494255e54752", + "0x1d5b0118939994aa8be89dc365f909309df84e7c92530aef25d62118b09e0572", + "0x8b34c5a5cd5a42a58bbc60166f3f2a4be7d79057691c708e7a9639c21b6f57c7", + "0x7b149005e7f8378189c70c33c073d897cb07f62ba5ae319088b3be204beea8e4", + "0xf2a41e8feb5d294faca47dd1f7a90f66b7b616addcd179ae60c5f173cd44a85d", + "0xa2875c8e5a226f2cf69f07e19b13a628ef6a8662f3a5de4c9d666ca5ebddb001", + "0x4231ca8bdccd59526900a487608912a4fc0918a6c693250bd67787bc61a9d09b", + "0x2b06301a6372e0fca0da8a15d4e31a08522ecb91efbda58c3e495e2ab7f4fceb", + "0xd0e19f62b07275097b56e7f409cd52826a1dbc0be26eeaae20562420559153dc", + "0xa4ecf1ef04bcc95ba0ed9214e9118129ae5497c37db94dda284dd536b4dd75c9", + "0x3dc87ba482aaac6b59678c899bfb1da9b768e1385e0f8e8574852efeee2db8c0", + "0x07f8df3f6ec63d926c3a76b17ad1750a9ac6c62a8cdffa549440e651f6087178", + "0x96952f8ba7c83d640119868a030cb7397624ef322b2d153aa3843259da5f468c", + "0x08eca2fb4295f069f3fa62849b354a9e10b8a8e9b771cb8d2790b28b7b09d70c", + "0xfd5832f531c8819c0ce9d031434c33eb442578e81cf711e8ba23e9b21d096e13", + "0xfee9a8bae124565c963b65fa47dcf7f0c9b5ef7e778c2d99539b8a04efd04522", + "0xead692739a0723a73dd38b3aa02f93d72b3b6922c2520ea0b74981eaafe7f6a1", + "0x890dd8befeee6c7c7b4942b02a3bf1a9d1b9e1140ecd1c07de570f38b6c323b6", + "0x690343489ed214b9195db6181c42237b7a62fc935a18ca1a5dc883a2045ceae7", + "0x4bdfdc1bef8c19b89344230c0f48841abfeea788a4973c34afff4d2039ce4417", + "0x6ef6a94338d794400f95f8c0b6d5a40df8b56c31e9bd0037bdd7e41234bb32a1", + "0x00b7568bfdf2d4780b8650a49f707752a12fe9a88302622e68f264622877acdc", + "0x83e96e0b864df30b53ae08075acc83f785e9b8b2bc80e8976b1a954f995df012", + "0x664305b610d0b3167dd25210acba7eea291a37a224546a6f6d59aa7b71d16e5f", + "0x3d3a6401ab83eabc2af15a23b9c0e6d123f661b3599c6131d5923a106f562ac8", + "0x7a11833fbc8ce3d9883088649b930238625e6f6136dfa06a00daf8e646cd020c", + "0x112c33932097c4ec4e18f6308b2a6502cbf746605f1e404555dd07703d60ba2d", + "0x9e77cd028749d69caf352a95f75dee842c0d9323e3618afa2927b2aaaf7fc4a8", + "0x7fe0a62bfd04e263b4c67c5808f6231ad6faca7ff0f5bc0c02177034608d6991", + "0xea820d62b423b68da2f8ce345dbb56e2205fdfae1fce261d64acc959fb30cccd", + "0xd8f6367448dec55e8e2e26b5d304d92969abde131d402de313b1705c0bfd528f", + "0x4b97f3b4e0bff7cfe322e4f50176f6bfb379a706d42308ae75b2a46735762a95", + "0x7425ff9cea5e4869332ce12ef727fbcb004add827eb567424fd4c17717def390", + "0xc7dcd4fd005ae8d4d9e125727b54a64e900b3fee9cdc82fb5057c012178c8483", + "0x8ba88bfba201db1db716f762b5517369d3ae232ca045d2932fc27f6c47b15806", + "0xad2f63fa4fddd0cfc7f6cb01116d285e8aad4b0c51fa9445d39a4cb4949ed020", + "0x366874aec4ea26ece424f5402604ec7df9f40fc4cb9087cd3f45e764b1e36ebf", + "0x7f27eb75010b0d5da72794c129042511e24794b6c8491c1ff2e257dadcc7052d", + "0x27eadc596f6eaeb9247704c3339f7fe4e649f683fd815f9d71270caf5d9e38cd", + "0xba3f72ce8f45b1575554bd0c64feda3959c2a68f0300f021b67880b56f7152e2", + "0x50833c82dc63533f7ec918cd6d58ffbef4e2d597f354589b8eb66c9de0fc9697", + "0x30fc354a8893f683ef03bb024254574b550710f3c05496976cd39166a29e1c98", + "0x1b6b8d13fca6583d358b173c1a255c3db9efed8ad72084eadf10e29868a26fdc", + "0xb1b2a80122d1210160d8649d31422a1edc26b23e8499aa3a88b047dc52b42222", + "0x4e6c85a13cc0c739fbdf844a4f52c78979a84a86db728e4a5d2043ee3b2fcb3e", + "0xe98c28b49aa690aecfa43527acd3e5a010c8f90faf79ef5b4b479a715fe66a99", + "0x5b56e2b50ec96f7bda3f529ed71321650d688e2ee5c16723f6199256532ee660", + "0x1c9b8f5106a23096f2f57dfdb2a7a82876f4374be97b6a818fdc3c742b216b09", + "0xcb6973f775356ec7596ed6f9a036258e98677c7c5b2358da75af28f553327506", + "0x26b42a54252893f59e8eca923a0d2f2c0fe507a680e8907e2904702791c42aea", + "0x25fec26921bb5b6cd9657588b09813270cad72947abc6cb2726764db44181ff2", + "0xdfbd186df632b63f4cf74db660c59e658e0b4b725fe244a563c6698dd94adaf4", + "0xd1e00635e2399f6fa625f5c204e4c1643a7b619271394141433d26d902479bbe", + "0x3d3323fea45851eb0bc0b6c80a79cc0d0582abd8032aba957e719c31bb7901e6", + "0xe7d7b4c68d4f55ea8b71b43ad20bdd86402d36b6360ed0ca18082942736a7e41", + "0x1436749eca0a72b74bf8d596e3499414d412fbea0b936ee3564c4f83de907092", + "0xa828c16af52bd4adcb64928fada82a02d0a49fd3f53c5083ca9acfd998f8af1d", + "0x0fe559ad45cde755dd41876c5a65a690d32fc3d294fafeaa43e3fe133ae48da8", + "0x8f91d2082e5a1e6c1c905936515ab5f03889ac67261ef1d892fd909a9379a8ba", + "0x3881a9fe4ba6a24dcfa86351be2ca741dc9b2078409b2e7e0140569f19733505", + "0x4a3295525bfdda29bb9a552d8dc5c992649699f5694f96ff5bb0647910386db2", + "0x337389b3e800bae87fdbe5271f2167f169ffeb4710ecdcea30f08b2cefba57b1", + "0x2978e1e3c2b5dfe0b41ceb5c9c4029f42d346a2123a199c52ba6efdbf1d5fb68", + "0x8abbdb4f1f88fe8900afdfe15f3d03244435d4fb871606a689c11f6420145b45" ] }, "nodes": [ diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 0d00478c599..1cd74d973c7 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -55,6 +55,3428 @@ "difficulty": "0x20000", "gasLimit": "0x5B8D80" }, + "hardcodedSync": { + "header": "f9023ea032ac0e3f2dcc2042b6b47cbe502d5c7dc39d27d147e3273e17fbdf7966518a69a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400e4a10650e5a6d6001c38ff8e64f97016a1645ca0c97490dcc8dc3a85050fb7df999bd772c3ab40cababcf5df4ea7141a9a183353a002bc045bf48b7208ffc5764f48c35162f488bd1213c5e96b3b06c0dd3a32f24ea07041b8f6d8db9964497fcb512b3de8e71cb87d89ab7ef592caff47b444f30637b901000008000000004000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000200000000000020080000004000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000080000040020800000000000000000000800000000000000000000000000000000000000000000000000000008000002000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000200000001000400000000000000000000000000000010000000000000000000000010090fffffffffffffffffffffffffffffffe836ac001837a1200830a4245845ae02fd896d583010a008650617269747986312e32342e31826c698416b80bf6b841cfbb3c579ee8e631a9b2916de71778e0c4f477d1424ed65cc9ca7958899c4cab09721b8eada42b49c146c870291efe475bb8d88652810819dc03ebda2659f3f100", + "totalDifficulty": "2330161772435517944412054200548742154048251186", + "CHTs": [ + "0xdb9557458495268ddd69409fc1f66631ed5ff9bf6c479be6eabe5d83a460acac", + "0xd413800c22172be6e0b7a36348c90098955991f119ddad32c5b928e8db4deb02", + "0x7f2f84afc6caad6efe59a0fb9ff523bdd96efbb5bd22a0f67b3be8bfb8bb036a", + "0x7b7d86ae379af1c88f75a4b44d3097213b3461b9b7fd7333eac581537982dbb8", + "0x8525f5fb8149a1a64a83ec1915a78f3ce03a4a9afa4683544076f40f0ddbeb59", + "0xcc4a4b3e1bad427ad0d8b8ffd1c1c0789a08a67a09fdb0d1ffa4b1e71eb43aea", + "0xbaeb6b0b2fded26cf7f731603df0838397489bc12fdf8713a7cff865f009c5ec", + "0x3dbef76befeb39249e5c65d068fd97b8aea736714001a6dc2353b46d44f4bf35", + "0x306d007ef62b7cfed18e711d1cf449c009fbd5a8af7c9af66f3cda47678b478e", + "0x6b6038335d65726218d1d0301e12e792488a7ea879367c95263a20870ac91aa6", + "0x85ab7fde05c7cf468c4a65c5f7817e902f16038b3ce5e359490acae9c7a4f6b8", + "0x6784db2e15b6dffe0db864b2738804cf7b9804ae8932a2bb93a6bd2f2d4a8c2b", + "0x634119343bbd64c312a540e290b227adf6a84872ca9ea0fb7b3a7f5c2a4ba293", + "0x5836715c071dcaed0a79c77c12a02d54e6af55baed2c9325e10debc6fb07726b", + "0x7508b06556911cddfe4fc80e8a24603fd93cc79081759d4b7f19b2a6550757be", + "0x85de35d1995609af96aab65b1509dae77281a72932cda1e52e6af1d2c81cd46b", + "0x6575f31d4a44a479af6e4f53b7f0a5a1156c6965767b6e06cc3da8b46fbf0355", + "0x1d2ca9c1629b0e0775756536de5afef7dba628856e87dc84e5e6d16b08e12bf1", + "0x776edcae4d9a2e2a461fdf99eaeb1e717e3599f77934e058094b769c0a51f0b6", + "0x7fdbd14ca3a7408577c4e5b3b982edec1e7a95db784a34f9828ef5a30878f85b", + "0x64bdaef77b520a11c7ba92f494caade113a7682a565126cc4231d825412cee6d", + "0xc413f58e336df38771b3616ff1c9a1cbc881e4729dfa0a4bcd18dfca8e22f2d3", + "0x8da02b95474762995773eea74254861bf3eb62c099488aea97d0d271677a513a", + "0xf8d0c469352bd199cf28c997530afc31eb6b47662e1de2a1af05bcf31e6d5d00", + "0x88d9d2f7c1c44d4d0498c1f5ec21ea5d2ed2987e62f8dc6b17359b40200dfff0", + "0xe389fde4b8b06ababced10fb3756ce80b01a36751defff9ee0528accbf979b0b", + "0xb1f3785c2d15132fe17cfd455d015a01628ccf0116006d57de6425ef32bcc63e", + "0x9b2b9e6c015d85d3ba14bdf6ba6889db43cb8dd02dd020d1a01a4e7831604f03", + "0x8b22134cbd6b94ed1d17c89dc73771a3d3df57bc5c4b3d1540631c18dada7e4f", + "0x0a08bcb5fc682d91f0f95f934b4a38a71afe763b4924c8d049e407dea2bbc467", + "0x1d67c81b3c9316621088b42599abaf7e7cce42d60da44d2eafc8b904413b2c77", + "0x7bbbc5f13015a3ddfed8d3abc1d85ddd4646af588b534656256d894677c08c0c", + "0x2a442700726b19f5c82f756b08d07e9bc2777fe1557c079cce7a391684fdb59f", + "0x94a08a1519a9261f664c972e0c56b4628c3a0ab25a245abb4957cddc8a8f4754", + "0x5982827a354ee3703427518938a9b5b281249c04265db359bc47a7061f994a3c", + "0x3dd33939d000789b3ae1221b47d80ab4b8b248f79c97ea69c10148a4f8e946b6", + "0x37e5bf322012483f8e702f8a2a511b5f1225293b7c1be743cc83c637ec83c5f5", + "0xe671341e7a0275c306d55183e36b06665d2380bec4865c4c7cba51612446cef7", + "0x57ace89c46a589ca5150fc99028f9d586c4a8b1b6cf7af8b17ec1a16ebbdf8df", + "0x633ea492c2391b957bdac23f5a9428a5ce69882dc90db968e2882304bdf2b560", + "0x16aaa8ad98f3d2c127ca4dee2c9e1a36a0d4009447240e3297484d7cb2d5ce73", + "0x21abe93df9c382e5897599f54a31d3f46ce8e5e969c655c61da1125e6abe45a4", + "0xb01895100c1b028bfaeb1a126c4b4208075ec2a15fbc29a6499edbf939e7866a", + "0xd635cec21335fe1a644ec8913ea79ea987b815964ff883f00fc01c3a18c9d7a6", + "0xe5c761d35900479ea482e7804a056ca810043389f96ad208f55282e2e7617000", + "0xfa73e547f6a32b8154abe367a0138219514bd0d3fc304c742cb8b3d1eb8f70c3", + "0xf9de607cdd47e7337c815f4fbd44d983da6e38d653c3d3fbf2c6ac8d33707a63", + "0xa0d2cde0aec685c1d6cc05b21bf59817f123700e778cfe5eb80eb11add7e3dbf", + "0xaaaa3bd9f11785b477762ea0a3fcbc983c8a11b34d64475d16bc8c7d43904b9b", + "0x0031a12ba8c6e7408c7ce7987179b7534f1aea95a10aacbba0dade542ef4e1b9", + "0x101544e606fc49a7555855b72be050aa8a7a77e1e8985c3f54dec8ff3bb49a83", + "0x62202e7ed22ddc5d0cb3ccdf81770d4ed935e771be3d689c4dfd24afdb9c20e0", + "0x312cfe1c896a2624e9b2096ef5f3579b543d76ae166cb468e76a3b3b7fccaec7", + "0xcf1820f096d4b80808c50fbbf8de1b57da7b399a6f40312a293c4b5c7eb6d73f", + "0x1dde45a5e8ee62605753259a78e2c34a74cd5cf053a4c045ec5467f9e1311161", + "0x6b6ee017250b468ef3ded726892be7e8dae77c9e9e998b7e9889a34ff5da0cfd", + "0xb82bad6b19786930dd7159f35a4a24336d3f3b5b905b43f2a58165e0845b881c", + "0x77d20bc08ac7a25e115a1d23157c35c6ec22afd89948daba7ebd4809c3b95a2d", + "0xbe24e34aeb20602c184302bb10ac1f424226a985741f34faba4f346d8937e737", + "0x505e5b92245ecfde4a870197f7ece1ad181b6e8be4efce08763a37947122f4ce", + "0x6aeb3807dfe7a6db67278b5b6b6ee9ebb8996034c5ec82b3446a8c2efd3588fb", + "0x495f38afce7862a6614ed3d35531994e8d1e81dede4a4c9702922a3c06084e20", + "0x4acef831186426af96b90e1007561bffe2e8074bb33955dc36cdffb85e61174b", + "0xb2d7638804d6ee3e0747a4de335a26506898cdfd9221fe7e7e464feb268136b1", + "0x1aaa327ed400e0f6780fbaf818fc1f69c6cf407ecf80aa4f769ce42bffed7cdc", + "0xb955281446f41ea2330d07603803e148d5f1a2519f6233cad87dfd1ce4985259", + "0xec5f0c5f001e7897464a5570543060957fe20f88a905d3769615355c240e4859", + "0x18f872e3796787ef015a99bb3bc5ee4d31eeeec260213da70bd452f64de14c6b", + "0x9df2268daa9354a8264b5e7428d390a8d813266188df966fd58549dbb66898bf", + "0x6fdf62c4c161997e854846ed44e2096ea948c40efcdba2479896ba87fe484138", + "0x206bf3386af35a010906ea7a5263a71fa47fd317d23b57e448e49a36082916ff", + "0x4f627219247a8a93fbaa32b7f95e84b45146752d245e54299e7f74ca7070b2a8", + "0x3235819426f3a8b7affa6b38c0627c8efe0c2abd1eac7f8d6545e4332ebbf4f7", + "0xb5e514ee180f781ffadbfacc1831926f24cb305c352bb76ed7ae0a8247e792cf", + "0x6f287758e18c7967a5d52c05f8458e2d3ab2ec86fe0ef1d3146b99d7c3e3f5b7", + "0xc17dee632a1da285bc78d6c83715810e0e003c65c61c4105899b440487bfd126", + "0x173bab1413b65b801e136fe2dbf335b7d1f8689a127eb549bcd24f55b0bfd979", + "0x7e85be26cca16f2f34468f1aadd30a4766e4fe9d3746455f301f7f6e1baedc6e", + "0x85a0a9be1ab79a754c8875688b19a12719087e09d4cbe03f29965bbffee8437c", + "0x9c1c826a39e48b1b8d9d88ed29ca2d1864425d28e273695e35168eb01179ee62", + "0xf88831327094e7ec631fb9cf42719f89c4bceefbf25130784f09f4fa0a3b0a05", + "0x813e01a9713693c11c2781ac98604e51d7c7f610effdac795f74d538f7e5ec89", + "0x35ad80a70b0086c0a762ec29c577b031ea85132f777a324410c3870128aa91b3", + "0x6db9c2349d95bd51dfcb499ff26e90bf73e999f25b693ffa232c573f67164104", + "0xcff82a9fddf588d3d40e642f1eba1b9d24ece27131104e2e3995d6643e8afbf7", + "0xc6bffabb187ad144e33e7e3867f94f754e7e479c503d03de4fa891d294b175e6", + "0xd360ab92cf13a519f5bb41ea825e9baac0bfdf2298220c5ea60304ee9ac15617", + "0x8920024d447d0635cbe88f642966da52c1ef74d3ddc6c1c2df1df80c0a0014a0", + "0xc64a9294f5ca5fd1e1e05403e625222568c32bfd2f2f95bed2ad532b4c3a33f7", + "0x258ec76b8532f1f5169b44d8f5e0c1ddfc19fafab4cfce7c6afddc8aa4978cab", + "0x47f2aac68456bc931a0a8c458b802651173b1ebda2e032fb9541139352148156", + "0xa87a36800ed7e27bbee7ad937c1ace3ae08e2ae50a6673af70a2ec6e44ef1ec5", + "0x9182c6debf58629bd0d37043cc70b3c5e4af18b8aaa23cc5b455f009d1686371", + "0x0fe5abb9ff345ca06fa55cdfaa0804a6523c3ae162638e95edee4ba092eec443", + "0x24d7d4eb0c17869860d83e8be8f7579212cab60655aea5fcf070cd1461191357", + "0xf0971d8a37bc9b6a54d37ac7cd90aa4766cfe78cf8a6f376dac2304cea05683d", + "0xdb3e2e62d2da694788d2a0aecb2226c01de2b9d655421a079e2bb34092e7fd8b", + "0x57100a2ff274daa465da031c86f9b282fa03724c93823399c08d6b014054d207", + "0xc81fd4efe86a9ad97415928ae213959f2a716361da4a2937ceaab7358f105382", + "0x5836a5c844e45ae687b388603d62d28d81cc98ee1eeea6a34dad79d7ea6a599c", + "0xc98ad6c12f3f371a69eccb37407b43d3185b68380dcefae448b2e43db41afeaa", + "0x33ea1db64fad9787532d20f7739dd53a35fa810db902f2c33dfec4d652921073", + "0x3219209ffb0a9c5ae33779564dbf8a9618fabd1c0830d32a06dfd5a3990f7dad", + "0xeb6a367ee7f10c5d2882d86850f4a2680f78ce9374b7218d7cff11f0b01ff336", + "0x026bb678fb224a4e62c0d31450cf5394f4f71b9519106a5e92d58464edfaf63f", + "0x040ae0a25cc2c70fa710d394be7212b81128d7593a5c210549a96bf391a2f58d", + "0xa32caa1d1b36281e2c917f1951b3b0a0acde7c78f775681dd09c7cb81a2f14be", + "0xfe532be3ae441c5e9ec98fa0e006fe8529dad0ae6ba384300eb2198841014391", + "0x49d3b4aa6742d68b59eea7b44aaeb0693670c7b3b43788e93cd99f10d7ddbb7c", + "0xb205da5396369be6b68fa19264df3326c2bc825d88814843ac4f654cc7f921a7", + "0x57521341b29c1ed0cb02e8a64c43155e6020c4d8cda103ff56b2d2bb0cacc749", + "0xbbfc055f310e3930447bd33092081917d7661056ded31d3828b9a4eaff3649ce", + "0x52fefff36b4a0a9c2ce8cda94cb792a8260507df759ae2348ce79a6df3a2aa17", + "0xc4a7420741c5e8e041b8c7765b5c48ab0ee01fdf780efc95f820fbf549e5331e", + "0xbf90dab5cfd58fe4899475a911afd460ed0bed6e79487d9739399f7749520642", + "0x1f27056f98106e007efed121b017e82fd5c9b2c05de65cfb28fa9f67edaa6eee", + "0x6ebc2d4f7bc27d116b499dcbbaef72f8dd053559dce743706ecae5ce5338b508", + "0xdc6eb02678ccd7b2db8a9a9272ee53fc8110415ae5e84fbb8bf981eb25ccda51", + "0x3e261edddd8d34ba379cf163dab618aabfc198ce81bcdb1484b71a5bc4b50fc5", + "0x128bdd0f27a6d741399010b26f4056f0a919e7c1bdebb1bb69f22d32c80a2b88", + "0x68a749488b6e5bbeef10c98b678f67d1a7e53fb62bf502dc3743bf3c9138247a", + "0x52dc462248ddfead4b4aa85f4b2179280799b902519e83f721a849cc2f2b6037", + "0x7d70e4fab02e6a462e4688e96f7fc56a4fb9a945da942925ae039c6f13907c29", + "0xc746bf3861b3b63bd15b3cf0f0b6c0c331da578c35705176b90dee8a5b1e0d6c", + "0x4e251d7c4b2ae114b2f11a532fa060f6f7b1c4f0bc760034fe4e69c053a43746", + "0xe67185a040a731762897ac2e07ec2b955644d0784d18c6351c805d28e83f776b", + "0xa8ed7fd02d1dca89683183877cdc2a4c9985b48141d7967b10b38b59b831cc6f", + "0xc1020b2e8587f3c967ea138ea755437d2660e69abe8caa0d9bf9da9201b50750", + "0xd789a8a4a025f5725759e359859f2e15f7901a077d7683e3572d9ddba15ae94c", + "0x54f4372c804a66eb887614df08364d0e6b1f10c090584619c89c43962f513eda", + "0x3aa00d2431ba1c4c03452536047bdad3a5af547d2e16baad0bfeea0e7a8c3722", + "0xb341d41f92def7f5bf2d7c9a39b9fcdb2892b95a63ffd7b643bffaa523783dbf", + "0x9796b217efb64cc5f829a668989bb1915206e016c9714325f068b8cb2cd303c7", + "0x5deef3457cc95fae69c47f35422ca8731c80da50fd7f664583d13bb44d2f9ac4", + "0xa381a97eb8cf01a9b162666aaf9dd3142c6b2a2247830faf693e894ce99809de", + "0x7418829d2890fc2514b6e4da7b5643af269016ce2dd31d1aa7333c66c1273a6b", + "0x65466713071b4b5abe6a9c9b0e9fab247d56d72fea481e96b65999e2a085de95", + "0x0f97a6523532b4b80a7b54c1850ac2b062ff99d0c7848457fc3465d0d60623dd", + "0xdd1826c79f92c089522f853f87b551104b8b173f1c1797a752f2e8da2fd506f0", + "0x86a635a38b956903ce95ed3af65257383e2d7d86e6b63a61deec3ea5c8acc081", + "0x4afbdcdbe4a647f1137d417ac3580a116022c87cd6e7511330c4f2494cd90a0e", + "0x1d179aa8b0cb3b27844da4f06734f199fca43b66319cd2f16a60722eda994121", + "0xb1f1e42972a0b99268f42f6149452019259565cfeecc3459a58c17ba69ec4ad1", + "0xb80f8b8bee43d9e98eba909691ed6c9e900e8757326f7d20b6e7ba741d404a4a", + "0xadfea6390b526ec42aec881cf8226b9ad94f28ca1e682237914b30564d887208", + "0x50619f2ddec37c184798dfe50b067ae4bc0401bcfc1ab4d42cc19627b7b183a6", + "0xa53a92d3d223652e6572a48ad7624aeb2bb24c10872d17ebefd41ead1579edb7", + "0xeef7725747b978d578e5b576bc18d5c6e7148b68c2389478e0102b7656e7f3e6", + "0xbda668b4961ca5f6951f6ac55ca3c03a66e475e21905dfa8e797cd4a5ef1381e", + "0xba8c3be48f94186114afaab72a27a21db0316856619b400645469511b2bcc165", + "0x44d80fc17e0d131e6e98a4567885cdfa5224aeba8616d8f369cc84f3b85566e1", + "0xdce65f6c57bb81f01fe80daa1c6869c890a4bdfaf0f016456098bbd13c376f72", + "0x0b63a4585671669622a3c751d5ff5433f07cb0e9f4dc0acd9dff493c6ed01495", + "0xa287abbc612e2d318488a370e792845ff01ba5f7d387a2f0d82c21fc3d236992", + "0xae83dd70c6cc9cbd2a418397401461687bfeb8fa6d606fb7105153e50b5dfce0", + "0x02e31ae89b0dd8f66b6590a1f65711145bb9154825b7c68ae5d76228d92f016b", + "0x1e38ed1613141cd046a2449540f1450ffdca2c1a8d9ec2f1ce8d9c74ee189d89", + "0xc8f4747dc7b311c1a234f7d7eff3e9000e11c38624c23519b889543d8d33dfb3", + "0xbb7aa989e7d116e3c288ed8fdc0c7884fb3c6183ced8a0ea63a9de037ebf49ee", + "0x88d5a00fda80c28fa6e6d0bf6a6891b492cd6c85526955cfdfbba2428c9353c0", + "0xab03bd8ecad4f1afd0ee84a2caee745d4b7ade0f32bfbd61db50be15688e4493", + "0xb9ee61e8ab9ad32da0728394b5ec53452014f6fd99a5409923cf75c8d739da5d", + "0xa4c357be81081b833b5d4fd3cf4644b2ef1a28fdf67a8e0b0b2af3e8cd6ade4e", + "0xfb56d0c3b65882317ba962e2953a75d9d9b43c9f40ea0894629dc09bb29f6712", + "0x0f354b29bf19612285957523fc7d487922795d8fe5fb0aa4019b94a1f13d89d7", + "0x61c6ec536ebec0a740ad39900a2a71cfae8e8ff81ce3a37c5a4354ae48d39ada", + "0x769d94d0b3fcdcf22eb6c36a7c5b18711c79f69c27e9a396476d03e92ab0d058", + "0x5009c84cc24149c0134790682e0a9bc88fa5a8d2bd650207309002c25bc345a4", + "0x32b697d3cf2ab3bfb9ef79d27f3e61eb423ec9d802f2256b1d8875df78ca5887", + "0x3b8ba94c607acdcaaa7f0f7ad30028ecaf4d505d0675df95c358607210a23eae", + "0x433ea023715de94c5885d16762c0caf40079f5377f3cf3f5ee871c6812182ebe", + "0x4758426d43b67ad4d6e7a36272a3d772b94dc497d45292b061ac655111c41240", + "0x12542964fe7e8c837cd8e20a0f80de473127bab6aecfcc5be266bc7bcee87ccf", + "0xbe7362114d69220ba08ce42396e92d87027a63c3287be0fcf633c8a2853b8c71", + "0x722e26ddb7fbcff7dec266ac0ca388353c3a34d8ee23bbaef579b7acda48241a", + "0x04ede2fbedd140490e0b215e89850b8bccb059cfd7a72bd2fc3118495aa4e811", + "0xf47ea26f501cc95c62c4da4c57e743bb20c4caf6e81b394ceea58bc64b1a77a6", + "0x6f208393c290c02f4a505a6e7b2420da859e7ee83583e9a41d709333e67dcf9f", + "0xbedadad9293e12d706c963f31fc06535dd23432f7b27d157e529cf73e4f5603a", + "0xbc3572c828c9c1d1f0c90f56bcee1fe414a413fdbb7362a416bf4033405276ee", + "0x084bdee3faf8a9e45990094d668f6ae0050c1427e3aa918223849357f7865633", + "0xec5a32f5ff6f3887e5aa33d6dd61d2d63e36520ff0647a9eff2355a7311a0fe5", + "0x13fd23c260c0298286e193f23295b67497fb00c60047017bc62f94f6a25d4574", + "0xda66b3d4773530c3a3b563a8721523dd10f4b598b3976aa2f3becbc15fdda495", + "0xfa981ea461800e9eedd73c1423291c69bb43555321e1c5710a052a12bdc68707", + "0x232b0ab7709616262fb48d32ff36284ceb5dafc823ff4f6d5b79e8ed12c7040a", + "0xd90bc0dc26f812e0f05433c30fd8e19e81a81ac589c49a528e86027e8a352e78", + "0x3666c6eaef02990c263e0611e90d793c82815bc0032c2ae16813e957659c6412", + "0x5b46e134edbbc9466540878a637ce22194f040f519efd98a52da8e9bff05595b", + "0x4bff68f29ddbf33950af965ccc3fad46c81b6e2371922abf27b88fb2d669b83e", + "0x67dbb166d4afd3d1c32b9ce9ed5da75a25eaa160f90baf0d46a74fb7ddb09dd2", + "0xdba720e169d3c1dfde88d08bdf445eb428908560a520ccaa1da84d2dc07369b7", + "0xeee7477387db069e7de5d10a8e77d7f3ac7d692b4d582b5256bac44ba3d8381e", + "0x968ffed5244efe79aa4dbe1bcc7a05e24b5e50d1fd4d92117e1b654707bd3c43", + "0xcff2abc22b0cb5865f9767b5f6fa4b1420e3b774ff4de6f593516db3511d9fe6", + "0xd710ff4e765bd0d5e2284c8a11726c4924b6ba159702214a6016555110c2a251", + "0x31523dcadfbc24f1d3011cc1cff03a4df5f2c10fc4bef7cf0bb807edd1c97520", + "0x079cf6974e4e64675de7ce75b1262e2fed194440c2789f6fd72110f105503754", + "0xb121c3ac31a421442faf07a4b553de22be8e1726a67b0feaa4d426e5b48930c5", + "0xc39a8aa81b5c0a95d0037e20f3043e16832cd4b4cfa78e59a424493cd8322754", + "0xcb30c5710457eb0d9ece9274fcf01a96758e6e48db64093b1a08f773f5bdd594", + "0x916203fb9c6cb117f46f66a6693501711481691c0bef0ba0563369841762c657", + "0xf6711b05e901583fe0b51177597d44354ce57364282e042e143f37185af0b13e", + "0x3f22f516c9fb33c327d2184b842edc2535dd6cf4969178c56ab98ac11996ea46", + "0xd51b6361e37ceb481bc6e37eb61432fdfe23d52f2b64aea70c0a12a3c79d2784", + "0x9a1e99c578e7f7a69b7d914c0f748b3f94b6b30bae1be056849bfecc74e31751", + "0x5539c971cb882506860bf724b3f3d05cc399af4640775ed805288468dd83cfd7", + "0xc54c50d46acb1fbe017364ebcb66b4563bc0ab60753b055a19b126a55c476bc7", + "0x3adb55f5b09858cb849ec9edc3adf5e3ffb8eac43434c1ccb817038610b57c08", + "0x5fa06980ab83374613079b9d61c53d6ba93d41af996f5d9fb5e5ef05d36d8aae", + "0x1b66a155b1ebb780d501ac9f6d14f8ce6c644af88b7f86f87b5815379258c494", + "0xb75860039c1886823bd489d9f3b92c4f6bc46629d3fedc9f7d6fde59a318518d", + "0xaffab6d2682c1641658270a5b63e9e46b0bb90c05eeded11079b8f7d33899983", + "0xb5aede6209f50349dcbdaf85ff444e2252bd3e8e2faac12b517552b493ce4cde", + "0xa7c3e97ca8efbde3c829f2e363c5aabde3afe2fde9a1d106f868e87c0fc0682f", + "0x84f7405932b9aabbda33ac93170ffb73ccd5c584f0f55c17af4cd66fc938f739", + "0x7eb2a3d7ef2dd3fc0fc337070f1429e9b472a5912f9217ce4777bbdd07911034", + "0xb208f1088e65776f684d8b097b847c98cee4e274d49b07918e4ebae9585c443e", + "0xe0cec73204567174e0594f4082d01d7b8e8d382a6602e40b35b3197ba2eead6b", + "0x06642dd13587031239255686a40625c53358c4ced6eab78c696413f3cad9c6d8", + "0xb91a9a676da327548f5ed89ca74608c9403b994ed8f0cefeb53a1b5b09e76da5", + "0xe7dec1d92e8d551a54e7e310ca217933375c3a3944371ad5975d1601d5c6d0ac", + "0xee0d0b46a607e2b7df37f24ee652dde4ff65c95eb94b93092452a56f6ef9c754", + "0x8ef8f5852fd8e1f96f82cd3f4bdc716824070b3eaccbc2cca5da345298b752e4", + "0xe801666d13de5a51eba7c9e1d149339023b1b56c513bcba2e37dcf22bdb261a2", + "0x37a53559f626a819de48d74f7e6b484ec90c1fac766adfe08bf9234a139b0fec", + "0xeb8d703867e169bb31f5390ec877a7c6c82aab53f144593b75fc1599604d6c80", + "0xfed3012f3f281de26b447003799eca69e9845c6b5be85bc42670a64487c92a3f", + "0xf70358dc2c4e9d449727affd9cf45ddefa0f3480d964f85aaeb1543427e062a5", + "0x6491b2c05e217b7f21094e96c3381164f9db86c480b0970a27d8e25c875f5b7a", + "0xb4561f6329dd718c03d7ef6be0224612d776b72511294d29b293eb2e0a7b5cad", + "0x89f4a1b613ee34e1728899eeb294c48a21c28da7035d5d036cc46439fa42c965", + "0xe78f95f15c015a18e4598e33f06f6517c4455cbd2efd0dec1bead6080f050b35", + "0x7c64eb0c96598f099d0e9383eeabdc303002819b35223f744bf8a2bb80cbe394", + "0x98e5b4eaf42e390156a730d9e80606d80e2c0c9203e5511af1cea5361af63165", + "0xa481b0af82146b7aeb690456acab564fe356b2b8a560c4b5ab46817167bbed33", + "0xddac876def8620f40cc43a04c8d939fa12bb6d985223caf955e8174c46578bab", + "0x10a97a5a30805c28828d6e4eb4205905845d121149b7146e7373cdad4850ac88", + "0xe14ce88a794100c126707edb5a99922d394e004ce5fe178fbd02c8a34202d4b4", + "0xc3f18b1d11de7706063e2aeee7159589f64539fee39db233ce6983b24ffff076", + "0x6ae533d2bf3f35c6f1f256b9d1fdd863d5394956ded7a80b56ab1e12da78c93c", + "0x79ec4573d7df2f3b48ea706582d48d29a8d1483ae29577fd85b11c346a22e3a9", + "0x263652485fc477fc5407ca079eb494d4618943d01ffbc27ba3824fbc34e6bd63", + "0xcd414c2dfd20a303c9fd623d847e0387cb93cff53d006f335358894be35ac0b3", + "0x75d23d879b23aca1f2152147212506b0cc789c3e15fa8644a6c89a10ac926336", + "0xe166233fed0bfa647b84b95b4a04553087b4f42784334f5017dfd2a8e246f0d5", + "0xc48f212eef40b227aa429405e6c63d25fb35e9889a33007fd1afcc2bbb57a8df", + "0xfe6e67fe4057baa0701a7bc7f98f1b59e8c0ef03401e564d51b9fbbb49a5d11c", + "0xc31d73c0443dad07f6eaffa3171c77c8da87c54780d4f374128adb79fee4ed54", + "0xa0ea13b2425ec84fea7bb9f121f0aa72cfb00e36019e63fee991606246569281", + "0xce7e8e4515b0ebfcdd0afdb002f9017076de88e278b914c902bafca65a8b12fb", + "0xd14a72a5605124a8545dfc4d7419f00e85083d558fc662dc17b3bb289107da83", + "0x3e89c3740c294a0f54068cf769091b1a976fe4e60ab4fa48b9c38c034c08e9a8", + "0x2ee8355965ba13e91d71bde2a72347709c97cc33bcaf1ecc6952c860b07c60c4", + "0x63a87a93a0e410e53146a60a46ca870604f8301e221fb5b470402aa2dd5b9c54", + "0x0bbdfc34316855dfa828a58923acd7ebc556c88a43b655d32bd46ec6008d8351", + "0x4721db737d99128133928670bd229a0a7fd2889e00e222378fe5f663e35587f5", + "0x4f52db42c0f03f342883d78d387ec913a65f92961276b0e718d4b5fa268aaadf", + "0xf7d28588843f736c341b8572322d1ab397e0c5863ac9a30facec3eae0126f3b8", + "0x48940fceeebf3fca0496483b58228516b9c54404fddd31e573c951b12d017d2e", + "0x87542780e6dad24843883c420ef6fbcb2ebea31b073fe54cbdbd5ffb2c4b30e2", + "0x35bb6ee5defc7d7489b24e9e8659b7131ab9f7673960f3ab9bc9324d6034f3da", + "0x11719cf1a1d10bc3c4a48ab177ad65039ff09d1dbb34b1b7c15fa78b5506b5ce", + "0xd086c0fa8b0a1f7cabd9bcc5a1e36137f59b7ed6d91057defc6f62fbbce73956", + "0xeb461e410c324c9ef9a0d240fc5f153e1af9e88810f1563767022723bbac62bf", + "0x10a384a0f6c927bc9efc21ae1b2988e79268de24065b91065b582aff4e0cbcb2", + "0x7020503d8d86fe9bce39301207283c9f9bea9d7789d0f1488506a4073d482d6d", + "0x93657d3b8bd95e33b9b13c3a4130a623d4ed6d8eca8cfde3e6fc9e16b3f1f898", + "0x40727606bcdee8714dc15b349561d8b7d293ca4231227384c56f1a8fab986041", + "0x5ba216663e223675ed7da19a7bbcb08483f6871cf11d911c3ba992829e40ce2d", + "0xe9eabb151a2d735f0ca36ac9ed65c612276a21e28b1a63b5fe632dba27207969", + "0xed88ead1835a70d30368a33955de7c4736bbdc22ba95f04aff7097589887b2bc", + "0xca47f392632e4684e54fd50f5cb8e6983c8c2085d4df8550e3398c4e2bfb9bb7", + "0xeb8699fcad43fac0bb54ab553c4f29c7d1a3ea6079e9d5218a14b675477576d8", + "0x912ab118b513c06e618f29f9a7273e8035b4723b3a21521a91a43100486759d1", + "0xc89d31d9d5bf2fcdcfbf8ba8c61307656bb5673474ea605d1e5d70ab1d7ba43a", + "0x8fbcad4bb94b91cec5d9ac2534666f019c807f8889d37e3107fba28002c7dd1c", + "0x3f606a227cd3a38e2d5da4c611b9069c109e9c291d390e5c1bb3b427be68c5d7", + "0xa69c47f146ba22a6f53562f4ec3d13e1cc5499db587095dadb4a89f6456be664", + "0x36a9e5d14b3fbc061dc83eccc0e6dc3f2a56f0a56e88a987f09d89257c2d2ccd", + "0x9d77184cdeaec05bdde7df7005467af592a625bb0a470e5b071d6cc6537a24b8", + "0x3f9634b50a524ff350dbd4e764d3c01d848b44400485f792d4ce4e17a3afed80", + "0x142e648622d2f13dbfa4c0e58f91ec0073455a6b327a2a2273fef05ca9fa7553", + "0xa4348c80308a3e0b0b4d290152bd09b24d2420281ff3240d2b54c406ba2ac003", + "0x95e86927eca33fadf4d35feb4514ecb90babbcf2ab5c801533a4d36ea8ccc87a", + "0xbefc0239b823cfca21afc0f57c144226a8a72f6acf86a1152d8a80ccb27475e1", + "0x1bdc16bd7d21c2cf818f4d3f5f1cab4a7d256ebb8b32a8464c6b6ca111c9ab87", + "0x04aa15ecdc0277166a77953b4596e2558af4295a342330ecf9d21b6221f21a40", + "0xb432d2660f59648ef7929901a0ce38ff577b4162a69ec92609c8ca1cbea5f8e1", + "0x985a13bc2bafb56e5ffd1b0e582790eff30786bbacc6e28ca57017d398f1552a", + "0x57c5399f6606f02bd06c9470246948e3d482ff9dec5de270f6c06dcc49c8c8dd", + "0xee471268956c3947f22dc8a6077c850f10c1227f50cd24ab7a059b94f3496274", + "0x97cc4534898ab427418bad275c9c21c18d6f51cead840bd5b800e27e1bb1f76f", + "0x1370774538f3c6aff104060091a573c94269421e5347d9ee26c9c5ec90956174", + "0x7b29a2dc9f4e8c3d43d3ec93d01484205583cfc6c8fac71ed0dd6eeab3c7e987", + "0x2127f737690dac5f24595b5d0b96e869f750b732fd8f004860b5510376b154a7", + "0x196f4545946a3a4b9d5a1c2ce3813e55245cefcbbe424eb50dc7126a6f7ce294", + "0x89a6c2dd239f741797b47166d4a97d8a6147b26c7f61471a272035fa6a19ca04", + "0xd4cec04b0a1a8a2240cd2745e53e55dd560c3da0bef625e3472a03c60e5e1346", + "0x482aa6954d7bfb528abdd0d2a44ca7256adc9d2b5c885f67af0424add0f85039", + "0x16d73722fc18c4c5fe53ec609695dab204ea3a0ac8d52356acc56377495dc715", + "0xa2fc87f2deaf252bc56f50d67e5ea24cdd23fc3a0931c69e5c7f832c57e6cf5c", + "0x95702d0ce28a00a2c52cac13db300b535e6be5aab6f1acd8f7f8f3664d8f1942", + "0xd7423e6ac1d49688437234bfcaff2f8075a6237b35b719084c6f9257d6b095ea", + "0xc1efed370db76aa0e6e31680e91ae03788ffb343c13700ed30012102a727ab05", + "0xad108c165dfc00e6db95fe8fb28a51a21f471d16093f761af92dc3c1a76cde18", + "0x579ff43e25ed4183ab6638a5b3b8ca5ee06343b410a47abecb154fa98fa701db", + "0x58446a3cb729e43ef984f52bd3a1c0c5bc2986b355993dc04826987c9a4c2b0d", + "0x916b6e17ed534b2ed79c4139250ced98cf81a39ce19092ca7593b8046b010fe9", + "0x5a85afb15b437acc1958c1a35beb35ea25a4e4bb2856fe82f4d2c257ad92e4ec", + "0x74f15f12f6acbbc1ebe68f82e5832c2581660451eecec1d2369ca842c0384927", + "0xe3724b93bfba09e69c4d3991f5bb7560dfa58f264a2ecefc1fae2a933fd81c75", + "0x4651a72f64ecfaa2b51804f6c02f0e341d43163b408786df50569668d6b1afc5", + "0xd67008562a459791d2de81c71369507475fc3727fb46f68ded3bdf313ae3dbaf", + "0xcfd841df8cc01abfdb09b47afd98caaaba19b900c7d4249eac819f24ef7ae98b", + "0xedb8f1bb736b4b16985f41b97209730b6f99d981fe3ca0c614d138cc9f3651e6", + "0xf03d65be04a3b5011007b48aa3eeae54b39166013f8f0977fe185036a2302360", + "0xdbc7e5449a0af2b69668ef3f860dbaf2b0e0053eb5f96bd5879f59d1535aac78", + "0x44e3d860cf489a017a5a0c99b7fe2facf87c7bbe8c641bc2ac020bd45ae278f3", + "0x8f2d4fb90e6fb5d1465e5e5368b36d44d2081842b2c3b1ac3c2789cc8e2061e7", + "0xb47a9bfac379a6414b66c2b79ced91d87f130b0c2f86c67ca5295fa656547b24", + "0x8975e42bd19f5ff5a6336f835a53e0e7d8ec1288b9f59c266e1da463fff8f24e", + "0x52a573f0165af4f0a8bbd90c8ec2539ff430ae8bb9818c2cbc2c91f82ec056df", + "0xba647605f77311d053ff9c76ac71e88b6d1dd6b4dd5296eb0b7fe3e07eb43880", + "0x1c6d4757e48f80ac0a247bc7b2649239d0284b2580248a8b6706f04ff47c1f1c", + "0xfe42314e663a9196f7bc6b795bdf2763f49467c9b2183eb02c25b5c79e20fc44", + "0x15b6054f899df7793f03ab925c1d8df2f94d6221552b890af6de5d8a5b7948f5", + "0x694798b4238b93838948377161ef5165af4dfbda5f0f9d8d2d37c083c3718393", + "0x58724b920890120f1f90ce8bc3e9c6639042b3cfa78123bc9917b8854315e31e", + "0x21f057c8e538eee76a95659618bccefab9a7a5ffc955781141a3eef71f3b3423", + "0xa5fec657cc7ab1b633023791470bb2c5a7f1dbfb3ccc4e6442565a791754f319", + "0x67a17493b80cf75ab905ccee157746c7ed048a8406fdd94af1c6916cfcb29220", + "0x9d5132754a73e0ba316da2f824f5264e851526c6a75bccd153cd41f232e1ba42", + "0xe9f6b8e973183e7b89ab72479003bcf07cd0d141521c23e4e4269f58f51692ad", + "0xe52cf37c47ddd837146288364ba448980c24dda74c6a2560a99ece3174c94a57", + "0xefb69d2b602cd8b073314ae5af7d6200d23335f1e46980c205ba0bdd979d0ec1", + "0x3e2f6e13459a82666bfc366941b39506d84b1b6a1c94e4361d51d30cc1bf4218", + "0xac8562bd8210325b1dcc8cc3c4214a97d04ce795c3fd9049c7296f0d855045a8", + "0x22b62db26899a50ef8630a9aac5cef645512355901ba14e8f1a3468610473756", + "0x24f7a40ba3243eed13a4c2ad7fb273a1fd822a3d2b8ec729b0e5184c3f791e76", + "0x1ea72f2b13fbc945e3ca51bd681b2e12e4ead38f42622ac3be54a1b89c826baf", + "0x95b26a476c67aa211235b0b177964422d037768a1c162526a53e73b2777b85ed", + "0x1ed2cbd748843651a8ab0a31b256d4d3c6bdf3cbd3db7e73090a679756880a6f", + "0x20e857d94a0038a51313c8a67d30f7aed8b335e7cebdffe8795ee03e62e5443f", + "0x9b807ff518a22a7a40521537b137cc25904b8d2607d7d9ce1f0e50f2327801b3", + "0x35e573f1dc47520f16eb43240dcddb95d167eb8e59430c608f17303a9c86b639", + "0xa06a21571951ec87f6cba9dec2cc9f1e55b4b4d5d3e2e9415d30fbe50370af12", + "0x7961da55526e7a67feeac00e625a1ca93607b7bc4d4d68142ba791e46d333e78", + "0x5accacce3901feda7004414e0d514129bcbb14ea727f34f58fddf4b928774589", + "0x0d66a4004a235178a69941894ccadc2e91a843c849284db82e90a088c3d3c6bc", + "0x8255a1650988cee8c57e30a5a8fa159f71fc2f3e23f799e11f5bb31b09c54667", + "0x7d6936163556f21f56185718a6b7de5bec0375a01f4c88467820d8c66dd983db", + "0x3e3c08ff6cd5f69aa8f85e9a5d8c91462cc228a41e392b7a544e2efb6af87cd8", + "0x4f401bca18b8cfab219430fd6807aff86867ea52f12b45ec224fa9dc318dd789", + "0xe14e32f37af0204cc56fb10ae891cb09b0c27a116ad42b5946dd1815f445cfe2", + "0xae46c70ae8bd612e760b614689d48b34358bf504a2414b660224312622917e4a", + "0xe8870fb901d8234646d87be0eb0b15d46f55c8d3765beb631dbd06da88d50038", + "0x997b7b18cccdd31b611bc01767a3be138f5ffb2c92de11aa1fa486a578c94799", + "0xecc5dea6b6e3d233f7caaf17e07a5f58febf9fa6d0736228da43b28cb5538dc0", + "0xb56b9b982a7915d85fef49df531e0a1e8e8d000b30da66104265eaa7317ee2cd", + "0x09601975476271e885e83f96799f15cfa6c0a67037b9d31eebf01cf510fdd752", + "0xab2e7c3c19f0d7aad30ff986e9b2c8a56f09906b851c53455af4d35d61b20a32", + "0xe5590d245bcc42d8efe40d677c42d840da1b32c49369bf352f46690bed9a4dfc", + "0xb46810ae0d11af6412e219bb99be0ac22c033433b1567a36a69cd962c9456d41", + "0xc296086ad6481ed8954c5542e4083388a4048132a952f500b2c362a19e8333c8", + "0xc39bf0d7e42ecfe35ab387932eb54ce0c1e502168ba5aa74b838aa17ec294d27", + "0x1ea48989819dcdf6aa0e9b0cc41d52a4d348fa80c8aaadb24091c517e3fd203b", + "0x58974a726103f506b2d8c904a8b942e247ca648678b7b98e484c203e4bf03ae8", + "0x0ccee08094a04e4db707f8d570c6098cb87b271a2aeeed08e0f589d2c162afa2", + "0x5a8620a1f85f856a8cfc105a05d4a935cfe626de46eac68e2c78c7b8fbb08c31", + "0x070101ef142836edb475e9e5bddfc821fbac8b2f8605ad9f52a1ae00bd0d1f6a", + "0x822efecd485d634912a4fdad41d72479c31b7cfaf664f3a0f78dc9ebb624cede", + "0xc6c7f14ff1b5618cfa096080c6fa59d301b3c2f516ed9f4eb0c3acdcac3e1ee2", + "0xbe85e53c24900f6d22564f33f05f1250c9f80b1b4616c0dcbb6f500f22d376b5", + "0xa84385d0d3f54995864695c96c5fdd30affe8dd9548b754edd12d80802706ef4", + "0xe12c3324e68b4efbb14fa5522ef6d2418ef7c397f390c2b91e30352ffb538c48", + "0x06cafdf319f45ac908dccc5e510b67be82635a488234d9b3fd016dd2f09667d3", + "0x236822c1c20ce528a5d9a985c2a2eaf8349a3ff1dc13cb7f9a8c7bb5bc39e9de", + "0xc438b7d70a69768bb81ab867d6772133a592f7cf770931eb51e893c106461143", + "0xa49a416419f910f762ea095d4e8eddaaa7b01b406e730d3bc1846d24b6952302", + "0x08c83875d8ad54befb643c8d8dc684358aa22c144b9448820c0a62e5ceb9e9a0", + "0xd81a30c959e06eeeab28bc3b95a1c8a3466f2552d51ec0bde69a1d1f107f5405", + "0x76803ab074a7170033dbcc33a68d2b497998dfde8b9ff86101fd54539d1bd393", + "0xf7b9503ce1753623091cd263ff23af68851445bdf97c166358b890ff9dc78f17", + "0xbef1f09e8233542c73ea380abf0115279469e2bbe3abd557b89d12b514bc7a7f", + "0x8ef2348cff8d0d40e6f1b0973636915adb3ca63fec663383b8afac1a46dd0e8b", + "0x9724f0ce677572033e30756e4fd356680bc64d171acf7483d5dfc936267d3d8d", + "0xe5fe7147af6d1d1d52d34714de41a7cf7bedf38bff1a29a25263beab0f59fe61", + "0x3782ed2e5a049f3d877c8480b590a5d2055918c17804fad7ee7a6c2a4358bdc6", + "0x9bb40bd9cbb5d20c8987aa4e75b0a8036d0d10d87c46abee889d5fc23d10c98a", + "0x75d9d23fb96bde45550b2cb8ae4759ad36fbcbed51f00cf1bd1d04d0f5d0400f", + "0x5a5f79793464475b35bd7fc427a745b76541ab65d62e500d93e5357e588948ac", + "0x903e3a38194c6eb3cc98c857b98ef68bb1fc988220b12138ab40141335b2b9af", + "0x9c5c6d1fc8f1242a0f3f41e6dd9cb7c1ce6dc644b1ce552b3dc0ff7db83251f6", + "0x77b89a725a743a7b31b01022e4ffd1f35f733461828f204cc75f4f00290a01ba", + "0xabc38d580c92f199cc0aece60899fb6967ca48a096b98991dd757ed1fba6c36f", + "0x61742ed64d417b66d67e4638d0bb60d95f88cca17cb7630b1254ac3c47739df5", + "0x47f7bdedee6e8eec229eb0f66fad208a8a05450c8b649e2dc400e1b5759f4b1e", + "0xdeea16c07180d8a4eb104e309343225a354a3adfbf1b8af733456a185f3ca669", + "0x6df5b47f5b11511f42b4e981d92d55cd9aa3373fd90735cfc4c594c516159027", + "0x5a5af9e8656afd3b52f4e27002f1be9b09c5e7a3746fac7e64f5973ed423c14f", + "0x1ccb86d370ee32261f76a3e9d5948c40489c26f2f4216535484d7bd586f2851b", + "0x313dda0f2ce1542eb1236a1d555959516abe06951460d77664650b6cb7613d5f", + "0xfcf5408ed6675b5d1c15629e02635d726777e63817c3ccac36d4726bf95fc4db", + "0xbf5f15c67971a4b624a8ee8f81086fe24f1940a084bbfa031d0b69b865d553c6", + "0x9fbc4b0ebc2a128d391b68be84f6ef7833d5413bd95f751b503799a54c55c3c5", + "0x7ba3b1dec981980a957680b3c125328bf3683578828412c3de197ad07d06565c", + "0x4d2ea255cff42df73c96d18fc2c372e5ea9fe80eab5c98a6c6579725bf4c6fa1", + "0x9793db50b81ac75df1846e8b8898dccfa822d69bc4f99f6bcdc95ace2e3317fe", + "0x21c1959416e88792275d6eba88e8fa503c40a1f4a4b78cbab5b94e6c1ef714ea", + "0x3161a8a5b42bcf792b44bc3f7fef3606978b6bf716effb5ca1b0fa6b85518ae1", + "0x59ca1b7fd1f09941c911a4a6d0365e7a852a420a43af73ee0bd76f6413c6f3f6", + "0x86db4d45c982f195667fefc3de1af4a17b083b6f3700e47568ea43829e686e06", + "0xe5a713d52d696cbe65220fb30a4183ff9121ae1868967eee002cc032fa41b07b", + "0x446668d8777d9666222a04bc9963f89873387535f485490adbbd15094e6cb9db", + "0xda139e22348743ae9d600e9e2f651a717b8864f7bc8a4881a875945daa2645fe", + "0xae22c6f51fa8c11daf898addd39665d7bdf6d266d42ddabd790accd6538a6778", + "0x1059bd6151a5a3de93e45f7b3c498225b759a46444717cef5e66879b6e0a43ab", + "0x893e490bd7a3cef98d878f4f55d22aa0456f934e16a5ed635bab5d993909b006", + "0xefff7bff0a97e0e51718eff0d61540e164cb131ebaf466f01516ebe956b6e0f5", + "0xe6eef674ead50579daf941c526fdb904419a37f009fd432ce0521835b7ea09d1", + "0x7cb9c0e3aed016176058c80a03eea8f70e6f0467cc744ee752d937422ddf455e", + "0x995c33746119fe51b3a3c71311fbd4d91810a2ad95a558101bd11ff1a9913da5", + "0x926048c8fa6053aaf47f8986f195d19f1a86a4e01d5b34c45c91a09f57be0cfc", + "0x18ff8ac452c3f84463c8d8d92fa6f5550149f0d9cc0bf9b9a6ff6f05a8e3dac4", + "0xb495eef7e11375f1fdd6fa2fe3f97e1b834c39abe60ef1eb75333f36474a57c8", + "0x8dd386ddc871b764849a057f98a838f0f66883cdaea5ce4a9728910d3e1d124b", + "0x344c77e81e60bb40be5a20fa14b7fdc8c4c696d523cfcabc408e04df7fb79259", + "0x6b55d08a7eeb8f800866f031cf194c0ac2292923fe0df0460fedddcc77ba59ae", + "0xa007e70a725287607f23c03a782cb36ebecd692b45c1273b62769ddd1d0caf1d", + "0xb196d7291e437b6a26d006634de1edd3096367faacaa2b64b6c52a5d2228fd43", + "0x7f4f82aaff92c6e348d8b52e3bffddc7d06780b3750630d40022d54e668ec761", + "0x942e657c2125a5f57351b6e5fc76cf6ff6690529034f65d1bfa18ec8827bb241", + "0xce436799308200b480aa234ee2a4ad407bed1142999a360ce8a3d2230bfd4285", + "0x9f3fe03371f56c4afa64fbf2379c7dda3752eb19077a4de4b412fb7b5a4721be", + "0x53f63ddffee8a93759f68730026c3a8c9026a1a61a17ecd8b98d29e3d24dd019", + "0x08c2112cf1abe207076a67b43f67402df0d9d99990cec96e10ca46f4799134c0", + "0x41c4a5929a07431a1a0918caa5294b9b0f706960afe8e75b0e4555e40e182d7e", + "0x188b2fbd1b54709384dbc8b62e21cb1cde0b5c743aa3c25d8ce5ba4557728a54", + "0x92cc75e85ad9a09407bd0c09d68436fc419eda5c29614e125ff99964e304c0e8", + "0xfad03371877721fb4477f73575cee54356114f0842222f6a343357a15d409568", + "0x6072b8482ccdfe974790727775e8c0c43228a724068a39e351a5c702e7086fe3", + "0xdea9c30a8f46fe7e34b191d90b14fe09aa61275a32063ccca2d138886419c60a", + "0x3c24861389a3d1a8ed5d2c71e052914d4dabca490be956b7ed63a2195d65bf60", + "0xa2dd585af11cc6d60b55ab7b5295db6f5fd49e34c58948ece2ba6a4417f53fed", + "0xd0cd3dfcdee7cf3b00e718b6086ffbad37e61b80df49c373371b6ea449e5dfe9", + "0x018a9cccbbee610c3d978afce046e1e729013fc7ae71a0d80b2c22054acc32bf", + "0x6cd7707d257de792f35bc5d5080ae5bcfc50188ec61b406743f0390e8f5e4ee0", + "0xf036437c80029ef8595f65cede2446255b436ab2b47cacebcbc513ee09bbc6dc", + "0x438c8373efeb9d010e459097f7eef12dfd469a5d447f5494742321fcad2f5fbd", + "0x97174ad7515662e1cde2300a93986316ce4b7ae00b7f35a0908cde607ef6070e", + "0x8527198f8104df2b8559ff578ef5e2a84a9f0ffd63d8faedf26a50b44a19932c", + "0x7e4b79ce0fa7dfb5b4cfb92a98a0f4de105ac1a931a34efe94c16e29d5b03fa0", + "0xc240072b872710ac52ef170ca53ab03b3f76f1e2c1cc40dd48ebec3d0636d6cf", + "0xf957c0f8495186575f4a1bd2fc19350c9fed57fd60a884999d943e5fdca35038", + "0x814f0dfbdf3cddeaa502feb0f13f879223d9f0a14d01d756c3b3e773b44ce581", + "0x999f07e2f640408c58cb9cc0d15b4ff6c90db7b85e98e6888f74beefce295c1d", + "0x71e4362451b4d259a942b2a0425a070a9f0053aebface053d9c02f9ca4a5ff3f", + "0x28a29356d506b43e9dc9fc05bf6c7533e6670f5ab1122f49ac572bc2c9b94b49", + "0xa6dc1aeb3352b65845baa0329491789262c71b444171e36a55f3e20ab5edc026", + "0x6a0d71aee995e2857459513c124ccf8f81212ef0f14ea8a99b24b395e763e2b5", + "0xebd35e5b9134079efbdb4759e0c2af7728b73caeabc2c2bfdc3f590d5eaabc68", + "0xf1a7367e7b712b141602d204924a0c8808c68b013006b344e30d207a3b8c179a", + "0xb142818bb0edf0b1cc120389d0bef91b1a7b3e1fe0058810bbf73d04cd573147", + "0x8aef2ed196ca7cea305211c656084a46438ccdb7d2549f24fe4bd3fabf11af57", + "0x934cdfed19bc7321061d3ad217879cd14def18b18f6d8d2baa625626214d39a0", + "0x16f1b202a884faa4dcccf5d408b3acb639a78aa1104d1bcae40182f71d94a1f6", + "0x5cdb53c18168fa65c252659ba594552ed95150a4f0f2b9391ea3fb56badfe814", + "0x304558b9ab585c1201af4e88848d81f5fbc380341bfe8df9e9ebd279a94a1c4b", + "0x7c13cf0890b8fea28d01b7446750a5f1429d343ba69525e3909f054495d30f41", + "0x38ff978ee475767c435e5cbf5c0ba9c10c48426a9839735b67e2d32028a1582e", + "0x7fc90ebe34bd2cea4744c1ca0f3968a304f7cbb133353cd0aa76b45d0e88a23b", + "0xb0da2f67974a7cd5a291665ee3d216d5f57df1b66e7a2f36dabbd97cc68bcd0b", + "0xc220942a0821ea338d4307365bd1be586dc8b3a89f2b0f60065c92375b1bfcf5", + "0xda1019e4bac45eae0717a35e7aad0c63e0063ba18a8e970cd631112a9baa3d3f", + "0x7efc5e52c0a590ceabce9eb4eab90c50a1bdf595b7a59b0ffb3e3091317377c0", + "0x2347c7c6cc6f741e484eac237688427292a65d01f037ab25419d3c17d538db6f", + "0x207e2f3f0e856faab65882a7d3cf09daa37f08406cb96e5bb4252c8d0fa7f27d", + "0xc425eaba8494a111289148c65db0c8d6a6dc27d16986b0b70ee4995723c878f1", + "0xf7778a3d1b7fd83b3d4926d2022cf823801a2749283c9ab4f86f87126b9c7e80", + "0x1316c7953bb3170efc234d13e9632e017ec4f58a30e4e062ead373b206461f1d", + "0x9b4cd6a0e47f2c64c0ba4d9a7565f74e956cf881bdc33b1176617bf9f25af5de", + "0xa972bf247d8428e97218ec0e9a36e3b7fad10ce9a3126bdeb2cac7e9b4e48e46", + "0xc6a4e22ff93e8c9483dfd8eb8f2c384c72fe69cc4f5644e8d68d419b92509c61", + "0x601a9a84099f3205c6aecd034b53f586382379dc39be605facbc2da5f793b990", + "0xb7ed45da8acd237dc9c265afbaa15300cc7cf72c740bbcc00eabaf4dd90cf9b1", + "0x37bcee935e0ef47df22a7f9833b3b3a3830efb1656059c450a7e6a144798552d", + "0x06e7ecbc0f4d4b16a24d4260d77d0161c5a627083589747c72f765281ca8d3c4", + "0xc45d35b6c6a81240767ee9d994c8e2f5823d8a4e0f51abb7187e234d6dd5076c", + "0xd3c726980fdf096fa314533ca3e882cb1c1a2a5eba4b9ccef7193e9ab7ce34b6", + "0xa6c23887788743ac8bdc123c7b21873889d538f7acc389c28d6ac9dd26da06ec", + "0xb8b8e38541b9143da71d68cb705ad5076b089b6174d99bab4b87428d8828ac9c", + "0xa70ec737a97e306a66b7ab8a7866d03d496bdac04a08a0ccede2b84583ee5d21", + "0x6d43013f53b03cbaa4c82a2d42f5336306301bc7a624542387cb0a822ce89a50", + "0xc24661eb76bee7b5db00df129db5c2038dff544a90de77809a447530e8200d02", + "0xfd291a2a58d472bb262b3e9b4b2c08f8ca40536082e05c081ccd502c77a78fde", + "0xa34be368c12bd1c05ada73b647d72da9595b0d618679905c2df760ff1a2b6dfa", + "0x4e68946f1b2d9f9a1c10f90b0d354084561bf5440a823945c2d95f76fe23a765", + "0x44e04796d2516db3ec1d1b47b47776999614e81f6d300e2dacbd4d15746982ea", + "0xaac3047a84d57dac9b3f3c8ba907bec354f99ec2d35b915f115f4af6a658cb41", + "0x58489c0ccf49e147ec986ffeca33e037dedabc57690bdefeee7af8a70b781fbf", + "0x3707fd39b11fa9b79749a84848deba1c70534a493769788de1610798b30eb70a", + "0x891483f79855a712f99bf6bbad19a3291c4d417a4f27d66868951c454ad1bbbf", + "0xbac1fbd157279efe1b895138c55e8da4be5dac3b78c179c4cf25a0c8b5e7c5a2", + "0xed050c00def0f6b5936324a13f426cda7229ffc68c7f0eb0ff6dadda957c737f", + "0xb0e759e352ea7ccca080e4ed51a6a4aa4573c7c0d703183da7a98918fa9bed81", + "0x914fb73a4233f0368088073688994cbb0bf5f973a5afadc11076cd64f92ec5d3", + "0x153136092380ba6be166df58738c72d5be76acafcab31474a72b7f7e70e9296b", + "0x7d4d6f2fef46e1b87a73acc8c6eac29195286af79ed7e07998aa966c536f8f80", + "0xa0d10b259aa47815403230b836be272c3dde8cea738868ded0d55d89f2692dae", + "0x13ba7e74aeb0ad66c77cd5112e1ae1b6d3eea84a7c306d161408ef592f2f3399", + "0x491fe1f14cc862fa156f04901a7a93ef26ad272cf98e4f29d28a6250f8b4738a", + "0x92a8a01853ee89642fcf51e42e6a39616f8374937a98ea579d9fe35557d37bdc", + "0xc140bc3ebebc1509940644318dab91a6b8722a54bc32ac7500d94d1aa24ae1ed", + "0x55a5a8541d36a244b1d73b32fbe99263cd6a7b3d9b88312747de6d66302e2a63", + "0x510caebe6714728c47beb114e95177c3a0fc2438369842278a17da9c4327caa5", + "0x8ec8d3e19017cdd4bb4b789ad29bca53d8635596e6771e09becb9e261df64be9", + "0x2e832a7e47a73b47ae881794122f86e1a06e1d84c5bd0a946bb61175dbb5c0bc", + "0xbdb48c7ec1f278b646faca580983ddf4088835803fc0dc2e505be6b092442d04", + "0xcee8eee843b37076f11f69b77094872966f88b4629240e04cea69d4eb16d642c", + "0xede0d0302e40a6e71dd63a52fc1bea3828c4dd56c754b576af9c441ffe2945aa", + "0x07c84f827310d73cc44181f612f5f5ee0ac1207b3f72ae857f9f1fc0180e8454", + "0x40c4dddc5fff7a7a5372de4d64945900e1d6908f378d87b4bb75e425d1fd3daf", + "0x61d9dec3abd29d998af2cadfdc7d22344b651efc717797a486712dd10a726c01", + "0x9de133af95e03c3bacdc17ee428c0ee05b70ef2b1b515edd6fe488db3d091e88", + "0x109aa9704907a39615ccbd296974e428bf5fbac0bce5af02d9c3a8e45e47e160", + "0x8a1f2230da7f048dda7d17e7347cb1cdd2bbcc2ed0908980f22ec070d158689f", + "0x9e8215bd095daa6870eca13dd025edfc700bb5f5ae4f0ef9d44a85b04f15596d", + "0xf93f90b45c5e3358a73392f21fe640c6aff9cbf352eb7a1725088313630d6226", + "0x4e4c1ceb1177bd15944b238624f6e41aa0713564eccbd7f0976f22cfb03c90b9", + "0x2b7d1e8792dc0271b3802e79e4531e42d93475471d880de288dd4cfdd85155df", + "0xbffb3529844e19c7e24a3bad1fd0b90d8319c6982badd3716ec897ae01b0ff57", + "0x497725904d682be0024f5327c62907f1507530231fe6437341e85373aa941d03", + "0x20c7929ae689311a8edc8672b1ff85d79b2187c46da7d0f1e0decdda16eec6b9", + "0x87fec4a78f73a200c7798a07e9f7d956aafc83ab4a90309591bb76152b8e11e3", + "0xabe053b8ae209ab83d827b63e43e08b9b4228b04d51026bcbf044531a2e8f86f", + "0x4220e78d59f01c20f45273e5183a2a36d6d89c2f406df441e76fa8b3f540c8e4", + "0xbbf658cff95c4f1cff08b95069d5eecd60ce5960818014edd66b4f0761708827", + "0x885d316eed1f99685d4dfb1d50701b7a0c9892131a99bf1c676d53c15ba1f7d7", + "0x0fd86d1ee76af5eacc36255f29606e4574b93b1501762118173cfb9997996c78", + "0x400114dc52b491898bd47923cd5d91384ad6a728f725ffe87c916ba858e58a95", + "0xd489355bf13693c3c70b031421c885aa09772cb9d10381d6a5dad584f2055790", + "0xbbe033546ee5909557cb5b96d466ca32973b455f34bba60ddcdee782d8b6cadb", + "0x207bdb63fcf0b403bdbeef4f714da0393b1760adcd1f1f5b21a178bc404c9617", + "0xa30b9d2cffd283cba9de68eed716761ea78170a8d7e6444068d64563c141dd2f", + "0x995015315151329c91ad8ad28aac545c50196dabf0ae393c72d9f369524c9fc8", + "0x3928c0b178546ff50c5668677d2605b701b06f4d28af0c189e746b73b9d5c53d", + "0x46bc7b35d38eb9efecb3082436f28e3d0e36465e41222dd8b8b47fd9857de499", + "0x93d83ff35c0e00277205f12b3ccc89ae35c28177023f2c37b562df491dfd0e1a", + "0x11442d3d7778f2e463da87bfe957768e36087cd2b777e8b0d78fedc624b9a9e7", + "0x2c4ca247e8c280db854ac3ff7d270ca3100b30377b6ff807b853da46c7321113", + "0x0f72e138a21dd3ddd2913dd1eeae525cd78aa578b909672b4450158bcae26aa4", + "0x6a02b4d5e27880290806d410461c10558f33ea04ab655d291e45a7baae5d48d6", + "0x5698a8526618fe20a06bbaa970590e97ca9677ad95b0b532cc816b2577ec1bc7", + "0x7fb913cf94da8bfd05526a954c1f2e1382ae275a060b646d2ba78f004d67d30b", + "0x1aab7d83cd25cceeadc8352a9de9600b0b69acf33a3e157e5e54044a4b1baa60", + "0x03df372e7293b449518d07c4d672c76157c97c6bdc8d7ea75b5d37daca19dbb7", + "0xa928453adde66a9ea45a6b19560fef2619fde93a0a0ee463d64ce538fed0f8a2", + "0xf9cb142d5728bc1dfd59812afcaff8877e6357a46ac9da8beb54c1cdb53bf4f2", + "0x3c67d2318e1867ee0bf234129e7f9ff7aced4d6a94bc2493df3d49d3ef7a1f1b", + "0xe7995735d058d5f1281298652cfec16318f36d90aabb73bec620db045a4127db", + "0x796b4fc8ff8d962425ad653c20cd5e3cf5802edf8fc363824cbb4a117e5dd9c6", + "0x3e1f5f3519dcd5649bed8a4fce463bce7b8a28ce4853b2a34c219c76d8e64238", + "0x0b56a06fcc04ecab448189e170470bcee6415c859a59a2d18b5e9a838bcf2ff3", + "0xa8ceb396b19d4c72d6379f27d0a8283a06c7920811c045dd2521b20d719c9f60", + "0x42c02012a9f184d3bf976ecdb7f65e7abd70b4a32493d75cbf0c3403f5ca358e", + "0x79aa61d2303214ca5099ce8d8c8b59d7d3f64d4af9a009683ca4fe2ecd1ba4a2", + "0xbf626f7b1e4be0c3fbd962e021d50f40e580f133b6127a71ee06c621fe6508f1", + "0x3a8e93479758ef89aca8a3311a16fb82fef78b19ed11c058625e6bc6d4a4dab0", + "0xb44da67d7c6114b0578183dd1287bf06f0f8185a41c77ea75728e48954b4959b", + "0xf49609ba698b8085cccdd8f95a51996d9df32cfb8d0293c01182482dd03b56f2", + "0x94226b7a92c9aea67f94df39675af2f27cdc9a95c847eeedf85ffa17238b3b58", + "0xcb27475102016a2ac05f8c8718e110b74fffcd6c2a97ad0b344ff07a6a806e2b", + "0x84b0c9983378884ad2ecd01c7851efa8c0906b4741d42581c3f1c52c47a88151", + "0xa9071e8c2f56b564873a782630fbe3bd292337b2b620eaead27a397ee3b3aafd", + "0x8c057d25493e712878bd8b628b3cff7bb1249ae41dd34c25ff57a3bd12b9a96d", + "0x7c2b71dbda144cfea3c1e492f0a1e30f2699f3f1968da76a97fe39f3867d37bf", + "0x63b9d33e4d168389637e6fff44d525b67b5e0c52bfab9fbeb53df0ecdd601984", + "0x2a74b62ae8feff55542905a34d6f45c1441891130351bc9959c62f53864385b5", + "0x725a488e62ba0c296ee78267ce714a8ac84ecc3fb8dc4b5147024ee500821dd7", + "0x6c54d3f508c1421a60a707000e1236dd6b45becf483b1f21a53723188c1629b6", + "0xea9072804289a3b9fabd8652a56c2da6e661f14ba764f72949f7fce38e517e7d", + "0x65118fa4f148eb7b0feabd60c0ab9d42802a5ad7685b70bee9ef8eab668c046b", + "0xb07416ee467668d8c7f92a260a6fc430bf636e29b9d5ded3dfac9751e006eb4a", + "0x55385976c32b170335a70a213780cada5fb0c6dd5402cd3056a60a40a6f13afd", + "0x7d9f44575cfa89ae8f4e160a1f432e3e05d02c40b9d25ca0c06df6d35226985c", + "0x12774d382f48d5be794157e2a601c3814135f8cb961d534e685368c3d605f430", + "0x2be48bbedbb5d66af410fa612328524aba00374c152a0b533fb2f15e98bcce10", + "0xcceb249b515238c46a805cbd452395633f28864f16959cef39ca13b69acdcc2c", + "0x90b5204c90b256708cc946daad4a70e3cbbcae36356b377ea6cb251568d8e87b", + "0x468a2c9bd83eabbd10a5e301201e54b9530b9a376452096bbed509240c6d7b08", + "0x322456bcf4495d9787fb66d0d8f21242210167a1dc622706c647e1495c19d064", + "0x1708f1ba83981d7d6d21b8a7d55a4bd9c6355195bf42eb96e870a36480f90cd1", + "0x904c7c58505bb73503c5baefa79936d96df91a15a6ce8121c7f38c632dc7172a", + "0xb2592d5491583e30e4b0e89820f6cd518d4b082436ccbb3a7685c365fb6e9aa4", + "0xf2b08ac926804a68d4c1dce8fda9cc1eaf14e963499f29527caf4797fc47933f", + "0xf9274e64683f5717fc4bce6bb2590921be5a67c1c3f9275bc390a438bdee8295", + "0x7d6c4c1ddfd161753d2782c80532479eac3ae593ca4decbe0b4308123759a218", + "0x3215152f21280b1baf712191a11b3bb80d48f936221a02d199f52437d878c402", + "0x748ac2bba96f92574ff048d2e3100b8e8543c181c8e817f3770e405f24b4e3be", + "0x056d9dd029b79d40d3599b6f6bf240603931a247979db979dd9e6dacdcc53d94", + "0x56c57e769cb7f53c4ca489db4de4eec62071cbed1bd33759c27662e411de0221", + "0xfc7a497be0b417bc1557eb04ec43f9ba4432cb029b6684c295b84e500527d5da", + "0xb505ce1021402ccac337fd5c5346fa162c6843b2d945b44ed45afee0139df1c3", + "0x267595787775e5a0d97e1cdf0a4deaaa785c03b8456a6e5b433767bbadb00ab8", + "0xdfd8e51ed2325e8f2d2bbcefcd24bf9242fbfd75dac246ac8186cf3a72b35de9", + "0x11004185cc8175d91364e878229f5aa5a5366130152e1dd8132cd22cb0333086", + "0xf5ec1ef381b33decb885d21749cc32ad02cfc66392281967758c3fb30158f9b2", + "0xef7fce98b3054d4fc282b38aeb4bddab1c35b085ad4ce803856157d7fc9025ce", + "0x7acbcfac776f80cf46614121866a2621df9302b7be20c079e224cc1377637586", + "0xef8433ec6eca61afc8bf7e8ccef7e1284aaacbb4972938fe061086307a6417a4", + "0x1f76cba9e66ca16339c3effb745c71443bcae09a22f1b07e39155a1805402890", + "0xd720f64f8ae3da220074c029256cb459b1ee8be67ed4dcaec10933cad35fc58b", + "0xf841bac34a5db54625473826eab74d3a53f7b3448e5835cdf4df370624d24aa7", + "0x7b784f45b8f2b0ec9229924fcbe26f66c306297cacec42af1c474566e1f83f6f", + "0xeb333d1de57ffe52d60603c66bbe9f2941fdb01f81832d418307596c156cf54a", + "0x06abb43d2b3733811dcf3059f48be59587425b5d24c086689191e5bc69fa03a3", + "0x76ffcb35a00362f10fb36d68eb7676093c3e36a3fe7ad65acd0f58a064865f2d", + "0xbfa99b31b08807772e417d9ed67daebed645ccfa0d94607dc0cce754bfdce0a5", + "0xa91db056c961f435693a047611028c7fb784ca015f450e146bc8e2b85ac8d592", + "0xf2489993da543373e00b5b42b8db157eae15026a65635e5784d06702d6574de4", + "0x1629e6d410d12987f412c01d14a21ae700e4939f45ec4ef0e1820905649b7899", + "0xf127b506db1c5b3a1aa6bcbb2c530e822bea1ab3deb497c54430fec6a60824f5", + "0x4860301daa24a54ae1902388dd072e7eae2ad449f4a86c123caf783284cbb7a4", + "0xa54be84ce7432042663e40822685cd4c3c1a33bdddb295dc32f9170ba7c95a14", + "0x576136e6b6f941a6861e863989da38d7234f524886f278f8a57e88bf925088a4", + "0x08e84b8d1e15a7aa660666a346a0b90db8cbbee7cc086378d4020d86b1385511", + "0x9229a29e091b9184dda6d66e244af33b0c536eb7e61b7777a5bb0d02f0a283dc", + "0x58e34e5a073bacffd29a05f85320aa52625a9cd27675954f739f3f9229e3a163", + "0x25d2f9f20d7cedf8582931d6dd9ef68233f3af9caf6c9c6d5a10f2b9372358ab", + "0xad43fec2e1ea1ff81772fadf5e38a4f280305cb225567becda2cd518ce2f1dd9", + "0x05195e944c209b1eefbe1925827e976c19d065d18b3e23d883ae2086471c73ac", + "0x62232485944c27ed398d4928cd9ad1680765a4efa652a925b97ae26220229fed", + "0x735c916d78f40581506a4cf286e044a6d61afe6d70daf97d80f8c584ce41d940", + "0x8b50f9bc93ce7c7582ebbd77bddcbc3a123e90d43434d63aa4b5c397a18bd1e1", + "0xa270240950e22fd66879927f8c51322f0feaffaf09e7bba8829ce5dd841b9e56", + "0x6791446d6f864992e3b50fb590719af98aadd7f8af54e4c71ec474cf0db56cb0", + "0xa22feb28061c72ce02f7d6bf27c7d04049900ec24394a73ea678b90c100de62e", + "0x0fbb9f4ef4d048767b036f40babd8769e185c549cd71e2e46cde94b2fc1916e6", + "0xb32bf314ae6b3994bf2caaa716691eb2116289a796f968ace5c49482965d2037", + "0xf68f7edc391befc772458ce2dc9e5a1c3eb9d3c709c4e177535a14a863eb686f", + "0xee3c3122cf1f7890fcbf409897c6ca4a634b6a90df2d33cafd8dbe1fd2895ea5", + "0x44c407d967d458d6cdbec3e4fd90e0f5fce309f702f08df5f7fa7d4d66ab8d90", + "0x1e4c7644e30228dd70194e600a57f98c3501a598835ba35a3b0c99f53101b108", + "0xb619a4deb408b73810fd4c5a827c0cdc3f7f9885470f63c468794c7a0796c184", + "0x69ad24f8814b17603ff6ffc1f585346e243a296f74bc3781453a512bfb746a9b", + "0xd311dacba946134de52ed8f98e5a643c0b4f8d5c6d2c928ebc5087b33b309422", + "0x59ac40ae911e0a13aafdb4961c459a9cc8168e444f9288cec782911aea1e5548", + "0xfbf447c35dabf67ad4e88a41e30c40133f166adbebaa154f0c571028f86bb183", + "0x64792ffea472b80e6241942b1191a4e4228e79c4e0a436873ed3eb714338aff7", + "0x618ea5b82192c2e43742b8d74e78234efbcd6332d74c18c97ca087be66baa8e9", + "0x8e659da466b2150870fd5ccd6b4c7e879f3d5e248bb386869bcef965fef02837", + "0x4ef68ce8190a3430e4aa1497ccfc26e31d17ce522f1f16bb7280fa9ca2d377b4", + "0x79a10cac12b7e9b922d9c8d1cac99ff5616826a5f176a81536402cb968377e9e", + "0xa4fe7b019557ab1cd8d212da8704a0a84e8078eb9ab53952c2ebc0c3914835b7", + "0x59916f12d4cdc91b9a0e135d84630d10c48a803dd9b84ae35fe00c29d1acaf58", + "0x802690bc2c2f03e08e2d2dc7216a033be7eadcce3180f220fa5baf411cfce958", + "0x40fce55d2c349a7f97a252f6ae7d10013c396710905abdac17ca794ee1e247e1", + "0x73dc6101cee72bcc15f9ef398f90f2c5e3f616c97b0c6714b65e9a6a83edc190", + "0x7a179bc76526a5752b82b1556692acb502a72e364ba1295aee91abc726c23de6", + "0x313f3a435058fe29e7e9c490553bd9791dad94ceea2ba672a2a2a3e7f69039c8", + "0xb528f654e6456ae46ca764295454d78f4d5a4334d49340a754b5d8ac24b0d21f", + "0xc06aefcbe61ee635fefaf4e2e933c22c73c48b55f8672cc6a3c8ee09836af286", + "0x6626a0134d8ead3f18aa09af7b1c05c01be0cd88c286535115edf3ff19e8f06c", + "0x90051f7019b8d99acbeb816ee256899d8f0a5504f156475cacc631f427273c40", + "0xaa93485a22e1fc2da4c5b5483ad81208bbac2595e758e23677e93521106c1665", + "0xb334853c4ed01341742733a9b1d7ba7430f3353fc1a52d0751808c98f621ab51", + "0x67d2672662726fb24d884ea92668fea97d9e0d908a11f70bd29126fdcaed009d", + "0x09cc08cd5c0da5caaf74d0e8e417fe151129ee7ee9b5082f415f2ede57351dca", + "0xf87ef937db4618c977d871e06bcd6e2eabc7a20faa0ec0f08deff573200b0aef", + "0xaab334b96f82ec056e3c8e1e95b9326f35d57408ce24e63071e182dc38d552b9", + "0xa0d5f838bf15f771f9adf19f82e01308ec34111bda56e2edadf5806dbe80aa88", + "0xf288f085a08d5edafdd58a3a0637a48f0f6cbc730b0d3a0530a6780cea152281", + "0x8a9e915a3e1ac769bc5e3b308fb05cd49d6cc40e97f6cf8cf789f1cbebf7bd6a", + "0xfabd2bf75fef724ead94c7b6e24026264ec2728bf792bd0595aad04900c69640", + "0x3b4a6d3a6e62b3fdc14173ff99419ef02b18134050f8433080e65322bb0934a2", + "0x8d72cbb4e088da0a6725163af3aa47a69b63120f3bd02b93e12788b144e1a26f", + "0x0a112bde7c1434c444519ab9371a553ac25250067c72171fa6779efee4bdb7d6", + "0x8b89d89dfa4a2cd35757629c84edf71815311ade9742e48b6f28d1886f1741b5", + "0x538bd079c14a70a3f6db4b45b528e405a210fd6e2343fbdccec4235a09f016d3", + "0x95ea30334671da97054445f307f3b991ccf1fc965ef148000253bca44f6f4209", + "0xce98031baee0108eb9695be729938f22ee71abd8f368c7284fa7c102c2c03672", + "0x916fa5e6d29e5b17d29e6393f96f2707b2e245ef49a671ca30987c9d31223ef8", + "0x1caceadd646069b69b86699e555e0695c756108dce2c74ebedaa00b8f4c1d4cd", + "0x46a5419c22b3bca18ad94d7b0f34af90c62bb3cf660a4b0b6d28bdc11b079390", + "0xa83044af490b0706b350357979a9e648e041ea747ffec7a50f952b71b9c42a66", + "0x677dff9b0b4ca0f39d526ef4a8fac9bb49d83b5618f73d7ef78c3ace311fd071", + "0xc85d8672b034eaca3715eb6db5408d00d8157c991fbfb55b8fe29ce168aaec9d", + "0x89869cff97616604b696706b28474ae54d88387c2d5a30e690c0e5b31bffffd2", + "0x168585a4f4a9a745a588d609d3eced8e550f1d69a7399547a60456df218bf4d5", + "0xcb4d9270dd367735a6844dcc314782b708ea9b2de82e5f1fc11bc83b0970938a", + "0xb3b2ba42395b4c15d6de64f7ce010486ce1dae4e6b14f01901cf1f4b6a538d30", + "0x11601920286560aeb98fe1436a1f66e2c9ee69ed2ce11ef1eaa6b4b3be447787", + "0x45cdc9aea631ac46062e1d848c3a737da5f7f1d396177196e52b4ae1019a73b7", + "0x113956d33be8473ea7b52f062945a1fafe98a424d50b8b418eb1b4f8403f7036", + "0x2d5a740fe5eabb6fd783b9c47ee75166e2ef7916e75bd5fbc40fa0a6680d97e1", + "0x3bd16b4f04c059d78b8a28627039d6e47954d6a87543c611d6fc8e2e941a04de", + "0x86b1f14be4ac193baaac8092ca3d377f47dfc4e41b6b81e02dd51655fb590c67", + "0x1cc63d91541476745e3732b4220403bc3c994be2e62c6fb2e788c5a47af7445b", + "0x5d09f5a6d1570b09f03b79e869b7f55b344a2c5087bd4c2c06c8d4a85f49095e", + "0x6b48201724527b22e31898ab54616f0008afdf463b9afb6f0c516e7347bf0519", + "0xe79894ec014f7835965959a9914ec4620c6dedaeeabe7aaa791965b30d503908", + "0xe549b3679ff2dd8cca080bbf27826ebdcc14a6ef6ff6f06a2f2ec93a4fb1baf6", + "0x5bbb4f98a26c9c9fa8ecb2b71bbe032c0c4d349bfeaa81790eeb066412de248f", + "0x614dbf21c81332c690c934bd9d9f4c640f3df9c9510e9aecd105f5d2563a6071", + "0x44231b331eabb55fc08363ce5da10d7df42626b94fc9dc4d08f99ac220ee145c", + "0x3e22a80bfbb6e99438d4394700bd26964ca97de1214b20c8a69fd1788c50a4c0", + "0x280ee234189ec732bec0b7a25b9bff60b04e7be32c54fcb95121b14725bf62a4", + "0xd94627e7ecf1abc160c432aed8c677eeb4a0502b3100737567bb2d19b1c81478", + "0x6b2de1031473d511a197f131e579522f8bb2bf9abfe7ee561d8e7ef9b1912b6b", + "0x80b1447503f606ec08175cdf5cadf774f3d0d2a1f447ba41ee66941811690b68", + "0xd0b95ce90aa06affd35cfe7d1f3b45fc121bdf2565ee5d3a1998a932c2fb6db9", + "0x4575abb623e43a73f1be5ee52988e2820cf35170b68c6ba8caeaff086783a1eb", + "0xa03708f13596c11a3b76c49b44102350c06aee7ba92b3f2bf3829952f6fd6c86", + "0x4916a6e3dbbcbc8a13c91f4db3f0695f94cca48b81cfd56b9836e7ea44af8daf", + "0xb73b5c9471a175c8eba25a4df896302b65af142819e047928b8847a5261e13ce", + "0xc5e4bf50a5d4825fcc44eadc3877bbbae0589fb5a2e9ce1b16bf9fd60056af5c", + "0x43abc2f7f189448316cec758251cc7b63526e95b16ad919e74fb50a9831b76fa", + "0x072a4368d93c89d6bf3beee22c6df5acac53b9c8225e53bf3e368739890c2bf3", + "0x395bc2072a773c314c9cfa3c9983f7d8d23fd77276a6cacc93f580405ffd03e3", + "0x50528bae45e8dff5a7d4533bd413b103edd5097c78f35f49d0674c6f4378f7d0", + "0x02c2b72bb7fcdc07939d7fcd641dc148ce0699e5b9c76e7af3984c36a7da08ad", + "0x0b6ce8ccf42bce819e02e2b0f725830fbf136095e361806a2b5eee5ec975af90", + "0x59da0fc5802651044d72946d162d95412e98e3a3bbc170139a5a54a9d0330a70", + "0x2d2f3bf4346e6f38045e925bcb90656bbac77f7edf2182a3c6835b2f6e61f9f8", + "0x213ddcd0341b130de4699b81b7eeaf93126907e52ee92213ecac458bd957eb5f", + "0x0ffbbec5a21fa439c09f975abc684ad9884d396433aaa4f4890e5e377d7cb4c6", + "0xf52462396c136854067622763c21ee796e880115bdf0fa08a07a130ced1031b4", + "0xfc9bd5b2de2b2ca5b16a7f7c608ed4218f3ab60499a691843548e530123ffdae", + "0x8eb92cab2abcc01f735011f27566324816450dfc5ae2d0af14137028b046bc29", + "0x0795e1456a6894c0ddfc3ff3cfa979855e39179b03c15285ce084bd483067a63", + "0xb8b428f8ff1ceea1e694133996663d000a9bf0304abceb7cdaeb6db5be74983d", + "0xe682c8aefc32e0ea3899f6708057ee708ce46125462e8dc2b2d4605f456e3539", + "0x100f58fdafde5a4e2070784f54088d7522f2537ab249095966cfc9b8250f6bc7", + "0x8efb5cf8633396437ab174527ced3ede99be7e20790ef382b5e25e49b7f49c23", + "0x196ee4cee920a9faa42cd5f3262af5b35dd212169550664a3c9c15bb3a3fd86a", + "0xd6781eebac997c5b8eed3b0058a058b3f6da487d143fee14711398a017d16333", + "0x096aaef445abfcd0de2a662b16cba39ce371d053fae63c27f3599df3d169ed0a", + "0x3eee47ffe2e9d5b29c5e1139911d57d3a3d8d87b4ef290dd95e88a8d9a56d890", + "0xacb1b75fdbc4c4850565ab27978e7d10f7c29d6528e7bf198958238a4be4846c", + "0xd0cd5035132f5f8b303aaaf10d6873482b4870a74965d8055c48e8449935b76b", + "0xe65aa97a1cd3aa5b9cc906157f7d9352cf6592abbeb66647623632a9f3a93b07", + "0x76d08e7ef145ee5f393fad5faca53efb07b9fb493157a6e0b290525127b5cabd", + "0x533af4ec13c168f2e7c7368cba5ab0a138a5633656b8c19f284c98c42018d849", + "0x0d61ae94270aa651231f1933cb968bfe0cd2f4e097ae2f0ad8d41b8e2a785327", + "0xc22f8e6418938369b4e505425a28488c54571c4a803df35a233f70ebb933c635", + "0x743c0c8d16b790edf5e51a8453601ada99965007cb4dda51c82cd68e7d77a224", + "0xe5a62da310591a98f6b3138ee367ad2a334cd48d430399c425b71a57ba44a46b", + "0x5a7dad70619d620e5991b7476d125af8db51b67935a49c786b57f09d3fbc4035", + "0x1459d52e06d83b9ef94f035d08af0d63f66ce87bdfc3fa25984292aa2680ec68", + "0x2139af4823664ad7b8f2d6222f86a5feb7a5df0f1a934e8af139d73a6d008d84", + "0x31a7000f3b576d91c543c5ffc4dff45205aee1120d9732c3a342318bbc4d72a7", + "0xe046d4e9ea0c367a2b47a0a23181e144d95f9a3b8d77244fd70384f031fba4b1", + "0x294de2ab05861fb25db6e1392e8eca830217680610165a2dc3f6131eea1d9918", + "0x1f2dc7721a6ec2f13b9c9dcfe3d166b323c53dac5ed49c883fb6104caa841184", + "0x3b2797e3eb732182ff4928045800ce8837b7b4796d9af977b118c080ebc1099c", + "0x4f076d935900c3cdcce4ca42e206caa7e63dbc926dbe230f640807bbb7965c60", + "0xcf8dd9699ad2fb397f19b16b851d85a565b4d197735f8e3c279de61fc4e45bdc", + "0x3d3544db3dc8e8fe1b672ec5ae8c341524bc7e1eb3c96bec3867ae910d7b85a7", + "0xb7d7bfdba9ead1c68bcd54c46c7ac2a34f5292333f62e7b91b193baee6c09037", + "0xa8fc4eea921532a7fe31196f68a915f6f935b8ab480b9943dfddb7279cc069f6", + "0x6c749c6ae083721c5f5613a581435fb837166bcb3f07325873ba321de17f4526", + "0xed17ee542d4953c8bd4a7035bd34be4e6e80b73ed19f86d3198c7efb661ea78d", + "0x24e11ece5e106eb20534043c2c9452d5faf327e0555bc3b8f923c108781dc1d9", + "0x094a0636d62e402344d2bc9c01fa145ba0f32e03383e5eeaf85b257eeac3acc1", + "0x0e02c54a2ddff2892841d6e450d8deb610057e559ade4b8c3c943bca63b31384", + "0xcf147eda0c90b66e59c407ae4b2edb236270672ffc4bb68ac7da7a23b0274c84", + "0xae8054abfb1b72499642a11f80348857e49aa315b8debd3d61cad8662ef56b08", + "0x8f9429544ab9309d5a18a2af44ae6bcaf2e04de344d9d55cf22d8c503caab64b", + "0x8c6288b1027063bde39e399be8e7c82a7f8f9b853fbc04a32f73404945002e4e", + "0x189a06ad980a6e9710acb970572b8c04c2fc041fdd169ccde19b5a939b69cd81", + "0x0ae24fe54c7724a8c075eed2813b90e1c520119e2eaab0a0578e8759868e3ae4", + "0x5d22a1a2f551aa1bef7b552ac797f5b2a22441f7c3fbdbd017f4c5dea89b7842", + "0xc1827d89c778f3fb6c35842aaf940bf8a829079e008421db792cf04018bc2b03", + "0xcd9547011c12cef89331daa486d5a89bf36c8dab81d5d0e4abdd9c2e35d2bd8f", + "0xf115534a66431250450d68d8c1ef80ab9a3c68e63a203094ccee81fcce0213dc", + "0xbe9a16558434d1f940ac08ce7bb0ed0b1e400583b7bcbd06dbd9fa933d1de6c6", + "0x692dc4f061262a3f2a50765773294909d03477b0663f47f4aa0f675f2c0cf0d4", + "0x6127590ebcd139f736331080139c1b3bc6aed2f3c961732395ace62edec7ca5f", + "0xdc75a2ea1a80516dda32d61a2d671fcd421ab9ecd81473230ff9d3be8aab444c", + "0x369e3a3621551d67f48e544d76a815cfcd9a72b188972b02c12ec433e54c5f7d", + "0x195110af607c6bf30e268ae88dc0245c6d3a34d392f0d7698e51eceb1e10ef4e", + "0x950743ee4492e360e7a594dbc4b786ef4ca1b061210fe967bb5acad5622f43fe", + "0x926f538cfba0853b453169710a7acd6c2a002b87d2826374bb55790ddeff417e", + "0xb93a4ff2a88a8ef3ac4c77b55e828172f20b9b9ed655ba7a37b00ffb524b5138", + "0x08947d220add3e64d2db582c988faa58556b11257b9b4d8ee817122085145340", + "0x28ce559274d5455f0f9db83b263ceb6f1a2bfc00a2512931b04cfa23e7887612", + "0xdeea519fbf4ff441c8e61ec1f0ade9258a50a10a4702d0be90b408f30b27aed8", + "0x3aa93241858d4d882409dacdb7e716e6fc8bbd19587c15e349ddd5a7d90e287b", + "0x87a42a8eb92cd20a8dea17bb9a241354559443dbb1b4f549e2f9764321a1549d", + "0x365f92d4e3e88e73a155edf264ff3adad231b6a8eb9de11a1fdd473d9f2fd27f", + "0x85056e53a4b8368bf1ac1327db65d01d35e72da358274dc7c0d47a924615dc87", + "0x0fa77604f4d0a3bfbcbe9019207fd21dfdb118d94b391c8f3467b7ede0085494", + "0xc58d6bcd06d9a666bd5217cc75ec70c65d90f45d3266d78262d44dd1c48853bc", + "0xce225ea3d493c85c9ff2719af2d7316577c7c87e43598210446575fa10263038", + "0x010a27979371a2f4c5790ec5d61aa1ea443347d1e8622b4869fa33816306afda", + "0x34cffe4d5ce1449e6c1efc3c6ef2dfa24b3502370dd847b536a41976cc1e7e55", + "0x423da7e80d01cdb061b17cce2dca3f31fb62c25ce0b25c7ee5a45df3ca02e72b", + "0xff680f2c9fe4896d1e117bdf7e655d7d86baeb0753ed21b373a621d954be262b", + "0x9527f4e412a189e2e1bdccf0217cb6159b912c0c3765d5ea7f9e54e2cb393b48", + "0xa14f94bab1a626a844886e0338510b09edc8eaf9f3b416787b72bb2729d22c3c", + "0xde5afc9aba2c6db5ab784212bc940193db7f03b695049dc969f1d5ddadbd722d", + "0xdb39c68d462695c642bb704f1fd8de951d4752bd15e25115032a5b36fbc6d2c4", + "0x64987238a6b0d048f5747a81ed04806e89108ac247e5ffb3fba66fd875797690", + "0x0eabaca3229eed1341b2e330bdfa87432bbb685a116d02f943dda9ac66b4e877", + "0x2247273340e0c7954df9a5db6700911a4f786eea68c98106a29ba0c3abe96baf", + "0xaa035892630e9168378963dc34c427fe2146d6bffc6c8d1c5026ef8c3ccf395d", + "0x26a8e42afb55511f170429010e07fcefdce8bff03e3acbb3f8571be05960bb6a", + "0xa95bd3416ceb31df25f3b5e262109680341f742c11580e2e83da5f36d8b84ea2", + "0x09929d531b919f43ccf5b6ab7e87265ede17ee5b4103fb3fe2bf608fe9075c25", + "0xe6ec4893fa4840d90006defa51d5599b5a164f0e19c54a624430b5e7be1f6280", + "0xc21953eb5683f71adf5e5229286e6167c48dd68f2599d7cc35817b4b9ea0dc35", + "0xf30d268431af3d017f42363da727dc3f4fb42c6c1397a2417f8a6d862131610e", + "0x8a686f06e784dedc2b9e015d7ca5232deda4df832428050361c4c24639898c40", + "0xac5ced4388aa2f66869f6c3f72de0e531787bd415c8472e1a491cf750b4d2d41", + "0x5f4bd5ed18dbc2dbfa1662c45363fbb662337f8253cb1260dfa54ef496b51ce5", + "0x67b8eb13416e83606e2b1544a02e0172a1a9c1b9cba1d56613d2c1ac4c243966", + "0x3f450fd3a47b94ad683939f8af79603cc390bfe4747c6c013321e39f6f1807ed", + "0xf7f5ddfaf17bdbf632bab24d9aa0bb6a960e0e7bf1ea3efb3b60bd558aa357fa", + "0xe00cad28e524f273884ed368866865d466c0afed78390d8586c2660944e0d007", + "0x370dc3ee72f58da1a1cfc6d5311c688f171251c46b322d07f61548c41948ee36", + "0xd5b426cb386ed0f0017206e0c551cb2ef9f3cf02a3d94f68cb499f8f900f740b", + "0x837bbfb8d1db4e394c5917798b251d7281e4e1d024d95a0f8e8963ffa0a3fd95", + "0x2e7b8bd8121d24134418f88bbf49f8888357fedb1ffe1f928ab0ed4d3ef96a1a", + "0xa695fa51c83d2eadfc3b3775c200a8b39a239aeec091b281a022c9a3aed96b7a", + "0xff4ce70579c4ebed37684fc8f2d774cc358ca29a54d2520989cfb66444a4449d", + "0x7a34a4cf28f43b160218d77f742251b92f8ce3b627c23f632fed544e9234b2d9", + "0x67a36d6b2f04573dce9a2f0adc37bb9922ab038d2e706330ab6bf72b60afd88e", + "0x5c81c0bf60c07bd82794389b682be408a09b34dfbf016453a174229152e0b763", + "0xbc48cdfd853ef43a5982252eabd16b0ce575690195fa2cfe12a66fe10b3555dd", + "0x2125afff5e4a9e2451df3955e3bd17c8f6b10e628f8c3060a30ebf6bc4c616da", + "0xcf447b12f03d41da20fce5d8046559be590173f902e96ebf3c9b037398fae548", + "0x58b29b2b214e0c58bd8e71fdceca3ba0825bf7614a504e7bceb87c7f13ae41d0", + "0x1683843f47ac40ad0ebee6ba68a87894fc94e37a11433882a8d9363bf7bf4b44", + "0x17d702c3071014ef41b20d93cf42084dc31db7c97121f2f41e1b0a8ba2c7d557", + "0xc3f57d154b1047b3cfcf25b393aea31e0c87dc20cd601a62fae58bd56158e30f", + "0x1034d9216d4db99620ed2a256c454cdfd9e803e1c066eda49bd2ba1288d59d2c", + "0xb4f23a426c5458e52a667cb01c734d6d7473cf0900139da17d355cb679d0406a", + "0x16b7beff5ba9edc9442bda4b46e34afb8fc1ed917d226a4beeb6d9d2410d8fdf", + "0x3b2cf0a7782ef7e1a1b4590df0930c44ec2053ec2f519612b0f20f6e48f47107", + "0xbde784b24ded1a05e6d650b238021e904c72cb35d02dfb6fce107925ac947873", + "0x7a42213f3c331c3d183703dcf4e7704b696728c6de4296161b1fe73c78277a01", + "0xaaa0c71970eee0f71ee064dc6c908dfa1d2c0637983a18a78ad6284a72a5e010", + "0x72f2af281d44553d2cc0645c0b1a01a9a089c282344a4d2d2e5271594c58ec3b", + "0x46c6cddfaaf1d204e735c4804be955fbd0c3aa2720a6d40640641b4e777b18e1", + "0x7e52fbfa76e745f3cfd6e0e0620e7597afb4cac20374e8a54c56dec4fb1d040b", + "0x69ac36b338093a55343f7b1e3b2288965e7113f255d34add5d08211932c35b1d", + "0x9cb03dc2371657f840b5da9fd420c4202176168b1411fbce0eb93eec3c342229", + "0x14eaee01119803c9c427f990418126a03d1ee9b829b23d78b11ad94e29f92c1a", + "0xfee4f3621e875f9b69254865849a58538cc742e79843ba229df2a179bceb5b82", + "0xdfbc9322655f9f2ab5e918c2dcf819f0b4d6de07905dd2f94607e3b564275f57", + "0x07c42d1a39c3fa351ae4aa0adf903c39f3f7ba020776293b0ea5250b09c4cfcd", + "0xad6101974f08962920d9edfcfe8bfa4181d9465c1a571b128a5767406c7c890a", + "0x9f29341ba8b368f9c4dacb12094979a0e9bf2f6969c5262a880e974ce98c2aee", + "0xbcb3768fca1e380de80628bc55e911aac7a3e9810794ab9b86fd2ccbf3a727cf", + "0x18d8a90af389f112f1229b591f3898ea5a0f2a6ea46eab7aec3c99d82ea40760", + "0xfcb7860baa54275ba72b34069fd8874ef29a22331b65586671ca2ce88410cc14", + "0xe8323d318b6d03ddedf163b07961e747830f51a8b7ba90ef4b568305d5a8589d", + "0xd7d9d5853392e3cf51e6a4b9b8d60e5e1eb0e00962bf70270ae7f3a64e2efcab", + "0x2f6cae0f3f4facc6d5b1e87f4dfb2698211cbb6429c00af32af1b8963aab2750", + "0x4fe11c9667cecc0cb8ffa78a2ae76cda09adb8c993746149bc322dd4dbb389f3", + "0x1d7c6bd7731617983089a3a450e3cabb5c9e48873a516d08646c9b90ec152615", + "0xf3cb5662cd5414b486fe8d664a799550957422ce0b990f36bdbd9403ceb9afbd", + "0xe0da2757036de2ef8539c522ecaea947e47b351f68a1426c86ec621ed4bf54cd", + "0xa865a7275662e1f977b260ba85d5ecf1236fba2ac01a69aed047b2d261ed2610", + "0x780cfe59c907e3db653c573888464c41c4b8883875fceb57501f60ea34fb1322", + "0x754f80993771441ad0836d84a0233bfde1a4fc0fd20e199c1a0b6a755932b83f", + "0x9253cdd043387ddae4da68098b995268b3983a17a200c8990b4de3c3102042fb", + "0x4aa535ff3fcf8ca9ba6ceabee3d59fedfa3c7632cf68fbbd3743ea9c86686fb8", + "0x4f5110933431db2c0880d9d4699e33e8f4bacc31e4971801ad968cc25f064d44", + "0xe4443aff0965d78b747dbe5b7e92b03b4c1898e7fd9911177f3afc3f8e765fc9", + "0xc7113de3a6ed094a63f9d1cc5f68d29801ec550d8dd48fcf1296f10b73f97988", + "0xd707b5f7b09c7b264e323df29236aadbc03389a9fd75da07c73b9eb76ef928ec", + "0xc671f6c1003e8a2fa46a0f6100b1ebe5fb4657b8a3bcc8c4190de8a5770e2bd7", + "0xa1f8030d4bb2d37062ecd95a87dce8b3ce7bc7be55de7aa1028adcdab436cb96", + "0xef9a06d2dc5c209a7f7747128c22b17c2724d62b655f07b57fbde1ec5926a168", + "0x82b15ac8a4341283ca4177e0e7b89378367e205ff8fd59e3e43439dae8d6101e", + "0xcf641779c36577bf02101d739b7b1bc19f1788b22d72f473bb4129a44869c26f", + "0xee111a9312dde0a65002434b38bac07e127167463068d047fc95eb53469dfa5a", + "0xc21dce0be4bf464ff63c59b104f3a9e8ac9a5900cdd77b7fc6676e4e2a17f260", + "0x546772808ee95a5453a95e581b86ccada861e2f37840de932c70ddf65450779c", + "0x748dd0b051d0dc1e5cf18584c1111b1fd7648b62d0f340539eaaf2ca155e292b", + "0x668719274b07db2b66d0f2bd7e5efb6e18455f25e49b07bad9d6c046ae8543bf", + "0x305c577aaa37c8f67c631de5a2ff8833841daa6a1f52e8f860e7b6cfaba5e921", + "0xa7a197c39bcfb74d5f3c523de12af1651b76106f422c1f52fed35e6628749804", + "0x6b46e5b4a447ab9f64a529756a689db73706c626a94b5fee28415c33c0175e94", + "0xedd9664015849f4dba53c83f75e8f86e44f8b79d3fb9bd48e526cabc85b8501d", + "0x218bf5e9a2db20afdbeb167f75574adacbf64463f11665f2b8be2b76d741fb95", + "0x9f1c7175bb294b7e24a5eb61de4da073a5af547e7dc911c9b05d98ef64358d58", + "0xd6d859b88c49be0bbc83b1d34d7c87331bf281136146651d3320ad49db320f30", + "0x3b4ecdff0b3eb94c8d7acc0e101b7fbee9aff87992fb2431fe2c4d9f44a394af", + "0xd33de0cf69370a33f13d9d7db35e3490c88dec0ee23b71ed040338049616e274", + "0x84d004e9a8ba6b1bac42e8d6bc1253ff21b47a1fb494e5d19caa1bcf34b6c22f", + "0x71057ea68aacfbaa3655aa22c75a22fae502a9afce8aa206a220d96654b9d4e0", + "0x8a47b01548946acdd553570ad9b9bf3c78bda4f96fba851ee9b0a94b355d1c55", + "0x53b7a7ae02459b17760ad47f69dec212ed628d3fe856af16a0568468e7a0b752", + "0x66ee4b75bd15f446fbbb3f1a9f0f3a159b8f6c66f708917156d7fee5fe64e6b6", + "0x706b81fb39b3e09eba9e83250f2b3e2b567f9fb1c397125fc0157e346d5ea352", + "0xcca91f2ce2b51595cfb86e0a7458d45654f61d35a66e49d25e6dab01ebb350c6", + "0x4397d4d33ec5ad07b3a583e9f39df02f5756dbca92fbfdfed59a11cbcf9e08b5", + "0x88ad8498c15ebfbdec6b1f68deb7515746e5c110910150eabadaafcf715a50ad", + "0x715d175a3badf17771c686793223fbd837f2579ed674539eebb0ce1244fd45c6", + "0x96acfa1d0cc7475359b4f1ee596aa2975a87f314e80d4baa0a6af7c7c77bb92b", + "0x26b4c14547c255841bac2852456f386e8addf8cd8c45cc9f4be0377e05411bbc", + "0x124524955310b1a35fdd19104b6c0bfef503541fa55d0b7c24efdb8d0cb33a4c", + "0x9806202158a5a5421e94f69a904670c161bf61ab1c41bd5d104ad9ba63866067", + "0xf156a5c71bbe49c45f91ec3185654ef8cc446e9d18d2ae6d51ea0f0409fc89b1", + "0x7003d7fb1b01fb6e036fa33ca535bcfb836415e7661277634c47c628d81bc140", + "0x6f23e519c11871c12185c1af12b8840ede513e28877f7e860603703b3853b14b", + "0x3aafd215a348dc20c5ee5444cc007cfa0e90157bd33c8a4c4de4fb5b7a231ea6", + "0xe8f6cdda4ae600ab617fb40d96d0b2c13ead6ed5e36eaac9f8cff9df918b35f1", + "0x75e63daa0a330a4b52efe0e0e447b345622fe35586037ae88e6e48a8b544a087", + "0x6c4c8865b2673508e4c62dcc711e9886e57043d758a60787c6241578670550bf", + "0x21ed5b252ba5e9607045ec6ec85455db4615a1fc43e22138ab3a087c5e6236ba", + "0x2e2ccc6f66368ae083905358a182b0cf3e85330dd2a3875a846baba61c9be3ca", + "0x4a8987c10833a298ff22cc199be4816aa05f25e39a10bf007e72790081ccc26c", + "0x7a4b05fa47d37c86aabe456bda0ae7bfea3b28a375697d4d19ea2b1676425016", + "0xe203aec00f8bed45f3cb0911860093a5fe228c22476f189f2dfe4621145f49ba", + "0x7b2ba1b4da99ad50a33de156eb412d0020efc63c85d0840af6d9ff9199ff7dd0", + "0x0b84a8362a67c9cd715fbb09e0a48e046afafe8814ea7e1c0bc99da9ca670bce", + "0xb9457e83e503f6b65bd357b0c1cfb655b4c157e213c1aa2e4ebe6b88524c20fe", + "0x401fa17417f9c8f21156a3e660fa2b0a27eea8fb287bda37ca309a3c918d1c91", + "0x8bd1e0e83f35107a65777a1889afef35f2d89e70e9ef3fd56a0fe77b5a5a07f7", + "0xafba338c738de0a748fff79650392894482f094f79bf0c88b871324a6db0b1a2", + "0x40e66643c2f93c60de74a976f7f05d753ab09d33601cc1421da1e987378be84b", + "0x4a5d0c268a86af032703b688745b91bde7090b4e3b245f235056b5d675760685", + "0xa8d7233658eb85c4a309293e35aa9768768e78b9635ff989b4a5a1b64f6f26b1", + "0x7b30cf0f31a942afa35ee2b30bd3e67cf0fc3c366eb35b1e331ad8805e9e0d40", + "0x5730206b218be1da571ff8022b975412746f88606ee3014626a03eac8893deb0", + "0x4dc767b54a2e685d7588f6fcc1468cfa7c7e47474297b29b15957b2f21fb90d2", + "0x528933096ece3ea9bd4b3e0fa78ecc95915eac29b8b608af3b18eb7fd4adaf50", + "0xbbbe02a2b2949c73839afa56e959b23d3dff141776137e5e804d5d37a69ecba7", + "0xd8c4081e5c0ffe7797f07db6e5696e04ff097410b1e45a649bca43362366bd87", + "0x46402c1f08238694bc32bcc396093230cd2e522c54dbf7d00d042986d22f00b3", + "0xfcfff397df45c333b4fdf271b63a4510c45310a3c9cc78b97b867372203228d6", + "0x6d2350213ec1c6a79fb7dfcb5a66f065fbc41d4250075d81b7647e4db991543c", + "0x393995f9a4a358d13b5fd9684510068f9fb86c71f2382230999bb36b41586a56", + "0xb3b65d3c835ed1aeed86f34117431fc46d62ee2209db054a5e04cc81c1f795fc", + "0xd1ed46b6e64544acd6f9fffb126fea4b74de84664c2b22c760eb89878cd44ad7", + "0xf21c944b3e41a4f630ad5452a28633c885427b386ca81ec9814ca14bc94bb2ed", + "0x54c5c6c093bd6cf2cc72e058fbeb26012d71fc8e2bc6987fbdadaaa48ccffec4", + "0xa2e79a266c6044703233fea5d0c31bcc22ae247eeb55a982bc2e1c0c64af1468", + "0xafd38477bf1cbad227b489818e335a79d38bd052f7957efb2d07b9adaff6c68c", + "0x4872bf318a2066d5338e31929da36fca3e2390d1dc8dfe88eae5ef854b81bf97", + "0x896b1e0fb7a6daa96f00f7ef633ad67bc4462c962ec288d7f924c64c978f21f9", + "0x0c3617575c8a625e7fe35c30312b147be400b2777ac4b1c0fd84ee233175faf1", + "0x6f47126daaecfa7b84568c26b02ee779763c9f63b4b7f5cb0cf0ccd4a2c0a499", + "0xedf2e0e03c0d321911693c1554254d82c764f2987dcb5c76a4204b1184906abf", + "0x5af810bb6ef491ccccf2dd00c658bddd02a1124ca26be59c97a69199605a2d8c", + "0xf8a597f22125a6f3fd76e28db6ca04fde9f5eff62b78e162855b9a48c51a0cf9", + "0x9b50cf0abbc883c6af57fb52c48defb2ae67f77de2f2ef5aa4fd42f6236f3f43", + "0x6eca9c995386aa4f161e6f4c6ff999cf6bf1bb4184d9beab567abaccfce9fc1d", + "0x7d7dd300658f784ec68cc3021a54680ac5767085657bf87ab6f76f05e505e6eb", + "0x1eab27e441a43a3534507ba0b5390a13c7df373813131b09b2eaabab179b5cdb", + "0x45efe5848f21e2b4f670bf06f0067fe453eb29ef45df102588c7b8f902005066", + "0x086f17e6047e9476d828eab4ba0016e3a4a0f51f25eace2c27445b5fc28926be", + "0x63547a7274cbc857d547291923cc9e507e3f4b6fe85b1ea88a527674f15403ce", + "0xdb0d2c2f050c4235e9fd03de4c491e09061ddfb4e55fda8ea25a8c8f013193c4", + "0x5f5bf14f72834ddb7ef96affc52b3461d0512fd9bb0337313cb7cedbfd858228", + "0x92c4250a5ba9ec5890c39a608770d500ac31ae5da1cc26c05aca55a453e15a25", + "0x4fb2c385632f512303dd76f4c9a3888837227bbb5e5b949a7b9d74906ea6d015", + "0x4814397680a72cd024c3df1faf854d03c0d308b74c93fb846e620de95de7bcbf", + "0x068512253a6b5ccc302e494d1b17ab082f2ff4ee710c58d345d6de4a436fc3ed", + "0xbcba2fe1b54c6fbe1438fcc26e955ecce58c5f30f4f19219195a413fbf1c6eba", + "0x29ad9a11da3f646ae4ef3a5202abab2ed8a7058f336a6039a5c41d3619752d6d", + "0x5fc2a5edf9264de88df58c3bbc705b8e73bba19179d097f414598bd4b5fd63bb", + "0x9592c969a049ac723d756bd2ffd95cf599087a1da14ee9f472ca07e7e54f8ed4", + "0x735ace051a5e3896a9dcc788654f95cf0dd9cc98eea1b5d8d7340f9e51eba698", + "0xed5ec9f70d613be406c237ab7e8e2480c7a81cc666316d984bb3f9c67e10d6da", + "0x3b8248b4de2768d9a4ed2ce07c8735103b480e23bd17ef1910d75d29c2791886", + "0x2a9ce5a8366862e7b790d865b0406d9d5d4013999f42caa9235d4c2b2813449a", + "0x6c67c00db439fbc9d548cbdb57377064419ac47211be90747c74c13b29d4e562", + "0x1695a7ad7e64d438a9b749b07180910a7af207bb46063a92d41be315cecfda67", + "0x6fcb36c8b8ae4d6e4bc21fd14e80dcb402561a011fb4e71408f05807b1141f49", + "0xf6ff3dd9e40b6bdf881654e12fc9959a928bb7d83a81189db1520bec70386ec8", + "0xf17f8b88f04772598eb87c8bd1b3a03f5d96ac68de7d36be6c1fbe5fd4a2ef4c", + "0xf5d9c9e25075f8ab6c34e9231d36becfe90df0ae6bece4ad1847dc4ea938ede3", + "0x5d409a230ffc6a7e149e94b0184bcd00eb8705fe173c67ccf4f81e2f0d3cb0a2", + "0x80647dea82a0c218462836c14cab2550f558391a901a708d7e4e6c28b4b71869", + "0x4ab906af7910a57f1f4bc338d5e952a899ed256e2a28e1947890a372aa29814d", + "0x6e6e180aac3ebd616af90069674ce54459f169d33d30d95d98351259d90a38ee", + "0x5d30699b02a45d5cafc14c945bbd208943ea83ac6a10229c199a92b87dc0c76f", + "0x19c26fe48c497a4b64a4d537eea9646cab7704dc28c46fc3510a14b226b9a690", + "0x5ddc881ec8fd1bd34601f06a5ae0cd23680e2e8bf12b78df48a5f86ed6e96ab1", + "0x39b933493defd81502420663a0c85df3a6cf727e4270816bb3cdec3dc58bc7ef", + "0x62a9e911426f267561f84210d7356069f6168c4e7afb9aca4a4a70d18fb34ba1", + "0xae792d0011eeabbae89f6de39ad44f0620e50e5ffe7392f9bb792a966d1f83f7", + "0x737b257fc55f1da44584687b3cca4bffda13ae014f089e75f0c75b0b2d08c426", + "0xe923546185355abaade908d18f3223bb9c404c4a399ff94419c3a5798c90d9ef", + "0xfbbd3e2dfe2e9e6f985d139dbcfa5b95da918acbf49de992d01875bd44b61e28", + "0x781d9962f2cbe94e355b93e4c0eb3a3de44d9779eabdc3c6d18e7120b3c0c01d", + "0x2722229fd2cef3564c38d8e4120a6ae89728ab4063c8199ec098f139b83ee0f2", + "0xe29866bef5051041d25449f334e4ca246df606c5d7c0bce7067c6c98cafd0534", + "0xe0320de1a972b563113eddbecfc90fe902f2ca80befe15378c94bd073b44eb92", + "0x9227e1d6c68bdd60cd0deb8ed760eee67af6623c44d05136251d89654f3f2e7d", + "0xfc3c7dd2d36ca954545f3a978cbd7e4c413ae38a0fb5cb59b84329b5f5ff2347", + "0x934c332cb52521de4216c29e40601d3250078fe9314a364064692daeb38f71a6", + "0x77aa1b31191caaf80acdf5d411c4b6b834a6e50f2f0ceb17e1f06a807e3eef01", + "0x43eb0928a0ab9a29ed084cbf9ae75d1e5593595d55fc8a32151bf56b9977a1dd", + "0xc6f4fe473048728c5031a465c9157e38c72367c7f937aa9633768b32839e765b", + "0x21dd6e252382965adf71b94fc0b9b2e6e5b0b9dc9732987e1fe8d8610b1125f9", + "0x9808b8c9e07babfb30c120a4a7d3582cf4259f8309e586ad42bdb9e9cdd3dbb4", + "0x72ec40a055dd6c5f21333f9540bbe7e38f28f39f90204f6f87f3c94faebabeb2", + "0x3a04743cd849a1a48e0b012f39fa4eb690c314eae7b0500ff1ea487a6d399734", + "0x484892e8d3585d871f7105a49cdda18af036d787b6519f9d32f8dac5a3eb9546", + "0x3a73f64acae91b70d39cb20c1ace35547e733b253b47339a1c47ad0841c7a27f", + "0xf33014797bb0e339f2f0dbcda6706dc6b33c8491cb9ef777ee2cb88b8fd1e35a", + "0xf94ec9b178e1e287fc2aa53d397960e89485ad22f306bdf0226212415900648f", + "0x8aac6aad1127202909e112df54be070e353fb9079dc5cbeac146ed09faabd4dc", + "0xb8fdae091491634efcb9b2f78f1258d401a9439d806fac04de4a0f9503d9259f", + "0x4e872ddaeda3ae79efbdfd3ad8e5ac3597003a933aa793c50fe74fb59ef43637", + "0x15293110604e842775b59198cb8dafbdf07b4069fa0c3e2d61ce6665ec8f6742", + "0x7423d6d010ca3aef37831e003164b583c2cde4e859705ea191e6ec687f08cc49", + "0x73828a90a0f97e5bd83c4a6484f84ef8af04d325b739a2cfb96b8cad36717b09", + "0xc9af1d054e4ba3af1002ff0ed63fc361be99f8c7bbe90fc951357ba28fafb8c2", + "0xff2849e97d79e7c25a58266dfeab64f512ebc57620d45d6f5106a71fa43063ec", + "0x98da87856c0aae3af6dece2efbe0a2f7bae295ece2b90b633ff894e5c83fd407", + "0xa17f5aec76c8f4aac84741baae18e179ce5c1ce0d23d3e2e5b4fc7f79ee91171", + "0x79c9a766323f5381dce7241fa53da4c7fa018a43556352c54b52fca209f3ee37", + "0xeccb07e66f967613c13a1e867f8a96bb2c96b7c0347e4262ebdb583eca48e71b", + "0x36c357f0249aff34dc519f420b77fe14357a009022262cca7f1467c2dff7d0cc", + "0xd52a496e2c176cd98b94e8dd4c18a9651f46ce47d70c51b21e5970bc7d81c96e", + "0xd3fbff9d80c163f6b9d4ad4660f4504101e167ba866266ff905f8564ca7ffb68", + "0x321b832e81f461e871bd05e6847f8548825464425036a1a92bc44fc30961fab1", + "0xb58be0aa640c7047e2b27c6044dfc44c216b4b69f48751686cf29e66a8dc985f", + "0x2c9153f20a845b8ec8e70cb1dba8436c7af618367c3344130defb1e7c39afe1d", + "0x6d129dba3e7c6e5ba8412d9290d7dcbd29b36f3e93eee6b6d203740de06802ca", + "0x5f8573d1de1c9b4725fb639b565a2ab6dc79d138c3d6495325e6ee609073965c", + "0x5f78ebcd3f73da424734bb2ba0c711fc54be4f21f29afb1c33af44c598d31dd1", + "0x6b48dbe0e509dfed74f60e16782d268076e53863b9f86e4078c90f4c6619b644", + "0xec30ba6ff376fc1ce9f4b87693e586b5fef2cc5a5ef26726d8e756b3c8e28920", + "0x8ac0cfa126e35c8dd715bb0ce13bc70c8d55c34be0abcb85576393a460762659", + "0x8825a63c211a92ba8f8f5aca7a27d1921df071072467c88ec9932a41d43ab5bf", + "0x39cf82416d543f45afcc6aa0cf68522d0d5ed4f76b07b9f742594a88309b393f", + "0x105449b542eb5ab0b1ec7ce69c5e8bed9a72b6470b644e0815f15c6d9122663f", + "0x10fd8c442d6d44b533675b937e5defb004271a87d4ca3b238a395002da42adf9", + "0x390a40177f4155c30bc10539a54991f4759ecea69c31e9b2904743834bbbc618", + "0x0f11e934cc159af39a4b22bcd6817b1abc21bc6fe81c442dece1c178d695787d", + "0xcfeb9c70d8e2d4e40bca485200c0b5db1152d9440237f76a58d4cebaf43cb1b9", + "0xc45c5247fcea2312642437f90870b6fb4b9927eb2af3adda30b5c738eefaa952", + "0xb6886cd5b6329ca5f5e36d1c49b7426b1a20d3e3455f660e662128193b6e1a32", + "0xb708efc6f2f6ab093482d8b53483a3d8216043a437da09433ad0eccd4c9d607b", + "0x12b76069143a66c55fa3ba54a27e2cf51a94d8300a6a6a317a65df345a9d77f8", + "0x0d9b6dacca16c1be986db368dc92d652984da9aad149ba7c22831ac94719139b", + "0xbe298f54460f273d2106a102dfda3e86d7eed783bac4ab88d8caadc0f3116ab0", + "0x82fbddaa5cf8847d2166d40f9fef5fad4933bf338422bc5457e5d5c29774e5b3", + "0x2a75f2442f4ed494666f48168ebe8620819d97f9749b279eafa550f20b1b622c", + "0xc874be785abc89e0fa92d089889ce06e1b2297f647c31cddd24d29017ba74b0c", + "0xa6984ff3e4f7ab1da131668f77342bb0182cd23593dded5e487c134b1b13a9cb", + "0x4293f4fb5bbd41aca9fb12f58e2427e20b791ea523fa125c40b72699ed89ce02", + "0xc316b1b066bf437d3933d7fbc8a8546a10f7c274d2ea84781d8a99633bdc0c3f", + "0xb40cf7adca885ffa6148d8008c5df235e938659d6249fd883960b847a409747c", + "0x3285b34b3e90a83293292221a89bb244a91ddf4647cf2d297c2116826c605640", + "0x465af97dbd1276496387568d41ec69961f70b382c6e0686c103a73bccf0f7830", + "0xda2cd161e715ffd3ca0eab361e66e55450230f9acddf8ee635b412807a9067d5", + "0x3136630cc6b24f59ba9c0347c6c612feb043f9fb58d1d26598331aa623fcee68", + "0x24014d00bd6ed71da4044cbbf256ef99927950736f084cba2a61046ed7c8d471", + "0xcf1824f9a407009243ade6df4e3f241dcb60bd7257d843792d12fcd42e659076", + "0xcfafe5abf154f2ca9b6f9d70a91149b01cc8fb6b8bd083e24559b860e439f04b", + "0xa4de7f7024d405f6738301df2132107b135ecf824777f1b844685bfaee6b30e7", + "0x507abab909bf25bd3907ff757a69acca54af0c21ed6faa975d20106908e8540f", + "0xd6e584b876926c3989b84151eb574d737bfd229151dbb0f653b693b2bac7c45b", + "0xed4eedd2952e96c9298f68a1f8ffc4772652517356ed4a02762a3355e7dc89f7", + "0x36d0a7f0f5ebf3c35a576ff56c8aaa1caa04dda95edda5d496381c9601949451", + "0x9beca310b79181f7695a0b6b49e923e7b67462904457df0af82c88b92fe4ac3b", + "0xcf792a534a0b5126116e9f7c9b92aa4d32083fbdb539c91dcb8de347000b49f5", + "0xd4024c9ca180adef5a9311c8a2fb0fe75e64728af00ca4ea1484548f182b5488", + "0x5517e825a0d6e1bd9ab4435278b8691ad2772b9edb581b58725483c4393187f4", + "0x9e4ae4c36d00217af787ee52862f87bd37cf391adb23a8b51fc05ed1ec3f6631", + "0xe428dd2523abc537b868bb6f5588597175a622767b600b1ed9486d09624c8ab1", + "0x2fb95198976ddfea942f737322470f9de6635f7116839e5148d3f64766f6fa2a", + "0x211ff8c237bba495c03bd6e8eea2a64f05c8a0eb15951751cfcc4c337f1cbd02", + "0x44c49c62604c39e38561c7d9285b9a2e168fa164a47c7b17f1fe83faaa3c581a", + "0xfe663bd908aa64290ccddcc300aa5f616455d8f10032af9317ddf717c94d0bd8", + "0xb04add424a6780e81e2cdafbd81699fc5ad621c666e1ab5583f3953ce8b3abdf", + "0x5f2f6958e89ad99e28e96059aa8b6e2d9518009f824874e327dbce226918e0a5", + "0x491c9e17210c2770c0cbe566aced7dcfcb6781e70a288f91d4eaac8dc4fa07a0", + "0x73651853f625c534d5848d1bf7f93433b09d9297b13d46aed9b022ddc37c4b85", + "0xb1333ff43af73637e2235f97a1a7a5f42c590cb15f93a733cbe16d1a9c187e0e", + "0xddca0492f5c36c8eba140575b4521227ad1216d04a7e60da7c9727cb2a756df3", + "0x6da48a25ef31b1e25e33b1df1c539b14e6d3837f8061c6a4faeccc861b7c908d", + "0x7d250fc602fefae7409a7edb1260f4c520d4717b881c8afb6551a89cc781efc9", + "0x043db87fb979042ae7ea709cebe4ad58028916f035e99382be9826f1236e5753", + "0x01b125ca25e2a254e0ce54e4f3da04c647ff6fe982f1df158c3caa90b1e2a2b6", + "0xec617f330285f2d4c6ad161250688cbe57bb81a5e45fb11354ac033e2fd724cf", + "0xf7cc72b3307f0ed731b990d2c10f71cf195b02f7e1d2767873c3ffc192cc43ae", + "0xf19619c5e62c5f244ef4156cc2c8f6edb6c230664e4c19ab32e1fa137c9ae173", + "0x91c313a770e9eeb92fa74c335f9cdb735bd14582b385d2a380bca534cf7a6dbe", + "0x14c1ecb6b06c18c240932c705154f009d9032dfe576ddb545a3a4cfab9968fc4", + "0x7d2cf6029c764b4c676c3a30567efa13f0fdd3cd6587631bd79cc08f26d75505", + "0x8c889efbf596d20043d654a6cda1a58d480ed2e3c3db65f51aabfd25f85784fc", + "0xe0bcdec3debf12856f3b4fc781d407a52b6b3d544b56cddf847105760a99775e", + "0x32c229b6b99b2173338bd7615a1a0c2c4fb5acafd41e332c9be7dba91b8e89dd", + "0xb24b187ffb16385b85e6782fcb4563309afefa8a7900cfdb81d024c2257913fc", + "0x81bc38df942c4c9c309f19e4fe5119f3d7fc2347fceb83f7d31e990a042581c0", + "0x1e6ec7caf14747f470d65bea046f7cc03e081271775be615905632ec9a18a637", + "0x4eea8052ac23fae83fd1fa63b328bb4c2c66277480b78ecc00132c1afa53d37c", + "0x8810dfc2084515339a0c6f1b3fa771aa0819b47498e57b3733aed0d40b9a55e5", + "0x3cefd28b10c2ada59c1bb66a832f1ce79c6d96dc0eae3b2759515839cad25ce0", + "0x8fb0cd31102c06d1e33f782fd9dd7f6f9af8e975e10fbe560183ca366d088039", + "0xbd7842672dba588021f7b395a55b949d41090039b14741ac667aa75977e00d62", + "0x7c4ceca9b53e12dcf2bd5a625274f30e2a825d5075d640c7bf78abe4bdab907a", + "0x945f8fd6e3171159a57fe5ad95e46cf93c494613247051b941bf4ee7fd6d4e29", + "0x01e9b5d3ec0f6f100907603f591e5007d086086476dcdca849996b98089b924a", + "0xec9545ab618538789965fd828fa8830ac17ee52489dcbbd71b296abcf12c11ba", + "0xdb1466a3705b6a035fc7794fafb497fd2e7606b003e73c6cae16b8d9b2aed314", + "0xdc36ec38da93a79b5a1e70d1cb3453f3ff324793d2fe64fc1c4e8fb1b22e7f29", + "0xc1f2a76b96cc31541362b5d6ae9271740bd540631b4f3f0274ecc5928e17e10b", + "0x4a5108aa8e22f9555d94caa9c29b9793b4a97e2c7270b8e24b2b3717d9efd8f1", + "0xc8938a2890c4f884837acb06c4a3854d1c03286d58d5d62c85c06e00d8597fe9", + "0x61e1708488fca9b334a1682d4f11bb046b5088151a7333655c733766ba0e5e5d", + "0x75705cfc2a41a44eada0a51ad75eb93972d84122658c487803287235c0a5a405", + "0xd818c5f5dcb79e84b2b41341261bf3e4e97f1bcbe572c1eb5be5f7e3eaa52db6", + "0xee9b8a62f9bb12306b38c129ddca08e1481db588b6e07b45a7defc3750cec078", + "0x1bf73759029c056f0e59b27a8d05714c916daf36517080e724662bffebf9e380", + "0x4ad981191be35ab37c559020fd42db86f57c56f51a902017aad1deb2d71debb8", + "0xea76176e1ae162188a798fc6ba2426c5e39b98a2832ef5f730c06d51f0b6d71f", + "0x1e425a410f888435fe7c1d6912efddf8ddc3a763a136ec730c31ca3ed0a3c162", + "0x5f6ba29d31dcbaa0220a7c2f901b987e968233bf19f398528e91973b421aacf6", + "0x935266f8976c34566a762204de924295a5203630aac2d2bc9c9cd0cc8286819e", + "0x323fa129d881b6406662cf69f01c720060a13cb7c93ea7fca3f089cf47d1b9c5", + "0xe17499346fcb6ac5f95e10c794f05ad12ba85d201c4d9a2571837b287dd90fb1", + "0x8bd288a3aa8be55687979fa9d94ef1d1ef8a0036bfc5615419920c6df3c31bc3", + "0xf05028fd3368402e82d4f6c6a4b12e622b048a612f80567d6e874541998b87b7", + "0x7e35b77cce743749b57b7614bf4f3724226ea82cc1f76e6f6232ef25b42eb6e3", + "0x58cb381e320b2ee7ebf17aba08316d86c6e8f2dc038f8fc6839e94f16b411a3c", + "0x24c1e91b745127f12bd8603ca59bacde6fe1b990a1d4de58c5e91c29da27e371", + "0xffb99ea8a8fc58a1c7e33ffcc199519165a452ed9b87196cbfb48ca23198e571", + "0xce37cc2df44d4308d1e5b846d46c9d7f2bd78f6b771b1eebcda1142858cbd4e9", + "0x0babd6dfc4f5a3da90ffd6f74297db7ecc7964f23bfdd3404f49c47cf7019856", + "0x97ba6463ece697d1b340dbea1e4e51e2f59e1f1283fef71d2aef12060b188b6c", + "0x3cb4d7dd238435f316ef70fee4bda79bce6b9a333bc10a36c2e58f7fa4bc24de", + "0xe44502680a574938a0f483c72cf5843ffc506bd2d9eae270bd108a4b7dd55422", + "0x3c9ef69fbc9a23ff7646a9d99f27584f3969b20bc56249dddc7f83fef68742b9", + "0x555a8316eb846760d2996998291e81d5f80bb0d8db71e5c02c42791ce83e456d", + "0xd4d68b9b231fa41e4571e258fb5d4770e843b3e50832aee6c7e327a568c062b7", + "0xe0a8bef3a6755a4d50f379f9f324f0404fe677372f307fc67ef2b938eedf986b", + "0x57f32b8c263c9fa6e3b5df8603307216469dff93a400290cc54f3a76b54a2a75", + "0x3749d954f6fd6dd710a0a9b4abcb0da071b3c50d125206c0caf4f4786d590d4d", + "0x58efd182fb42171c896accf391b30f1916503f616102251b9dccf2a45a823c5f", + "0xe44810336515f4f45693cbc57ad0eff2105d70faca32097f7ad6aa505c4d3b67", + "0x0d720fe2f29af2607ee5582016bd0f122f63d0f82a84c4931446a184843594dd", + "0xb3106d35e5a904b6d460ffa8cb494f6a95045d717b3f532847105bad0dc5ecc6", + "0xd1bcc88ff9f5ed1b7625e7242ecddb2b615401dd8fcd01c9b9f03a6d22d144cd", + "0xd4d4702668cc3673bd4266be291aa0f25e8ff835df3c43d556df01342986a279", + "0x9fb62301f00d441319f81de73fd49fa1126a29b3a11b022b3a92401dcea15772", + "0xdac3eda26ad4eda3d83c0e83d65c74ca4c4c3ae47eb4e5e82c6b315f80266125", + "0x7b24a259081a547d55e9af822fc54d5dc6f69ee3e961ebd0a0248ac36f6e25dc", + "0x64e96157f5e4be77c9f50df8ea9c518026ce1d7db6adc52189c9354922504635", + "0x35ee981b1a7d307671605b25399cad71503fc9ffc00d2f9ca80e868901e9c269", + "0x6965520591a7697f7c62ce4aaa6bd90691ae1a89a5f8e29237ce5241d8003636", + "0x30c305cc886b538fb8808be71bddeaec3a1276986906b7f028347511bbb653e0", + "0x5f63caf0aba563f62811903619a10786761011d2fa6fb58e835b8dcd5cbcb3ff", + "0x6d7219f08e8288e4dad53a7fe227951e81d9ff2633bbfa636a3d0b147b98342d", + "0xef315cb919bc5537bdc9bc47d2dda7442e4a372c74163fc2134173773ebfd7a6", + "0x83016cc642eb5b55b5a667d36acccc35eb9c33cec2caa28ec263f00800bca2c1", + "0x0c855426475046350b58fb7e179202cd794f482598d73ad05bb0072774561493", + "0xcc8dcd45a49fa55fdd2871245cbc611613f203203ae4ffdb1e647e7143b8513b", + "0xefdb25f8a05ae4c869bbfbcac9c302f3dcd8a917eca4d5807deb09833e876820", + "0x055646d6adfd108be923b275e21c07162227694df780512d0dbd7a0b58cdda91", + "0x4abdf1b201aaaf4724e81ff29e8d48a223f7b98ed6d9c9696375047b7643280b", + "0x929ef44a9c004029274bc1dbe13b49bd6452ea3a3ee6d378dc296c9baf0b1e9b", + "0x909a57470dee2764e5ca646d6711de3908b3b35d98e73f67adc23a3a8aa3c48b", + "0x42e5bfa041faf65f224d7985ad464a526a18fe591a156c0b70df9d397beb9aa3", + "0x241d0b24f3c0e08a17f10d579e49e72af7d2e4d0f0d621ea8975d50a3901950c", + "0xb1f3ce2968fed1bfcf363a031d79cae0174d642e931862adff7ee97f947522ed", + "0x7e4db35d3aaf0bdba5cf1d5465f77e6c927f42b775e8ec2bbfb43be36270b5b7", + "0x7995fbf9d69f7222ddb9d28bacc6d97c61780755e933d3dd47998f1f3747aa32", + "0x31317d422307751b59eeb45270518af357bcbf7ef413f81c8e7c6bd48d79d696", + "0x5c58fe54e2781cf91a9d09e080a9ae5b6a8124cc06275aea65ffe422567aca2d", + "0xa4da628ada51d57b378717218e6753fda428e2b8ce88859f37837b4c2fcc5076", + "0x9c9f744e7e3275808f9913767657af8a33a7717e45adfd84305cfbcce328a065", + "0x1381182d1b1ecd75969148742706a27a044cdeeb5cd984886945e5de5f3311d5", + "0x71a4759a9096d67a4061ad639ea4ff7df35c811eb1c7b10638aac889584567f2", + "0x1bf9536eb1692291213d4f7f340647025c10793c2c84e8e775db5cb5afb5022f", + "0xf2af02ebd1cf78bf30a215d80133c7d5f7361a58b827efa23e940e7c91430af0", + "0xa90ab1a925b660baff138369712be90a6cf8ebb658ccccaa9e8b0305adcb4ab0", + "0xbcaff27b022e0873b10da43c78b1395f1878e2ab1c8cf33368988a6060c6132f", + "0x6154955bb4a81d1b96e618ab29a53c393ec78153a733f90227c9f83683131eeb", + "0x451b4a606ef40653e1ccd38b07fd4e8efd9fe796e01b5a5772ff903b45042187", + "0x011e748c7fbb39346bba2b3235c185fde946d28627e2f6ed39c68076d5e6fcec", + "0xa849d075319c4f0cb13f3115ab99e0cdf0341d719f5c65a36b100ac1bec98826", + "0x1e61220e9a615b1ec127001aaa19f307c268bfbf14bca900ba1005539a7ced1d", + "0xebc6254608585c487baf6e312130a06468551cf4ea171335480881f42ec626a7", + "0xce073708172f6fd1e6d792f4b9fe088dc06e164422c5e85e4098c0c8672bdecd", + "0x8102653797d93a7d372b1ddbd92c8c8cebf79fdc8213392668d62181c2639a48", + "0x2062a79855e50c96f3eceae62ab0f873eb3f051f66931efdb00649f07b82061f", + "0x28302f6a2106296e587b03f2f0963ae9c8f8eca56198f7d5e0fb52d4485e1da0", + "0xdb69e062fd4f03ad8327c3b33fce7efdd2a1455cb9c1c90a7e2e9127b12ca041", + "0x984232b5675edfe8312be559135281ff49be1219e3ab17e84560221368166aae", + "0x303557f3d60ebeaa591cf88e583c366a7db4adf1031b3de9c8d3381466e15b7a", + "0x2179d8b03104be3b8d2e6f4ab4c6b9851bf85ed4545aee93fc40d3320d3b5d2c", + "0x708174830261838f9d87279a51c4d65814f7da2495c1a7ba1eb867ae7217bdce", + "0x5c5b77681b0d9d6789aea3494c60571311f2b6690de38c2e4c2a8caa738afe5b", + "0x68782d0db788b3e7441e94e4300a93c50d641c060677c6ac98ac50c69ee972ec", + "0x3c3acde8f5a99d8e131d33c7d55ed4415f0c230ed6fb711627b11e464faa3264", + "0x0289fabcc6d32e03cf75d7958e22ae050c8fa6b31c03221d78ddab3469d9b95f", + "0xf10cc55e619ba8b9aa5ab92c272ed1459020ae6f43e45fd9d427075d86230c36", + "0x20ae1b4f3c79618339a0f0627919ab94809328164ec1dfa6b9e1f556e68ce770", + "0x071e6f74436830ace1c6bca63d915218d8f561e184d15cd83ddb199319907dad", + "0x7334a6ac9991ef0876f0b4bbe18dfc407e748c65ee79bcf114c1a2a71b46f41a", + "0x4f44e709a1e59bfc7315843f399add75d5c1e8c3cbd0f485afee94e1c4cb0d33", + "0xec0514297634ea605be68932d68de290e15306061e20a16b2e3bf675fe573bc8", + "0x9c72bdae94b6f57b594c11872ee21af41c704ba1addfaf8ec4d828d6ac6101a7", + "0x1d1a60f27879b14930bb0351e39d3d31233e7d55f3ecae5c9cad4affdd2edb67", + "0xff4fe06f62b19f1e6079955baafbcf5b74627785b5edf90cc49ac75490a07f8b", + "0xcfc332e8af474ce72548c5f0fd50d4e6c10858376b0ddfb706e99703177b31e5", + "0xd7d5eb515bad41cf09df99d5fe0400ecab66ebcc9f7af53ff8cad256d9ad2bea", + "0xe6f7024457d9e945da6737c34090f689bbaacd479849a7c64afb6aee85b6950f", + "0x15fff05c7ff12fb455b77b5430532011748a52abce46919f69ee0a4c30b59fd0", + "0xaccd46e8d8482209373407310b988ba3e1f39d6eb17f07861d33bfaefeab3347", + "0xd97650055032b7bdbabc7b49b7343d0362d6241aa45fb17ce9ca1815e7d58983", + "0x0a4b45c31d3a1dab81b47da37e896360fe5a1e45903f59d6ad0f0b8ceb2a7747", + "0x8b2a42405ceba8740c02c526023247a262088e35588fa4253eb6e229c273463f", + "0xf43516578e7fd03970d57b08384b0bb3441ee7f50213c2ac0d1830d43c857abb", + "0xe2aa1bc333310c27fd699455b06398679a100f6a942c0eb37f70da89d7f025f7", + "0x1f13aa876a2a348d7de6adaf51e8af65ad7bfe0332c4c9cbb4dd709dbde8e1a2", + "0xd766018ae514f5b7daddf6e716bf4570456cdd46e7a3be68c1c515f2df441bf3", + "0xa2ce855ff00054aea57559662ac95b2445c1fa2491d9f4448183a474396daa53", + "0x8583ceb1254f6546539fdd57d1fa1e3580d81f1aa44dbc875de8b0f56e5e7ea5", + "0x7e09579f21572f2ee72399c3ef67c01a5f3f27ee4a3c43e8b6f692e231fdcf1d", + "0x6153e318c7eb123db88f9afbe8ff1c8f66e1cc0e8704db45730912a8281b3366", + "0xd31dc325333526bfcfd29e50e5fe13cd696e5948910abf46e66dc73f7d271942", + "0x9089fab0aa038217485edcae76bab74735a1fd2897c30a610f5e43f1d2da5425", + "0xe193e06c904f53031be5910209b7aab785bca6b65e917351764e2f231800bc4c", + "0xf732414a066d5a8fd13241f5aaa9570e5c6285119a1f7c69063a8b4cb62729ff", + "0xe149ce7e516f9d54df933717a11040e4a9bbf8ce13c5a3612288009a99724295", + "0xf29212544b867ec2505e35cc5ce79ede41fcafd676f41df15af7f178d6dc5cd7", + "0xcdbad6c9eab35d13dc6461ffaa793b180e28085b8047cc56a5328f4066ca944e", + "0x13f5597439e924b31cc8ab8b9cce0776a8d89bdf7e6a0a306763ae259bb92787", + "0x791e0daad106b9ba1ad684994744d2ce89c6e413c51954321d9eb3d87e0ad14e", + "0x892436f41d7a6d8385d66f6ff19fc7235dc6241477d2745792bf3a38085c8d5b", + "0x68b0efdb41ac9e0c2cf0df78ff6f9f790c3c1ba63ecec6bdf9426d860952f81f", + "0xcb4cca4320ab1a4ff11f868d769ce9fbae1e98d154207acc85acf2f8dab8c4f4", + "0x3dd2dc9e0d99e9ff820f22283ccae495545ff37b6e7e89b3d721bdb5ee169eb8", + "0xad216b8e962ca5b8f388c89bdca543059065c7b6573c5c0868be031b74c2e184", + "0x36953abc02bfd8d72b7667b068f63f6c441e78938b15591440a9550ef796b8c8", + "0xbf85fd9301cb248c0e616e4297e2d4ec43783bde218ab67a7e2049059236f633", + "0xd6764c6e1f3e8d671f1cfc1e55c4d65b274fccdf783ab1b27eab1099b9f46299", + "0xe1f4b5fc4fa5e50ea8a7129f2786d7b13531d608ad6e413d3acd0637ddbfc5ae", + "0x225f99906c6ffebd2c77eda9c7b2e318740a36f84b8d6424b2f479f3e98b1fed", + "0x7850e352fda7e9b524fb1b1c04ee4695ba3613441ce0c5321b26b9cdb3317625", + "0x4913a582ff57cb276667a4eef0e85d31c79ff5f048b8b017dc89653fece5e88e", + "0x1cf357321372b71199a20da7e7490bafa5d9f837fdd3e433a68e8f84d03fa550", + "0x978cd04d02821dc54a1ae97385ca618a91ab42e9c227b5da2be433369825aff4", + "0xef0098b9b604b3bf4b7898d887b5f36ba8c196606b5688476547e89981e84a21", + "0x1c9cf750c7a5188cd346781612291b20ab07039831a77e55ed890987a876a412", + "0x6bd6e5e5f57b23bab83994c68760951a0a5126976fa9c46a99bef5b329ec7cc6", + "0x14db2e7acd6fccb3b019382385a1f988dc368d5da69cb96956901bc4ce06ec1d", + "0x48c20e5365cd6febb128db3fb93ca7a88b7f2cd3dfc5b7a6fda331e62d8f6875", + "0xec6ae4cd53c6c40f3b77e82cbf386d478120145c0c18f26220eeeefccc54b883", + "0xb27738db32dcb1fb5637ee6b86c528aa9ad75a47777931d45285f0745d6d9618", + "0xfe9671bdffedf2170714da275ff0dfdd533ba1be2ce2590bc1ebdea9208bc951", + "0x25cbe60b7936b87c09e92b9982cfd1bf80ee1d6ce65133434ac330065c9a60c1", + "0xc777ee866895e41d8e7320601a8341fcd99c98ba9d600888397f1788ed79fce9", + "0x63425e84adaa76af6e58807d3fc3dc294e9bd9c32a170a60d8571c667ee804bd", + "0x086c8a54c5d1c2f4160d7f0f5f6c1a333ca91875ba23727025d77225e2f4db95", + "0xd8da17ce51dc8419c40723d1c3a88f74fe336f9a4f98eca61bf1349b0d4a89da", + "0x0d2169c32328187125474e97c7a917253b90dfecec0682f3ca7982e064fffdf7", + "0xc83f335b6903eb3ad4b0f94fd6bb3a8b5b463d0137547a4252043d58ac00df75", + "0x175f57c174875ebc474879251e4bca53bb7efa9f27f456f10266864719e073e2", + "0xb0ea4c419abf7a74ed69807b3d14e0de6def5f55e645fbf0a625c7e9e3765201", + "0x4a246d6ec272afa613f9b6aa288477795bceb920d6b3ed1a78286314cccc2e35", + "0xd3af9fcf65dce23d27b46704753c0b4b24dc752db5389876d31181313cf91ec2", + "0x7301d3627cd3bc2ab317c377e4f81ef6b07ba64939813b20050b53c8f63a533c", + "0xcf785d9ca7c95247ae005537d0db37ae9c54494b0a2c1e655e9c5ee1292e8338", + "0x3de4a30d38f8ef549ae45b777149a547c8cc785c6e6f48e5dba40b7bc7fb4c82", + "0x27fbff002680b942c31cc8f04211be03c8646f024857ae52121dec778163452f", + "0x2a37be7d47abffbfd08f1aff379a27e1d9dd79833f67b466a59b8ebad854e3ea", + "0xedf73b72736afb79d07c6e726c74b88039da0c21285ae55b5e2c8191d3f802f0", + "0x99a6e045680aaa9aa3c175140a9337aee7967d78e97b41a0cb37c03f60c24b63", + "0x5baf77fcc6542689195c10fedca877c6d59ec418867f25c79d4c3ffd36493b84", + "0x85d64816bc21349e07c5dc852a8790c6169d26274dc4a7fc35c53c199c8f6dff", + "0xb59cca680fc9baee6d3d80e11e374bfe8c111b0f47be83157e54e6d18ca93e02", + "0xae13047af776510ee9d13cd6af0e669495704651d5894f30e5e49c6c9d33bd0c", + "0xb2cc9c6705f969f07f700e3d9fc62fbd9de299ca3510985ae5e6fe339e187c75", + "0xb198d0787de7b8e5e9beae4821f587608770fab12845a901edb33da4c50dd217", + "0x7fec95f60944c1796bf42a978a3a771613b889fbb14e6cfcaad143819bafff9b", + "0xda81d0a99cb64b0c8828a05f11bbe38719cd6ddd6cdbdc814a317cee492b1503", + "0x554823c8958d8631a06ea110de162710e66da426210c4c89bb210684c7dd9394", + "0x0914908175ce4d9fb7415d5fdb52367c616a1b95198c9421459cc1c769911cc2", + "0xfbb629523797ff98da78d0f41e2acc45acbb20e4a1e0e1dacbce45c69216a964", + "0xd88684c269bdced43c0bccbf8c041aa6fa2fa9354a6aa67d7053aaa0f2074962", + "0x3920c4c386860756180fb1f7fe605801f7696d5b9e4e1576e1aae0e8525df880", + "0x5deb5c080a346877454cd98ee36312bc3e4a79b3cd9f3c39971d892ed955e927", + "0xe099ae7dfa63b764ef3952ef921cd229acead0b0e047af94030ae09a34b0be2a", + "0x7e754b454ded479b4bf36835b0d52074183c9eb6c42398d3e7338948992d08bc", + "0x1b22378457b71df9263473eceba4f57933f11d33d31be11ec5edcb36df0dfd95", + "0x6605794adab619d57a2ad55913afe54cd5ec219f3d6740185409ac61d32a2567", + "0xa1039d1a4bb3e763dae6dca5b8c00deac9bf0b76c178eff53527a95852c587c0", + "0x9d43d1daf7c4295431136143ae7ad2192b71c16e8da4cd1ae9a282d113122c6f", + "0x38d5c14dc112d21963208fb735e8f76d9842c2ad13e2cdf32b0f6e70006f911c", + "0x09396c809912d9403208968d6f13d8845398b26e93f444acf7538e5c357df7b3", + "0x1ed6f3b995bfbabb0d55b107b2b3ec11c4be5cd68f207d9d059a8eb7671ccb8a", + "0x69db9592c01441747056fc5c646057d4bb992e4affd23654af7f24c47a002900", + "0xef015d193b0137175d8de710c2141d23cae1130c368a20f19bd59f9289d1a17b", + "0xeb63f8ea306392d336b2a8e0568e1a067d8f40c4e2b28f7911ebe48a67638942", + "0xfb12bbb145b5dc7ead7ad984045e62b922649a70ec00da06ebd9eba65fc83c23", + "0x10bdd7c613ce8584ac10f75891afefacc98cb0c711504e0f0284f634d19c3714", + "0xab851b2b35fcf427bd0407865a5989c533b855e65a9891e39b2a5e161a345af1", + "0x6bce48ac8c3553878ff831b672de737cfc7d7c3293e86fe322d229ea3f5d2c78", + "0x0c7313d927f845de9f7c03c09775e2c8fb8e9f2fe63413fff066e9f38d799ed0", + "0x347135f2e53f4002b5687d287b5134de9134eeef4cfa4d4494b086d957157870", + "0xedde43ae708664ffeb9d92cbeb03daa5fc0c7d1d03ac3e9d6541dabe9ac50c65", + "0xd14aabe2a11d404dcbabfbbd8d7c73ec05af5a0f9fcb79bc8f198f00420a2179", + "0x2c9d2e1c881d46c0fd68fffbd5ac45e3dbde2a4d1ddbb77d0ddc4f520ab83c94", + "0x42ea8109042da88b6ed9c71dca34907f54c356b46db55955e3a6cc1541904a0c", + "0xf81c890a5e8660bee4d5a0f18cc0f3a709ce48a5a49a36f0138ab6431783263c", + "0x492144091be2113571cf9cc84c53390fd00db10eafa2f5533f78b8a5d6bdc7b8", + "0xb42ff2a6b3d1e736c56a37a0a46f927caa4ba9fa6bd3f2d1a98459c7c30eb262", + "0x464c4d7daf1acf7786041d3c797f15354cc03cc5620454abdd88679659df1292", + "0xd5dca22e9c436660ee18a941129578021359c0bf2f22008b161c91494ed80594", + "0xb54d6f7ab969f0f95ca94d0a2070b5f2aca9f991e3b64a60c903a03d3d48e938", + "0x1261a3e911769c5c55151982e994aefd4d773fd96e8583f41a44cda306b4e1ab", + "0x669a364ae954397361f4c703c102513315552af241e306406fafb3dc70db8ec9", + "0x54d5a3162659886b7a0aad65839ef2cb72233dab58bb91961d6b6ccb1476da8d", + "0x449242a1b0ecd0bcfe9acdfb2b6779c9f291c98c09add8e13981617486423bbb", + "0x4dda9dcd34dbf574f62d475b7e3052b2e393be6331ab4b0ddb3f1a6270041e8d", + "0xd23f7682f463c5f58940bd199136afba80496fab562aaf665710ff1d5cddee66", + "0x70503762d711f0ed6eac70a12b728f3d84152094b1e4f9495870433592cfa268", + "0xcba23bd9ebcf36500a69fb8be017f0ebfe9872abba5070c6702047e3814dfd0e", + "0x0e2fd927efdd930e1843103c837526ea8f846230ef6ec9f0e8af61f9d3b19aff", + "0x518a527d8d9af923c12692405837e35d58a4625ca36c2041e539d9e369589192", + "0x0a697ad4d29f33cf10f6e08024a18d36a09f459f8ca427cc8b36def0fbdabc1f", + "0x5d96d5562fd252ca3b5f2bc6e6439572ec842764594463b349fc50cc8681d8d0", + "0xa093f86f7e70f80c308ce12554c6c23cdfc02dfda87579335ff1983d549619a5", + "0xef0d1f6787ea178b22a66632a6e44ff464b7de08afd8dfc780f39720b4746a08", + "0xd3a6e3eeaf50eb34d9af9ea4fc461fd4784ecbc6a2b7a8eadc37796d7f00218c", + "0x4c1dac930f116474ffb251df529847732dc575ab404342e651d6fcd67708be96", + "0xd5ef4aa7047c1ba5f18e81417886490624b5520743a1cfacbb04df4dc7724af7", + "0x2c0b01e814e880c5d9b9e01c08671e9a5bce1aa1190e58e0fcee1acf14b36cf8", + "0x464c6952f2738c8b28819299565a7ad027ffff4bd74d06ffe210ac5a44760975", + "0x5bb7a03847d5d77fa84567f913b2da4b87e4d2d453bd5194dcb15a2d07fb284a", + "0x7dd9b9c68e2df4a415c1c4898e979229a764cbda85c215bdf9b8eb2fc0af21e0", + "0x75048e56ab8cdf0cc6031e3a57fce809e540664872bfef2aa32fcedffc32e597", + "0x6c570e74626bdc74454167d24b0e755469e57930c0c5514847db10dd224beede", + "0x511151b41b26e5137b1e564295744e6b9115a277fe569a355a63cd483e2af7c3", + "0x885899509c8d7dcbbe3f9b6fc3ab2b1ec3df00909c92450dee7b329ba7abbe7d", + "0x40bc202e2040897eb3e06346d5d5c71276985470ed2e582b6f32ab8e4107984a", + "0xb442612b838cbc33bd65416baca317ae931bb2b6724bd565ca181a4aae95b590", + "0x23be2219b6842dfbe704c7fdb2bd4723cc4c12fff81ef96e0368f0feed5486ba", + "0x8ce2344dc7c2f11924f54185e191f22b536ec7a9ed82930e223e0dcac3ea6649", + "0x68b8de1cd88ae7fd5be9d8eaa51af21efe55359e5dba2aac1125232d01ddaf1a", + "0xc771dc187da76a5c761c9f00dbd9f50bbc0f149ef98f897c519457104c9f1a0c", + "0x697ef9d13cb317e94d4a40b9c6f45cba2680d6a2247e50ceff250be0f0934fa0", + "0xeae45a6899bdc251611165055e02b3fe3fe65dd938fbef43b01da4282d7fbe8d", + "0x3a352faefaf059235c46420d95a5d26618933e993ec97dee1a87cf55be10d4d8", + "0x59a105b2a42cbdec8ac080fbd09c98bd671ba47ac654c69fcffa0089ab9f4d95", + "0xb2e2c32ca966983c1951db62ef157be6824228d14468d1cb9856d53f9be6a9f7", + "0x67371fdd266043a11d59d4f05f0c5d920eb2f60b434928d7b558099623050c9c", + "0x0d0b97a7b38358d661718b2b77f50d1ab580632f030985d9e44ef3116cafa38c", + "0x2d19591fcdb7bbfe41412891fa43201363d0a5b18a48994674dfeb211701507c", + "0x7b42ac2c855a619963157ad7f3d36bcd1de0ea5689dd3e454aa2afc7b28dd071", + "0x16298885164e7c509b99d5a05549f95f57f3401f723cab1719b76a2bbce8b0d5", + "0x91b028e3ebca0b60cbc4080fb0f816d834f0898fd00ff42080b3e8dceb28d66d", + "0xe3802595c56c2981e3a4b35c149e29c421107c47ee6df2b27e979f59bb06cd3e", + "0xd285c7cdd2fa2eefce09e902c86a1856ab4cfe33e6695e94dca8fa74695a5424", + "0x2b78d2e0c0770ffc67b92d56c4b26a675e7f3639ea394842edf9019ad6920b2c", + "0x495f1461f887371cd29e86bebfedbd429f7eecbc7c759ccfa56500d7845db4df", + "0xeec765f7d794010adaf8dd7f07674eefed3f6d5b9dc43e39a3b3537288b9c9ac", + "0x1a4f6372274bdce3bc6ea83f768561d6c9ed996e72145d524211df0130f3b7b7", + "0x3955a47abdd98eebd3d38244e408aab387096dfa74443b9f607fb6fa59456e64", + "0x7930f2d3fb73869045d7b144061eb1445ea74202b8f090f4f017c27e1c4350ed", + "0xfe0e4fed81793226f51942fec125072e439e701bebbb049337a5f7b24576d29e", + "0x87a4cad6943d444f9da79e4fcbffc198c96752ae72ee3fc2487a82e724a045cf", + "0xde75d28f56b1fc3e411dbfd9a56fd748de3f7490b931328f3a5131c143832218", + "0xffed1a9fe59006557ecf383d162f0f6011b59f63bfc693d61b77232329f8d956", + "0x1cf303aae3e5d342a33d369736563133519e1434f981bbe6067f444e16d89230", + "0xf3be3a8b280dde0fd0aa8322cb7836136b8801420602e45c8ceb84ebed7c7e02", + "0x2813d9eec11134a3987955f4389d4bf07fb4b986b700d982f89d2c81caa2ac1d", + "0x28f236d43bab078d0e9662be120609f8de33bb4661596317905815e7771b42d4", + "0xd72f262c68e657dac4247a7db98fd115b1865942071d0eb06f68ddbb64b392d9", + "0x4215eb42c3bb1333a0acfc8240f1b5d9938b68acdcf0c048fa037d90cd6c59aa", + "0x5a70ad627a347a1884a9e7fdd6c87cb7c0d5922ad69054a3b9d56e96aee436c0", + "0x8ad7e96941d03426434d6b7e0eac92a04e94108d2b1fe71178b582f6d861e2c3", + "0x9902aa9f7e7f1e9e1da269bb387739c103b3ff7c67032097e309df96768b21ed", + "0x0af467ddad68dce1180ecaf84a397e5c8fc98281ac52c10d064e5972fcf87d52", + "0x4f945046721c0071c9b53a8324b391126d26c8bef20435d60a6aaa69e2d156f1", + "0x78bacb8175c8dd89e4c12b74aa687211114b47906d763e0f26cba8410e5e3300", + "0xdf20aab8a9e472d877262d3985813365acdab5dffd05139f0fb87eeae10a4627", + "0xda39d3fa1f48b617d3586f3700119f60a294c1e3d2546393e3a4bf09ba5e3030", + "0xb6ee6e1a15c36710e6d37d2cee67f4646ac94de616c3ad65b08cf6b7aa3b32c7", + "0x17fdf37e749a06f9b8768d73993bb7fcff8b6da75ff4545c1facd812c5c89031", + "0x17c88f6d416ac2e913cf054b9116f8639a566dca223243fa9dba0e0dbe047597", + "0xa04fa8fb398b38a48e134c62d9e31fabce109651e25fab8d32318bc6409edbcc", + "0xfcc5dd8bb39b3782154608c5e3c2a6b050382ded90f0b8352c645ca2b80a88eb", + "0x6b3f1cc76318f33d63b204bdd72a009a7e2acc1a81ff6530739c41990de6552d", + "0x5f4e8c17b0f337f546abdc595f953cfd056015e3add1aacc4e058b318277a3cd", + "0xd9917cc1fe0d4b12b85b2713c9942cdb07178e4c6f594baa4fc2617491d0ff07", + "0x2f6df9e5f1b821365dae46222c7f252a13693fc34a9ff96c1038f154496b49a1", + "0x5807dc551b31c69db61bd1619ad0f9631483957bafc20d4ab1a3e6902332fca5", + "0x04b97d025d8a5b1ac619c36ba6dc8185c05b4f1244993f684299f7368ebeae3f", + "0x16c71e2b84a27105527ae46ad63c9e2eb8d2145168c285ae2f7065e5354d768e", + "0xa562d2718f87e2086106f87bbb574bcb1e767cbf9471999018eb3cc21515b004", + "0xc2ff97b7e8736ef6de59a226cf0ce16353eab76b4a8b8ee147995238dff57d73", + "0xa9abdc4a8f70bc74134eed2e64045b24a1e9290ddbdc6d833179fdb4122c2293", + "0xbf0473bfd49593b516300cae47d7e603f9a2ac0767db39e2ee6e028083099490", + "0x8479dc0704190c2e34795dcb6dd447a4aa25672b9e45dd2e39f3864fc9521203", + "0xe03fe87b29737c7e663196fb33c69f02a35caed2e791f2a15a562bd2989d8cd5", + "0xf50fecb879d837e8556ebf2a5ae833649ff8f97118caa2e3b617b59153b65b4b", + "0x0eddf32c7032a26f6a0e0cce24ad9cb266d11500db33b863dc5d3470e3ee0a60", + "0x85161c9ae941dac62edc22409804ff1ae3111d9f903843a7f86b7a138e702da8", + "0xaba0acb42e5acf464de70e965b47872964d7241a57e21fe753535540b8e04a53", + "0x70de7226fe37eec9dfd4c7902761d0ee25a24748d47dd73202f9c10269bcfd18", + "0xe5f9e07e4757f99c0b3042102abbcc59b1472f45b53313626fa49fffb13a318b", + "0xe4e4be40e0d945d84851d54c2a317f0c56cb1a2a78b9efe1c58d996f9f7be4d8", + "0x5f45e651327d2fed7f559b97e56f2c954e82b843c59cd2e550628639f7f36d26", + "0xdb33bd941740ca4d547b52f857ab2fb06a5d144eef147b5dca309b6edfa730cb", + "0xdbedd24c3f6fb0f3d1fb2eefeb658076338a5274f01bf988dc65c7062f211d73", + "0xbe54c3757785c7346e4e94e2f975e97c6a9c542b2a621281b95529b58d3ba7cb", + "0xff9a08a7d3bad55b530fc2ce5b8437ad524b176f151b10366376e8752630a1fc", + "0xb8e1cc41b404d9b605c67ca266bb338f4b94db9d04f71c33b6205a7aad5e581f", + "0xbc06897480daec866c9faf1723f19873448feedff8237f8163ccd796dcc2a4c2", + "0x1681fa8a577b819397aef568125a2f81aeb94d313c5f37c8041a6fc8cd4619ae", + "0x91b95548f18cd07f37ae2b7d53c56a37dba797361f986d1dbf290e169a8f9bcd", + "0x2e0daea275060cf0d7759fea5f50a5d22bc13c2ad85b1776154409f4d4eb30c4", + "0x1999fb0544b4155419e2e84fed331c401f6a2e3314117acc21da81a135bdbb47", + "0xa35676895a52c8b1de46ee4059d57d1fb5efd480828fdb120048294347c3c18f", + "0x8892717f9562e3f1e5dd2f88b45c299ad91e8ab05dcf6be1c0de7a95d0ee7a3b", + "0x91ac521bd8ddbc2efc821a82c6336d01cca79b55c36fc05932ba588d68bb62ef", + "0x76850eae9c3e3984a06d664df14c1e3ab86532b16624e93603fa098df1136ec9", + "0x4379c37011e615085ad33e48b21781b943437e073964033d6bf2dc9fe85fad21", + "0x15cf24d1b72cf5c797531314204207e899820c07f2c611377fa4a8d2b23e9e64", + "0x964b36d4050d4eacf96a2e71bdde62d6908efc0291795432b45b3032f78c5fca", + "0x5e8abbf414ebf24bca3f1db28a81e34ab73491ef8535fd661661ff7064b989c9", + "0xc1499796680c37d46d0844a902f0ef966efc8117c2460e73f89b1d81a3b35f76", + "0x16be9d9569bc82d5245e0d2f5f2efe4a52ef09277d84efdfecf219ce5c7368e4", + "0x05c7f5f0b28e1fca9441830a38e54813e4ea3a73c7c4f7a873781040e4718c95", + "0x0902c45ce41d4e6cbddd66046e9baac2ff2b6fe4b4b5fce0ee91932d57f74edc", + "0x523cb2017561cba6cabdbcbb54ba2f97d6a52a5ada114c533912c457a4fcd02e", + "0x9df4d35c4f05636670123ee3d9a6255c9adddfd7d17cac6ea2b6e8dd33becc09", + "0x05638d9e998b4eff7249981556c9493fbcdc39f78d34f6c120cf87a0b4153316", + "0x451c25c490adda5cecad4a7569450e4be71b08e6541f0e122683ea3544b74375", + "0xa82e2fc3c1d30e7bc9f5a4a83ac3efdd57a7d05617889001c075086dfdb0d206", + "0xb2e0beed5b15c9db6e0d4f31a2111c4dcc193c0dae3ad9fd320d0e2bd4410ca1", + "0x40183f421d938e028836b39156862b8af8f88b207ac17b9f7535df0f6e7c8bcf", + "0x311e6dfe62efa8e3b5ee21ed0abb73d1ec69b357e689f22d04d7010b3e6c9ed0", + "0x7abd56b8ecedeb87fc6ae95d2a108829f8ccb109e05d75ae19ea67bfa73a13e1", + "0x46771d8f8adaea3d100fa756a801c22d277e1ada2256fb7e613730484a856de3", + "0x3463faf96b0c752199950ccdc1ba7b16c07df750fb76c10c8ecb1b155e3ce021", + "0xddd0b47ff5d1fd28ea7bef1247f683c3c2ae6356b8260376b390b0e4770c2c70", + "0xe50cc4bf0b3278ec508e7d9d0f233e942721dc9116c56d65182c5afc04219574", + "0xa567e9287f6e919a716ca159f6f59e0ebc6e27bada9e0312e4e7a248f3a1a195", + "0xfdec56f24cd59d833907cb21a4311c47d4baaea891efdfd4cc1fe48f875ba73d", + "0xda2ecee4f7f28fd5893d7db76b248fd5a5c8ad18002230177438f1209e92449b", + "0x267e150fd803d5dfa94dbd099f8960c52278fe338d1786b1678ba7de6c101625", + "0xf70ae6d7f25e486d08489d70481e7e537eedd8303b71c656e80ec04359dba398", + "0xa02efe6e14630c760bd69af9a6fb3f8391b5e7ba3cfb8bad4958421b3cd067f5", + "0xa5c4ac4a8cf93b8695d2f1b080ea00745b52a656b6f55e4debfed402226f3605", + "0x434c8b7d449c62e779aca1daba7e2c5b7f264dca8879768dc0b9c02c02ff77c1", + "0x67268d79875e46e0abd507e67b75e5cbbf9aa3de463284e96c057ce2f3be893d", + "0xc3d6c58cd4418eea6fa0e0be7de002279c761588135be2dd2dc152c6f580d75d", + "0x52f6b52e67e84c9cf8d56fd1dfa7d8e45e4e4129d33f9a942307929d28ff2859", + "0x8833fecfb8236f00abb49621694b0fd2a59a41f41035d2704a81d05a196fc4ae", + "0xca068fd3b005b08c2f3daef99d7447332a7720880ad94aaec632d54c591063f9", + "0xa3de1f4bb4c142ad685773b15e9a4e97c35267eac119e3c29e0aa36f2b814487", + "0xe8433c0f128f18299bda56175b279a5e271a8af30e3176aa48f6a734352e5b1f", + "0x9727cfeb52499b591e360f88de264235661a21fbe7242ace5d849d90bc506c74", + "0xa0c2265b8ab7baccbf56801e5d06baf4ce6af5879bd7e193f5fbc67a717cf2b4", + "0xb6303d8b21a2d08fb82154142bbd014329841a5564adbd217468597302d4cbb2", + "0xc6571041af75a5bbb7552811ded08fd4d93b8e33e974451771a629593df7d656", + "0xcdbd84961c2639aa0159de12abaef96152026ba3710385ca44e2080b5ef6008b", + "0xec8fab8e1adf154822c799dd35e2627420663b4d1f9439c79d89f360467fc216", + "0x8aaafbfb4414ab5c8ea23ccc43b5abd2349194cdf98792bbff46b7734a886d00", + "0x1e2462355a74d1a705e3c3f28d826a6b229a134c472f8d2541e9d03ac37d8d2f", + "0xd4e33157363845de8fa0564d1145e4a46eb22fc909c6b182e6bd7aba4b380613", + "0x7949178782807772e6f9160a14b54fb0ed503d5c1630932cf17cd9e385b00ee7", + "0x089d7d1b5a0f3ec62db8d1c11a95365688a47bdb14954b72770d5cdb7af3a365", + "0x69fe40a2c3b725eb25be1310ba0b97e8974b17ce9eb233eafc1306a6ccd7a463", + "0xfb4cf8727985a7d97917d3b020ee11dcdb08cded73085363f625a37ed0d8b04f", + "0x5ffa2a923b9a50832644a8bd39f0ee569f9e4ad8f50c4e1d57c9ec96a1c03477", + "0x8360233860f889d96a7e077d221b4ab6d9e3f7f1c5fcb20287ce486e9c244979", + "0xeef9332e4fdb2022128df42a2f311dc5ac080c7273e1a24b50774058b1d9adf7", + "0x89d790c825dd9b3de1635ba3162fc0a3a99467747869b409db97d95f7ff6cf59", + "0x04a088709bb769fcb5b670fa79cd97ec2dee21e62992cb2df693e1f18b3a2d11", + "0x86519becccecba9b91d0af72c176a414589b056dab914f877fe8032ca1b8ef9b", + "0xe61b3d8ddc856aa2ab755d4097ab9040ddf3554a1d8493fc5b93b5fd58aa0fa4", + "0xd8efd5557426e233870b8bcb53e0fc89fe79545d4c2d1aaf13409a7fba84acef", + "0x0b74a2eefcd26ca8322495468afa0c2ed24db0e4cb8ddf30bb84f9d2bd9dc4a4", + "0xa9fbda8887f5ab139d567d9a14c507e574352003b6fed49d3cc3ea49ccb544c0", + "0x078261958231fa17c1b904ec7b80ec7c2a0e49925a2309abc701521b90306b6b", + "0xc4d9c5af76a0b6c55ed8243985779bc77d4ef86adfa63a8ceac44efe908ed012", + "0xb02867e224a85e4a929894919fdd1f3460f909ac276278129d7fbc859f56915d", + "0x7a66267c51322887433994e3a01fdff4600e596a06e1c627c5a50c42e2bf203e", + "0xa66849c9503997ed600daabeb23c1e316d938d7c36561013f41d9a994d819735", + "0x572641c0124606eab803d11c3548ea828cf67b3d238eda5efde6098a210ba6fd", + "0x0a920057716b8b6b968bd5a28478ff99224b687bc6c97e26669fa1dbaf99850e", + "0xe198e1c691d14b3ad0a6b1888f7ae40ca60042ac91ffca0d6df3b4bd12090898", + "0xcf8cceabc0ccdcb4951cc37f625c1e8c120620e42ff3f1ff4a72e4f6dd6139cd", + "0xfb06a9c8215be6da3ade6c298f565f7c3116d12c87da1fc9fa48d17240e3b545", + "0xc967f1f8b116fb2faac0ae0760622a488cecc6498c074ee0f013d985475c914d", + "0x7351f762b23b48612b1369c3a7754ac2414e4d337f94cbee4fc1adc29759eba4", + "0xc3410fbbcda7e7bb868ed399d8950db593b7e79d5fd482a5fdb6e6bf342fe6e8", + "0x68c7626ebe19b8d30af71d3cf3635dd7c7912aed7a47bec3c369b72eedcffd05", + "0x3de93c3bb133dcfdf07ede31fb2933d8acda317e7680e7bd18cc1485f30b9225", + "0x4f2c0cc1f9f2f2c1b84448cd9b033d95f74940f6dde28dff0cffeb2840b6eb67", + "0x4e2934f4981c6a3591ba4048b0f3794a6b92bbad76e94d68ec4a99ff95601d06", + "0x8ae0d36b4e3212e9055cef96398fa706d9df90c2ced2c89c4828758b62154840", + "0xde41a196177d404534cc4b46f6b877ca4dc22a443f6a4680915e43046396e8ef", + "0xcd273ae452ad455f430d5f57d6411454fd2fef1698f9b8c23a4fec298936e47f", + "0x95c9ab467c02ae75c80cf924e81ff6c9f9f9176b828bc3dead827d4707fc5cdb", + "0xf9ad1ac9623d7b8b55dc1b363ac5e6b81fee9cb0bba042ee9802b74f3d6d12ef", + "0xb77f49f9fe7da05e6233e1aafd35cfa8042f8ac8220bb04fba898bf75b485237", + "0x6c7dd1ae1b2c378203b2be05abaff1e6f24d9a16d2fc4fc76bf237e61f5b0951", + "0x50c1046183493f9a0b860effdce20c193a7c7e89cbb509cdbfc839c522c99677", + "0x38a84d66ab731cdc96ae16a7f0dfb8c61c586bd0755cd409f4a785d426ab2e74", + "0xedf3c6c8ea853068d511c74639236e1daafb2caf96964e5b0daa22d354e39658", + "0x3445d411938c39b0168b96f8a4b0e32206a531910bbf52743faf37b3581f3236", + "0x4c418ec9d20b934a3f237b4c13682cc1638ba8e517e86d168e8c990971098f97", + "0xa610b6a8777a0467100a3581087f5bbcc1e7d4b697d9f53d00d9fa6f0d77247c", + "0xdc9e46a16000ec340bbaf70284f6a1528dbec79e4e8c371d4b04847f8c844089", + "0x34e76ef7897de33eb66e4ae37b5534c6240540048c525f858dc832b166593181", + "0x36dda3dbe43f18880aad5a4f25ec29bfa2da4a6c7f964e6418c0cd421bdbea36", + "0x64221de18086e9361ec07e4cede9e0103109d315d97684f26f05e831ee2878fa", + "0xd0fdddc2384a132f50ae0670cac8e62e918aff264277d350faa66a0e95430a2c", + "0x4da406b43c8247743de53b0a395e47204ca3f0d15f2a29d8715e11a71001257d", + "0xd0e67a0d70cd2140f55941d6ca90cd15ca6886ae013ccca40c0afc0bb8bbe016", + "0x70e6b1561209e95921f3800b1c48ee3bf3e532f5571bb2e4a5d82e9b288eaa33", + "0xbbe85ae238d623b1434dc75fb5e5d09a75578d2b85c59b8e69d635befc784248", + "0xc617186c1cc1c807b9626ae1a68d8d4fcd6b42aa153dc586d5ee2192cf9918ef", + "0x018329ceb98202471fcd740a34c7c987c2daa081b0d105b86b5b948c8248ab63", + "0xa1bd431642f0e1dd5f0bf01e610c29e5d695b8f578faeb0f511a7a9a2fa3116e", + "0xc8df41c2aae79331b86e7b007a28e2731f27f50609e9b4924678b8ff24d509e4", + "0x377c56c1c8b9686225cfed2710e4934c17ce890222c7482e7fe7fc77ebccc52e", + "0x0262617467f33b9eb0f3b28f368f5d08483a38dc9423510442eb88537c6d49f6", + "0xcdfd57a4737a718352b19c48aa72c41b2be0a7267ec7abbc3b539c81fb5a4b7a", + "0xace32a66c3c9540cbbd81c26a429487e3ee135677b8a43ee7468c0fc0c584c05", + "0xd4a50046105d5d01c4c928a0ade2d1a82db88ec52dc1f02b7c2daecbe9985841", + "0x350c5fd3734cd35dc6e02080e087858bef8d8dfdee44bd8e2bf75aef795a961f", + "0x5e597461c6e1468b3056a2cd4483e85a8b38dc27195ba60d50ef9952aa640a49", + "0x4f9d19414803bee7dc37e16413e033bb710543d86b38d6133adb1ab4ce90cd0e", + "0x3470068fedcdb6183c16ab34a1743e2414151eeb7a46d71961c1359adff1e214", + "0x66054a35bf4b53cec8302e2c94b8be80f3692fcbee87da4f894769799453771e", + "0x752d55b28bc47a388b098fc5b6b5f60ffe153459ddc1c0da007cafb3be151be8", + "0x3b969e58d42a927a7b214ed99c34ca6a77234703908bbf4ffa17e17e21fb8cc1", + "0x6f0157bcb211940600bb88d08f026fe4af881dd11d8dd1351ca014c88c3db72c", + "0x8592dac47e72c7bc32099c102a582c00543a0d35f2dfbdb9b57068c79d077815", + "0x8c95e048954d689645df63ae447101dceed5e75d154502c61f37990e5a97ddca", + "0x9f4a5e8e60a88088c391040bc01c46538f0cfc032344a882bf5f00cfe1b10d3d", + "0x04817ac392930b9b4d81cd529703b6688717da8101fa8a327fe49c503c0694ea", + "0x446d3e1470d3f965fce24932f5f1824f998c9cbcd9eac1c9ed7fc7a323658bdd", + "0x8603a9e9b6b852768b751175cdd2b23e354777e38408903b42d67a108c1b0999", + "0xd04177d8e00ab233b6336da228ac1b9d683128c66a85f1eaf2d462e7d52c9ac9", + "0xb01c3a41c7864d5f14f7b2f18bd5e4576c2d4d296d78927f75dcc50f488b54ee", + "0x6c7f1c0024685c819230e8accfc6a0e5f967b440d069bfff8c79185f152f940f", + "0xa2106a57c2faaea7c6ed8c7edd48e64ffadca5c03674672da9a972b4d32ffc7c", + "0x2c245fd6206db27c4f95be2fc01b04d24febc0e7781efb69623bc5214e7ddb69", + "0xf4aadfddb0d2d00668dbb5a7aa1cbd4302d0778d3697af4cb2ceed68e5dd1639", + "0xca6ff39151d73d4ff9aafb89ec0843e5d93eceacdd69b1c95cfc745857397c15", + "0xa18081aa619e1ee71c310a810c8b3198d515a0954edd34994fedc974f24bd0a3", + "0xc05f8f372ddc52ad91874e45aa48683c969331a3c472708714c19af1d8e3dc07", + "0x57a2027a86cf6e524d7a4e7b0b920a98ddbcce80f018bf402f7fbe73cb366614", + "0x3fcbb5d3f51987fb786b0ff83f39526e2aaf1791abc5aabf2f11a6ec8ea4bad4", + "0x61dbfda0b2940f034dd239375ecb5c8fa7385547a6ffd4bc5951bca8f5c8bf0e", + "0x662820a806693485407041ced34740b6ed57649bdb2d346aba5cb77108f697bf", + "0xe368491b3e2fd70d2c6f06c6e05a41f2bce9fca28df109882fd1bf3e47c82287", + "0x6cedbe3468d4903c73316b43534912e1b69cba4623791121b309fe37b6ad9b64", + "0x6517d421dbdf6e9041df293e6112572b8229208430277c85a7e52acad8a760fb", + "0x8a1602ba31438ed89e0f922aa165e0740e9cd9caccd82ca7ac79c176fdd0a2e3", + "0x09a07f8791bc59a20a326a727803822d1dd8de5e9281870818469145ee90f114", + "0xf6c3a82062633e2072f5b2c59b78b3f6613663afb2b35546c1240c696aaff8a5", + "0x1b4ce49dc9f835afcb3c34e92caa9a30db92c0fc2cec32c1746cc5eda1caeff0", + "0x2bea42fdae58791ac76d7bc2fbfc08712cb8ecb70b011a271572f047a678293b", + "0x01964b0ad4072d281dd451f41ce9e2d61f990bb104fecf29baf012779652f8e3", + "0x773cf0d41e03244bc688be7660101ba39fbdfa2cc94e6bfb02a1dd291c5c7265", + "0x651f0346eac119d14bba1a1078536dd986024c4dc5cc5953b4d9cad09735f97f", + "0xa4389eb16c42465582dbcbb6af80198f8412091c6ef2ecc7ec84c093f8925306", + "0xed75036dbba0069f415af01cdc723c0901676182960e2e2b51994f0e0c6ce0e2", + "0xac433ea4fa502fe9d126115a386eabeb86df2c895e3908bcd02a9d7d125dcb00", + "0xa65d04561f73a2f6e1f107c3759143c136b12619ab498ff7ad31994e7db5438b", + "0x6d9815c2f081d54013ad118b2c0ff456aa1396eacae1dffef461c2f2ba066527", + "0xab192c650d80aeba5b885a67d07512a6f532fae12ea69a3eb39af7da95c64b8f", + "0xa1d329666928263f1980f72c9a21414c7302fb5e77cd1dd7a91c4dc5d6d748ef", + "0x9e84e47ddab8900337e35ae9287dbd041d0b1d059582f95d375f3231eefd428f", + "0x89c11687a6c5e5a5b45255b4a8ffbe337d8706470c3a39063a960d103ade6af6", + "0x3547ba85cf24a64983968f8587f28bace1a797a93ecc16ce6787263f0de18185", + "0xa98634b1d1c39ec41c7cfa6a4f353c4c276f0618fbb3bd257008b43bb33b262b", + "0xec39ca2cdf7a3798a1530c8bd1424622822f6824415b2964d0467ba313faa940", + "0x8e66c39bc71e16085bba945ac0aed19f3f169d9d2dc7c0ec090583bb896e1a51", + "0xfd7f6e227a8c9025a57c73ff8c82265bc69c9aaa185eebfa924ef608234f1937", + "0xf55d1247afbfc35128a41465800daf2f90c1d57866e4bd37f92bc8278baa95a7", + "0xe82faf145ba98fb5af7e32f5aa90e7b2aafe9e2074c86bcb2aabe17ff35a025b", + "0x62abf9c26e0e5a7c2ca3047c8ae9f27c5215846595b4f41aff72c8a05ce42549", + "0xfc5cd59f7ff8b54d787cc77e29af8f9f78102be33ab4fd561481dbae04426b3d", + "0x69af5e5777a5ee39cc76a049e268845af3e1ecfd0b8de8644197469460880a31", + "0x8c1ea859c343697564a88b170973903e588967d89b63d511f63218bafa4c4aa5", + "0x8f9c38834fee0d5653d4df327232737d342f9b389df61f5cd377164e38a91e6a", + "0xbdaff64768fcdb9210cf8e33fe94a6cb38ba068c2d21d970efe6cf5cfb919eb1", + "0xf64aac8df844e56afa1413e9765a955b6879af44202a43e3f9aa15db421f6643", + "0x06762bddba350befcfddef5148ea1f05729760cafe5f018eb71285b92e30ad96", + "0x536ff0949c7f34762613747c2b7d14f605d6bf0ac328346e34b4fae516771af3", + "0xc30d536522242b0b805546882d5a283d517efc518abbdd674156b6f67dbaecab", + "0x818fcbac4a40b856bed993b9021286fa5f59f0b76b25af731f4123a83b5eb90b", + "0x2e6c3d4de85428210eda505421b253bf3964f5b2403084a1202d940de2d6dfdf", + "0xb31f7199cc69689b24ee2f52c8b50746ba3ecba904c49e2b352f8d6a64f514f5", + "0xf910446802e79809cb62cf6d958d570186ec7a477a16ebf6c0eb45c245c514ae", + "0x36e60616ab618daa724963f56bec00da5cbfac517a41f291da6e6cda890d68ff", + "0x4ae4e0c39ed59901fc74ef1fe52643f1f4341457aab052be71382d9945115b47", + "0xf5038c706b2cdcb2337a88ff34ed3e8e3093fe95d48e0342fb3bc3c0adc2ce51", + "0x021c48a8ce17f06cf41f89033a70b201b73d2fdc5c314bc313e8cff57cda9fd5", + "0x363c94da2187a9e497c77688f70baec16e64c4454db1f0dab37925fbfb9139c8", + "0x2d7c8407dd4ac5ea3212b18e103f10626d8bbc0cd18fe261409043399f026b99", + "0x05c3dea4c6599a259c3297c51c38c13f618ee5372c6b43e1945396bdd7a91229", + "0x7eb49d1da78b683659a33b9346c65bddcf6154043c97438274394e3ba868d0ea", + "0x17c008f4a8fdde5d0dce03adc57310580912599fca0535a42144526b4a630503", + "0x0011edd3b9175a765f1ab25a3123b91ec9ff9f233e8f782a2001ced391da2f05", + "0xcb62dd00e7a67019c782abd7e4bf7e3eef12614b03f90219434bba24e3070097", + "0xee086e5721066d4d8886e61e228facef0f518f8140926067be9f0f55b261558a", + "0x683c738a40a8fb871f3f7ef575a422d9fc60511ef4c84cf0fa9161605c10ef2f", + "0x43a4ef42030692e416d28c72f899fa83b4e3d3066fedc72d8c1ce0c3f7f60dcd", + "0x964a579e0415c2875382d1dc5953a54850494ace6077f7ed247f00eeada0bf1d", + "0x286bca4d5a0ce6fe9c9ecab2110fef1c13f71f8e11c37ab5667e164d2f4cb3e5", + "0xf2faf12c85d82d434a5db7d43d51bc99508bb11db731d7a22136d08f57901639", + "0x645944ae04d68cf3c993f75d75f217c8a78531ea3f17718aea08c849bb705382", + "0x7e4c87b6078ae798210fc39cb080772ad2034dcd9ec0f7a28b2de7d7e15377b0", + "0x4760f5e4af303ec759aea4fc2add0759caa3ae96bff4f727c0654f81d02a763f", + "0xe2f15372e72f6e8852c7289b192e959fb797fed0fb9581afd755e4352ec288e2", + "0x760975db833255fb7f325477153462be406b63ce08e6ed0da0dc48f9dac5375b", + "0x2ea20f22253680c49663ee8df8c74aa2f0703223c5d0dcb3db37b8c3ae7475a7", + "0xe7622392c52ce0d6cd698806142e6e26c9d86c81f1877bfbe9022ef150cae57b", + "0xe973760c42ebed38e37252019fd73f4ef14f2503bd3ffb2d859124b7e25ee557", + "0x7d0c3cb847b2cb7c1a5341e0214e830ef886073983e08498f89617b5833c22e0", + "0x5f5939c73fb684dd39227cdc88af51936e59a9881f8fb63e071366b9df4a6b36", + "0x081d5b53b84e2fe7f8cb04a6a6a045e4c11dc726710b6e9994f426fa9d32ed9b", + "0x436e895e16cc13777cd0b740538a64bb3a1360a7038e6fe8efa3ed3f590d05a3", + "0x55a611a3cc6106a86768053e268658cb541c8ca17a66a4a90a375772f0b5e016", + "0x583da6ef703398a2b781acd935f9916932050fa0cbbe1548b86d40b3b1941fd4", + "0x055531e88f18a0d79546a3bf00cce987c33ee0f97ecb7550b3c301530b279bec", + "0x4408c0007dd2dabe7814546fdc336f3ebc5a1dcc7daa1d8a38a9db819eb86374", + "0xcf6e7dab9c72babdc051fcf35ea89e793aa6fe380830d61870cfb4ebc3e7d919", + "0xdb02f15887419e3f89e1930d620748ca53e7f0c026ea8b60cd6e9ebc62f9da1a", + "0x4d1bb9da4321c7f2962a275272c6c1b1c3da6ca9549c19134dfbd43cccd76359", + "0x6ea8fc2a9138c404993edc83b3f54b0d5d94c85367c8e6884ef5d889ccf1bfa3", + "0x4ff5c77a56a90c20872cc7ab5b868557f7fd5d0103503d4217ea2d0079690ef9", + "0x5edd2bd35b9d24b9d5a3c68025061137c82e04261291c4d958d9e0e9a2763329", + "0xefc287bb7ef397298052013ab79d5a46a3a80a55f60e42c66746c9a25ef2dd15", + "0x986fbdb20fba887f3e4441a5b4b98824e1ab4df9aa43cc1d151eeacc55bbf4b3", + "0xbc70117b2b1204e3868a610bf3d2819095185245be082c96ffd3e0c2e406be51", + "0xaaacb52b835b235c76b02960517159cd1f2fb08681f13c8352a04820a990fbce", + "0x43e8b0fb11a657e4afc022573de30184947153497936d6cd47dfb2ccb61bb110", + "0x63fc1cbad428e16b1e2063db10c85ceb6684680c044adc2aed184054492cb19e", + "0x776674ec78cddc642e69ee9b16f2ee876655ca3efaf6a24a72c99a998d55348d", + "0x09dfc550074184d46ec04de265047ce529bdf2c02f7b44e428742f674c31a0de", + "0x897263eb076edb3071a306922207d17cceba6ad179d0f7fead2912ee42c69774", + "0xbbd230729752cb6d078eb853681e85823d2946095ba318d44b28eca479bf217f", + "0xe731c6c7938b7f2dafa8b5935cff095289b993d5fa4dcbaa715e6817d83fc823", + "0x04fe3b2d9727b05033eb4955f0c6693b0e63de665db904bc62b4dad5ce59a487", + "0x881aec4ca776991226a24f1ba9c736f9e86a051cffd1ed42d563c01a602fd126", + "0x9dd5adf0aba333d3cf13bbd8636dcec128911b675f159d11fadbf75137e1b766", + "0x26fb6742fa3be87da75218a1a138a3ed64cfa939791cbc718c181e226b5ecebb", + "0xad0c9794ce6109aa72c3b0ea6110fe96191ce3efc89bef5a99696ae84380ef3c", + "0xd710b6759276fc3149afc75ede514256c092a9e044555ece9fe27e27364181e8", + "0xeaf3b11fee973c4aae9fd19de92a7b14ecd347275c64b2343a2e4f97d1204785", + "0xcfc68b631ffa430c95ea583a1a1cef0a43e3ca182deb646c399a451ce55aa921", + "0x52057b9108fdf67ce8b7a28596e933ff57369b9ec9f1183b79cb0d0c9f32d651", + "0x1b99aa1987d512c71cfecbe56d6bdb4828ff254d055dfe1b23c472ffa4a6c3ba", + "0x64968b18cf678d322a84d54b2a91e77f44c108e2d722cb1f52708cfb824d227e", + "0x51be4bb756c2a3b74d4552310d49c7edf084014ea2787e349bc32143295380c3", + "0xf98742fa2e646e8add000e8ff892eae0fbee6f61a2a200eb129758285938a881", + "0x0f963737d026fc353f0576ae146a0dc7a8a27f31138b3753101a07f0e833f1f3", + "0xc3af9d91a1e44a3e865f44e75cffd5e9b135b04fe6d423895fb1911ec08573b3", + "0x366072ca53e1b7c312088a2c3504894c2bbbe1f1fc3204e22a22b5b619e09a9b", + "0x46ca1ff3099150438131eb934083404728921e498773b5d91ea59814e8078588", + "0xe2b18d6bba927615a8f9252188c141864cd61cfe570ba65f7290e4ac0739b403", + "0x6844fe922e79f335ff103ec551476f4433d4617bf9f3e25efe5340cff0c9406e", + "0xd433ef7f7b8d1d517815e5f77f95a2f3e5100a08a1ba9e5de78fa57076d1d307", + "0x6a2a72db31e9cad268f13dd07c3c91d2c2c23e0c92c6f1047a6f3d59f447b821", + "0x9f0ceb8da593cf1c70f4eeb08a3f7dfb6f682ac4bc1c175efac43b10e100ac46", + "0x5ac594092618aeb04d6ab2c5b2612f1d4ad57162e62aff2d04decb0ace6658ae", + "0x003792b77b6c078c98e3ebdc29014a2c24c238a79e71ed5e36e27c1e273583af", + "0x15e869175252c89249a7728c33bb8e4c67f90f3c802d80356d25344ea05e9249", + "0xfa67b16cab4a3f1f8c4e8f6b3fe98f5be59e0f13ebc50d32f9d1dcf55fa4c984", + "0x3259027d8095d69e4bdaa0ed9c7d80681f4e40222b1d03347a141a634de40344", + "0x8aa2f2b46d0f85d66ebe39c00fd999b67d576e2fa119fad6783d6af4939fb25b", + "0x0f6073a427daebb861b9e1c45ab46ca9b8410e8f094137b979f6d17662fe4ed1", + "0xc9a4e1be21bb3dbde859c1bbd9ef9b63f8312f95c3d961414338ee8f9c8611d4", + "0x1c24d8de991c7daffe35d65f90c9eaeda59163f481140928c737d1066a95c01a", + "0x94f41fc0f4257b24ed6ee005e62486dff71f6ce8176b9fddede2eaff25d9fe55", + "0x9fda793acc69eb63981e28716bd20e8fa3ac091595929d943c651f73f6559593", + "0xf7eb671c5e563de2698cf69b2976e25a91c2c462eb7583d754211b252b4f8479", + "0xaac71c1761b78cb396167f177572144e68e1051ca3c332e94514041b9c7833e9", + "0xaec9323ccb0314b0407a591c05a0eb83e48052eda78fb5e9116cf32c902a79da", + "0x73a2019eee50ec26354b6f7d47416bc10982ac44ef47ce4720b6e73aed28f869", + "0xa45d192de4836829a913a20b14a9d8c95dadc04edaa07edd2599f2a75f85f5f4", + "0xcd8f6adf06fc2f226bcb713fcde720e205e4bae7a188d5135e3728d752835dea", + "0x59614e66b31bcaee5066f04bffdf318879126e7bbebdefe39b921fdfa5c1ba67", + "0xb27c406a25b24d78aa543a26b8321e43aea21523c7805215ded3d72c9043e0c0", + "0x1485ccd46c327cdae534d95c4b61611213377dbde0728f2ab309a65b69012deb", + "0xfd69566c9456b5af6a515aa031b326011cae67e88708557cefc5f1e67d76cd49", + "0xc7e49938469e6a6d27fdde544dcb48ef3f761d60ba4671163f505de1ca644228", + "0x96cdf2b037a658f75433883813f9edae930769dde761fde991e141fe383d82e0", + "0xc0ba35adef71f25b99450a0bb0a46b450dddc56ecea4c831a53dbea55463c594", + "0x97de7293e71b1779b23c3b51fd85e46d7ac86c55c18385d9c54d3da1c458a387", + "0xa72bf43cb3dc7ae59052542fa2bb2d5b921f49ac14485c1e9bfd1286af59abc3", + "0xbe7d7862602bb9911073bd4a8ec5421901a3a66698ed478102f02df87727fc12", + "0x7d17171e3edbeeb85326d785c2a68d6666526d8912c6aac44bf16fd0c0ef9834", + "0x3f3a36b17fbcc5ad93d99e71ac0bb2acb10b24fbb914773a0991c52287c201ce", + "0x0ddcef7f14d933eb8b28e5877e71595116a98e408b416f01de80be49a8e52957", + "0xccd5bc27319844f5b389b3b15e564ceecb55a91d748f145709025913fbfdaf91", + "0xaf27df2c5e88c00e482e78e44de581fd17edc2ae91e3b7d1017badf00aa8bc51", + "0xa850950e04076c8653eda7cd11761d6a8e9b46a070ece44dcbf5b8e99d9fb0c3", + "0x6c934e50d34130b0ea5d5776ab74fbf4ecf48f8a178115f7e93670599b406653", + "0xc6d3df6d3c0ea6c8573b314e7e0a8065d76d27333c0d6032b97637fc7013aa5e", + "0x4f7cfed4bad1d65ddbb1e28c8d9814450af8d573c0f1880d5647eb008a13a44f", + "0x0a3162cbd7a81248f449393fbd62f65ca948e9134cfc722554f28b2ef7ba4f89", + "0x6cb294c5c312be01110ff0566dd76d4b36e86c76587084faf6ff7f28b717873a", + "0x799574f8dee1769273651e19b56c17d3aa27d3422feee1d18080608b4882e2de", + "0xec0537da4c25bb664270f90fa72c0ede19127f7bfce5724762700715986f5b2e", + "0xb955c2ff50d42cce782c991be3eef70de85a1a382aaa6f7775c456d87a987592", + "0x79f931169917ff38a71b45d85a5f8e068bf45e8ece7a8e5530a0b4eb01efef9a", + "0x8d20869224be1328197ed93a88fd53d0b31ebeff49870bf7851d6e8dab77f730", + "0xe6323bef31280b55572d866f315b97f5be96148a3d640284110a23115a59ae27", + "0x47c847e3a20412135b22a2bed001bd32dcae67a70e5681a5e14a210553eff25d", + "0xb71b250754e11a7c9fe804a33e15a662321d9449fc63b1038a17d58273fab04a", + "0x89128e0b4180512ba5c75216b3030192d9b1574df87f1b926c5c7aecec92a7d3", + "0xbad078b9e9b0328b48dea551a962e437b51902c056c5b0776482712f9db786bf", + "0x4d5aed467fd88e4e026bf006aca0a78717d6b52f311d32449b1104f415bb5515", + "0xe72015b43036bfb62431d15335e719c549c61162f4879c0eaa81421017922d15", + "0xf70009d15065bd1570ef3fe2273da35e894206361590d38a4bd414ede7d69d06", + "0x2a4a2d96e00f06616d77b29a72d7c494cb6c29f50811ea616452ac769910005b", + "0x21f9218ff5737a4e6e6a167f83691dd6445a23732cdf4491ba7e24747fa0391b", + "0x26461e3689a21987bb38091f0fdc4f371002f4a84eb3b618e8c7ffdd6b3f1a31", + "0xd683d8a1f060a5e9cd282d641dd852ae20b7b1c0f9ba785d5ea15b234ace728e", + "0x6b4c803a6643293b9160d82212e5b3405b69a4115dde4de0258a24832ac658bc", + "0xe9a00afe1af35d7811d82e2312d02c5daace99f050e42388e76e5c1b745d8779", + "0xe756e9edf9bb83f450ba9791a245adcb89ee4fe56770d1894086ed6be3d089aa", + "0x729d6bfa3c1d41089d53e08164418779c9abf94d8276a8a8e7f1e4ff492183bd", + "0xd582a6b03425d0ab29d1405232e088822467053d470a99c3127c46ecc02dc93f", + "0x69ac67b95b725e5102ac7ccb59b46e4a4457e368b90f80624d84a37104ab166e", + "0x8de7f79cb5eb8dc096e9307968dd1b46acf940994dc1fc27156c5168e1ae5364", + "0xaf5fa4455d5b4ce635f9394f1ad4840e4686d80dd52696fc392c3eb89b7a536d", + "0xcfd7922b5650cab0a29e0468cf1e816f741b8b7af1768308f78ec0ac800870fd", + "0x5e14d14657d534de1846182929bcbe7c086d0bb9c418019193406ddaf34a7e5f", + "0xd727f88dbb4a62310cbdbdcbbe40023937a1f681b7d8f6186665129b9cbd32d1", + "0x5739e5a0f02a3239eb0f2b1242c7e8e0042bf7bede814cfdc6775e172d34bcde", + "0xd426e8bf6dc9171c6850a492b883bd4c92468b861f0c539ca890e444f854f44f", + "0x8f9b7d20a62ec75492dba773b54ed3416ff18adf070be3b3a35a803da5aba931", + "0x8af025719c903aa861de42fe4d082321f600c17e4b3a5f342ca408787957922d", + "0x43133e4fac22d85951ef650fada9a746b464a0659f370ee40ac6286d5ac3968d", + "0xd95ef78d2685255b58a7a0a581d953837b1d891f8764d2842c76137bb8f92628", + "0x5fc07f1fe21167cb65405edef11d30206ed7907d396252ed460365c9d6ea89fd", + "0x3b86a46c42d2ce31c39ac0bd352ac1feac8705e825c17b06d0f9db4f15f0b793", + "0x3672191b6d718f4ffe5e17039c25be00b258336cdf959abcb1615d7e77fbf415", + "0x017faf0c950fd86809e7a0acf0d7dea5b13d41b21c60d4844ce57459af471963", + "0x5236905646defeaf3666262c1781392fbafc496693b0f26167e14622ffd5e224", + "0xac45332d1c62566039b653fe67725544d531d0d0d385cb31d18d461e36ff3c4b", + "0x2ddde66714e4fefcf8d1130e2847d92bc758b39fe7a2b87dcecf9b3d0d1bc5f6", + "0xe8c6c341b96f9771c5897a0423dec64b2d3f57aa5923b0f694988302c99c1864", + "0xd31b332e66e44f8804ab8d224d179b3dc20f718dcc6b254273f2539311ae9038", + "0x2776a9d5ded89c9a8bb243b41bda3760dc173c41f16bc477a0c6e2de420f7aea", + "0x19c9b95e82cd6277e16bdbb383593459eae5584e8b746de7262b447f313f1052", + "0x6d602a973ee15804f76848823844da1ded9e2fe49b689e4e4c62948bbfb699ed", + "0xf8feaafdb855524369a0d0f011cee5f545b7e2dfc210148b13f84e0cfc5a7a49", + "0xe242c86f0d4421c505b4722b38c13e73c760d0d82bfb77fe6677a738e3f19679", + "0xe1d5352fdf59b76318738f0932c4960a590e46a0073694d9518a6e8a779206e6", + "0x7db333e369dc65cd5f8718ef0cbf38def00cd60bcc47c1ce2034203c6b2f8b38", + "0x1a57adefa64ef6f07306db76e9425624d106e73bc554822cb99b4697bb317f02", + "0x4a6acaff19b541b0b2fd43d9165f179fbefd353f8fda107d53926e71ecf68a8b", + "0xe5e886e9b31a3378ba585b16dc81f0d5cad83f4fc5aae85945e9a8898dd038c7", + "0x4d59ae8cb31c36c39c2aec16ff682862c097aadc499da6de1ffa72a6ed87b4d2", + "0xb92d833f46038c267f09c500c2ae557810709d7db9bd210ad4df55c65bc0826d", + "0xf1b971e2530edc4703ceb21b58a750a37399c05bec8a02409895af98df7e5e6d", + "0xbf1508b24e5d01809d39c110816f3ad5d703ebaeca4f218b24925dd9577fad40", + "0x2e25a66f7a580845ecf04e66fdb0ddc0e17237f6812f5f2a1640c3511c9f9db4", + "0x5e4f36c5ec099fbc35ca767f548304f8631700326b3a4497f8977d72c3727f13", + "0xaba60fa3aa0661858a1143d01d9408834c2be440cf06d72a93e4df1df6617853", + "0x42d149eec229a03ad942d1745ec4742f9f39a03534df077977f3f4691c939eb3", + "0x6b276de3cd30f0d7659292ba6e8bea190cc24badf88c10bf269fb4d6927b16e0", + "0xd978546ce32bc1123773b6562ae0a7a55b7d82c72f2aef2a56394c9940e7cd12", + "0x297a80b1aad7e95f57ba4f31c4835728a48f7af0e9adfa10d40fae8bd18cce12", + "0xef0d03d9db22500fae80ddba96bed81bf4769e645b25dd717c5ab0748e3da691", + "0x1a094a2ca17fad3f0e2703cd172bcdf4a0ce28e01840655a0bd19cd398153601", + "0x78f08815cffd7e21af3392d2ba9ce33335d8f25758631f9eb6352b826723d093", + "0x827646562aaa1ff4a12d97e59da6aa7c9166418dd2ba204e448bb12b321b7be7", + "0x5c0e92edb551cc6d182b35b9408d2538aa982b105003606575b5514c8e40729f", + "0x416dc98309f2e650eaf9a122508c163cc9e3c9d719812e0a6388b84fd48016ce", + "0x4f8382c1eee160e6877d95ce97b3a53cf7607c59483176cf55b40b47d198efcc", + "0x8acbe66fee2f75c73255b39489f15e6eaee75585426406d96ce786bf53076b6e", + "0x74ab3f7057275e0769c3356bb7515f108c69b42f4501a9d3873433e22639a240", + "0xe0bb35e880ee793203ad5ea844081b6fa99eeed85f570b6bfbbc0efbdd7f79ce", + "0x5761b5e7f8872c8cc13278f3c2ff836c325f4179b89897d0c5b6846752c312dd", + "0xeda698bc3ec12d8004406a7c7c9e3a16fa085a8448901352ce3713efdac58930", + "0x22138b1713dd83a25b1434813492910fa8e54d8feb9eebe1aa5d2bcb6ec2c69f", + "0x4ce3cfc5b1fe6f87e9830840e85b81ff6117ab62300953524c39bfdbf7868980", + "0x6a6c7372b5c90808a6a966c0b90419b5efc739e5ad5ca1fd0d6c9583ac37f240", + "0x257fb60e826d4a92c030a645375fb46b3790c5b318b56b1a299e09e0e7ee3911", + "0x5f577cc4d21c818bd18e427e6d9ebd8f207fc71ad5f883d0e24eb9f856e3e10a", + "0x0f387595af36d3d5df451ff3de879016c6cf575fc1f02d40d547ee91f6aa36c5", + "0xd8ae5a19d1327025446b5e16d0585740839bf32d9c5798bd39e3e0697113efac", + "0x10e80ae2881a780061bac8bae4514f0df0077152639aa0da1b9d8b3ae234e184", + "0x377f9a9fc5a6fdc69cc76f6f36282cedbe9c83bc43dc345fb49db28ef6b37cf9", + "0x2d52e3af5f7ca108b3ac7cfc495b96e05e2d7f82f7f83ee3234c84b77a1874ab", + "0xaad9190dc0748ae3f78e9e5a3b4ae10eb6bb0b2617cc2d16ad3806bdd994688c", + "0x83b863f21344a6a576f805ed480eb72d3ae3dd06a2979b539a43f2c955429a24", + "0xd4d0622b957b87f71610bf3af65ab018360d320ebf328222df10899830ca33a0", + "0x7ca92b8bf0337d0bc56aab4c1a57e29addf6f0a4b9070482f06a7ee89ccbde84", + "0xcb9c71abfdb931e30a67e7b77d247be70b005076b64fb138be12f260f9c73334", + "0xfe44663a9c2067fe4bb8b43d241438cc63af9638cc1859b5d4c7c7f89318e558", + "0xc962b737dd9438cff5272e16038ef0ca55c4e1b5497d75ef5a0aa53ac6c09448", + "0x2b3a80ef8b20644facd31b5d1618814507c8f603dd8079ba40da09b550f3a2ad", + "0x4664f49d6f114ae491a0364d007724cffe144f4085d91f24f8d3fe87f5b8e393", + "0x1e2456e2e055decfa092a838d2052b12527c6e56b43a787518b121b61f7e316b", + "0x2f45b1ef6d6ae7196818f81278f226f3e0fd535d3a27b63497a6fd208f195c0b", + "0xaf265121e6406f84f7711447d3118c02b446c0d6db9c4ef266208adaa1acc0ec", + "0xbdf275c92443f0755251473e89ff46d741681c7eb2e7811eae25a0f1853c0bc3", + "0x5adf59b0a9cc02fb5bb5c469a52582efec5c317ee1896d8df49d15c18db944d5", + "0xd9aec0aa26bdd240b709a688a0b0565f3543a9b3686b78efeaf070140f2eaef2", + "0x1f4890ecb2250b7ca57a092a0a40b0e4b0abeceaac015189e0f6e9486ce4bc7b", + "0xb0be545c813daf899627b982dae9edd9de72ae54094dd8eb25570423e5c5dbf6", + "0x0f98f4ac26d2966ff4b129950dfcb287098fef2e60c3bfeb1156425fab8db92b", + "0x5622210376d1016d0b7615552cf3d66cbbc2d39d3eeaa2bb100cc2328a81cd95", + "0xe3523e80affdd0ccc3090ce202e7aa408ebaea9fcaa1e705242b948eb15f3cca", + "0x98154cd06a09aa5f9d3e4b4c824f1efdf6eb5ad4b5c0deb1a16a8372bd073a94", + "0x6680dde58fd0b4ee4626a8564f827c8c2cb9c7d0ceb4437412f30a15ad486689", + "0x61f7582008e42c3bedf33342c9c47003a6ce9264c977204ab5ef778f6e6d234b", + "0xa8ffa5ea4717d9f8d55db7d5626799aa102f1e340d80c68896a14204ac38c8f2", + "0xb83aed2db0ce9eb79c45259f66d72cd00546caf8e39e5efe91bd03ec64cf96ee", + "0xae616f4c1416b46a21390e0bd5336935490b9894eaa7c653fd9909086a1df5be", + "0x18f84c5cbad9477e0571574a0bed0714d3fa587ca21e39839a95752e6e3f0299", + "0xdd5d5c64b54437f649d7004d54863160da8db8518ccc99ddaf6942fb551dd798", + "0x72b7fd1a0758b72010c216bc7394a19c1a0cb6620386a8a91c21d3db69004b49", + "0x2dafd23aeae504b4ebd17ed518648939cd63f5e0e7448bd8c0fcc78dceec4059", + "0x787827158ba2f53c21c6d05eeca56fd0fc2fc08026bf09c76cb17583340944e4", + "0xb1a4b60e4d00c8189d940ed2fc070c1238d03d58d572ddd029ae794e47352df5", + "0x33e1420671ccba2d938f5b75d45bd31d90c5b424d9a02e7e7eb4ca60ae402443", + "0x094b7129d1087747705a683bbbe61b13c546decbed3953c7867aef485865c7df", + "0xde05a46ee5e26ff79801bf32d1f4bb4dab2127ea60f7bb037dfafbc16678e1d0", + "0xc81b90e47d6aae3641ddbfade2f8146324456ef372da470b319528114131743b", + "0x2b835f2a36503a9ef3591f1913924ab134d3fba8c95153f1cc80d503c74a1af1", + "0xfe99568c1fc3808ad05d99fe2261b27308c97bb39a965f96119e012ca8ae63e1", + "0x2bc9ac9d5a461286cbfbdc7d6181c795321ea0779835322b5e09381db7169be6", + "0x6cf2449053f134a8ae48a4f0007ac1f8f39d30d9c3269155b8922581a64b5d43", + "0x7ff755adbbfee435992589e1eb09e92532624a9888375497ab3f46d921aa3aad", + "0xe708615d47cd53d7856688d2ce264311f7f94631f318588726b88ef29dafd93b", + "0x96e1a15735e93923060b3954925e8d52b0a4b5cf6516190efb907bdfe6bc34ec", + "0xd33e1c73fa37307c1199ee2dcdf3a0e92152f3f6f9f667ebafa190837a77cc66", + "0x57fa01905f12ba8decb5f5beda857a607e32e9781d39a46001679f537d57391b", + "0x2e5f2df2fb0d327f4b574c0a37c243b7fb4210af7a0796cc2c880252ad8438cc", + "0x26714de3dfeb00f0d8c27bc6729b89d3b55b82cc1eed2999f742c89fab424fb5", + "0x7bd11bfbafe1e87b58428db1f819f4ff2455a4f90db5e60e3d84b28d818a1173", + "0xfcf5fc7965f836dd04e54a9ce577aad76d10464b678259ef1c8bc2a0a0c67723", + "0xdb2e6587cea3bcc6f109e350d6c138cf919229e884a2597e4d6e599c26625736", + "0xd23ff7e12ed5f3177dfdbb51edba35d879fda9fc4ecb2c6f89bbd6addb772697", + "0x0a64a15947b2f5a87070fc3b8171485aac3e131619fb8c88b6bb2cdc1969a5f2", + "0x17d617aa1c6ccbd70ead8237a312152f42926333e8d9165266c497ee9a18da61", + "0x74082588643fb771a733c66b4ddbefcb50daf6742323e05ef4a2604c5d56eb83", + "0xa2cbc98dde5cc72ef8b0d222037f01d308a550ede1f3097c4bf7fa3e36914258", + "0xb7e7d0fc915050bcb17f685f798292ce93d3776096c2b3a252f0fafb4c799230", + "0x6f4f736ebd9941ebb79da6456d8ad423a3711f26d3cb643b81c8e02fc5689af1", + "0x21a21b15bf03238f62f610971eaa96dc5dd41ad45a6be2867afe6206f7ddaa20", + "0x459ef1b2c13a6bf1ad48e62b2020851a4505bcb88923bf0d5ec2408c309b973a", + "0xccb6429f43f6447cb714d4bed7e003239ff6926804185c6c51aabab4b355939f", + "0x5e580a7635cbfb695c97fd68a118ea37680c7408f1504b723189470826016f8d", + "0xc523d6c489334472d1af61a7ba1732195edc25bbf68eb821d1acb14ed5c98663", + "0x31a01c69fa6a86680831350cb67fd5fa06fe8accbd5cb6e2ce0ec689dbb23114", + "0x4fd4d85570c94d03c49e9aa60cd6bd6e684bc77d3b04eb5fc6b2b7f206ba9bc1", + "0x29b8a2ddb612c8c135eeb9f3d8791b603e7bf4d860c0d0b6bab53deb22b2070c", + "0xb156a9272bc83b3b85b93ae2c43f7accaceec85e1d77ddb1343b18356e00d572", + "0xcb08ef4355bb9e2ecc478bb4e80425acb497650f20509e10e134f3f60b216866", + "0xe2f0614ef7265b21deeda6d174341d59b7d13655ee7d473e5c4636dcf788d674", + "0x0727823720192b8a7a66ff04cf1913a31f0dd5b71dc145840533c30e0b7eed06", + "0x4b321b6181092414a3816b076bc86551fb8763ddb401a6923daa9c54c788ec5b", + "0x3831bf3c54c1aad7f557b8c914dc6e3d4c106169175d1e988eb028d160d49473", + "0x95d94729d493223bbd8649cb5117f14c279fac44fe40d1de1e82b7bd1d9261ea", + "0xe2632a472234dc31a473885d7a72e84c24f7883069afed9dbcb643cc5c32af55", + "0xc9bfa80366e9c466df9cda1b1c97de5f627a0142552e97f0554e597b8bc6563f", + "0x345a832166ef2f750ff143a57fadcb439233cb8292124d20bdcc294fafc5cb92", + "0xf8e032c077431b49212307adb00743b054e996e6d3dd101a40959cf19b9ec796", + "0x2243b4956a00a8d2d09275010330f4268d2f536cfa14741313231e6a7b33f445", + "0x12e0f3ff844f21b058d0e311e266cae6d0ab5dce8952d6133a95fb8659e337a7", + "0xf6d80062e8efaef3021b7a747220e713003c37ec733ff8cd15ace6b58ce60fa7", + "0x58c2f923852b77377eb36cb9c26f1b73be98a55c9b0dc65982098e5580ac8e26", + "0xb517d1be70a5d39a4da4ce46821d678257836e6f70621f529c4019d974eaaedd", + "0xa25aa7b0b4c5a3a0f063d4d2493d8b9ab46afc091161df9b1840f47d42334433", + "0xe1795c2a1fc25ea19e6599b070aa9209f2e89a10f0524d8aa78e921c12251514", + "0xdbec5c0577039e79efcad6ba30e0693127b50dd3b108281cfbb4adee3f212ca1", + "0x2c4835b03837ea2310484879212f94fdac6bd2dafbee292ed67f55851053f969", + "0xe0d9e5d1f86eb15c09f41181c96d64fa1ce3a9c69b3ceadad476353e0de1423c", + "0x2a0cff721302a055d3aefdfce14020b3f2418110084c0b1ac1c30a07e3ce988c", + "0xc8ab63d730c578afbb7611167850159fed6d1e73fc3c0b406db19934073ac0ca", + "0x3855c134a5a94513c46470411794ed81d83b29a8da353709035f6e224a9da80e", + "0x6b54eb434f5cb21a1e01b9f067647b857d9b236044220dcfadca3617ef2b568a", + "0x710ae824655688ac255d8046d8fd8438b110d768bdf9bcf4debc9381e02e873c", + "0xde3196ef84179c193b82b1175a417820a9403bdc06c4bfbb5010c8d83172edbd", + "0x5f4e1710e4896439b22f34cf4485b27edf1c35a2b49328eb8f018cb690d4ab04", + "0x37aaadc6f1e57a61a8fd925a6b583105eac77105e167735fc117b347ca58ef47", + "0xc02093ebafb3fc424cef40f5d8699681a4ef9fcad5c8b52002bd911f23812a58", + "0x34d274e1699647b5883100c125da1fce744238bdfe4e1ca2a694a5efb03a44eb", + "0xc14618c6491fe32dcc5848c2ae2a1aa26832343a1ca21bf327ae2a0ad182c85d", + "0x434b07e53641dd82eec95f4b472c1d1d9855ef8492ccd53137ecc82b2bfa5845", + "0xef6763df32b5ab25d8371067949efbdb7f2b9924685918ce3d8068766d6e729d", + "0xe534aacf1e9b44d4464b82ee17ed9cde79ca3a574c5869ff5b6f44d292d1a926", + "0x45ee62bf59e4bfcc76208dce86cc8234727de291de27a69a72bf15ce78488a1d", + "0xb170601af6545cbbab9d707a4623a07b9cb69471f994b769bb534338d3b556d4", + "0x73c8e569840ff39b4dbb24a7adc678e1e7b63621aa77a5533ca968e260d8b638", + "0xad8002631bf3e364dd09f094028a9f4faa5c67ad311838cf65215d6a17d58a04", + "0xee81a28db1d369d17ae97346196672e6f00fd622865cd618ad8447acab9bea7c", + "0xa8caab152258db32f3f03f44ce090e3759538b33d5e557f4a9a4169a0d436754", + "0xfc037393a2fc3a24a567923bca89a7714c72c742c1c466dc0d47296eb6d81b2c", + "0x1ff9e9455c7aa193842f453554c89ab25dd9033b0f7dce5c795e19b1c84b44f8", + "0x894d063e6911b107a6a42a542d99bca6f77192a0852029c0b5cd31a47c8bd2fa", + "0x6df6ca69e3a40334a4c081d74474e00c98ad6793f5cc58b5520be41eff4b17cb", + "0x688504ac6a0ae42368f496f0651e4c1f8ce13fa707a6b98eb52c1f264eac14b3", + "0x6f200669f73cfce5f2f0d9318673ed75c38371476e94ec96dbfcc683aa583816", + "0xff4a6e25786931e08a89007848dba7f62f84a776f7d926bd6983c2d9dd3a14a6", + "0x496c57858748bccddfeee4c5e496119f29a627a659349a4f8f65d1016e92d841", + "0xa5fefc6e3ea89e87875efe37fa9d796f678c6abfdd651897184b52d966fbdbc1", + "0x08e6f4c847dd3aff0e6e45c63939869cf7b007f712ffd79a16313eebf77eb4b1", + "0x00351e602b0508184ea47bad9e47b77071640422296e6574e1ab52cc02552a59", + "0xe1980e52f5fd5b81c96c6c9f1e6baf14bac191388d7e29e1191110fe68d6c88f", + "0x2ba58560d35e709c358a6caa9347c51961642756f4cd28d09b8aeaa532f7c382", + "0x3b8c4425cf002597f470d30c40ca0e40f019d72e33ca6ac54a5c80509bb4e45e", + "0x25da4aab586d49e195e1f9e0d8371d3368e88e3801ab9db750a40df31b2556ac", + "0x9b2693658ec603d976ec25a76c8ffb492d0647581da186a5b7b49bc6c18eafb8", + "0xd27630e4ef91c7144b5db0de4fd83fa53aafc8a463991819a919916fccb66aa5", + "0xd296657df9243ccfa00571774c0bfc0b85a64ceba954b876cb40713aca41d24f", + "0x9cd59fb8b4582d88a9af204976da07e57e066d48bc15b7c707c17dd11536f735", + "0xd6789d7ca6f21a983e7ff5baddd5c7743bf9a76419136384662a685060f16eb0", + "0x38e752a76cf82b63556556042e8cd6e4304d08338aea8746c55ee5864eae341c", + "0x56efa0c6d7d82b0d6b9ef82ea4b8d792d2786ac54b001d77e8493129accec545", + "0x9bb4717f3ab9f8d8a8fa059ef6d09716dea547ad0a1d99eb41d5ef3d21a46d78", + "0x2a616d50d6c4199351074e4bfb6701c3a8a6a65a235a7de581fcf40c6b50eff5", + "0x5a7f0e8b42847b84813d9129819636a60d7f50271f4c1dfac09b7bac0e00be54", + "0xd046e59d18b22e4ad6b9c83a41599afcd2d89d6bfa59f95dae874e8491b1469f", + "0x851c439d105b3622e675f986d249065d7936a7013a05d920bef87e44bc2bb08e", + "0x8e8c4e96b687a26e22a340465a8334fb8594544e7cd652f0e667ae5849cc082b", + "0x355ef21e4e57693374780b2a871b20f361f472074e938e9f33e7b4ebbfd9f447", + "0xbc97e95990cd4a23b97759f2a5ccc45359118ba88dd99895b2e5a3736753b756", + "0xf01b5e69d8d5871473833acaca6d2a1adaea66b76aec97e258bf72f50bcdec41", + "0x3eef80b3124ee89c5fda3a87aeb870dc5fbc781df98e7b0fc1a868acc3b01259", + "0x218a98c02e2b81ccef1bfc460703e57eb8ee5696553cab7b8ce9c95da70ea058", + "0xed6a555d0a858e362e15791f49cca517b74f0f764d8b032c0278becacb694739", + "0x23d9e9207f88148f7648c0955bcccae4138b029ed5b4bf2d574987a568d8283a", + "0x28af6fc0dcb7f57f8541a8b2bb3e781a0ff4d9020cdf26a8119a93401d45eab7", + "0x01989d5a75479a5a6eeb10430746b76a639a9716b8557b7864a1b7b778d265bf", + "0x475611d8792a80560752a9573f864f9ef3153a4c30bb16f7bf1bccb69241a8a4", + "0x0e52e291214aa6300ab1d875db31fbe6274d9769cf7dabef852b5d847e3c6a2b", + "0x04ea3fdf2d26c297c4276344bfc70b4a7645bb22382127f8ce9a621967a54ae4", + "0x64694ef5067706b01581730944a112fedcca32ce9e9103119d9ea4b4b75efd23", + "0xf37ab55394c6233443e1341d03ff07009f1b0771d12b202a78e2789a97e83c7f", + "0x4d723e3c6d46625adfaeccdd1d8bc3811539a7b658050ea0bc9dec625f180df3", + "0xf44e4c0d2e30b8bf0aad255325dba7e2093bb518b56e9c89625f67d5c139a65d", + "0xcd9bdda98c027168fcba6eed7c551291b59613aac11e6e02a00989c93a13225c", + "0x5fae33477d301fda6e6e0e29bb6ddf39c1720aacdf33a4b854806f8a09cf5e6b", + "0x464ae4d9549ea34f25c28ce8daae16fc129adc7ecf71527cfe6df6e1fed72234", + "0x01079ed69a40bd07152e241433be91d61bc1338d83a686d619fa1a21e8c57727", + "0x1f36d242a382eadc149704d8d525e4ac25e0fd2741876022e8bb474d3c726ce2", + "0xe54d3b597d9e37ff213472332bf31a0b16ffc809540c593b1478666019205dd9", + "0x24fd9f8ef011c060d698711a163444b20dde695a1b0db81dc3dc171ad227619a", + "0x01fe14f246bcec9826c6b5dd668b256baba5939749ed90932a603b1cab47fdc8", + "0x6e4f521a4824ae2306c046f5545c2f7ce911104d9ac1204095b8951ef5d63cb5", + "0xd8f0f8bfa160374ebfc90fa7966df4391c1aecea802e3b04a03c087080f01fb0", + "0xb4720294d8b145f29af00f220e076b271b587e9af98653efa47e2d47bbe6d95e", + "0x93223951fd8a31a3e6c98fa17cd33086e8155779930440a7c2fd25eca31f682e", + "0x752fb11e15acc591e78509137beb18cbf177877e4a9846bd33acb1a6426d1999", + "0x3304e2f07aafd6b10cdce727c41ed85ce0fb80e59fee6b96b9a2e98f73280979", + "0xa756425b9dedd5e6c2197ab4a76c14e76b250d7ce4e2b8ada00fc61e9f62dae7", + "0xdcc034de60f855c63dd2c5a9cd4930a45a54e416558c6945cf8e058d55886d32", + "0x77ab21e42cd147f95466d22f5e95e965e38ff22938eaa6b5bca2810d6a9e2e4a", + "0x65e59fd9132b911d65da3c1094a6b8523ed5d9b7eb8822b8d2273b55ce4aac61", + "0xff6aba7d3fd54e3948829cb59ae47084eb809481665c5c09300b834567ee4b66", + "0x0a2b95075de7b0579ccc23f174b3fdf6a4ce6aa9a42f1ace679953fba0956d41", + "0xcc6f0e601cfdbb0631c13df4decb454d5cbd554363694faeaccd4edf16a9ec26", + "0xf2937d3b0c62b8f47cbac34a29d0a7fe92ddda227f984ab360521d5168274583", + "0x9f0e54b594397e29868adafea8686c5e3536fe8ea767274e277d77a5ef2917c5", + "0xfb8ec9c26eae16db5dcd2f05476d89416d2c56a841157685dbd1653274ded2e7", + "0x07d71ac9ba4b3f0a616205d182155d7a34b2463c2db95a47b8d03a45382b8e18", + "0x6e5d854c2848a36b6feef20c80a87a88a40af50888e787652ca54601a7d37d90", + "0xf9bb21fa1e3d6af9962a9946d7fa4430708193335cf32766ed56aca50fc368b9", + "0x7750970996ed6e687ca27f08481be0fd426318aad87cdba015ce129dc896b41b", + "0x4ff8c843185d1b5b4291788c869ba3723969d2dde2d74a9b8fe27ba71da67ae5", + "0xd5730d698ac2ab71bc360f24bcd7a71b8001ddc86205d7274e636bda83d8e3a3", + "0xde41dece62466d3ca8700150723f0782fd624162030086be716485e12d5a93bc", + "0x7a709bc4ed84e8bf45818e0e918115d686504fa0dce6a3bf8513d0bd488dd39e", + "0x620fe2d0affe0c46bbd0b74ab6d7c3bc6b4950915cb83742c832c6117ea42347", + "0x542ee63637f2115e11a3e132bb4246d809232772e08b23401eb8a8f0067a4ed9", + "0xa284a3dfebff214c436ad67d8a36162a1810bd7a51387ab68188267a1e166d2b", + "0x0ea68982e12031ad38aff543ca7d623ca8945e649527eef2afca28993de42ebc", + "0x1249a7d56112d4146105a1f257bfd399f18aaaa94ed5198df8634c89c807d4c3", + "0xa691469bf6b8f7caa8559865c0c99f77350f41e0de9851dc887d850be5809cf6", + "0x34ee8cca77c5b32a79cc0a6811cc73910cd0353fb860171443f08d17e3f18174", + "0x73a7b7f8bb18df6038c0df35ee55b0fcb4735c7e0977efc98008c710530216ba", + "0x0a8d0b414621d022fbaf4a1c0a07169e879a857fb105637cd8193633ce755f11", + "0x36f21a7a7d142d026e9222b884b583387f10ba692b1cc9232a32ab401affd684", + "0xb5b69e29e0558368a8abc4ff3ca022d158fb11ac6f2138cbe0be84b387e1ab7c", + "0xa57d1845ab38ef86763a374b0323b7ff84722941b06dde3c5cec61de40c9afca", + "0xe8063bccc4fec0a51a6d57ff999a7169e15d93c0d7cc3ed57c065cf8afa912f9", + "0xe9b89463cfd719b357f878a927bbc72ca3d06f8b88f9a5c8568ef2afd3118ed0", + "0x4f2ae01579376ef5a2ac6e849cb2d3befdc4e5e814a5b8de31941183697e51dc", + "0x6356b87dcc8f1c6c83a2601be987b44f77180da8b8d8186e6c61eec301ffab06", + "0x4f2918a79394961e5802b8aed07d89b3b5b459a3d9706f0749ec65f3b3d9ebc9", + "0x145016d42f0052f68aae089538ffa956cfb2c5a0f26763fdaa940e427bea7ff8", + "0x897e9dd36d2c12e8941763ac6090321db8cf73de4319c99f5e4343d5eacc856f", + "0x7c1cafd66922a53506f93d8aeb80dfacc9da69e6b73cd3e4a9779cfee5e4f64b", + "0xbd76e3eb8ceeb1f47ed865351b54cf491173ef562a51f068966b71cd294766ee", + "0x600135fd75adae0801296f92e1a7219287ec588fb4627d18095887da1c71ee2d", + "0x1bbd55de061070b1060b4184583e9b5b2e307197235c986dc1a3b942f64cb107", + "0x07e182e958faeacdecdc43de50c8d4226c6f697d7dd4e2ca9754687605719068", + "0x3591aa6b10db91679824f182cb58ecbce7210444314eb4b4e657cbe6518a55a6", + "0x8948a1a48823911e4e16b54b3cf789c8b04a3c26008f97f3c71577a22c23cb02", + "0xd37594cbc0353af27e1e70e249db20f3f16bbdcdbfee1ded9bbbb178c3454d3d", + "0x639159845a1397fe73d7ab041d7d9a74b99ad8009e3d63d37f329df35afcec0d", + "0xe41e444d9f8b0daec348208914d665db316136f42614013a35e3c7e97e219dc7", + "0x2ed6880fd4b6631ee593d3161dddf19021a1365650009d01e264243e032f4f6e", + "0xa6e5eb641f39345184365aad2c9258d21ef4b7c65ee5dba93825aba5e8e481c4", + "0xe2880fe0d6e512ae4e0e78a9249f6319407ec2def2c5745292b750d16cc41786", + "0x54729b299e086a2ce795d339e5e20cf87afdfeaab0dc6fbbd0ce5f55194c319d", + "0xd3d3dc4b51e0d0487c9a09281e1115f593bd24cd09a113c0f1a89468ca1ea2b5", + "0xc86f8dc093f2adaf17fbeda345eb2f4ace3df6d5bde0c99e85200eae84cb892c", + "0x84ba70a7754f31ae366693375c5daf4fa38f7f086791c1aded55198adfb91392", + "0xc7ccc21a8a1b96591c32e98d2c7ad358279c2c1bf6bf51dadb18cb9504a1d751", + "0xdce9df5d5bc2852e8fa61e254a9aff0f03628659df28f51dca37a5a6816bc479", + "0x6d0a555491a6fb3f592fad8b97754d02bc6166257e5a83131fe9d859e05d1531", + "0xdf805b41cf7c7b9346ed152953e6334cca6725a6428e81b9fa4227329d231ce1", + "0xf94a98ffcfd4e28d863e790d1d6f507445f9e64165b3937b0c40af11789d5296", + "0x56723b13f5112f637e1e84c18bc3dafcdbc40508bb6a88c68f3a46e56f5783d6", + "0xd550a9d0bbb3745e7f5b7e290f6755b030cab20ecb6f5daf701dd3850737692f", + "0x7d88f7a5af354de5678a270b8083ce441be4c1bd6875a337b244d93bd3cf0d2b", + "0x52b48af317cb248300cebad6fa682a741f3dde7da4bf0e7c4162f9f1607e7d68", + "0x04a7147b282fead783019f3453ad8d95618f416eb7ac0d80cbe3be8f68a13c31", + "0x4be24f18efeb4c1f8b12f124bd1f48d3edd1777629094292616bd89ad580682e", + "0x146f8719d2e7f74deb3619ce6dbb782850431bd5a5fdf5f5d2dd33a54874f536", + "0x6497f392deeeb3359e35622360f6416da4d0986ef0770ba22876cf1990e5903d", + "0x858d7fc84e4504c9e5f54cca2c9facdacd309d742aa7657c6f90e25e4d7b6f84", + "0x6fc455af373dfa77825bbaa65b1539e9eda251850479b83db15b9be2b5e144c4", + "0x3893304198a242335c96423344d68ffeda11c17c9b6c5785bc59482c385f60d4", + "0x3b2a22d6d87679b173a1e82db970e6cec44179be8218489a8aa863b7603adc3d", + "0x52534879ad0d442147ca743ea21fb5dde78510c11da353fc21636f9725f9609a", + "0x194e094c77eaf3973447de9faa29007b7b895e3c855cd01c0d5609e478df10ae", + "0x64ca084e56ecda7e9f2a10b0b2262f29d5bb8bd361019367dc41bc8f97963961", + "0x05754bcc136f5b541e59f1c40c99572fe188f6f2eec3d91989072ff3f3c1ceee", + "0xaad0bc1df434492344bf9351345d3288340aff851f687f952e84d968e1a29afa", + "0x90c5f0e124e125b2fae5d2ae5c8a1f5fe065ac2cdaf62829733599c69f66d674", + "0xc20d9e82fda10425082d631b6705815ac17aea924aa2ca534066d76734ed1bdf", + "0x68fc07e734ecb1c3951262cf804b831ff32e285246ebeffda3949e62d31d937d", + "0x7e472ad7b556415586fb5950e8d0b85e895b8c9c7fa31952936247c8117fa0b6", + "0xf5c3457576bf1b624f0f558bdba237ec349349c60926eff5c3ba8c55b32fd6be", + "0xf9c3dd5d7fcadfe33b2dabfcc4f732661985a72166afb8d16486028b89f35bc2", + "0xa493336b47637629c4bbbb89e8c8e1272722db0f7f781f4f78185d6125f0e5a9", + "0xc8cab7f153c08cdc9607263c5129fa8278a7228188c950806d5732db541cc59e", + "0x85c0c18f11c32eac54537d2c492eb9cabea9a39d2e1ac56d8087c02f68f64bd0", + "0x26a001beca07a641ad1e3ea64c63e395c436836d098818f937b4354b7a925122", + "0x75cdeed9ee0eacc02eef853a54a6f0201693cd1a60d26e504d5ef16110ede59a", + "0x8e4a5fd1a18f9513cf70dcfedeea862dfa2b61cbee80fc204bb0315a2c051424", + "0xa42896ce30565041da64ffff0a80ee6a6e280d0459e5c29c0fa3a79587d4a330", + "0xe65f4193189ca1da6d6fefef1c2f14bb340e56271b2bae3024dce98dea451cca", + "0x48c844ef658f2270efa4be7b85879cdaa2d7cb27f5fe9cdce0ec4389a5801707", + "0xedf37c427ac85a7c317bce25f06acf626cbe86e79f99f148667a95c03ccd34c9", + "0xbeca93d3b7e0f9d2f2a6b9b9ff7fcfff658c0d417830e46a3aa233f31908782c", + "0x61dac332da33e3533b9eecc1a287e732cfb9a666ef32de6bf2d2706792264927", + "0x622624f3810a1e24d48f54082f0df3ab3227c9cf9d39b007875a3428e2d70208", + "0xc1276025a1c848b7dbdd6f4dc1b7b2f4b19dcc7b0e312897758ca538ea334bff", + "0xefa6b7d35c2aeebf0d472745aaf6d4118279a88273b7513d5a21c3f619af8f76", + "0x2250fd4931ae5059e99572a7bfcee0117090c362075c0d90eda1ba2be2c864bb", + "0xe9b7860868856d1ba5d17cfcc78020485a36814482e1e8812555094dd4e85ff0", + "0x4df6b40297b258ae69a8858e54ea4f45d58b0ab1b0f1b35c3bcc4f96c928c58a", + "0xd17bcb3447f309b3ce0a48b651de3d979810cd9cb7edecb9b44366644e25c729", + "0x7292155c0cf9a6466c80ac2930f8305cf9458f64f40523a6b5e08d2ddc180080", + "0x536bc35368df05c3d3773b27110217c2df04d2f86e6e8a8dbf9dcd13cbbcb984", + "0x0f4dd55ebf1e1ea736108e62612972036dc533bc4e52a8480e3c875a7961ef69", + "0x902334a20d083b4634a79aae1a2b4158df3832d4c7f9105e8aeb8e38ac0be589", + "0xbbce2d76e50b1150179456ec4ce4faabcddc8700435675ebe94204325ee6f710", + "0x6cc4afc371970811c0cbeed73acc72641066edf1d81a585f28987ca1c11e8ed8", + "0x7cf1f9f26bdc8c7ca419400a03d683564bd5947068e4a01670200358d339b12b", + "0xf1e37f56a2eefc9688ebd8a95772f98b9f995e3fa9ba6601095f973cd34a13aa", + "0xfd7ee922a80adc2f6719e6e1e90add658033c7165441e399a3f61e93ed56af2b", + "0xd8ee732eedd804de6063af6b828fd6c4d9496115a367cfdd424a035646cc9e02", + "0xbf6658fb5940aabd9cf82fd9e808c9a23d04d171a62d0601d2c9dd67009f0b36", + "0xaaf7099280336cb78b87d9cc3c06694c4a66aea2a095ed614a4578fa8d61cbf9", + "0x46e23a8b56b9061bb89a42253998e7fda17289a12c63fd239a0c2866df529f3f", + "0x19b3323694c1dc611fe3722987d1a927dbf1a1ccd211b3c148798cce7b814fea", + "0xc16ac7ee79c7ac2223f79bd97a193c3bb68f609affa1596b061e9ba32a4978b2", + "0x5b929b2451c9c284c40c745bd441e1db499e336ea8a0b616e925ae780a6553bd", + "0x954a69859410a4a8309ddedda3f1af305c0baf02b1c0cffb27c0f89e629e4dac", + "0xff44052a4c53837e32b9bf4bc6080e78d3a78108a69100bcb05a85d4cf9e65e7", + "0x6199a3fdaf20c64b9587cf303682571f0de0bfcbf6ae34b4cc20485228a39043", + "0x0472d6b6c1efa88008d9931b3a1348a8892a61897e8634f2416758667da516f7", + "0x566bfd31096a3829990cc587e64e2a4477349e91b1b37ad6100be6b3de6250b9", + "0x5f51ac85ca1ebfbd382b4d60281d3746d98950aec6cd6bc1ca5ab22eff929a20", + "0xd45228a818a9f5d8325d2fe4873ddf5b0cccf4bc6ca907a08887adc19223936e", + "0x71d00ba260caf196d91b48601bb92052272067d1eddc4492f8709c3494ca253e", + "0xea6234921dde61659d45b0c36da969b7d3ed641c53cb54392e5a56da9f8df1d3", + "0x5a0dd2c3c892862da0f65bb4be26de9984c65aa2ff90526e6deaa1a3c079e7ac", + "0x18fde3435086b1d71fd5d24888c99bfcc2d4e7146ef4715192f4213ee9af70fa", + "0xbdf9a94e2cc27a784153c66df5d7f25316300d43f5a802cb7c5d6979a502c23b", + "0xb111d486bad8fddd2cd7d22e49d3ea3f4a0177af6fbebcdcff7f7f6585dc97ac", + "0x56921a22df9c98a49aa2602e551ac3e3d07f857faa228b56dd55ff3962f2646d", + "0xf8c7cc4743849e6cae415696d543445b22150afd4f4badbe9365f169a8aae3fb", + "0x8b9945119a385c746b1eae86d57e2a53453ab4183d49aea9412003a5e815ae8b", + "0x0dd84a3fbdb5a44b934a223503e9dcc73f893d35c77c3110c005398c640d011c", + "0x0960711a40b3c268874fa251c6c642c9e43ab14adf98daff1bc44949ca4a472d", + "0x4097f47259eea82fa8a531ec8c32b20b0064a0c47ecbeb1c426514498e5cb703", + "0xb17fab14bf8cc4aa51a1209711533b566b907d83f17b5ba62187681951307e74", + "0xcf522b0a5f9c427dcd8a7c6e358b7bea8d683bcb1fcee19fb3ecc05b85afe281", + "0x61eba4f90383706a2220ed3ba48020c14b3b6f1b76bedfdd3dd84cf66e7b93dc", + "0x112dffaef31440102f9660a5d73880a7df7b4cbf3c5189b9cc86c7641ac87f21", + "0x908edf9e1920e01592cc0478bc15011699771fba5a3624296521b1997e409d06", + "0x44636c1768f04f94d933c5d93679572d01e9d69f88251e67e8ccca7a50d63bb3", + "0x146add71dd815d75bd46324c8820e2c3d485567ad276f0ce1e2b63c294c989cc", + "0xc3cd14435b5cbd2657f38726908aefd18b21d9fcc82e80b7e1ab0be96a13a2a2", + "0x7d9cee568a4ecbf2d1f980d8946595bc599bf56ad6b07ffb2a83e3b479b1dd07", + "0xfafb0df45cb663db42cdbfb09f7381a49fabaf9266f1ff788dd31ce22c30bd55", + "0xd16d87925d29d26760244c938cefeb1366bf9551545342fdb7583325e08850f6", + "0xc6186d21f0f3391a8456d1b1753da24806d02cb9c3391a40c9fe84143d5ce31d", + "0x14b9cc8f7d3e37d7af07f80c72ae6528b326b146c6380ad0bbdd8fda89d225a4", + "0x5580ba4d7233e13cce87ba2e2607db7a4e87e571d5b1b1a75887f261e03d393a", + "0x07b144469f1d123ef7249ef2c445760a995c2c70f6e48e6e166d5f3508f4333b", + "0x0d883f633ceb91e413494b00e9dd563cdf121d2a2dd397baf4d29f7664633475", + "0xc619796115f48419208b0122a9b18a0bbefc05f8d96c39248973d66583ffd8dc", + "0x994e6fe6c27ba71693d04b2e02ba9c0d8679d1b10fbe733240ee5c323ac5f936", + "0x88b987ef2d0f823fcd17ed43ab28bdcdc23d23127e462ddafe56163e4be4a980", + "0x67e115f2ec5c6f6f7983b4bc2c2ecd21f639a8da639da2a594b018be2a3bfe64", + "0x8e4b8ff44b5028560b047780ce05353c94fba885e186b1b198cac5e90a6cb990", + "0x0a0fcd91048ef7e0833552ca444ed59d74fe7151190d57e5b7fddeb02f119300", + "0x9a5203fa1af89bb99c8d2228d396731ede004ae03afab9566195b89ddfa51a8e", + "0xd540a1122c44c8e728a78048884f79fbe5367873fcc73cc46a9d4b5b4848e3c9", + "0xbf8a42d56b46f6036c6382bd1e970b1d6b5f72ba54d1d5b8d0a3edaa165b7165", + "0xe0262a446e33431abd61bf3e199fca97a575c7ccb97710c2a1847188157909f6", + "0xe7f717feae9bdcd172fa4b6b701f0ca5b58671f9608b5b5a01d51a048241418d", + "0xc0ee34d09069301fa5ac3378ff176efb2b526665925eaf67965699c8fa002c8b", + "0x241837a9dea17bf12b78b30255177b3f14f1871a7b9eaf5c964d30eeb2038212", + "0x2e5204320b7ff83e16ba9727b5df0eab080dd2ea374db22a664f0045540ad936", + "0xaf4e24e4430a008265a6f113c097729ba1802e23d119ae0efef2f2a8bfe4ca0a", + "0x462b2de54860e6d8efcbfde08b381d74eb8e61cd2b311cf14300853aa2f9e88f", + "0xfba00f6c3e6262fa9f282d179b976894376e7e644c1d745302cfdd21cbc3e311", + "0xfbd6361624060852c33c3199ecf0fcbd8e56549d64786d320850ef3911dc9fdf", + "0x7be237a921be1921f90265288026ab1ff7d951e1412bc93470e09bd40a17ce97", + "0x64f51dd23a43c312e57bb2c0da1fde00b48b36eb1c9142589bb66407acde869a", + "0x721c44f4450bc4d92330caf7faf277faa1f10ee8f4614f9f903b27e8b82d8e9e", + "0x71a65acf3a07914cfa45698674a9fb1a35618e6f849aac0be337e44afa7b814c", + "0x620969bddd7756c5d3990528b1ac4dbc81becbac02843b3c4c75ee991ebbf4f5", + "0xef0f2a4fca1191d5615ac096dbae87ecd3aa1a83c46c43a3cd48395a47b2b65e", + "0x5f9bdefe969c0554757a1bf17d990451a58cd2ac60cdb521679081699ba4c2df", + "0x8ffa4537562335a6e21036f6c3af75614887e1c0e54bdd719f53c4675e4e8948", + "0x700d67449ab43081029dd61cec4b31cad71335d822df7ae4053e5040e47090ed", + "0x22a9ede76ca8f831125f7e6d1600aa373934f0cefa888e84a0481247b2c98d2c", + "0xb5b7c6c9ca26d8981191b27dee2aad72dfcd7e6d135d09c3b0b5bbc6e9d64849", + "0xa24232b8ea1e1ef8a07cce001d37d148a07ecbf0792690470c106804476e61fc", + "0x254935114b97e601fc5653001b01faa3f0fac11653926e749cb114cdb8239874", + "0xdec3d44fc5130107d8270358b91d7e0d933e74c4bec6d97cdc9b6f77a1fbe1db", + "0xe947a36694956d7d65315377c81225aee6128c7f075c2a37db61b7b917599008", + "0x4451d920ca782f22a3dba977235c49a4e3b97d8de1fdf9cc9d819dbe7237ddc7", + "0x234caa79670cfa3aa39b37887e2cce3f88ab5472bf2c2e7063b9c9b9424b20d2", + "0x79d8c448a7c637fd4f4e545968bfb5fa59a62948bc7b9031eb4c17493efb41d2", + "0x0b8cc0552966a5ffa6567c51ca7e36f5ad1bbfb5dbf5a52759314721d4e5f463", + "0x774983d323706ba773f8058519a450ae096be9001790cb5e51d00ce1ff206b46", + "0x0dab876db72ff5b208e61e18360e37b2fa6425a3eadc178fdcf654ca273374b0", + "0x20339939f9a89a1c38d6a2dc5ac9a505f2f899a158966cb18775831b045baee4", + "0xa42e2405b8a4a4da00dbe1d2e2a7244e2270f9ce16f054128b93b076af58cb08", + "0x149f8b8bcc176aed12a041b55d040b306ea7d34cc84d5eae4dee06d7a1f204a9", + "0x9b8a117cd1948845b4b98086d80c3ba055a138e471fd3ce38173e3b06b55499f", + "0x22db704c6cd8a8efb8ba974ec4d0ddcf64b1396aabd57cfc271e47ddc5c66363", + "0x25366f36babf4dcd6a41a218cfc8007521c9934f3b70a6835eb5490ce5c32937", + "0x5d21555e54954b075214c3eea858256b109667ebba80b117eaf08a11d4c9a9e7", + "0xcd876855021bdd0ccfc05ae507c711b9ef1ddd7aeebb7e2d330d1205528fc2f3", + "0x09355ca9b36a3aeac9c496af56af3719df2e1e052a878731061720e1b77ff35d", + "0x488d20b385f25d7c6519042136ed3c959a7b341d0118220407034b9527bfa040", + "0x0c516cb443e22322e176465b7c2e0359823374cd4aba574d4104a70e002c1f37", + "0x586593c505b94eba3ea1f7dd3eaa1ffab88548e150997d05b336dea37cd9a971", + "0xa1ebea5af17b8c85755ca5693fafdb4fce32c5e1f6b87127b3306138612d3ca3", + "0x7cb91701609765f3df12a2c051219622cb4a662507c6a14384553364de076dd3", + "0x3d5540773e424e0a92c40204f7c531efcba2467d27d204e0f3c6e655b44e5c87", + "0xc59531ab703c789a20fdbbdd08179893bf671c0d2041631c75d4221bb865b3c4", + "0x7df727560b0f89ef9af22de693230ea551e315918b0cf268cdc07f10690ef2e1", + "0x6d95bde1d89676d0efde7c58d71f91cecf8777e701f7f02a59b9679058e67ac8", + "0x225dae1c7d795471bb2498f380f2a144bdf457734cd3090925027375303e840e", + "0xf14008b13b4db1498bb9a902f1468367e0040cf4d21922ba288adb2a4fee0a93", + "0x36f293cff22d6d738d3cee9e22772f9e3a344a5eee2caefbba321054226c4762", + "0xca2c1e34994d1c454d4abd4b2bf939534a2ceadd6c6a3103d40de4725f77e403", + "0x4c1c6a5ec4bae84cdb0f3252b9f721da9ad348ad1ca6986ffa5e5735603cb005", + "0x0d35e0d8950362606c804221ef0b5feb04b0ad62d5d90134bf1fe119bc5a9eb9", + "0xa8bdf0d3fc34cb80cd14429fbadd0a2d73273e454d96aae4448f60c42f0150ab", + "0x11cc9d0d3064d5c7468a8c0a4146df476f254b7bd8f748fb42d899ce9964ffff", + "0x6d8752e6f51856b90d4723a34d94db4aec1f8da55f2b0d94f263ef0393dc57d9", + "0x038a4fb7f9cea5e3779a026873da89b85d03ba8c9038124eeadf88fa85696f1d", + "0x9d55a956aa38c72d7fb45f856c440b012ce8969c2990c7e1fd48357daf8ecfa2", + "0x163ded59e9ba07e781e07a5329c2921babb49be1a36bc7a54e22b3bc325840f5", + "0x0afd0e16f53b05aab3a77749fd114b353fc848d5e17dd8d701c37baf5c976298", + "0x5ca8f5796743e66d24f7dd342da174ee646c60dd8bf1e7564a814ff28b0922f7", + "0x5e856feff23db5b9892430e9e493b10e2fa2db28bf6833523f158ec1946eba82", + "0x59dec8e839a2d9ba33a5a687fcb92d8b450585864660c202d7e79bbccfe49f57", + "0x8b0a8363e98ac24707164bc767c0f6df7ba6b4ed5584f14693a06b08c3a23c4b", + "0x9214f12639d8f39488579e8265d33850dffe16aee099318da700475551da4ba4", + "0xc98baaa91e6f46d6c218fdc79aeab7d46063fc22107e457eca0559d500489d8d", + "0xeed3ee9c8c71a9035585dbc7a69f91966ff45ca33d81ff0ac69dd9ecbc05df05", + "0xa4b2f4ff38e28613f5ddbccf9f8b4cd17cf50704e398ac3b9b7be043d631ac36", + "0x7de22d2449411bc1e342ad3ee83af0aab2461dfdd7dd51b915a17fbf4350a660", + "0xb644191de416e8385167f5ce348cc3fd3020b69aa7f8e4ce4b58d796b401e3aa", + "0xfa137d84153b3ddcbbea95c810592ca1d219a825a3a9144a1f60a2f15890d959", + "0xb297211d2aa65b91fdedbdc6445e56c012e7d4e99250727f0f18471a204097d9", + "0x87c07e37c34bf4fbaaa2cabcd7c72842828fe0bd4e0af3dbda59a8b7dd8f5832", + "0x60a8ed3981341120c3e6c821f09332c6b83770357dbb1bbcb535fa771ab9ce56", + "0xe79330fb9dab7ff5ebd8511290b629e0feb97ed3907199f47b422e2b62192cbe", + "0x699c36af1b18f84f1443cb7dda84e24eeba099c59b2a3d45a9757b528a459ecf", + "0x0cf4295cec116acd9b74e3ab126b020e82dc216259a40003f493f15d1c89a9d0", + "0xf89bc33459d999b54f77f66ec80613d2b4a7d7e5ca5d58d5d2d9f9f65d9947d7", + "0x2d3a04ea977f6aecbfb671f1ece353c899c6597660a945c78be66a9c3868ede2", + "0x064e090bcd4bfe32f0b9a2756a01f2764d82b7fbc71ecd6eeab2f018ca1a0237", + "0xa3d1be5a6aea2bd18f5ce206e0f8c2ca898e4d4581d2d9ef3bc1b62b86b4d6b8", + "0x3be703b1204cb9800e53bf8b1521eae921f7f6567080f9fe385e712390d92161", + "0xee5c0b22d83a67a2a9ac8661c79d8212252dcf7d4062420cb57878ab8b9dbc66", + "0xbb9813100f3153ff7472f61f97fbaf603f228eb6cd715031018b913c70070d52", + "0xe416f16bb22dba18d653ef75e374b73722723a9f426696ee7477598e1aad6458", + "0xe2d51294dba9887f33cb3009ce096a4e9d086b3bdb114fff71f3438bbd784a0a", + "0xfb6aabfa3219f4401ac3ee4bf697052aec4cba80f755208b42fffbb1b0b3b1e4", + "0xf4d28c88355ed07f3c2007b9e8b7f4e6b1ccd988ba2b32fec0733d57a178d123", + "0x824ff2ab95f74ef02726a483f38342338c16d895a1da8cee5177ee1e4719e465", + "0x8aeec0b4a40bee3ae28552df14d4b6855ffacfc3d01ccde285e66228abc0771a", + "0x5573c773bb5bb5c5236109ef3eda585d2da1c5c38eac46b908fe283c4d519145", + "0xb82014148f595f5e440b729035cbdc2490db0523b7d00f9f0fbd4c383090fd4c", + "0x3bd847f5f5514f396e663821c8865296e3d3f7e817da4e93ba1c9b98b1758812", + "0xe5bd2846840a2049c0f78fddcb4892639156ece271097b56a74fd338f3862066", + "0x916ea84d9ed21144b3f9d73b03d02fbec444449c3a1f982c30bb20c0f75e64f5", + "0x2c7c705d9ec24d6cfbfb7f2bbbc46aee8e3c81a41becf39a23ac19df32dc19a5", + "0xfb9693cb2fab44966e6a0ec4c118a68354de660ae0bbbbe4da349df91e231fdb", + "0x64503206586c60381d9cb74e5f548e417ae80767d48e15c61d2f08f50548b7dd", + "0xc7bcdb552852328cc3d511538e3a0c94dfe1b77d489f3a44cbfab30b3b781036", + "0x4d68f37bbe1a45eaa3e72e3543d23063a4eaa1d38ae56909fe11b309230c8632", + "0xc21a5df0d75ec8d06498535c40ee76a330eb90add0cb99b9f0f4671f504ab1a0", + "0x5558d71b23fd39caf7021402520090f13b50cba5edd669ecf7eac05196e03531", + "0x2164e1ba3b7d927af0ba644481273ccebc5646e2c49825d456a1e75fc7c80db8", + "0xf10702b40b03ef7ae672004cd1747705636f7432a7493021aa8c900397b0123c", + "0xdef29e2febf8fd4a3313106832f3f723469f352f614f20e7d0e6c2e298240060", + "0xe62566d6d85c3ca3d33b8daf61b518abe76b28ec26b91a0b747ec3affab41285", + "0x1c286207dfee4b99fc86818c7614804782c8921d8d8f8815cd2f190f42b992a8", + "0x3670362acbc89076aa41149033484fa2cdaae47c8c10461f6e886040cbabd1df", + "0x8a74d7452f3a76bd20e2d1686243b90243d3d0b40b5b98fd313ff33c8d932e70", + "0x13f1f59beccce0f8d8066742249156a5dc0f21918588b6b145ab40d3eb4bb822", + "0xacdff4a0adff4cfd4756dac55df04e23cc1b9a6447d11d9bd86361fcfb6534cf", + "0x54fa4bbcab952b44cd3cb6042d6ef87fd9131f1850b8de0a44f221ca20a490cc", + "0xa06748708ef2e6c391d0d11c6c8043d91f9f1abe8292d55d70d616ebc5a94ed6", + "0x64dd68699969109d334ab59d64d8d22e114382bf2ebec5fc7ec66875a795276e", + "0x6e66b02d463c76d3a217202c527f798a4c472b37b234bbe0d3d8e6c16a34719d", + "0x3773853e93233b5c39d7bd53b89b769aff1504d9ef433c46b3caca15637ffe93", + "0x817633f3cc0665d68f497362bba1d32d3512016b2490047a245175654cc3d851", + "0x41e14c9198fd548c4b70963eeb24679cd7138dc061988cdd452f2de7cb85c14b", + "0x9ef5c3f4acda962833a68cf1298198b68ad38cd3ef9f8dde0add0dce93e4925f", + "0x7336e43b284042dabf2326e15f9717399fe3d3aee9586118a6047024ce3fbaac", + "0xfd037d85e4f6d39887ea64406302acaedb64a72c1ebb122519c2fbd236d789ca", + "0xa28129819bdab4818cd82aa1bfb0d31d642f66b6f072a079bfc414cfa6d7385f", + "0x02b7d36f55c39b97e2a882d47bb150dc74bab3e3d3c44a13d0149bd87f653f82", + "0xdc6609b3e7e5acd44d8bdd69913d864061c4c5b5d34a24a25c04affed384e687", + "0x0c5adc52eb0e98c0945a821a270e00c1b8424fc88eab4e4e53d8b047c2990509", + "0xb47060a6278b3da926c799a4c01e9682b2c38b9a255427499c03ee9305156939", + "0x8cdfbe9548608021b7fbf4a9845bdc03d2187885a25972f434af7706d8e9743a", + "0xf29db31d7986d96f18766658ae38aaf4210b22bfb14ddd1ee7c8e6a534292fcf", + "0x2be2578382bf5a26aced019adf5e1be8eaada7226996ad0968b41e0211950064", + "0x0fdcf225eb3c840d6a9dab17976b86c02a3a2ad6c457d8ae90a90120cb71239a", + "0x04412b8786da3f17b29aefcd1de44359ca334d551e4b84ab93ef562c16c34bfe", + "0x0be08908e549fb47570db3f9850a43dc3bea22fb569e7e56763029c2612f28dc", + "0x43312d35db155b984f27756d5f74c5028a9d182c346287b6d22318d6d09fa287", + "0xd99d026f8d05e8301728fe546ac68d0b7161d4c5f39d321d81c2d84af8dd9479", + "0x2aa222445dc7ce013979a51aeccbb0331d0b9618bd44d6eeb41978402d787a4e", + "0x7106550433791e214c8d1bc44a6bb74c13cb04ef44d888e4e86618a7699a6c0d", + "0x4cafa83063379aa62aec4ab93ea53b6ee3340b567bd8bea89b1f576ab2b32def", + "0xaa19fc5e04747c49682a08a04e26588ff2097586546c7e6307ebae3faff31ccc", + "0xc95bd63ec24007b5bfb3f3b62b358e32b7c4b562a3904d858b30131ae5146df5", + "0x33aca1207ba456f03f62dc351c975ee927b48d2c9ba394a56e955ab1b2cda20d", + "0xa3d6317111e98d624e5a68256f142ad3c99c3d2fe997650fd65d584579f9d6dc", + "0xfa3d58b3b49da8411398ed8b288f70757be569475c02f9ba23a4d913679b8ae1", + "0xeb470c4d3513dc24664d00944e9fc6da9fbdaacad66900accf0467ecff11d6e4", + "0x9a339d9d68706dbb4300222a5ac8b5823ac55af237273e0aad0999aeab8c72b4", + "0x0b67fe0a96dd8688b8fa98ce128e025402173dc49e0de904c390ddb828f059ee", + "0x634ac8f82795f1cd08f8cafdf00f869100f84350157e12d5a87de7d013a856cd", + "0x1530833bee82f5fa0aa8dab062da230024ed503e352de3956831a92cdbe36199", + "0x69b26efea6cca6ac3ae1bba540db8fb9288e421163bcc50172669053e7751584", + "0x8a4fa2c094135582d17b7733f74e7fe4dbdd0ccd0e5671696739639b64752c5a", + "0xfbff6abda57f9b1689cb7ea8809555db3efd4b21b0b2b1351199654d044fcca4", + "0x16425718846535b46733b84761e16648fa7eabae0e5995108a2fc6c3f324ddf4", + "0xc72eb88c5161469517e7980f86ed414b4e5e54dcfa734e2255908100795078ee", + "0x91e0e6cf1fabea993097496cf7ccfb023e798363bdf8a85bb5e73866f1442ab4", + "0x2530aacd1b1238514aba9ac1d13de20aad119ac4994984bfa04518a31051b973", + "0x481970f2e7e34a0064d136e87cd59fbf6131341027ab27458b9803aeb7e79983", + "0x99beb276484210f5b55e2b3662304a73c86a46633f3ff5aedb133217b7b593b7", + "0x0541564d394f368aa15e88097bb26d951d099e103b5866a3186455f422af1b8f", + "0xdab00c8928bddd0b3773af6dda612de649c18e4029c54eaf8467f82b153af878", + "0x343a7e702237917aa5d06778a592d1f279eac470beb8f340ab338c41a31826e6", + "0xce9fb58528596c0da68cfcd52d4556c41d7d6e8b858d665bfd110bb95a76b3cf", + "0xd40e49ffc0eec56394bb73f469b0aa1e1667eb4f912f5c3e82cf395545af07b5", + "0xcccf0af25ebe7d4e84acedcc9a88e885a4b99ab77b9881c524bf0e7aab724192", + "0x0ff189bfed3b2f56a3448bc08ac2dc6eb1d64125c95971ea0ce0fd5b7ea74416", + "0x60d25468039d7e8a89117eb468b4f561ea072554520d7010047680c1ddf5e70c", + "0xcd7a3c31ab25c421547b379a508fa0cf6d86cb9ce96377a5174ddcc315fee2ee", + "0xf681f339b4698b7f5016e9c7cb9a516d230a3f769b0da08096372bc87664ce5b", + "0x93dfe64853f84944856a2b79789ac7c73d18826e9a4fa6d970dbef77d000f7c3", + "0xc599ae73c9dee91ddef71fe0303080403753e3610ab73f242f3f8fe49b598b4c", + "0xf87d38124c8014802c3f523d56eb08ddffe645ed5d84ec1f11d025a88c594cdb", + "0x556e5962355580a0c44e5d80b28abcbf5a55feb5c81bd7b7a74c4aa664a7bf6b", + "0xdbb37e17df80f67cb8958590469d6d8a602b11b4dd28c8bdf8cbe873a386e644", + "0xb4932582d58d113231ead5a2d31eb8ccc0aca98a8dbdd9a450bf66fb4d65e18c", + "0x91ef1100276650f3dcdf96395859c123ee6fcb4686eecbb97bbbd6ed6ec6a656", + "0xfd5d42dfcb6c00aed36fb6f5a38aea10198758e59fdc4ca80b6baef694793fd6", + "0xb9d56c16bc71828af33e2a58b504ad96c96ea445c4fa56ba3703d6c8a971d9b0", + "0xa6ea2c5703efc858f9ec4a96062d32cfa23feb7d7bce6c25a12535c23b395809", + "0x72c1fc542e61af3181e988774989c782875d3b978df6e837b3a601839225dbdd", + "0xf332d4922e029f84d9aa2f49f910191df88f7f1d96d59ffe03d8956b0a5d54ff", + "0xe45ca95879c07250f3a317bb34d7f5bd0188fc947bbeb04262afd9c78039e197", + "0xc8c33079ba577066cb8e5af8c0682ff5575aa64cb30e400e5ed73fc749933d9f", + "0xc3e6fa3de28bee05a531d588d4895e63452eca2a188385727d466b87462c54c0", + "0x6740e11063142bf755d0bef9c254673af1f72807c3be4c531212efff63636f6e", + "0xce52344424c05c60bc7130b05febd30f611a081fd287757442687ef4adda6948", + "0x99491636ce876cd89f40d38ead2ba1579a050c16400052d516dad0a89b092069", + "0xbf6cd1f7f026023683c23d9f0d891e765823885b211420b9a6b33947138776c9", + "0x7b478202b808e4a54037acc93daa1136c6fb27d89b9f897b9fd3fe9afba73ee8", + "0x2cb32599960b97177a94c84ad7a047967eb2e212415afb7f1626a75a75cf1b46", + "0x62ef86c77b59fc2261a10ff39d74aceb1b7f7051758e5372081bbd911f56ccb6", + "0xcdd56a98c6b30e17a3239158ff7d91a415a28e7bb7e9528cc9996c8db8745667", + "0x8e432c62c747d730b197d6462d9369e5e9c3fadb7f36702c4c76803c5dccaee3", + "0x9eca51d69547f45fac4b49f0c6f126e9b5c67259880d28112dab89ab8264ed9f", + "0xdfcf59e4a92c389ed131b40b048abcd0725aab626f4fdd3575a37b4a3a206549", + "0x5152046f56a54c8f926ed10300d516f30a4a624aa7fbb888e465ba7359c4f3cf", + "0x54135b5e02b568eeeae74e59f1796650424233966758fcd1d007a727145509bd", + "0x9253844423f0fb792a2248fb887ffd10be43114b810b2635486ca0f6d43bdbf5", + "0xf3394a79eb65ff0184fad992adf3d0a86b5e6df85b629abed224a85460261db3", + "0xa4a1b651f300133e86986fd3a881e6577c6fcac410bc58c63f4b031e2ee2bdbd", + "0x5e074eec6c53dc49c55b50c584b0855e8c5a3c64dc72e73e5cdc1b086d07596f", + "0xf110a1c5c23d3bb9ac48d2bb03972e11e04b52da5eb62db65a4f4a2ac8d2c068", + "0xad11be682bcc25d30ac1eb6ad15990499d488c402ac6ef78085ef8faa5d4a248", + "0x0e13e09b2e3b8de9e5fc9e93382f06b64f03f98c3e26a5b3af811d32136ed0d5", + "0x494944f0a5afa4efbd967941129275dd6046535ad489443db1a384798cd7a02b", + "0x38474b45706c7cc93dd2ce11c41ac7f12f494c38f3a00c9cd38e44bc8771e04d", + "0x9a986ee21db81a38be8d1ed319f2d2558eb22de3899942fdb6395a188320de30", + "0x13ba368a9882ee28efcdfe67f4bfbb263fc8bc1c07b6f1369d3bd5ffdcbb3a01", + "0x451ff9f8e52bedb6a0f47ca9093b83b7d9a61e94329403d8eb913868945e0b6e", + "0xa04bf418215767d2aa8e6a8c6bf6563c80fd6f439d8d8759d2a43d8f4fa69630", + "0x551df5f968cdd4d0b78c1927b20383ddb6183a62f80480983d23f734be98c265", + "0x0df43d41084f9aaead6b9d77cc8f7760772ea1d27bc574bcde7061985e2891eb", + "0xcd8fb777f3d81581c5ad765b4f6d7f9c8d45c92466c65fdfb02637f226aca9f8", + "0xe4a92928a67ce00b8569eebd95c446ab82ba5beefdf467ffb0ac1bb08f4f471e", + "0x3ae0b6e5ed51401ac85ed96a84326cc1e894fb89a24269c9f3cd25ca157cc698", + "0x8363e4315a1a914a3d98eaadc9d985324073cc04e55b5859264c997d6d22834a", + "0x1e77238479593a1ab25b61990f3876869d2d87c9817e061dd82eb43e6404e0e9", + "0xbf35e78bd78e97326d6cc6c87f9f9c89362234327d06a65344cc9e692cd0d739", + "0xdbfa8ae2f7df4c5c0391e50c5cf9e144b45763a13ee250033d133c08b33f8029", + "0x828df5dd874a8e47e198ef4751dfec528c34348378574baeb2cb3b85f2376dfa", + "0x60deecf89aa73bf16f800255387ce9b9b74e02820b335cd96eef4b41939461c8", + "0x4e6a6312ff2847e8e419be96cbaf266ffa7aa91139d9d59da4b29c7e28aa813f", + "0x6c0d32f28bd65f020ac3c803fbed871422d6c6f02cab380056721825cb05cc22", + "0x7639acfede0e940dcea1965352cacf2b08f8ba0cd4254608a1033e2c80b1f12b", + "0x235155d27105a7f73b46d0c4a91c5a4978eda6d69db1af58d13b89076ebb98d8", + "0xcd1cb877b7b138f598658a39d1e135ae211a2169b2afefcd80923f244630233c", + "0xe9744fc928cf00f5ce170b81d28f5bc8f324d37fa535f2cbc2a23d82406d0423", + "0xe376bdbf2b052cc9d5f00f36b0af4d360174ae54b52620439c25d3430f405cb5", + "0x5a00ca653123aa856545902da24e3066386d1df00be733f95a4d105bb722b085", + "0x8e7995454fa8c9e7da6f19d9860cd0ddcaf1232033d43325b211c39023ca4d7b", + "0x8047e3cf7584e57729cc92c406f2c9caf41d9f5b3fc3a1f14e9357c954972474", + "0x7de15b023b1f923008d08ef6312fe8c3db5f499a26fcb3594795f47a30d28c85", + "0x7924df166e716bd934f98797b4a7f344693bacef336bad132ce068c6b70e5ab8", + "0x9ba0b15b18f2735800255de7b9e52fa971f2ec7bdc7de455c2e989abd27d35c3", + "0x9a5707a0ee4ff0d88fd8f9b5382ffddc558dc6c21ed9c8daad043a4ff4a561e1", + "0x898ea840f2e1e07c23fb9e18045e8addf5291661a72d6517b029620b52b0eea2", + "0x8f5ff6dfcc7c8ea2022c7b5d8ebcdbf713d303f164230a74192ca06fcd2ef20b", + "0x1508febeb95c2d3ffc8f1d13787bb9883be3529f8d71accdd55e747211fa8c08", + "0x2c7e4797847fe62a55f64c64977462cb792d9ec899e16f1a46851aa670d09eb3", + "0x825588a04dc941ba395deb99c00c282373e042a064cfc1ff557f54d8e0479187", + "0xef56430f5950a91b9a2028a549d4aedefd7322e36793d3cfaad18f97b58e9e3a", + "0xb92537e03ab350a4fd855bbe5175e8ff0e0df0fa8588885fdfd33bd2e37650b8", + "0x57b54ecd05c5582b98b62caadaef9e3386962a15c302caadde0f3ab2de98ab8b", + "0xa3f9ebe4db242dbfe248bdf7f504fe1f92079c60babdfad99a1a1adf446b3750", + "0x0939ffdb6c07b240cc1448f7276d7c8b436051e9488942d4b1a5afe5a0103aa6", + "0x778210367f625571f9d075ba06aa1ef5a8b59a411ec25b4e9540e7dede11e013", + "0x12087182676e11950138448ec4258ba3bd6ae31662f13db6cbc46c52a266dec9", + "0x7dd65f0f816152a53d8221e5554f4d3dd293219b0537a600caa6c5b758deb4cf", + "0x060370c4afa823b9cac3b2a87af1a989f8478169da3e12ad4073731a6729112c", + "0xe57c5b36d7372b192549e2ed987cc16beb412db8e22c3acdaf1f1c95ce1af81b", + "0xa9946d302b6f3dc7ccae4e4a69c21c862da4dcb9df371a8b6486534d8d3c6e76", + "0x350669a215b44b8cabfb6019d89f5268b299d6fd9db56fbea93cdd9f4991a977", + "0x4bbfa211e42c2b92c1cc979f6303e2eb428292500c6b59f0ddeb87c3fdb4b314", + "0xd243e1fe99ff82487def980022b204794fe4eb5b8fd657b851f7f5f323eb81f6", + "0x0eba7b7031613d9c2cce87ae3a9ff6e7b57b8e537913657c5c97f80a65f774c8", + "0xa5ad33c7f0755f82a0d6f47ed774bd8f2a00a66f2a967a52372dcee62f52c099", + "0x36d42846ce8b3021f00a615c0423d1bb1f00ed05df1748249a79c8a515a5cff7", + "0x7808d7655fb173387cc5601c469a26402b631c1d3e490b1c1d25e2e2e4dc3807", + "0x533b133383362a66e34e9e261442d4b867ea762b4422d2ebae579c144621ce20", + "0x46e2dffa796139a441b4b2a2ecc9530924ba032bee783cfae1ea1623508d55a7", + "0x0acaaa36ef65ec28c8a5447a2d594e48e4382737fac248b7895d3521cf2730b7", + "0xf191dcf174b7a1b026a9e2ad51a49a684abbd84556988b8cef315c3c5804f032", + "0x940284119cf5d5667d45103ef0cc790cb6540926c0f645911c669ccb78f6f127", + "0xc8be6193a1a094924999b527d81561f1ab47966c6fee7699418aeff2e16dd27f", + "0x3aa137a876b08b74d0e507ec47e72ae5d2049e01a83c68b90860ed7e9b594f4c", + "0xe375dba7c6b94fef6314cf569f887010165f40f930156e15c2897ac50db96e4a", + "0x82c766f09a89d2d8644603c21005c342208e2a61922eb13b476dcfa9de9ebc4f", + "0x06bb8f251decb2ec72365235d98bb9c0e0d0a18f7ef7b069f70eb432455ebb7c", + "0xdc4d5d8aa9f4a4e224510a32df3ac984428b8bbf38a9638fad1c74a22cb32c0f", + "0xfa394e11c7ea81618a3735ff52c67d182a013caa52897b10e1057de7a95b6f92", + "0xbe3dfee256c7cea8b110e9915e167d56479f5593cc5a8bd7e6375539c9ca8984", + "0x3caf7941bd973212ba085982ea0707889aea831d3df45468060a1f8afff8da93", + "0x17ac6c1fa00755480ab3fdd4d5969e8477d55ecac99ad1b1dc123e677560062b", + "0xdaa4e5841582d605767a49d59dcdde3067a61681f40e55e19adf73fcabdc65a6", + "0x465b0a0f2c6dc1583d1517a303947d372af513284cf2fbbda30831032c45674b", + "0x450b14d7773bb9ce708f8dc12aa7b8a9a83161eb8086d6fbe91fdf940f24cea3", + "0x0893e90abc7481e9413d33560ee9087d5e39305c0ee7fd8168d09da19c9a9e26", + "0x3b3e3615b3cb2402f807b1f7568174a6972421f3c6fada50c489428ac6d3a3e0", + "0x8ca9eb6c550474b93362bc8eaf6cfd7f39808dc115242310ff4ff6e5acfc121a", + "0xc55d95d03f1359410a23debadc8691ea0b53f4cc50073b449546c4422b16c037", + "0x26adc021bed5d143a3933824ecea25e0b6c577d8cdb9b899a86fbf706338dbd5", + "0x81b350f0026673f871a8981d899a31e2892730fb58e4b0273351b256e74151df", + "0x8a97e6e927342a4b9ebfeda5f5eede61ddd23b8b4421a0d2a8baedfaca168cfc", + "0x96ac659b574a4e63a8874a91fbf045f90f460b6c5b1222d72d8ddc240c870907", + "0x77c0baada7e37994e9f91075fc8ec335ce0a5d4f1627ceeb0a79034bed0b0f41", + "0x3b626e112b641b7ac01efabb2faa0b0a9166be0f156becd1254f0365d6f08a12", + "0xa15072f15329fb0c090eb5f1f91299421abd81efb05a00efd1361fa10228d584", + "0xb44bd4b0648b95e0d427cc5173d605fe21b00a5ee2c26d44d7c9a4f49e0fb521", + "0x0794d131e1ad17eb35301fab7566269e99b48b2e4cddc5b75f0aa15996220f03", + "0x994a7c6159433a62ebae86bb4212983478372b94fb3712bf025fbe3c5169038f", + "0x154a2ac1a23bf367f6873a7b51014d4377dc1008767510440a490365c4c1fedc", + "0x5881a0306e88c24bff0354b5df839f86178d2ba5e54d3cb80889df8e72952c38", + "0x770ae9a90625a5424e470f484f2c97b4f191eed61e15813dd59cafcc5bd0f127", + "0x6eb956fc5c743e7a2e02d694cb9c643e5ef97f960e90b75989aa91d3da1edc5b", + "0x3100b5a08d157428c6c10271486d050f913f436fc99e6fcc9b8eb1be9dfc39fe", + "0x507a78e12cf89269bc156b2fe5d991cffcd6ca6d7d085aadf8fdbb44d7689b16", + "0x0d2d43bfc425c8686487ca97d7ae5888535f5bf4d5e4feff6769ac36e1ee0946", + "0xfe866c43ed650b6fb1d3719df09ccb5126c36add42428bb8048a6841a88b4520", + "0x73ee2d004147c22f7beb21ec84293d6cd5974289a6f4eaba670da364df657a9b", + "0xe20395be53c10d9885bb2c7cfd78927051903ff4ad8301cb6f4e54c471b79308", + "0xc039903cfa0af94172d211f2e5c2c653d7d31905a1c194aea0a4be85c2dae075", + "0x468490362f1a7781b4e08d05bc1417107daf8dbeb092f1ab1a9e2d8e604741cc", + "0x186a3a6e4e1ce30ec18c1d72ecc4fac270a7d1ba9cdca0b7937794913f25c603", + "0x2fad6bab068378729dc7edeaa8ed516b6274396f21d24382d889f1146deedf70", + "0x257f8eb447ab096ce41e774fc4874335e77f750cc0d6bf4bf3e6b9d699de203d", + "0x4ace53b3bf327fd95451be5144dd2d62d906a25234959e33410bfd28e615bf11", + "0x0dbe710b12cd27f1196c9d7f1c5a981194ffae507b36b287cb758c32e264cc17", + "0x2c6def5c3a93b3c718839efe26835b0096efea132f6870ece1c33a7e91a2ba8a", + "0x2781ca465483c0079336532daf646104b9260c29cba0b6f4399feb557760825f", + "0xfcdecd6aa3e2c1b4d9f1991894cfe5d75f198dd445cf61ccce1c32fa8ec19e98", + "0x951185273ba63162c2d920f5acc888a7e4c1c6e755ab1215d8df5089276caf43", + "0x3e092b4e7488ba0172ed20dd9189f06d19a74269231edb0a592979eaf7c0ab88", + "0xd03afe649dcaae2de18474e82cd88935f50091394511a1f334e7590249d2583b", + "0x20c54aac1af04178d8c6ad55dced6e5cd2b83963f53ca65cdcf503708206285f", + "0xd8102d6cb1ab6c9f5f13a38ad0c375587877b22a6836a882f128804d5577b527", + "0x323445a4e659b00a2abd18bbddfa87dbd824877eab5693930c63a4704f0072f8", + "0x21caf56fdbf708f486b7756928bb74f117cad771a850dabc2a69291faf2e8d6c", + "0x4227752d2a7118b37d2089ed9319095d388c9048c0082f337d62d5275abb1145", + "0x78b96472d555ffb616105b2b471e2893ad6e1f8b735c4596be9d74f028932693", + "0xb11adf3fa7f2922095d6811564831e7371f87f4d417c730927949cc6b5227bda", + "0xebc5565e3b1338fd34f4427bb60075f6461dc072b097ea9a95237a411cd8fc8f", + "0xf4becc05db259bcf2790f79cc1fd1c88396db483c2c85c127818374be47da818", + "0x8178c8a0e6eebe2be426cd30266ef6574973d200e84339196bf6401dff1fe746", + "0x3d5a6f60d5351d577ffd38306e3a12606a1a3aea9023f2b8b8bd2452847d6b9b", + "0xa80644fc78939a7e41d390c6156ddc0d2b96f80265e5ef333c49e167dc585ef9", + "0x3e141f89a256b3b45cae79ac0c604dd9a19c09af6f685157872b42031bd62e1b", + "0x01a6910b5403b23b6e0102f4e012e0a0c06dedb944d36ad4c4e2eba8cb3be4ba", + "0xea5bed79158402d5f0c295f363a211b26d9ddf4d4d04e95564cffcfadbcce518", + "0x3a9d2d41ee14a76564ccf9a56d7c6d1ce732475ffa64499706b50e8ecd0e2050", + "0x8be57936b28e208f26fd382bc1404ea474001287a2c4d21e5213bd9327253ce2", + "0x672af36bc6de92544997f7cde2ea8870ae0f09b4cb2c22e8fd2f64bd88911f60", + "0x0d8d34a4ca78aea4627d1439402d4f0c64f130043e45bd6db1a0511dd16328f1", + "0x376539fe4c0de33e48d4c308800fbcd3606b82482ef9addbf5bf9092d6a55f92", + "0x93a25650ba0615e36facc75fa2ec8e86d6135022a31d86722307432871d6b72a", + "0xe95b8505b1ab584e83efd0bfb62a0d3c45785ac2ab74ff5e58178b2e742aa6d7", + "0x6fb4db8b3eb5b55916e2b06536b179ffec93b7300e3be36234e4ebb915a840bc", + "0x5d7545abcd38bffaf08f6745872e0dec47b0867df5102f42d83fce722dfe4406", + "0xb6eb5b0ef418cd1158ce9588e003e944d8afbd704eaab53d2643defa365115c3", + "0xfcf5ae4e3d7e2ba5e29653d5b732a1d86f18e2aa79ea2354958ab5dda5c57f4b", + "0x95aaf721f3c015305eaa78a8879d2f33b9270deee9d03acce855f0f44480dad0", + "0x054b3629ed6ab0be7ad07d3c658acc3ecfba8e9ab68492838b35690556dd722c", + "0xd87e3fd945b27bc037299325752c775a76f1c3b5b7c825fb9b6e2f6dd3680975", + "0x827fb42c7548a9f034a835a54ccc598398d2a8281677638197bd8d2bba4fdd31", + "0x7db908e4263cf7cdb822e42acf0fc9aa94999a1ddc327b6535e0a33c5237d1e5", + "0xa022198a7f3027a864615df968dd6c77d03878e12b9f6adeee611deffc82f33c", + "0x19269380075fff6af87dd26b7824ea70398e3802ea3c6fb2b4c2ee630562dc75", + "0xa13f3c9a337d9aaf86b0a5e5d5bda796d2f1d99c7548278d0b752e304392c3c3", + "0x13067c9ed1f15b7365541cf00ee6d7790aa0cf24ef3c60b10f16d0b5d0d67266", + "0x8d17d62ac8abfbe2b9696f918d92912199177e94ec49628baba2ff3897ce8323", + "0xbf65bee541ac0ed5f7529637a156446214c77018c5c59f0774b410bc9d2812c3", + "0xb3980e23fd6ad0683e19db55b7a8837a14c5c809f52de2950788ddc7f6d2187c", + "0x2e633f27e48af14dbd484a42b002517456028a2323c49916d777ec5d00accd2a", + "0xa44bfae290d8ac9e0ade331b4c362f5008152a38199996bc71d17e41d4a90069", + "0x8cfa7989fe18f803b1fcd926ed6e835286acbcd4dda22ffefb24cd3fdacf2389", + "0xf5b997a3440078a7c1322b70bae558cffc1234bf459cd295d5cd3d9be135242f", + "0x2fb715d33fe3c624ed35cb931c0a5b38475c1b97b743c15d5f0835d4836c1e02", + "0x9d1f7e02c66eeb6a75899233c02467624b46b7720a0a38b9af62a363480bf8dd", + "0x0c0a8f695812e88e92db4304d43c7a12c4958350b4df66813235dd0a69fdc643", + "0xca7e816b73d005cf04f08dcb5fcba1657fb6d339a2435fd74670155d097d6fda", + "0x4160cfa822311731d67d0f23948b99abd2fab077dde4efabc3a9625686a5aa73", + "0xdf9702f40c2564b7d460c35d25642b58179e12e859f935f7b87d41bcdddb517f", + "0xd24e79820676effc95265384449ee4bd8edfc7b747f2285b99518a2658470c5f", + "0xc79e6494fb1d7f01a4e8c36b221956e16097e92da140c3d3ccf336d5d99252e4", + "0xff84f37720a37852a94d31e3552d7605e403ca42c74830cd2856055448bd60f6", + "0xef0c3c8ca70dd9227d2cac50c3c6dbc272124b74eade2f26e6d20e21de527f92", + "0x82a1e299f56312e65bb42a054c044d58914109a9e914792ae888fcd94e30897c", + "0x948894d3791476e20b63650460960af12d2a33a4d9b23b6509ebe216e77e1cc3", + "0xd7dc6732db63ff742830bd429766ae73ee21ff37fd3831f5ca0e39c3cc16e284", + "0x594af612776eaa16e4f10c2416d5912f025df7c1284653ba844bbb3985e53b1d", + "0x348ee29dea90b5e6cd96abe5aac2537734efc4f5564e854dfd8153408f6222d4", + "0x9eab3769bdda9b57cf3b2a8d07a6dc2e07c856a15a79faa7890582b43f26e6ac", + "0xb97f381205bb10d19ffa24dd62f64b8687422c1a2967ca3b1b1bd59e30f5b5b3", + "0xf2bad3504422193b7f8dec65b2edb5bae77a3ec12a6403be0cf98e6372c59886", + "0x36a4a3f86f14ddf99c0822988616018d1d569a55f3e51cceab26d2a5ed6d1f3e", + "0x2976ced02e0fd21ee9992f847e912e4cb480d676347c721a1d8cf088242d2208", + "0xc6fe83273f10de94767eb3d67bd5e7ded408d674248cd87ed64e1e8384f15998", + "0xbdbe5d93b2812f44914fcb97b0fcc61a6cce96b9bc811e3cfdd6c9ac05619faf", + "0x415e343e7ae318153d4a9930f9779aefdfed85eb31a5f63810836beee854a370", + "0x33767db7f68c7432d03ccc405554fcb662044f6e43a5e073a8dd473f012bba66", + "0x32a7cf4985194e23827f89e1589da83b9158e98219b173f7295fd0c25310fc79", + "0xa304a15516c340a220b119243565f8a75bf6edf678029e0344ed6c1a49fa96c2", + "0x88c0c9b589f7c89d38f3f83a18dc38d9a3bcd752c214805c0876ddf2a3b45b86", + "0x216643d8038ec1cb6809b8ac77cf909dd160cf433da853e0572705e00aa210f9", + "0x4e5bfb91e5929da7d07e2e4ec30ca006cfc8399439cbab8c0a612e1f951fe35e", + "0xb20afc9312798f01965cfd83deb2a254f477636a565eb0578d8b6a86abf16fe4", + "0x83ad6dabfd5de39138c7dbac41b9548ec3fd601487ef3215fd520b4d8fd505f0", + "0xe96fe232f32f9f4a45842d502ca714f933412210eda69d28eb11bfefe1f60786", + "0x838711b43402e0c6ffa32b6c96ff20d47d8e00cfa39cab1526e7a6a6ab48a239", + "0x1d29b1af9a80c63e675ce5e957a98f31c57975fd6ff48adc3f62192393881c9c", + "0xece5ad70b3b260c8c7247d1e29c95a6347ade7034c26e9a470c0469bc9a91900", + "0x2cac591b892b14911202dc80a32e50c1c80a82a6f78a8a704bbc3e0c4f726cf1", + "0x1999c48903a3a6ab132189d27889c19c29eb04e65aa7d9a8c35722dabbc66cde", + "0xd03f863788d323b508d695a6ac3fcbaf93b44401efaebd5b7942c635c10a7eb8", + "0x57e92bc43ab1a66e45c054e6b46240838422dcaed9701d65e3fe41035b7479ce", + "0x848a6f66c7f5c3c25ae9f0783891c5f004600f274967870a4e9aeb91c34f11cb", + "0x193448bef47c66cfdf060191e4bc58820a3e1c9424a8c9933a1315bbc874d4c6", + "0xb9821736ea8e93609f701ebd178f00e87d4c7931deb9287a76ee40424eb377fd", + "0x88b01f8ec4bed91861870404d1191cd0144e0615943c609e006aa7570462ca0b", + "0x4014996b1a6ec5e1bc625a304ff1bcbd310b7094065dc6a75cb4070f44fd343f", + "0x1b1db3c8dfd7843c993cc50b4dea25179310ba77d1ce0459bad775bad54c7cf8", + "0x7ac6bef10622a0863b979573f8b9b34b9008980a6752027838ba7a50e68b077b", + "0xcaf393ba83566504254674bb9e8cabec2b1c366f4e7a867b8da663fd0dee1a01", + "0x05769a695b0b171e849df667fd873d1de4d1b0fcf67588986569e631417df8ae", + "0x13c76a5de115bd5bf30c939e21504d27e10d7e0ac5ea1ba4e71cec387b469e1f", + "0xfa24eacdcb99a7d18c49e095649ca414b3477d4188a3129120847dd513083030", + "0x907c3b7af8b74131260997f69c41850437dd00ba24b660371f23a1706835336b", + "0x4e812bb9a20644e2c48296e39688409d3499bb2a250abfaf8b0cf56ad0125aab", + "0x3238205f0b9d4062ae1ad8a5191d65f2f50bb3c0b7e1351fb8b66fab97a314d4", + "0x9130f27aba4aae0e7d48375a67f25fff231998d7b7815f24a2a8e86fff39ed6f", + "0xcf32280598cd5a0579a5f250b8e418567d31f3334fe8245c0a874d508eac745f", + "0x150f4bcda2e49b6d09a975335d33dc480db17ac59a508f28f6f05dd1d3caa22e", + "0x379b96da6a733c88a0888fd3a270c889f5e2c0728272e3ed1d654c7fe582d9f2", + "0x8df473f7e356f0dabe0d6f917728732a3f9e0519cb8e399ade5dd98762d0c1fc", + "0xf8b8368aa697e7748404e589f2f2f4d2808e7cb35086dce48437702afb8b882b", + "0x2b3560074c07e7955151dfc09b1293fd759d286b65dcdcf7b2c9f3dbff404816", + "0xa6361ee7b8af32325cb36304f400c9c685767c96d0b5181e7503ddc8a36eafb2", + "0x51405ec92bb2c7fb57f95c555150afb6351035e7553a63d26fb87e1827a6c3b7", + "0xa0290cadd15d77123903184806de7f04723cbe2eb4bcc2da4c926bfb3195cd54", + "0x4bbfd31db415a8bcba7188529ccf09d7cc10037f2c3dc7671ace6d4dd60a35c1", + "0x918152123a239ae6c50d9895940626e7f77ea624596d1144989a5fb7e10ef48e", + "0xef73abb8745093394fc130c7145e2de31c9457151ed78bcf63171b7633e22dec", + "0x09f80e170b2a1d599185c562344821d0e36bb48f91d8205653eba143deea6cb6", + "0x793055e11ded973ae3b55bb95ef6e985ecef03497e76e4e23ac477f6ad070fc2", + "0x2ae7e9c72203cc2aacbb79cd7cb5cb7fc4b997c9c740578253cea957ffd847e0", + "0x9f8caf269df06cc8c81cde32f1ee4f081d8a2ea8d945663e0339456e583c4703", + "0xb8533ef2fdac7587034839d1ce877bbccee50c473d4546c3fceeb7ecbf661f77", + "0x31a51d443ca2a588596b3c6a0ddd5fddf7abe8138177babd8205d165de21e76a", + "0x0a60c5ce88246c2e999725b2be6c330dd2482145fb0859ac0dad38f11e24e5f9", + "0x87d81ca8b664f33920634c62eab8f0ba3fafdf28ca19279b4d0c60a71eb738cd", + "0x1070087084fc2cc2e47fe731b8f08736cbef46194d16f418c87befc693c8a8b4", + "0x09140a959753b2c1622f0ad55f8f5d34b5f52a5ad6de7b6112e4ea1b8fda9e1a", + "0xf3af8d94fba3f4a6e018ebc0fe5088710876209a39e37b85e6b6bfda70f097ca", + "0x3346983bc9ed1f7f4f112b38526a92e7b416f30e4d1c7a934c7d74974f86dfec", + "0x587472df09a53693596d6bd1f60485df25fdd54fdcfa4c20f3558107f3bd4588", + "0x4c408ab0922f27796fd4fef68bc20c6385647a8ad4397a4a553fb68c5ce1710d", + "0x2eddf19c4a6ea3c2ec855e5b90ef78f3f861bc6317369db137f1a7f89110e69e", + "0x30391283286a30ea6df7b5739c7955a1a659bb0c46f3ffef8a58c0140d7386c2", + "0x8ca8497844280911bd97ce06b69d9e09a86ea135ca0adce596614fb6c584d0e0", + "0x9a699d399b3ea784ecc1e4f2dedd9ebf9a383fe44f40b4cc67dcce4ce98cd61a", + "0x013681943970f17a86dacea448bdbcd0d0ff56b243ef2c147ba77e58f1b47c8a", + "0x8717f032bc745c9a16eeacd20f3d86872e9cef3c4c777a8dfd867ab898e73fee", + "0xe3d4059812ed8f3d4e23583544131dde2a56276dd513d2679be07a36ee08dc48", + "0x265ff09a3d0413bc7bef45d66e34180c432b5f66ca96f8c39d390a83c5821411", + "0xddcdf72b890fafd78daf04a9e2afa824de34b761c25876763d9814fe41a9fba0", + "0x75168bbb488d49dc440360206d5b36d8934b1d9c50d8d8239cbdcbd27f238796", + "0x57aeafa912ef24841935fbe295c7f922b61bd729afce4537ed4985d06fed8eb7", + "0x7be35f0ba773bbabb596b674d73d8f0b9e6746688322dc99536e52d6f0100183", + "0xceb32481ad49ec6c259273d2b302352f121fe3c0d6a38c2576fd0667ef1c1088", + "0x1e1a7e3edefa2943844e452e8d4959f06681449e91622a537e196c7f3c069f5f", + "0xc4c5f628c0e705d6ed6e84b26f74d76a4ae13b9a602f4ca8fec8d94318b1e05c", + "0x324a02a05df574b12be04d2ae137c409a87963d524eac913d2b671d950aecfed", + "0xb1c115671fde450792a1bf3541d8024e84fa4239b3fd894af3ffa25bf4d10da3", + "0x9e9db6ae30894084f36122ca1946b96851c0e2282cc4361fdcaec5381552c26d", + "0x230b1fdb77d049d548a6cbb9b4dc8ddb983c3225591a323820b908cb79ac5ffa", + "0x88bc17b5d10e4b474c9f85c935ae3cd914aa437185f9bc7c03d66cf407e102ff", + "0x6ee030f383a99122c498a9c43bb51ed46932be9cab7efad96fac65f3b39d032d", + "0xd600f1dfab24e5b671a68e56d2d27f288e9b15ecd870b0fb3d811c1cb6fe17ae", + "0xe892c488faa1e15b040acfee5411b0c6cc93d1d9082a605436a0757a0cec7a85", + "0x8607ed1eca84dcec9c9c2d9ca8f9dcc952de7ea3c54c051d0d41e78fe725cebf", + "0xd9f378c67ea3834d89a85d72bfab542d6877370c8b542d1be2766e867a25229e", + "0x725ca420d55211930c77e292f602f58c281c12a2d10d77ac70f128c122272485", + "0xc141d38375f3269e92d6ed85dde2cfff491b9fa60b3554ca9909b944838f7781", + "0x572f4aa12ec73e99f35c523c864ccc964422946a0ffc5606792cb65944a1c61c", + "0xfb2f827d05901a25debd15a6b5a45d6a42f2fa84e212f79493e46e760cf8d620", + "0x9f08663b613bf973e1861e244e61e4b842853b8a388360234c85982e94ad96e0", + "0x17ce1320123e19c42bf806a0f204c9475cb3340a0434eddf3d8954b08d8a3c26", + "0xb3d935cccef673064e94e186c4649d19dbd7d6fba4ab7802eeb44fe4e6448bb2", + "0x2a04d4c2b009e424a88196f109923ab308052c6709b0f37f31131a74db07ca2f", + "0xd30500ba7ad6548049313227f37e094507e03d2a71792fe28f2dabe6c7a477fd", + "0x133f0204075c4a44764bd55409878a85f730f412a64d8098bf26246ed89fb88d", + "0x0dd3f70cb92468b09475aa687e81d84b7b5551038813b1dcecf9ad62394bf29d", + "0xe9b2107b3efdfa5b52ebd9d25bc17cbf934190af323cbb821aa01454809cc5b7", + "0x5a10e855a18fb6e2beed325f9d4df38645e52c8098761996a455eb3320c2819c", + "0x7ff65f7a24f95a7408272ee4122f202e2d651c084495b5173bb046bc4618f96b", + "0x06b0e4bd3381c9983715fcfa8c3f48b4beb289754fe7bfe8caf5eb21901c8ad9", + "0x5ef4e799c3d7bc81fddaf790f00166b63255836f5e03bdf584ad2535e05d3cc1", + "0x9efde50127e985d2c255ef17a7a5c82b46242f18230cc68bac49867184e897e9", + "0x78309317ac6418cbf58090dc8091b3746ae1b5f05b8b082610eb28d101e519b8", + "0x81851a87801abc649ddf08e1e372e7d0a50c8d18661bb3a13193389b06854ca6", + "0xc5170992c381aff40d4d02f0b1978ee689dc9ea00d0665d53c642c6e1617f82d", + "0x9c4d06f36bfd2a08a02715c5eea44ca07adc04b1176f7a47a3404af181feefcb", + "0x7f1910a654df3160f91affee5f286299958a5665ed0d37e39ebf429b281f5b4e", + "0xb60950ce3005d7854f9f957b4f1f49f0b4e781728697ad312769ee4ab80433eb", + "0xda6666bca71087804de7b3567e1f0047bd69f8f62d0bc7f63aec65ce8222ca2d", + "0x7e9625d6fe07985ae5a378a35cd5108c1db05e429328f639504fc17527b2e04a", + "0xeb606494a39941d272aaa9cc3e18d2c502b0438de5ae974e6687e2c2c433104b", + "0xfbbdb8353f8288217930f085c51e0c67eb9fa268cc66c0a96673918501119802", + "0x071dde3764caad8163d85a5a7d9a05f31b857828db55819afc95b08e10d6c87b", + "0x262a03e39027887a11b93963c7ca4676cc2352fbe46a05ca2e432902ca4235ee", + "0x1366a718f5e2a2b328943afa839241903a4bdb776b6f732d6a0172ff8c9f544c", + "0xe04d325284bd27091857f289c6bc8ded91dd16ff7ecb157e39965c3c98058e34", + "0x648d5113a9c413874f2e8187905045f9d8e044e29cd4dca0658d283d0944a130", + "0xe7706395d101ed29949e59b10f69214eeed0377be7af3cfa8231b917c6793023", + "0x7d37f50db8c210bec2d202a7211565d53ccac0e9b17baf887a9b865f4a57ddb6", + "0x73302fd966c3e65c0d0e7d610dcfd1a87970d26fd2ac15deb73d812a878fb8d6", + "0x7cb0a793aa40ea9894377e0f941b284a792065a8fb20a0bf60e8dc51744f07cb", + "0x1c2435e5e922dbd482e3279cbf88a632e34fdfc1e7bbadba3247e11089871ef4", + "0x8fbf585e305c90965c47c190b2e125276a5cf5747ea57e60e9bd36feefc7225e", + "0x320d5616868006a5f311c79c86761b47f683ab7ea1025e794a9ee45b699793a2", + "0x8706208d64c31ebf34d6c4126f72787f3d604dc7c0f72ea74075bd21afe21686", + "0xac6a123d378afdcc284d34bf487714e4cf9a090da9d9f3d67bd5510ebde00415", + "0x623376328e2e3c6ffb9a25250a24a5b8486915317fab74c46c06cbda943dd74d", + "0xbbb4c4513c3902167bc14cb17738633113cfe22ed5846d409fde2446740f6b9a", + "0x62ce10523cbfd602cf3e3e5b8c09b310f4bf1d7c645e3a2cca9d20d156b51f4c", + "0xf427a9a8c4390d7a4237f0b72cd19343c4986e771b180421c21dfb37e6912c74", + "0x52980fbe4416be30e88b1fa6e3325a0037feec3b6c40ae66f9d5e884f2deb153", + "0x9aaf58f469e9c8362e3016de4b12350e8f3c28f86ce58702fda69be65267dd04", + "0x0fdf4d58461e0e9477d39c18eb528501eeaa066dd61aed414a50613182057934", + "0x708b1667152c18475d00a25c8b87de03dfa6b2270bda21278c0dc0faf21464cd", + "0xf7903da3c49bd894edc260ac372926d90763b459539eca32eb3865d4a16c9bd5", + "0xf9b6180481cb5b2f4692793de59cd707c71b3f6f7396a40e506fffecd3c4fe7d", + "0x6f298c8d88b0e5120805b453e0ad10f6d65809fb0558c4bb5a344ee00aab4745", + "0x4bb3b6e0cf86c6937668b4a298da229492d98d99212c88e3e60af9e89fe7a4b1", + "0x0e2b0211c17ff6e28c459ea410d3bf33838eeba869c4d46238a25994fcb9dfbf", + "0x113e8f5c4c21ba5909963c3e65b112c78c19b8f3d6526c55de1af9a4b1eb8d60", + "0xf19f2f2e0a8de0d04a26dd1a10e96257f4a6a764b92d7c360453db32d65e89ea", + "0xb20efac16095e63f5f530de22271ecebb1fa7bf4d8ce6f49057327d692caa5cc", + "0x8781f616535ce6b3352820758ea0ddc74ac97e49a3ae9eae6ab0bda4e8741606", + "0x205895b72b02e22c73c3fc2e814c121d6b899c821d72f1b02bfd8c122fd817dd", + "0xee8e1b3a255140333295253ecfbf9a2d375d5ba1ea2879bd72088f6c62b3f9a9", + "0x4d3c138f077007962fa3fc56c7e5bb409c860d11ba48ca9658e67473fc4c4417", + "0x283ee3738c2bda7631f3f30fa2c29d3f3bed26c63180c61e1de03504b48f7c38", + "0x900a45ce2bc0f4b331d3df872f3d34c350f6b7dcdd704e36670eba878776b303", + "0xcd148e1b7d3a4ed41c51129d14cb226ac20ff975de1de2a802ba93b0e872f2f6", + "0xeccc9ff6f75fc844cdc8a723ee3f168d3f54788aa99a5f81aa9e609f8b4e4ba4", + "0x9e4ba2027ba44f31bdeb8ef27db30474de2f3728fa0607f098eaf8f03faa2fee", + "0x8d7289beac6c06009f0b72c2634c176a0784afc8bbd484bcd8040500b15f902e", + "0x9624bce0632d9a49d9b040a45da65e1d686dc6e6eed7eb3ec1536384b5cb3530", + "0x8187e9b62c764ebb82f5bda0bde0cda2842c47dff910e81c03db5c83dcf02da2", + "0xab7be6424ecf0041a1a0aa6c57cc231270ee6e50b80e6a8e07f6e40e8e11931c", + "0x43d8ffb420ac0cfec24a8d378d7d35230aef8887268414779b09247543b2f044", + "0x185cd7124a200639a0f60f1412ec44083f742960e46897a85d45a04bf5ab2516", + "0x91025f84bb714cd201f4d3539f7c5e6c7cf9fa83b399704ed0130b311c6886ba", + "0x13100633274ce0d423732cbc1bc1610123959f15974868af0b1900b74ca4cda5", + "0x3b00927007417f0d762f6b37c7ec0441e963a9afcf3d54e5be1adfa4278010b7", + "0xa8e59f21955c983044955aca7bca29aad4d408a1c958ddbc2ae526a87e3fabbd", + "0xcb836def3579f067bc45c0dee5f9a80eba544348c7bda65964c6b1fa2866e0b2", + "0x404d40e1bcf36d7d4e34b32eadbcf5cfa858be1499b088fe8ace025a2e73d3a4", + "0x2d9a5f05bec8712d206349bdc8fb8ec897cf2ed28d295cd275c31c5ce46c4fea", + "0x48c577fcf9d050f2b35ba0195606d8b8d91ac17e524fe0b6ec16be1ce7cda0d0", + "0xcffe1c3ab5caf25224c870cdfd63b4faa738362299cd37cea8b66cb1542f0201", + "0x7bc007a452ddb66827cef27c5bad01e87265cb38cf8e111ee7eebb21cd263bb8", + "0x8c26cc0839859eba7744b73a03f6318e3ea249736ae20bd206461e79bd7e401d", + "0x165e4a10b343dc952ee54c56f21b74b6486929dbb59ff24e066115bf35c223b1", + "0x2ea42214e74cd75bea948323313453dc6242fb0593f7e267abf5e544e0ad7d2f", + "0x2caa11a0a255bb4db80e305ccff40608534e638a17cb8bbfe6580a035cbc8ffa", + "0x0ad0490a3008883d02cc92624352fb7caba9a97cc46f82d1e64480559778edd9", + "0xfb24953b551a2b544ed6c6cad2755e6aa634112c3e225607a0efcb0d811ffaa9", + "0x4ec8e3591d27b911b1495f6fcf5e6dcc9461e9e602b67a5bd536bb0e6bc68f88", + "0x790b7eecb797e391d27085b27cdc5d4be20bf78de9918c3d1ed72ece2738dfee", + "0x7b73acfbce9837bbc5f821412c92a1b58b3af2bdf08b4c4cbbd12e151efcc90a", + "0x16e576b05c5c95fd38ac7d53699ee8b8b3431d78a5f671535590cc1c59c78039", + "0x2b4bddc77ed675df91af490a565c6ece5247335c90de744d6863e24e624bacbf", + "0x277efde1689605ebdaaaf4b9364449345ac664b5fe270736b2a7f2a97301dbbf", + "0xf727799af7a95e92eaea1bb2e3a0f79cecea663113e4781797101acfde46c234", + "0x54eb62372f7c5893d6be0a031edd80a25cbea3db2a0edde69ef4bcbfeaa24b4d", + "0xcab1e0eaa0aa475de501b2e3fbb5ed790744040a465a4256c4397e85a31f9eca", + "0xa0c54864bb507baf47aeef61433ef7418f68295f08d24c8acfac1eb18982163c", + "0x9a76cba0046b4e4cc89aa333a0f633147056044624c1b4c1c61a8a62f1f98573", + "0x510d25772f6e14f8e14905b05d8cfd6384561994ec3c92cc76fd37ae6a9812dd", + "0x39ffb78991cfab4236e4bc04325331dd8be2e06c4162f8e51aa592b27e1fa0ed", + "0x45c4d7eed33f4be6f8c0aba3ef42ad6a6e5f654b104895d9d662ea28704d6b43", + "0x21887c54231da9d400b964c63cb2f5378ca3c15f118fa105c0b2545528cf302d", + "0xb71cd47b4a6d40f9b18133c456c2aa7eb2bfe6170ca723a0c584ea28483d13dc", + "0xfb3c2158485851f4f564370c590f4a6b8f6481e6e4736ce9280a89d946b0e016", + "0x5c3ff34c067986eea52db9443be346eb1576498cedefc4a66379b24a3244fcc3", + "0xb27349be4de4d9be3cc9e904f72455c2f131c0beae6757592f49b2f0efd546e1", + "0x15877d8cccfa9f9cfd60408c5a6a173597c2e091a47fcdbaaf0a944a2232edda", + "0xa004d11f0d305763a613cb6d3d44a493ff669c5098b63b3f03e6402adc207bb9", + "0xc033417010a0f390418ff55348055e8b3e676c1d060f0cca2dad80aadc3b253b", + "0x035224e9c4e562b1f0c080ae58a7e9b8d48e565ab0be332fe580303a6b3661ca", + "0x6c7f4fcba6dbe1150b5bc6ebcf176ec3427e555978ca7978bdafa674cd50f4fe", + "0x4f62b3544c9828f9b7aff8fd5991e32b4f18e72c12b1d582c671a71aab4cbacc", + "0x8124e36227c5788e3608c63a93a8a0d966e4d8e12a81e2fa2378a969dabe0ef2", + "0xfffb09addea705c2ae3583b45e80908640b728867cdb8d49b2b1150280795b49", + "0x6ff99c0f0c3b3e208373fa3b7f031b8023b6660801a8ddbde0fe8668310ba332", + "0xfff2fb5a358d3f2bcaf5040e7e0fb9ad96fc918f3be7fc077a8aba08edc64a9d", + "0x3d734511c149e8c1f617fc48fc9edbe27da5e2837dc634ad4a359cb4fc1ce32c", + "0x0c8903bcec94ac45ebe8ee7c5875c23216d9399f7d14fcae79b7af4efcb4e503", + "0xf020a8e3254695e8c5a7b0a952531af6c886719b9354d4142946304220f18b53", + "0x4e1b5e445e923e783b878b943b0d9c9d2427cd8b71c346b79968faaf2a3ad337", + "0xea488d31ea2b67854997c6a88db87a13b4594b429b0dcb531eefede8e22308c0", + "0xc5dd53b4f8c9379c0f86e6b1270b6838d6a6e689865542791917251273c5360e", + "0x1646e9b43ac92494a90ae04647a4047f8de9640aa6f2c2c137962bbcfc80c8bf", + "0xf2f64a9c2e2de9ea1e314d84d44769a114c7035722f5cf7633145c13c5986216", + "0x62f06eb562f3c838c3b24a3da792769e9de8e2bfeefbd70c7aeb9271f19f439a", + "0x1cb36e1cfcfc9e4d8292cccd8d8b8f0bf90db7b63878e147188b16ec19754110", + "0x0316d23ebb039aa69d6b3b9b4603d9092f800b191735abe2a8ea2937b943f725", + "0x4c85e7f1e285380f4d80efd1d572781a93234149b8628350df7d93cb7625155c", + "0xde0010a2a469394e8422f52d128b930aa52a773368c3b8bf38a0dc830f161f8b", + "0x05ef4316554e9e05ca9a16c20f178481b630322c8dd438cbbc18c2bda644fc7e", + "0x64673e06bfcbe84232442ed29179e0b235d29e398e2867a484c2b60727377bc0", + "0x8dfe2659a262b307fb1cfd68fb18925a310691dbadab254c0a81aa9f9ea05c7e", + "0xb0a9fd59b0cbf68d53654d131aff4449c0fdd18217970c3de8d1adfe58d1f4c9", + "0x4ba2ff3b6232b74f661271aa29654638b05ce829083f54be06d8ad4290182910", + "0xe087ab9202b948f3c20cf02cb21f5f1b97d508773d8d7c2e5baf14fd52845076", + "0x702e6b8f663d10c1054de9751594d33f9e0915f1d3c71b36cd9c974574ebc85d", + "0x4dbec1c6654555295d0dada515dc606c18fd72e55b3cdb63ae018b1661c4385a", + "0x151d1c8c60780242caf26e5aeb8860f0ee9bcc4968e96c8c540d3ed0690d9635", + "0xf385a1e79bf23ea44d14b3f8668175342846ebc31e5a6790fca01b52074aa6eb", + "0xf5e94b06a1fbff820e98af762dcbeab9d38a45fe4099728543dc4784ec34b1e4", + "0x2396c1dc9e8b6cb903f97aff55b026511d64b88b08a05c83bc2ffd6becf60ee3", + "0x4b76c7764b5b098c3168779d95ca4aef2b861201c427c416c97b81372436d9ce", + "0x1a5d26c1839a09d7116868abdb2626467ed948bda413adeeb09c1eb146863369", + "0x25d61eb2338186246b78e3a4c4857c89cc6df0c77ec0f19b2d58ee9277c02d38", + "0xb9fab6c7fe62208f5f9c2714747714883987a513f115ba8d4c6904df172e9b0f", + "0x44f2066089cbd0ebae33e1b58179db26332ae99534ae4f864abc94fbcbdf1acd", + "0x97ffcb0dc94906687481210847ad2522c7cbff5758f6242c8a6ead1a010c0423", + "0xd681901709d666912f87058a300cf15b0bad137f4f0993809c37372ae1a73bc8", + "0x1e89c647ffabf82e228aa2ad65a989da66fb9f4a8d0f3efc7d66d72ef75f449d", + "0x40177f69aa2c7f7711c6e2212c2278a861100f1a46a99c340992e776f278bd99", + "0x8c09a1a9e84305a94b702fe21ed39db90d2c0eee6ff21185c555496e99c9807f", + "0xe13af929bc3b6b693936cbe82ffec90cd2d2e177758af41d5c7c7f8b3922582b", + "0x4ed170e95d7b677fc97533837ea0e350a30df6a3862d7b7794e051fbba68adca", + "0x5603af56d81026197df080dc437f9dbedfc82f1acc26f2ade39db63033b7a053", + "0x815bce3f12b5c5b5ef1585ab98a025aaa8117efdb75d2b677abb4522e4b933eb", + "0x603c0103be82ae58d4af604be625016b64c4985e3f2aae31ed620d1635d85a7d", + "0xcec52fdf68b04fccc6c7dc2990412c955d08b6bd4a7a3f0f9fa77d77d1c3481e", + "0x1b3a7d5f6206a15645ed55669485dc4e1cdf7ba41f3488427e8b7202d6175552", + "0x59946fdb729dbda327e825d64932da21571c83e4170c1c7748c527bc81937fee", + "0x676793de267e7078dc3b6927cd472eb1babd4f537bdd8386ee65b88166cd592c", + "0xc5379a7f5ffd7942f9b7590ff83592d91fdbddfa09c040006564434379868110", + "0x44860e8cc625991899e5a5c16d805f6b1aab9e1a79fa462e4ff2f92d6c40e76a", + "0xaa31dc38a358e3a1fc78c4cabbf05517b2ff78e23befdfcf7595074bc0b5498d", + "0x9e7d9885b3a84dc90dc25f1a48987d8d4cc1cd08f51baf1c3f33e86fd17341fd", + "0xd6790620e79c46699c21b0bd61cd09baa1e2b350fddf6d125c4c06fe30a3244c", + "0x4f60d8a3dc5859f69f1b96507527d2afbf899854e72d0d12ef27086dce561a53", + "0x67bd7c84772d709e1276a1863ab4b26ec84eb02767a804ffbda23eba3a8af0d8", + "0x707155713c08309b0ce29e867a9c025e36876935398a87d1153a997801cd7b96", + "0xe94c592379266a58679af9df945fb443b790e1c5a7318a5a1738070ec479d1eb", + "0x00205e95873d1670a9212fdcae09b06fc941128e4db1427fae7b3de33105c292", + "0x0a730cf91406030fea04d74b78d1625a3e5c73a1e7f39fda6db9225e064697ec", + "0xc32b3134dab797f09bc4986a7d9a969b9331a99e431b4026abde8d06a7910f19", + "0x7b9fc8ad3f2bc9e4c680e2400fad27bd0de271f193cb4f7e9727a87e999aecf1", + "0x39d65165378d375fed612489145d41dd4f9d57fcdce1a5fbba35a09210edb201", + "0xebe86247c803ebe65de42feab2d95a8d45775f352a0079e6a868692f444fabfd", + "0x04eb04c01e29b4a0f96cc9072576a8f7f3cda3fbf9b4050f3853ebf763bd85f8", + "0x701a86ebe017b55312ad8277eee062bf0a1b1ea2595631c9c28c740da3d4c117", + "0x57d6119ae2469213c921ac6606f41ed137181c179d6e207d21693399d3b21e67", + "0xdc189a5837c11ead4c6a1b7530b718476a8d0ca879fa4e499d72f7d8fec348de", + "0x96511948f65eed76fd3e17c9f1201e605ad2ee59778df04fcfeab5206dd29192", + "0xdb3930b8a1e2a8eb35940084eb0e98dc53aa1d3aa563e3ca6b260a50cb3a68a9", + "0x806d567cb6fd15fb18007354be55fee1c2b5f0aa1b1e5229ed0e758910af617f", + "0x6e2e8273a970e21164be1e548b92963ab241a68da41e9e231c12ee08bfa4129d", + "0x168e45c60dec2496e48b471b7d2fe1b829e9111191e6bddc936d0787fd42eaf7", + "0xab1ec5c8aeee05f24428c291a4d8afe776a92826f6e58dde95f8bf63e5c8ea29", + "0xa9db30a831b1ff69e38b342ee4fd3c9a8c3f5cf7b647a0c7f5735a4682eb42db", + "0x2b55ec4fe76bde0bc4f8d769d3b182e4ac7fcfd85a28c89fd7fa5d511f41969d", + "0x74ca1b5889e8920833042da86aa8d1259463827bc0cc9e7796144927757e7db9", + "0x5a3d4a8bfd449265b74b85e62305c3184209f12f4f55271cebd7d2df56b9983c", + "0x0b450e356dedc2d73ce19c6028dc5d36818cd3714879e5a402dd8cf7465b2253", + "0x073f03a0316a886c4cd71d4cec42ee7705b6cd897932b6547612f3cbc5c6b8c6", + "0xff2b0244634cc4fc8cae0b44f737dd47db2cb60e05578a34b336c46d0ddc8f09", + "0xedf8c719f93e1bd0cd421bdc14c03f2795dce10bbec5647eb98f5a64da5e7f74", + "0xe9192cd76b33b1d4b09e7d8c3e1ccecdb7a532420dac942934ab76d6491fafb5", + "0x5fa7a590d22896c2ae781644ca8db3ecf779691609dee9d0554ce562624a1e9e", + "0xe6af198683501ff90b9d14a343553e0c5d7c5b9fdf653311e022ad4a33eab72f", + "0x3c28170602ddcb77078d6f715a6629aebe4a35b2498a2cad37057f3357598dd5", + "0x29aa81bc8d9c54f146917aca4b1ea1a0f147f6ced0d23a647a51af942826bbf1", + "0x0056b54bb953c389159a761d3a405b71cb54162481f5cae225b86c8d2f409960", + "0x3c4d9ec5c31c3c087545487bfcda5db713f1ad44450eb310a66d66330b67a0d0", + "0xbbf3002577b95053f241733cdf991602a570a6f33935d50ad64bd31ea9a8714b", + "0xed526f4ea68cbb5a15baaaf6ea698e2d293afe848f3056b803646046aa6d5526", + "0x0162b7210309d0144b8464d21afdbd80b5ac8bc3cf5a93f32fbb87565fd4c30c", + "0xb051288210e1d0ef546dffc2e52026815261e2ea866e1276809000a3e7e3d060", + "0x76397a5e4c77029699eb10959f51ab090437888ea06b1c5d0cdf16b74bc44d3a", + "0xb5cd5928e3dae6cee3ef0fdf7f1deff66628ca8ec29743bf1aedba2e10fcf9b7", + "0x6d1f9aa0f4ab673ca6d0d0f10bdb491882fd1d582c2489eddfe7084eaca0b034", + "0xc636f215b9918856a0ef971a2340dd3d3019ba671c0118c352a1bf64e50f0e61", + "0x8ed6b16c3b89411cdb2a92cd42f2ba4983b26a83eb3112a6a376015458aea55c", + "0xa964e5da59c92492270317ca6a0b86402cb22e0c568dcd20a90b3e826846e634", + "0x2f16af813410d4c3519d9bce71c3c31ff09799d42760f49790f3789a2d365046", + "0xefe1139708e6ec67886b9cc3d6efa9b2b67868c626c3541e7d7a17c75434f2ae", + "0x199135b37713cdf4e1ef3766e331ea84f8e4911552de1e3c133ce9a3a3b52e1f", + "0x400cd17cba12320d710833bc5089c070c482f6fd4188b704628ff47611ca12a3", + "0xaf26e7080fc110911a649b03f8212b43626cf75c867b2af9e70cf35fa99092b3", + "0x346dcdf1ea179f89187527d73747c6bad12ee0efe4c02eda34ad3704d24638a3", + "0xa6df7e1b1a8fc69ad26110c0166383e5d4db331e98fbebb1b56611e0f7539a46", + "0x9d2b7acf84de840c1cc035a355360919ab5599ffce825dcf9598b6c8c23bae24", + "0xf18a92492752d0a118efb2ea386767122acfaa728a39d788cbe1e836ea0f6378", + "0x28f49f4f5a61322658ca40035c0340af61bbde7bd42b74c4a1867b19992dc787", + "0x890dd6356256b7bcdcb27d415c10709c6e898e5f947ca209389b42872102b36b", + "0xa24f6907d5fef0a0c28e79c3be437bab1e4470d29365b9b4779378099a9c3007", + "0x7ce1d586d950a3875954ef50e2b6bacb51e8cb11db45c34b709868aa7eb6bb4f", + "0x5cd316a998fca726c58a56079b8793d208f2324e399413aad3fafae077d834c3", + "0xd367cca6c37fe087c9acf4cedc12ae875eccfa34a4798bf916a2ff1cb245a8b0", + "0x78a1dc488545388a618cfb6eb0047236adaf32c0b5bb3dd35a1843720e41afd3", + "0xb7bdc303b26e920a184e250c398ffae03fe29491523b68e2a9fd658c7f55a734", + "0x72ea58270b1512daa51c08840dfc33e657c4495a5f50bb6ade1fe4e7f2e5d35b", + "0x3af82e240d734c66ecf715b2fa6d42a5976f5451694a9669ed49cb4ce6d495c8", + "0xd875ad205979ae78c6d334e5c2c0c539574172be4f2113e53dce70ac6320e1d3", + "0xa808ff0a2eba422021f62c0de2cb9ea114dcf340fbd97ab0506461578db78104", + "0xc6d5c1cbcb505220f3f47fd100470180620e47cb5b7ea81b4e6b27976ae093e0", + "0x3f788657a09cc34dbf670108046d4debe140154ea8283f5a762b2a6f1927cc89", + "0x0441ef2e2865848be1d3bbf10dd99bd9b307dc6a3833cc8066f71fcc9fd4657c", + "0xa033b833635e284605c2a25cf4b9ed595a8f6b7b6928a60f849019b68e412197", + "0x0c6bf4f59f2369da915c5cda4358a1b84326c94cfde7886fa99c3cd8cce00d3a", + "0x16f8cd5f6cab6aa0968931090a06cd78804da1332ae794954e43e880e6436380", + "0xc44d1853d161e5970cc4b0541aa7498948da07226d9747191d677c1c6c61260a", + "0x63fa006b716a07a172580b605dec90a99f4eb1caa2b6272918e21206b3b08186", + "0xdb0d7fe87810eb83bad89d04f279a06a316e9cc9afd6b249f77ff8da54dcffcf", + "0x04a1e3ca62cc77963b58ef79a9e2ad8ef54216034bd160728a7fa4806c0ccb62", + "0x3db1db1cc10010514a98f45142815604a945544ecb6438c63de232009f525ddf", + "0xfd6619df5d873b255c6e516cf0e12ec1114613a5d803e877fbfff779ec20a1a4", + "0x581ba19ac99cbbcc948c61e0614c64008eda6a58604e9197aa8470266821f331", + "0x316dc2404582e1ab45bef960907fc16e6223639d1875f6cb7dca9c7744cbdd30", + "0xa5c585326fda6f89e33d470abeeeb12a6a65ce9624cf01c5e2ffe5e397ec8efd", + "0xf08862fef3ea5a98b6b4bcbf0b57b482dfa149ba4d5e530829eecef1b5e0ecf9", + "0x7bcb4c42db39ab193745ac34c75e68ab457aa03c83da11f7396df2491a300666", + "0x69424ab7bf19ccf3583048e9c315a5a5d4a7d85359d6b4a3a7ec001be96d7212", + "0xa686da5793c201b92867db72a5f8671ff473cc12617437874644012ff242984c", + "0xf8c11302b69a3b2ad86e7826f8cc85d0ebe21e6420ebab0a7093feb7f15b985c", + "0x6ed81186ae9545a36b50f9a0fa0c82f2f52bbda7e8e936819628629e29402018", + "0xa91851b0638a92d2733b63125085982e5ff2acfffe66f71d3b218ac4ddb4d268", + "0x895ec76e33463b1e9f6a38a15a787ba84812d8d3fa6385824618b7de7f8235d7", + "0xa2c45ceebbb227ca7396e407e26c88bbf0432483608dfd169a085c5372ebbe5d", + "0x8cd8558d7c920df4bff9226cb91dc674d8788376c694ecd27bd84291255b237a", + "0xd9e3c84a853e9b551d296c560048283aff22e0ea3a0853e60505932f06fc0b40", + "0x5148cbb68497c824a428f87cac9512dbe313abf6f4c2b9fe6ee78cf909d4322c", + "0xd5d0a750818cd28793a1238c194503635e07870a65d5a8eae084a6a7d152069e", + "0x83c94a89524371c5bfc66e3ebfdab49eafaeb77fddd5b31bf3eba609cdccb083", + "0x4c3e549fbc7854bb417e50dd281890c745e9748ac7d830acd9c867a2abc64db5", + "0x642f75489711b36d89b0432f92f1ee19d3b8cc1fa99d2c55e8659426068da0c0", + "0xa4a944abbeff1a3d718e28a194bee6bc066f01aafcd0d674919e19c4ce1f473e", + "0xc9336cd020b35855fc7c4c3febdc2a19d4466e22d76ea44977f50fcf00d30772", + "0x0ea3c8090512fea72c5d457e0f3aa72fa0fdda928124177fc07587db60ee4c8a", + "0x4792e45b5fe8a3e2179b0745521a8269d887f8751be3f2c8e1cc8aa9ea0ecb7c", + "0x7ecb169f378c9577eb1af269377c16d25b09dd2aae49705bef1d143b099ffd48", + "0xf9722b9bd88dd8712c2df0826798b903e4e46ebea1caacec33e626b1954bda88", + "0xc7596d6ba28215314a8c0cdda3929284a0f98b14b67eee8bdeeb245a042bf5b9", + "0xb14ae9ee5e30cdf8fcaa8839e06f1dd1c273b9a7f8aa33d6a7f8a2761d6411b6", + "0x160de9ec9947611c32bed5b39fb688fd8521e0be0c992f318e8ea596e932aa85", + "0x166b7e4682502a245b971d27420a50d028febe29a06ada52709290dce6ff65c0", + "0xb3c6774d9d1415508baa55827001283840a3cde35900f0274eb78cc169b20e48", + "0x067c6e4818cb6dc6e098d2f41a0f0d4d555d3079a271e15e24b40c2b33d48c91", + "0x5f43937304d8f1c5915bed915daf11310fe77358a83b3dd2579986e9e63a418d", + "0x361e8400ee55784c4edb63507bc047de04fef5e5c96c4f70c9a61cb5d2fd3f5d", + "0xd6e24a0733e82cdd74b1ac6ec0a54ef3bbad0f68461f804cefe07a4d7e15b359", + "0xa3ef3d7ed01caca083c8cd24b0b2e6b93f307ab3bcd7fb15cc49de6e76a85054", + "0xcb22fe8e323ef120f5ea5f6604ccf7d84adeef7b15f3d81247a676604d127979", + "0x39094ded1f8ba3edb8f9628d72375ba2700942e0870a267ccfa75419231f8ef5", + "0xcdcde1fbcfc0138689d35a44fc9dd9f0b9b43f6bfeb9fe29ca02018ee5e2c358", + "0x75759de7eafcd4114962bde0db7b64e175787ea56aecb37f5b1045900ee8cc0d", + "0x53cc30b0160d81c37e5b9ace29a55bf07beef84f1cd71307b140e2bfb533d0b0", + "0xea48a27931ef94e6babd0342424cafdc835663b381983dd325b00c8b12ef9f28", + "0x3189d2f6c9623c4570d93e4c26ec30cad659f8482fd4bfae5325932fe57afda0", + "0xf0822c0d02fdfa65e48362ca1915c07797df6f87e0a98391ab4046ee4266b758", + "0x4245d5e75abe515824bebc31ec8e2ed9e5ab027fae1c9c74b49e9522c496f00e", + "0xe4c84eb52baf4e9bade65b3711b6bab7e16fd8a21d1162a24911ecdda4ec4c97", + "0xd73d7c7f12b4dc0ef75f4aa6f006a2efd64a6f54f848daa05efaf9fbbc1743c9", + "0x3e73cab1286dcb25621a108bf70103b8a67aad50d03b2a27b15f32e74d2ecf76", + "0xeb61a019301e6d597516b59bc2314f75afd9f8c76ce5ee4b2abcea2d5af65d22", + "0x6e1beb679490b6480aea261f776194bc2943aa7b4aed0edcc06a96472b6a5012", + "0x5c753161fc23f9bb1fc76df8bdfaab24fe0091337a36a56d0f5f959e4a72d903", + "0xc60ec5c3fd1986c8478f5714691a31acf469a5ad47d31e1e6137969328e86707", + "0xae9bfdfb4a7e54835186e3f161249d435420f83a238786f23c261ff0705cefc0", + "0x3a7ca5b57771c703881e05743b76622360ffec308e21b649fa9d2b77eb0485e3", + "0x093ffff3c8d30950e82d67887d44844d21f5d0d333534c65115146d92d667778", + "0x6b460d7cdcced9aa43dd87660e073e6ad6c068c7ff84aeb86decae8a18f0b0ed", + "0x1e23074207fa45234ca76dff1a5b4d78ee87839029b9bf4235cf5484a14a2ef0", + "0x4236c643b14fe734a6fb1e4f9ccd7b6b502ee5d24fee3af1201d6fcd5e2a4991", + "0xebf1cabb6606d20194f82bdfc22fef39e8b73691c802c6421015615cb8651ae4", + "0xa065c07d917d768a40ef583dba8570be0e67c5c067286fa6ea55183ed17aff9e", + "0x2ffce3fba6265f1a82be15315ed6fbaf8710133f2b8242c6a3a3b40da66e98c4", + "0xc814a7b871102332fe8d4daf0c8f7333a9751e3f29b7b02ed4d15a8c217d1490", + "0x29a0b87325be7115d4605df2b65991421f6594b3d3348238a6101deccc88742c", + "0x1fa4239e68c4fb68ec4e8786801d25ccf225336d095888879953c4543a47ca57", + "0x2bc5a052f0832c656a03210175d28fdd0109676e5cd6daf08614b6d9380e0156", + "0xfbea1e39f1d77d1cab4b111962e1b0bc8580fa4d353efe89b95d1ff5f9d249ce", + "0x4e3c512ca97b1d6dc6ad8f0c17e336aadb740ac907924ca6e037c3820d484a90", + "0x26e3d31503539f6fb1220ec960fa450ba15db330a82b97584f48af03e71d3fe7", + "0x37c3e1d006c31c06526b0c02df45329ce4ecbae209231a2222dd835ead7bd813", + "0x9eec04ec09974b5bcea99b021c6fca264f32b3ac895dda421482b865e9d0c340", + "0xa7a9d9fee641431f2b2f217a57a32ec61f03a1c692304768d58d48ee1c7411c6", + "0x87a5638751fc6b716bc25e92292a977f0de1b5f53fabc89b342a3f8c096e509d", + "0x084dfd89d9e63f625d7bc139a9584182937321d0a5e2b61e280cfcce053813db", + "0x30b73b647de41f3e753770f967615d695df8b77fc0e1f770d9cfd8a8b7bfc1cf", + "0x8b05b1906879d64f6534f7231ae5aef00d86c62915537ee54956b2cadccd9c7f", + "0xf1c883baf6073d2244d5b1a40b7e7ab99a22252e6ed34627fdca985ab87d94cd", + "0xb6c207b47b98f0b550eec7dafb5e6bb23a4f1061055542bc1805b6e89dfe763f", + "0xb5a37524abfd343f821cef4a3d6c66d5343bb56dbb4f5217f7c32b888d72c3fe", + "0x326124edc233211d1dec747ca38045125b3891938e8b449b0980be57fab79a26", + "0x4857dc3260a16bba60639a37fe309f46351d2bdc15c1689b6b86c16ee8b4d2b0", + "0x6728195d486a624099eee5c9b07ff62cb8abc7a66aa7f2aa3cbc565ee614a17f", + "0x0a7ac687337258206323a3c49d88ad4ed495e9a18c848a3d8ff51be0eebfaf68", + "0xe0c1882697acb508290737788cfab9880ed09469e4093f6c95e7282f4bdae4cd", + "0x80f763c0e43b60aad58f01aac1275f310b3cde5e3e8f2fb47dc6587b4a5b21c3", + "0xf7b62180b642b826340dd1f69477a136146d341983e4bd875823d804ba205c94", + "0x6e775aba73a0596d398c5ccb9d0adb8d6236cd7dc235e833e69a0a2a369d225f", + "0xa3c65ff864601acedf9ebea681039ae9d19b961b84c39c40561c2ab42b9956dc", + "0x5f5dd206d841a2a0a85186e2dff2f7d862e47e1bc11fdf0c883412643cff72d2", + "0x39df5dbc5ebeb3d6e94e02e90f987070d9f73060e3751cb5fb6c00d737d53a24", + "0xf3a78e92493d0fdf6430671c820949fc39729a366b8b3355634522bccc6fc7fa", + "0xd12bf11fcd9ad2026a340671edf4e0fcdc6d107f338b5e8cd1e110ce8b2b1f97", + "0xf69a0ce968327b516a50bbad9d035e3eaf78e501c11807516ffbe6d847103c12", + "0xbdbe28bf74fbfc5eedbd363cf4cc2792e948ffd66df8006372396ab2b901d9b7", + "0x10fed02d557ad1ba3794d9e97efaa8bf7d6ec86b08c04c1a3c63e099ac3c6fdc", + "0x0735058d7226f806a87f80fe5a55bc6756c96da1fb92b058c08bb2dc6356f4a2", + "0x9c63cf37aa1e235f4fde0cf88c13c3e87396646136de26757dfce9373bbad078", + "0x54105bc5dae2cfc5860308caa5efddaf6d6fa16b6506900851bf8d9311d85945", + "0x26a920994c14e7ca38d62bbecc09c4885acd455160910ad3b778338fe08dba20", + "0xb7d2bd9ec2f0c1824ed85476d70eb3ae85c132545b09b5a3fc89bb647db61c29", + "0x44f8a25051ce2d5c3b6edd22364657af990fd2b327acdd258bd818dcea5d8f10", + "0xc504b1cc18b99305f83cfb82a9452ef1b6650acc7a7513771a9f1b9c4d258894", + "0xae14ce142031a2a1500aefe7d5bb5f2c48fef2d40bcb3cebc4465b5f588dec0d", + "0x26a6a67c3642f7b63505fba8bc8f4f2db35875820853a7e93b7015cb59ad5288", + "0xef2cebfed16dc3ec1ed7adf4d31a907b1c48986f3bc678f0e0d42260f3e5366d", + "0xcde8bd5a558e4b4aca53d0d164ab030a9206e0a3dc3d52750454cd5dbde67a87", + "0x80213b7c8404bcb599c6acd3d0c7b97c821f9eb36d1a261c7d59c66aaf783557", + "0x84974ac71d8599e8b481f4ef1ddd2365540c97d8a14bc55b036477b8b930a1b0", + "0x22d700ec6faf569754dace5bd720287156b44a7c647338568df8316e4a3a1590", + "0x0f174bb7672e56e087429fc4ada9fdfd4dea9f94abd976a2d9c1b3b2103883d8", + "0xa31dce1e1597f2603aba9b84f545c56947496b648b770ee9bee76b26b076ed0a", + "0x3bcdc44880d4cf88f9d3a107bb254607cd799cab841346ea3dd2e10dc461947e", + "0x54d99c8c46ffb8d4a6c2453cb2ef92abbea6cf8d666f627afcb1f7383e248c9b", + "0x4bad0aac0f99bbe49041b0d7b7da2d0b379cd9a1a4e845f04ee6c399020062f4", + "0xadb0bb1b69fb15d78f835ef5d2de20273faef16889952c0578d3be609573ad68", + "0x04adca8a68fa1db84b226f2e46d3328be74cb9596e037d9e2bc612e5bfa0910a", + "0x9630ded627a97f9641e9606a5ea8eb5e04e0a7e52dea484b2498049e26a596c9", + "0x146544215d83359045dd52eb7821325178f25f950585174c97ce6431e84c432b", + "0x743b7f7b7e0e4bd94ce1cf7fd26a42fe3e60946b46f12094336624b22799abfa", + "0xbe5842fcf8d27fd42b2dd344f4fa80a5ec75576ab0d3bf7df076d2c62c87ee63", + "0x0913189b9ea0086155d331989622986163ceb9d8df937b013466350d5b6cb9f0", + "0x179863d8ee06cc5012fde594f93fabd674cd718e529214acf0855ba7920e0e5d", + "0xaba24275c0e3fc84593d75c0ed0ef64562b2ca29a63c9651ce2972f466f588c6", + "0x59953a3a63270197712f70bc8c1f3fbb974f3373967c76c6ecb05b36624c4e9e", + "0xb03b28ea463ee70e33fe1431556e4186a773476100a61200a72dae7b5a917400", + "0xbe29685ad0f0e4f4e06f7aef6ac68716345a503096669c02f9a4cf2645b20fb4", + "0x77349196f4b655fdf90ac091bf217cb4afc46efd8b3738438fafea3ec8bf6afa", + "0xe0f3c1b6b1f9a822f765a8657ba73b6dac6856b86d73aee29ac8c67870cb5d49", + "0x1e9967c1aa6cae9e6d6ce588cc7be4458e30f004f07f0886bcea9f1894409541", + "0x48e90887d177e254c035c4e6341e43e2fd4b69934f357ef0633a4876af886ba2", + "0x18b962c2749d6fcc59615c7fe48242c4593b18d9c777bc8929f663bb2e500a62", + "0x437628a508e2589d87073ae2cce6867feceab7ed948913a5f367aba70ac752d8", + "0xc76db66e84e99a50d9d43255bd34937dd98666850f01c7abb61a59c61c48a51e", + "0x9c97b43a11c959976be2dfa43d3e427c81c9f65f0cec38a30174753911a0aa62", + "0xe7a8db25a547dc1ec612c3270d98ecc5d358edf0093e9a47f97bc162e2563c56", + "0xf8e9f99e26b147e30bd22a71a02c2e87a4f816947b23be23d7a998bab0bf42e3", + "0x9cc232de33ef4d9c2701403ee75627560a4a290ec00e9fe2bc3e48d22729e4f6", + "0x83b328313a8256d67a76a199607871c9d7d91ac4bba03e4c7eed2850b863f014", + "0xf785f6f42d160759627f956c381c0b2afe133191361126e1dfdcef8ef96a19b6", + "0xba15c02abdb13795b7ffbd05ae808df3ba6dd49d3f6bdbb7594301fdcdafefce", + "0x7cf481f442daaf09047af092254ea96b3e6fceff47e7354dca59ce92a7f0192f", + "0xaa09cc16199e82bf7ca1c664df1683dd68f60392383aa86f7a4d70db4fcc9ae5", + "0xf48584eb70849f03500c2992ca9d8a25c6b4af1dc6b267bf96b8daa844653671", + "0xaaea21fc3ffc8af49d5b6c8ff06d212fd5cecdcf1ee8bbbf11081b610e5efd56", + "0xc3b611e4a4769a4cd86fb97594b05eeaa1438a531661d0c46498ad1d5ff0533b", + "0x86ed5238ab44b097b901bbf7a2f76c4e554227377fd05cbde62ad678b9b40521", + "0xcecc96f7e1da3a85044251681174c283cdf818549338d0ac8c55ac32941c4c52", + "0x8e476a409ebebb50a6b4ea63a57fb97a94325048b98e9038155f44cad234c5b3", + "0xb0cdd01f69adb4482f4a95869c27e7f488b8d645e9da2a1eed7c50db91bddef4", + "0xd59c2ef502068560309402eeafba81b6104e4481d08d294fec8f4a14ebe421f8", + "0x117637dcdf602facd5ba4ebfb788cc6e894172a41ccd461371fb6dc3b29ed1e3", + "0x2088af0cc8a2d219cea2658be188bce545e095d526152531ae04a0c1026e15f7", + "0xbe9d09c236fc2464f9e96468304cb107c1015618c0777414048260ecf3073a80", + "0x0e21d49b429787ecc39920a7b1e57bbef8b54f6dff555afa96c6d664eba18002", + "0xe93a96a4f59c51c991822d4ee0ce843f194df8ef1df1aaa3b15ffd4a3deb2902", + "0xfe432910348f2ae69089ab89571297f755f70d9e52918b761b7cf059bc8fbfcd", + "0x7589450a89b93dd85dda9fad10249d5662653eeb34135a8c5dcfeee2723e714e", + "0xdbcbd8f60a88aec563061478b12c5ab4ceabe1deb3f2df53fd862fd6742c69ac", + "0x4c77ea8aa197a0446c2c85bac546f8eeb7bbce07abb092450f11bb3fb6410575", + "0x465ecdf71fee3c0e42f2dbddafa3cbfb53f4c9a886777cf13dc55064dd29b07b", + "0xd220779d8eba431d33a23b369241b357b399875205cc432069b445426d7a3099", + "0xc6b84a981cf211d41e16ad44b1e90fdcb71a92230c9ac679874f0cecaeb25254", + "0x31841dbf1cfba19ac78cd40136a8ed9f35a77d48fc927e049d58d62b3ff7592e", + "0x0dc4eef3839d33dd5a516a3d4227a3ce23a9a5532d146f37dee88898ee75e7f9", + "0x6859f52e3c1ceab008c2fd85fba4901d7543c99ce5aaf36ccd6534f4898894e6", + "0xd16539f006277c2a3dcd96d3f7e9fac7d5bb0d63afb1d208960e597ce29ac429", + "0xe0ef33cdd414f24ac2e67ab2329d3d728f3924c50032857e57dcc9999e37a182", + "0xf50b311a95bb72916c6d4dad0db9779144a85915a12f895829ca5de9d697fa52", + "0x3f773b516c1779a4c5cec58f6e3a0c1bbbefb939db70bd84ea4370548df29c06", + "0xa3348605b4ee98db29b6bf80eb8181f4200d691e27345732cdcdd09c395f0256", + "0x4f2970a9d6dac5eaabfbb17a916bef4571e1147ffb5e241360c6941ec5628815", + "0x1b7f448f52b39279d47b572e55bfbcf893e7d106436a46db2a0ecd888d7806c2", + "0x89196aa22dbf319c88fadac3c051c445c6d59eb60a62ee71158e4893bdff8706", + "0x1ecc71d15d386ece87caaab915d0a10ad763cdd38bdac269108e17da3183d0ec", + "0x99b80ec779eb253869cc4351371ac8f1896016de0c501271a0a15bc4130f40e0", + "0x09d601e2ef7b509d5343a8b6de63d70f99a453540138d0596b80e2f39212fe4d", + "0x2e0412de93ff148a1365719ef562f54addcfaffa64a630d2bebbe48275377d14", + "0xfcde011b08437d8db6c4e8661b98ec829e204729badd675782a7792648a32c40", + "0x075e3439595f2e5953419638c391ad68d634da037df91cd75ab062f5635232a0", + "0xe1c770b2b8f17b25736880a7d28e09845626879f61fa7bae77202178d26e2db4", + "0x10eb4649692dc022f7542da5156c8005f2a9d6c4b0ac81b5ef087bd989a83534", + "0x612745b3b43e42cb44d302016ab33eeb1924b8ed1a1bc4ea86985d88184a1704", + "0xbc23be71d7cc509307ebd055d02e396e867e74ff401583b5801546b12cfbce30", + "0x55be4d6f914bf5041a111b949ba61807b53707ad6aaaecb347e9bd53251cfc98", + "0x6207ddddfa073ecbeac270e0490bd4f1b126e25523350e45713f8f76074035ea", + "0x7c2806322ae925abe44606def3a91a9546ce5557e61517d22c94a6eb358aeea8", + "0x2660eb9fe82891120afbbf8d17c3a0c6e71a7373bdc961b398fb3924d769534c", + "0x8e94fda030985bee8161a349c74a10715ab29b4c404c4200332a124f8e6c8eb6", + "0x77c264bbd45e806388df32d1d30b7567af8463c310b2e00ac075f202594df289", + "0x11307dbd441966c22a78712e8026ef0be95c009a075b1d75881f45a9547c9469", + "0xd487cb10ea6f81c67836eefb9cf326cb01464b8a4c640359da0ffd0dfb5ddfab", + "0x32e5ceb716c69e4aa115de40404f0406841a43b9d1a7503629edfd830b8070c4", + "0xfc69abcbaaac051ad68462b2b6fb289f093cc8f965a31e4914fc1c3ecca0a62a", + "0xdb2c7749b7f5e8e60861730a3f39531c9fae68bc6d5cfd884b054b14ddfea8a3", + "0xa641637ef64ad91eaa7cb24851870874c04c74e3c57825cc00bcfca56cd671d5", + "0x6e55a7184ed79701a582293b72c847df32be67859a34cb73d1efddcf92c7f1ae", + "0x0d30de75a74723ccaf326a096048686a6236a5d9728e398b531ea34a20273e35", + "0xaf9e881b47ab25b2b667a9232cf562ddb07d30194f6a3358cd6aacc414e98f3a", + "0xbda5685b8567d1c43530fca95e4c671d4f090e50d0ae631eb7082f260036d5d9", + "0x21fe5a7e105e0e2f68698e20f88a9662bceb20bfcc884d493cfbed72fc78ae8a", + "0x1b45a77d8ce14a769f196ac4a195207a63241ac8c8ee42e17c3e0b340b1c1492", + "0xf8fc91a39b6e08d874500e240a6abea002794f104592d18ea01449589b06dc22", + "0x45d9330d6eecf2eaca322e83df77277c76f9a95b99c5fddd55bd77697cd1159d", + "0xbbd726c3aedf917c4741952ee3a21d3c1655aa27cdd98f44d15dddeda185c520", + "0xbce90dfdf79213f5e6c69adfd7efeabe74edd6e2f07a1af7324cea9d70615386", + "0xe50e0dbb2106fa5433506694325d6ebdfdf5270c17bfd255bf3e5e7c0177015f", + "0x22ff7ec5117adf2f0aae8532dd371ad9d902a69babe3b26cfce4a324854092a9", + "0x638b7c73e85e4aa5074daf2daf66c002c00de5e8196c2c01e6945d7aef6661a2", + "0x322d5f71ce4a0e743ce017f6ce76944023e858109a0c36fbab41c796b6f9c8ba", + "0xb55e7340a551bc76ec89ff3ce1c7bda807c75b6a89f0e97ff4a4ea59d232e91b", + "0xe7084bc046f4975a04be1ae50f4e46e69b7d0a3a3886e60f989ebac4a7d3ccd8", + "0xc540174cecd421363ed6b4a95fc554f0ed0a7e4622cb2c0643555eaddebf287a", + "0x03e84b7ce420aa276d9adce1da92c950688839cdd3dd621f797eba5b6986b3f8", + "0xb75090e43bc5790bdfc86a5c9eac4384d099daef3d40e9fde443409f4efe91ca", + "0x7e72b4a7ece28fef076331bac790e49ebf926423f2414c9cd78788c8cca28761", + "0x9b9b702deaa509fface95de5048fb864b80d7891fabdc7a9770af1b24777f5dc", + "0x1b056b381e1c60a3c126f2e5c4ed98252755a5d3b7f3528584dfd128eedfc89f", + "0x8711c4892f49f2c1fb0739de8eaf08ae8c8c279ec73e42fb4da5b25f22d73fc6", + "0x70ae1c1cd310003a4b4e36dfb0dc7351b6f49aafa2cfb5d691fb59a724fbd387", + "0x796d8689110932ef6582af180818bd11bb9df2b06ab1107879612dccc190c334", + "0x58ba45b6ff40da3f3b76da55a0ea9ca63aa135ce308c5d262886e6b1e8869621", + "0x8c2a83da544b209010c6b52618c3137c1066e4fec0e1731d6be408ee881d5844", + "0x1591af374ba5612ece1d642e9bd280a9318c5bda73ed67bc1e7d65ef5616cf6e", + "0x666b3f1a401843af2bfde18ce659965b5c200972da47752fc2b4bfce55625af8", + "0x23331ecfd36f8dc53c388ec3d97a1f364a55b8d701389fd56b867a828eedd187", + "0xd995e1e27b596233e33acabfe03adfeed6d34b421b16d5700fa4b3c234b91ef9", + "0x819d8d3a0471a292c89d0093c3458d12bf83b60394f8c03053bdde51cc08b217", + "0xca27ca64436b71096f37d6e0442a9a93097029d5f4b6d042e2a6bdb3edf94103", + "0x65d5ed59626e98c2bbd6350e4a10e3e45d7479eb2cb6538c5e020fbcb900fef9", + "0x812b423882226db0bfcf2bcb9f1bac80eec3388755dbcf6b613c9f6faf1517ff", + "0x000182526c28c1fb862e74300fa89181cb137a39dcc02fea67bd3a03900fdf4a", + "0x1cfc60d220c883c273603f885193858926f072d3e0094a337d12268007644d5d", + "0x453d43c8dfc8df47751045173fe9e5d200fff28042282d67c0ca9230728329be", + "0x591091aad61a44c41c91b9ddbd1b6159fc9eec6e9c5839c6a0252dfa11436e08", + "0x464a2b049caf36d77652c2d721850d1f8db2fa70ca0964c7f020152612bea380", + "0x8ba06aad1a433193692ffeba643a481e2932f8a2ac35ebeb04c9ff81866d294f", + "0x4d915cf4c14d518463805c6bc92edbec4e8e8689e141c542d743c40640559bab", + "0x0e72daf5ad4857e563921671bcc26eb186f37b9f9d44655341311a6b529200ed", + "0x07ee736bd010d419da4e5c37ed17cf5739a56a78947b4257264acea62b5d6334", + "0xfa03e571d821780ce501373b529ca3de36a53f58e197d64b57f0941288487734", + "0x3293babf49116d584283c915c0c8a26f9c696eff261e74d107dff21e8b2d08ac", + "0xb2f169d84ee6d4ba54b1d526282ab04b7539f216e62362fb20a569f129d2f89f", + "0xdfbdf7d63f67a6986a6c5f9ea2b49d375147b224dc1e489a45fd7731230038cb", + "0x827d46b120f6b1501977fd5ad96fd96090fda549d59922d8607c90ada10ec8c0", + "0x8e15c4714f44297868b988e72b2326eec72e148a849cd39c0447862a9f34fc9a", + "0x311aaecf73140d37dc35479828c96923690265c3591fca9b01b8cad0aa411f23", + "0x47de3df6c970ea79568dc7b2c65cdf8bb630d427d67ec9552cdc928b749a113e", + "0x72e70bd58cd9fe64b27016ea29637bc6d5f13507a803431a14465cdf371dd9f4", + "0x46367ab41a9815df566c20f6f0223ddfec61f02e087e5498402688770739f94e", + "0xf3238ded6fc3b6f389a84766a8ee6663f26a54c077b49ceab1661bd08b4a37af", + "0x0770db8ba56663e8590afb552b42e4db3748e44ff33cf19c483c2bd5cab61742", + "0xe88be10da232234c33a267b9b534417385bd21f9d670fdc0b3e73ad155871ec4", + "0x725cd4f97cd34753d7c39a5a072d2de361f41a4489720a99974df1b821e576ac", + "0x10778832a2f1bfb25ce014c78a2aadddfa245e5e539719fad270cbbed5958e55", + "0x4467fe919d607e0dfd78119a648aae22fc56e508eb68052ad1c9bae0d7c5a2e0", + "0xedcb7a0986dd70d8fed81c4a50c864bc3086a3b34ddaf437be7f445f454d7c88", + "0xb278f42c1518ba3b6d6aec679936d2130915f02f8002f8563b855d7cb3b79ff6", + "0xaa4b012061ef7e6073c95147a118266c6d3417ccd0133eb57d7fdb7b1ba3a5c4", + "0xaa263496af99304030953d11d771ae5e337bcc24050e9c944c9e89650f6ae256", + "0x3f99f4bb34f441ea82655d5ac40ae0a307c6ea000ae1a2eeb2709ffc0c624362", + "0xeedc934109c18a446c42cf36bb5d0b9755b439eb62c18c7d334c13c38d379707", + "0x663b6e16d36687a79cb14792580fd32a7c35bd15df6e6fd36bb498ca12b98b93", + "0xa4c2d103e57cc53f50c63066fb7802b6d77c474ef603e6e6b8ecd759c8161737", + "0x3d381365e830f7fcefa8a466f348f5be81a3dd5c72d918501881244417c67594", + "0xe3ee1ee45c13527eada86f390f69d112b97bb0bd20b40e609ac6be9dee116de4", + "0x9479836ff23cafc57b92900c5349180e90afc75571ec738021dff05f9e2681e3", + "0x7ec50e215e840a94aea029294fd6a48d27905886e53a1239699558631661dfd2", + "0x8c58dc1ee71c06c9a94d5fd15aa8fa4f7d90c8bc8d0eaab7d8d0bb2baa9ae4e5", + "0x017a3cf0c797ceedf53dec3cd522ffd6ad4f10ebf709b20dfe669ba1fe0a3287", + "0xe733cb71d8dca2d6e3c71d9cfdf792c8a6fd242af91fb17bf599eea1b6b75cfd", + "0x6e820e5269a6b6fb9e9c2f477cf796078a3c2edfb7ac8b99150d6660ffd22f0f", + "0xbf1d3b3dae3b10422e2c354533f8bd504b1f5852c942618a0f6b415c3b162175", + "0x12fc9bd3a29e5ceae601c6a4e7c92bfe6b22684cc1f828dbd2127ea56e1aa300", + "0xc19e28d20c121a0345d89b097acbb6c15d97253895d06b8dec219f11f84159a5", + "0x73f03ac8b09a769db2a30f44b77d4d5dd6d61fa97afebe6795acc9c5c10cd7a5", + "0xa92cac86cf8bfc4fda37a94e5f55763840084dabe413f2432c4b50ddcd3523b7", + "0xf7eb6d87cdbb534507ca9ce4cc42a03eb843d608d6e2bb42c79bde78d0dd05b9", + "0x3bffe93f111e1883a29b897fc4b33c50f32db2470d819316577bc38e1a5ed179", + "0xe44f4633ce949bd8312b23178b6ff0e3d72b30dabc546ed5b5f2dd97b490be38", + "0x5e6dd4f45c09aebeff5c87b5e8c3b7b77ce4991f230dc7f0dc62f460e684f371", + "0xf1e0440dc83803d73ae9a3bb6454a824194bf9ce4670adc598ee97d1e150dbe8", + "0xef43649067273a56948dcae0271f9a336067610769b2ca4553eb7bd891ff6731", + "0xd9bf0ef6e8c057bea8046402e5bdf0977eb34bfbfc9f14a37576a8ba09232dae", + "0x38196dcd11fd1c406b5201be0286eed3a94a263a1990b66272c9b8764a5f2f43", + "0xa7e55d25456b2cb9541239879d751e489adfc4c0e232445a9232f4462aa17294", + "0x379ea9b1194e78792ddb00740e0c87585ab9a1060e6a2239fa6c5a9130a2a490", + "0xea0d1449333060d955f4dbbd0c0e70593489585465b37202cb4936164296addd", + "0xac2adc5be7eae9e0a63b5758c964ed5b203f37309d92ffb1d22aaae041fd9f0b", + "0x37be79f2f0ebbd92f82502d12dfe42f98f2e75517f444a295426b6829a6b0739", + "0x51a86fba7b41a59b84cc56d264f5d6d83a40f233f7d316c143c29bf424fbf6d3", + "0x248215d9d66288e4c2ee0c182abece81ffdeabea2b16eb986c14d10d69ae4efe", + "0xd8affec4833fd827b2ec6d4c1905e8cc3266e8a825a7502b59585fe7d5ee653c", + "0x00cdc19f0fa69766a3aeae1dd17cd9f61afe15ef6128a957f72fb3cec4cdc02d", + "0x8c8b43d75591539f17fd442b604a58763abbf17a408958ca181c3593dcf0afe6", + "0x055f6cd0e80234feb885657182cd2fc44fea12c6041d20cad8d257f2b4f16319", + "0x487a48fce29c08736e352e4217ba5714f361f02fb8500ce6a2e9ece79b1ac783", + "0x807974b9c1da9879f8967e7dfe02e8e3fa23d08526963c8b22688ef10de36374", + "0x080fcd507842ea3176b14ca52d844df2f9796b4f1281f7d03180c0461d28b801", + "0x95e5e32410daebb3a023678845b2e1fb9097161681c150450c7b76fb8c5c1311", + "0x420611006cd3a391071c6fa22e82d836b5db225fc266b99e126934d5fdf4ac84", + "0x4bcb71688e5ac4271354485f2a28a3c63d67e028183db2a16b15dd718bb89762", + "0xd428d57137d70ec31c6299ed366f69057d9bf93ad06e62332db04db5c3cb425a", + "0xa384c72f5ac5864dca1aef91fb19d3233e4ae3333d68bb320a583f532cd7766e", + "0x9df6e7ec6a1f455ade59bf1cebf6ae1ffb94d1b05249c35964aece90f2ec9f80", + "0xe53ec67b4d7c04b2c7cc7abd797d6a7c8b759b24c8389d103222f3fc83ade921", + "0xf6031d3cc54fe050642891cb57466ad51e0e8f24a8ac52d592e531b0fb87c971", + "0x842c6b20d8a93c3b23e679094fa903feee295c933c9092ca444bb12f966dd650", + "0x38b30dce467bc4347f65f7c7cc4c8a17f58d58b1779e302954fea9e061bb16d4", + "0xe23303957fac2f117e5749e48e11842d6f5a03e97acefb4667630d281351da5a", + "0x47a9c1072f12cf0f42d209cdd33ec885e6e21d13587cd8f75eeb1f879ab55f05", + "0xaed88507af6c779fdce8b5afe124a51528828e734744d8c12cc289c21d7eaa47", + "0x1b6146a607cdc5dac7cc1a88f260ccc2f5883c8a95665b2c9761d9a119b09009", + "0x6ed83952b5bc9b18ea070cddbcca46e42d1f4419c17a51a2dbbe47a0fe7df731", + "0x7544a913c1e6bebe68a6c04dc903860e5e6fb66d4845dd0d98b3ff4e5c33e3ea", + "0xfb6eea6e7399be0c2673dda0ab64a6802d6b2eef1550341d894f1f4146ce9270", + "0xddb39bcae9dc685e7bee0757743f2dd67b56d26247931f4f184f9e8f0f603f28", + "0x363c1bca93f3ff58a48f7d233bf4617769da4774faef4154abc84a99f39c05d0", + "0xd3a56170fd60ab7c75b33943a5f56ec935471b45e9b31825da160498eeee4c69", + "0x347834e86b3ae5fba9a7873e36bd780317cbf7649c8c01875dce04db8e97f450", + "0xe2295dc1850609e564a072b4592b62ec6a0781477d929c9293e65ec494ff027c", + "0x4ecca654f4c6f701c975301f051efc05e9adf0e908fba6dbeec42dc99ea0c2f1", + "0x6b2662a790d931d1f22062a5dd2518b30d980c84d3bf5b69ff0182aaabb124cf", + "0xcf838b75182078fdd33855bec6cd789f0d4975edc3387aa04246cc73f423da0d", + "0x791a7252fa21bf3183b621d65d6a7b584ce1de93a05da8e44a52572fb72a4b4f", + "0x82cbedcb5b48e87ed79935f8a2f93fa5367c32fb14de3ffd2e8947fc8a61fd76", + "0x84a1a28a08d0b6cf71128636355ea3a045d564cacdf67fc29868deb32ba0df3b", + "0xf97f154b9d62135748f94d714ed0b87012584d784df893ad581c36b5b04ef2f5", + "0xc03cec8562c67e6bbf59f97590560141778f5a265b314a6213c440f5703db388", + "0x50735a0e040ca5596ded470e5068b9b7d93676d8f3d181edfc26b5a52981cf0f", + "0xbbb1b6b1366bef92cc978ce644cfcb951ed00d7969e7d89b77bf2de745210797", + "0x116d30e2696ee09337bf9e1a78ab4d8e2cee7c53505afe2b8f027cdeb34640cd", + "0x294855f629441397876e7a0649a1e5ec1cc3ae8f425c24be34ca45e005bcc3ae", + "0xe54763eb5c965fc0c6ff3e975802f9a5049fc3404fe790c31df8a3dd5b366a24", + "0x0413d30f913089871fa15d643ec78f2503d13d025d2b73a6b1a879a910da2ec1", + "0xa430e9153e8e0d9fbb50f0764a0b70e5add25fbd6d5d29bafa77ee93c483e4fd", + "0xa4c61e3928031abbc4b02a892f19706a313bbdfd5bb413eaf852ce84005f186c", + "0x4e242ca7106cf988584cc61bba6e2185f6b6c377a2c4db291e6a801a5b66e1d3", + "0x23b37072cd63dfe8ae9b84b9bb74130a90bd603a5b992ce78b6e2c068ef35b43", + "0xef7e50ea520ca6a595541606ad895beb80bd06cb68984572396e1ea0ceb2428e", + "0x29e48294e6dfc86bea2bf76ee9daa816a59840ad1c0878d77cca43a67a217891", + "0x419809205842b124efb16d84b5defd6985b3c774fb6bd443f1ef72a2801fffa9", + "0xb25461244545d4b6f9c1c846dd09dbf25459d6492b1209814f22a3323ba74832", + "0xee26501773c29c20a4e860047ce14e4af4f6234736e1156002ddfceadde41c79", + "0x3705a24875542eb6b893c0b48266b141af1b5eac2826e88ca4645cff47a75400", + "0xeeb8999c6eff73cee7ae33ddc065e3b3857f213e80a94d832693356f0bddf504", + "0xcddca06cab74354633b9fa50fcd22c838a9d69a129fbb3c17dd0008df9b23524", + "0xfdb23fdaaf80f26f0e95aee174446f7e7182283d652a332ec075d86f6f3f8730", + "0xb3cf34c2dde0952c0d46633ec3e4fca78a3ee8242f2b46b4fc4444afac7d611e", + "0x2d9485c467207fc78b2de05decaffb155b01446050b7a6679923181dc05a646f", + "0x508eb22f40e6e60ecefdde86c50c81f9e73253ca0658a63ffee65f6fa39d898f", + "0x4af2ccccefa90b3028576e09f522bb667a428560f8c94cb159477313b551e384", + "0xd85f3073e44e61bc52696ff86194679a1ebc3e7dce62805c8b03372e03dbafa8", + "0x86ed94dbc666a541088ec977764bc543ae892d73feb39b0b09dd47664768a53d", + "0x36934b9186a56e71ed0c0f51331a99b3f16f07d5b50a1b770fd0ad91562bd0c1", + "0xebe80ebae860665714be6e5b9e8e7cd5608c8b4466453a15ca2fdf5d21b193eb", + "0xcbdccd3919f1b52732a89ff592a6f1dc34da53f5dc409cfec7fc01ef1f61cfd8", + "0xac2a1fc08c3d4b20db35ed4f879921df5e61a6596e655dfb2c6d5ec916ad6bde", + "0x4e072a9ed4432b5f205808f79515fa1d023cf0e6c2137a2a8876b5aaebee28b5", + "0x096aaf5a90b5e6ed00510bb1af1c475c32fd3de2c800b281d2558c20c0288e08", + "0x0f60a5da86c795d88bc025909c8f4c9484ea6489e900c4070d851e91f27afbe5", + "0xc6532945ae1b3fe27002f5d035eff11c62f6b1e9866f23c52af52cdfc8c19c2e", + "0x7404e33f0864651428778f7a39fdaf11a236c8a68a30674d619546518c380928", + "0xc44a5ea175a1d64b02326e7e49782968d9f808a7854c1e338314766bd96b95d0", + "0x435c5d7e5f41b84a55a11606992a4d8ec543cb5062b46f897954035755f9c9ba", + "0x854e9945fb93e485d4da05069f354093750e8eae98a4ef140a4018f3baacd246", + "0xd9e43cac6d5ec4f110baa3c940c5cf35125ab44a102a621e78d824f1abfacde3", + "0x99e780c379a3a94186a99ce600fe88963e58d61d851c6437f7a5ec3c2a4cf6fa", + "0x32786b25ba696ca57c302d136bb7453a5dfc065fcd17e8c38a47a3806e8d4990", + "0xe4d0e757ec64fc8f485839bd34c5caa72ad0f33405fdea6fe437280b427ee6b1", + "0x65e36e757ffb5386f130d783da437e3c7eba37e80ecb8e3017fa6753cef1753b", + "0x3b5be8acf141f95673e207a7c4df7c81fe88767ade0f785f5165c7f03e284008", + "0x988ccc28f0fe0f667ccab304d7cd0d56354419ef8b7149099d1515aa384a0ab2", + "0xeb198fa97ce093081073e2f6d531df421a9692d086387221f215677e9626c6f0", + "0xd6b98b2c6ffbf467dfd0a6365ccc478aefdd8872cfff6f8176023be4ac1d00bc", + "0xa14078605f856243d5195898a5f1e91878bd5ce04458d2a64b0a6ea7f608a18f", + "0x9ccc3a6730ffaa7488c75a31772c956f911eb7002fc245d803e2ca8d45810a13", + "0xc220e09c2646b44edbc09b43748855653861e2211eadc84e7a9cf9b233c85483", + "0x64ffdfad8e5becd8a87aa11a5feec484fa9bf13ea9e73beb7d92e396589a4f93", + "0x791b62a9fec44f975f11e5e5ee56ca70202d0de728eb6a7acd7c40cdeabf0088", + "0xe0359eae31308bf682f09147977b20f40425ae465fddea0515c89a75cd569305", + "0x16199dc2b3e744a4928b767467d02053576f98a5963a9c123dc760c0e4944987", + "0xbb0a149368f44e9b033245d758f1d906d061bd7b226adc1ddffb9f6118e85339", + "0xc600086572f4ecef9f3388a1fc242b099807e61463a934a42dd6bb683193b8d5", + "0x5adca1ea45a4113c166eb85779efc6836c072293e47d2c746b73b2956237b05f", + "0x0bc8f8aa233108727de0e439264f9220a6d5f085112521868c10934dd4100f7c", + "0xeb9edb2bfc6d973c762e283348290da7f3ea45ac449a521e0b3bc41e818aa702", + "0x4684a177b066091979171a6d0ad0a3eab2e7fb19c1bd173786d2db8b1795e49b", + "0xc877565ea3cee7cc08aef811c986cb58d31358c5bc1595bf8f41da9d2b6833df", + "0xe56178ad5772adca0b3f5eebdaa03af33df4451e2797892d12ccc98caee4f401", + "0x3f02d423f1769519c746b6ff632ecc88f6c6161300579c05b704353a13225814", + "0xc2cb58c5152a16f20d9489af5c259483e46ea76f76778947dadf653fb17703cd", + "0x9598d6265c31d75e15323b7125eedb124361b08f1e695e573b4743a3b54bf137", + "0xd401867574d59042a58837137cae986c1ccf45051165816a28f77274d78e6e1c", + "0xd5bd34c381e34dc538839a4a20a5de9e5c87d944f05f889a6c0bf0abf39b583d", + "0x5802fa750e2a8b4ace972d927c4fee3db2c1c3e12f52a20bcc17a04d1f15b01b", + "0x9b13a2989252a0e796ee57e61889ca55bfcfa49d9285ec859e20ddbc8ae59f57", + "0x134da834b7cc2f81f2582366d270d566dd95fa1ad867c795fedc1d74f1dd78c0", + "0x3cc3ddced0ac6b0833ff5bc9763e5323c375a6c32d588b53b98c7e30b2660c05", + "0x8f79d40ed56567479f2510c4e1e81edaee9eb15c3fab934bbfb6c19583032f45", + "0x423e59300c8a57adb8a20cf17b6686238d3d24ed6b0887573539772d209c03f8", + "0xfb633f9f16d9d9f3889495193d5d5250c533b2d2feacfa8b77a598bd1573e59c", + "0x1a2c990aac12d4e85479edd998b7cd84419e64e1d64b71b6e5de354ac220aa5e", + "0x7d37124ba47aed15bd9f12aba6eb1e4ba760965cdb0b0b8049a2dd1a4590bd0d", + "0x5305defebd2a61fee315fbd92c33a971f901310a837b78a89132a3e6757d9ad5", + "0x90c9890e4e15d5285b15596d61471c5e699222bcab2c40d613a20b1e4d0a448a", + "0xa9f12a1a2b93a8f62ce5c31eafeaabd0f3053ca10382048f5493e2f4a3def390", + "0xd32998eb20d224ebfa0f2c87c23cf9cf707dea92f12dbb5c1cce2ee1ef010573", + "0x58259819f210344220294ce925298a770d4b945f69bf6e310d74428943d513a7", + "0x7a7e8cf127d88a93a5ab3e59f9fec2e0a35d9ddbf90396830c37c0a29352099a", + "0x27a39ae87afd6ea727aa75062cf53d35aa420787f0679a9817b15b77c2fd4243", + "0xea8404bc312c47dc19ecfd815780e1fddabed7e1c2268194de2755767f8c6c2b", + "0x2726489dedccf450d85a877501537c51b0037fd7fa3f46150bd5004160c56d24", + "0x1a6752f65e4199b1d7bfa5385a4de60ac0786a0c2276fcd98ec12480ce9ab3f6", + "0x2d6c57ca96d71f4d23b37bfcd63f70c8877afdcd20b9061372c5a9f4f5ec883b", + "0xd7d2d6c6b39a8bd276806810d77303e1fffbc2065f971462d3549b0841bc5159", + "0x72389b3e6dbb07c0cd4ec60f80d67ea24c5997e36457896c7047dba6bd388c0c", + "0xa683c35204e5d8378c5994a2b2cb66ef7cea7f72ce4a014f9de96e270d141f93", + "0xe73c7804f0a92e71739f049cc6d1f4296d6763694ce0f02222cce3a802b95e0c", + "0xe1d2a0db423aae642cf9e0d0a3a0e033ec287d72ad5d6775fb2ca0b754b5ccd1", + "0x2836a91b6f0a5da378fdcb358773b86fe4e2a497b5a8b0c6ea770f8168950cf5", + "0x207c070a56e477b151ac222d7d5582e4233a84f1760561b2c5ec26b6913b5be1", + "0xc6b82e66925ef9ac29b147459a0c7cf6810167b81d5a0d8119409bfde901e5fa", + "0x54f789a01b71afa8ea9a693866109c0fdbed99cbe60e976593a45ecaa2c51d86", + "0x67428f7da1b0ec6712491af063524e25bf846d1bcf1341fb5cd16de664e55253", + "0x9cb30239c73ca41a78aa23de7a5259e5c5320cb742d86e248e800cd4b7842f47", + "0x4ec478de462ba0bb5ee4f2bfcaafb9ee3fd65e2bcc18b39624db625d72ebbdb9", + "0xe9ba31abc5a0305325522cedfd3106cd0994a1be4462264ae630190ea3fd24e9", + "0xa293c713fa4280c0bc8febf0625bb7abe075f875e923cdeea554a48511eb1e57", + "0xa75d09ee8fa14ef49c5dbe05589f169ef70ee94963b7099fe61e4cc8b4c013ab", + "0xf0942330d11fdae546533e347054610329e3ea14b4f219d510f7e6535c9a3ee7", + "0x026d67e672413886db8a70f720b14cfdfb41adb82b7f439d5ba21b589b54e122", + "0xd49061710cb1c459d4a3386b2885cf835e9817d10381382ef8b4212c6d56d4a0", + "0xda04b4d64907968d284ca3072752af0cfc15ef3e5b866a22477bda9b1ad4bcf9", + "0xc3132e5a5899adf1daf3af4215cae7871cace74e8d876f450ebf0fdebe5372da", + "0x5305450d6a19385eec8c77fbf5be40e36551d7febcf1f7ebe6cabf3190e8fd76", + "0xbd7583e3d3d1af3619f54ae1824316f6d23a780647fb2b357db18076e602ae1b", + "0xcd515185622f58e69ad4f90618097d4c81177daad8719f046d3c14d6ce8375c3", + "0x5d518bf18a83f88660fdba41c8996b1e73dedd6cf5f0debd51703edb9e79296e", + "0xae7b3276b47d580f0275b8aeea0ed17f341a455275b5d8c321525a1258629dd5", + "0xf04a5b0379da532ef5a47e391f9db4a0224bd5de6661840ed9fea3b498bb3f69", + "0x617a8557906db76f6fbe284ef9df52298ecf840346589fc51f624b9686d5e218", + "0xc194d85f5a618d76aab6e49f5de491da2f602429dd772f364fe7fdfd3c6f0daf", + "0x6b138060c922aceeb0254e17c3a3548dd3e6904c61a67e058f961e080b3d9ad5", + "0x4de0534ace9c02822d3cf3d81d6dfbfcbd0964114503b56fba7db23b5f2befe9", + "0x06633e9de11b22610b6ef1fc1e8b952252099961f34d71789d8aee0e2f5785b6", + "0x8bfc843363eeb99dae04524455ae4df46ed6e6664edbb640c835305005dad194", + "0xf2f6f86a2e67a269cfdb62df43b9740b42a6eae3f52639acc93e9a8035194628", + "0x1584d00e4fa8d3f0e989f87002f9ff1851351044f99e6194fca52262da38f447", + "0xdc0801def9cf3897fd30f8200f0b6dc4966209e8879f26a7993154b135b4513d", + "0xb1b0fc31bfedf7bfbe445412e84ebdd76c3a09821a4436e72b95ffde019b955d", + "0x3c4e13e63d1bd76e1db089bec2acdc6fe39bbc6588bf4f4af117682aa8a7235f", + "0x2a6bb94e42fc21a26dff4db8004e9043a7a98d6d9583016cecad2baf37b4e882", + "0x7a0981e129e50d8abf6b5a8e0375b8631ca58ef7f9d39a455a4a4913b8951494", + "0x026e94b9b4b3fd407c2c39f8de81e0d0ecbdc0fc82c9ee8675e1a211ab24dc2f", + "0x60b20d6f87e1f3005df1b1bd5fb68ffe20f1fa54f21843ba5510c8169b917d72", + "0x8fa31f4aa8e666c9bd9d42395e08260525bf5ad2ff5719071ca84bdf6b671740", + "0x3e1e9d1a96c083b9e8c07e1ce163a13e5917db9731b6e29f51e2571fb4a8aadd", + "0x36645bfddd95120b6fbcdc9ad54ef1b1ffc8d0a3ab45851b692351ce2327d22d", + "0xc4589b30dc638fd5699e5e26300aac149843985846cec28590df72ab210c7145", + "0x6a050a8820f15c057644330083fa0b93deaf677a5569caeda70bc641051f9a38", + "0x9e2adb3df7bbb722d9ae61237166ba29ec84075f1e1c0b69077119222326803f", + "0x2e41470d47f517c606fe7cd40eb625fa20e07688e40cb1f9caddd80f27877547", + "0x248391e2db6d16b0d1fff77cfaafa82dd191e83ec7991c9a594a78b15b30183c", + "0x484e31e2b718d4803e71ce2223d1d24f1ea1e882ef0a01cc7704d6b306912e3b", + "0x0a14dc947165f37c01a8e225df6c0449347d987533f3aadcb25abe8066a31f5c", + "0x822ea0893ce74adf36d3138df4a6916e27d622abc1cb055ea8c82ddeb6f1b6c3", + "0x72ef874be609700ae58ae6706b6f4d6aadd5bd3fbfa5e017ac88125250ced8f0", + "0xf7e54a1ed7a15b3c5d99f09c5748d9e0944d93e88c7dbff78d33a9f0174f7856", + "0x5ae68f0dc97744f54a5e4aa402beaa4af17f8dedc81e5e98da566d802f6251df", + "0xa378c978831cf0853bdcd75e74218d0401eba6e8879a280d0f6552b7d4681c21", + "0x5229296eb8b7f594144a34635c87f1bf97f070249800af63827b8c3efc0d8426", + "0x3cecae54847f7732bd075cc4546c97d38963f633aeab68cac58a7d5a3177e6eb", + "0x7c14a4b4bd76b14f95a3cc9c046d609902090d7f15c694be9651ad437ac52683", + "0xb3f4b86defe35acb24a651602124c0595702de42fb3eed8d1366196e6c16402d", + "0xe50e7c9bf26de635ae23f434127b15f7640694988221b210969978a3fe8601e1", + "0xdd2fb9e00863ee8bd9e7f9b1f797aaa2127e66aa8d4cf6feeb7936fa3d46acbb", + "0xc543bb209f2682fbdefa8dacf51720954f37734dc3b1a34af1adfb6f0476bec1", + "0xd377c42d4e61fecde1ef150b4f2fd6fdbab18fc3c13bd6d3cda845e69516d3cb", + "0x622b34f8f3a6e6cdc035ae3359530551437c1e04aaa48c85d3da759b3afc7325", + "0x3e56eb277800889b4ca4a12a20eb33e17c78736636ed761882682ec91468de47", + "0x9c704ca0434b69c8c5731c139bb15f7fad0ac71b8c6863d5f85181e98d08a224", + "0x68499ddc9a08d967055b2e2faa974c93ec7da5d362912f7a164e8a022787f8bc", + "0xd2bb02824aba917a5ba22255e64f8576c72befd94daa60b7aad3065babbcebc8", + "0x8f6cb9bc8007964e4beca887943dc2ce64bd4bec91afb62d9d4449c5705c7086", + "0xd553a7e7d878b1747b87e6306b3a822167a945bc63ce650c57e194d8cd41beb2", + "0xc62ac1e135b490551bc99c70ca634bc3e47502b4be25d7a0e406cb26ba03ca18", + "0x4327232514afa77b8fe208a7a2094051b78b8c16b8eaf9da6dc30403c4c9896d", + "0x6b888ffa7a69d53fa6f70a9b083f7b49de19f680e29f838309aeec7f1821b00e", + "0xd3019c640f0413a1b787e99cbdf7f9d45f9a2c0afcce3288402cc797ce4f06f3", + "0x1baa3e5575457458859b2f2fc0f2bb09ae3f593787c62f1479e84842f69de91e", + "0xad1b8e08cf8cbf3d717e6766123974cf2450dcc0bf746133d71c2f15077eb8d1", + "0x817174986957d2d04f538fe5ca307d1f524a69c80cf97831002d1ddfe56bcb5f", + "0xaa2892eb967f4e588dfc6b6634e5b2aa88263f4b1e1e85998bea7f54f5015664", + "0x7bcaef11f9680e02b0008fc057819f06a1d117e318a43aee196dcdbc6b991dce", + "0xe56ad921fe297cdf000f04756cefabd75d309add549622cf3a7604d0d02d4d1f", + "0x988d447115c47d44f9d7abfdb380fe8927bce830a37b9be320d5154db934df2b", + "0x431001a2fc696bdc0e682f591434dde3344d994232191931c0a6e5d2e5498e90", + "0x6ed8c0e4597fca7c1c74ac524dedfb830714330b020dc1d1b2aea51bc311c4e4", + "0x8fb32fdb2670a4796df796379fb142e6ed6fa2e5f1fd51fb582a60befaf7df55", + "0xfcb88679cc8b85dbdb25dfc1b9f0a4602aa0d787e9e70ebd0a5728ff2e3b9572", + "0x00d82f45bf1088446a2706e923d8f43c800071c8f988239cfce7ad6a8c31b6dd", + "0xdf684190b2ce730df2b1cd78563dde0cab5539b30d0a06247d79f3aec73d617e", + "0xb0f93511970266249814b3073424d5ecf9b47edf7133009deacd317435940676", + "0x073ec7ff65ee722dcc829b69e80791a856a2200560f992316be6bdf497b5eac4", + "0x2d2a90d480df14e521db3dd380b470c29232e44e12838b54b51216a95659733c", + "0xd72e78f576726e546906e0e936baa1fc6625777edebf69da76c489b9ac057029", + "0x03ff5273dc2b190a1f52fa97e28945dda7b88c6d866551c9928a73d6ffb3f133", + "0xe23267e18401d49d5c2d130d91757d17d7dc074d055665fb33d4778559504f17", + "0x89fd9be047d599e128f9ab20b96fc506ddb8c30dd5a9b6782b05f18165f939a4", + "0x732b8ef837394ff6a580c3c21e72a72a2976fa7ee07a7152e0ba5101d5891f7c", + "0xe9999336ab64957ddaea70edad6e72a29b37bec1498deabc5d8341a93ee67197", + "0x49f60577477613545b37efb5317d9142d9f5d6d081908e1c061f6be452216b73", + "0x6fff08789f48c852189fcfb0327acce4e20281ae54c3b821790b2856c7ec1ff3", + "0x447f89ebe76365d8e308034e90241562bde8834dc1075eac89e28183b2a4769b", + "0x469eb409c46e96cd0e75878cde67974e319f00b0d336bdfedc098021ddc4f407", + "0xdd8365129aa6aa4ce914b5f1a917a573b7ee3a3ced4de5318859e8ea2d512de4", + "0x1ccda602493afe6ec11be1d523d3d76c7e79bb93aaa8dcb298e8bf3b9d5a13bd", + "0xfa3a4de9d5c620eb4d160ca7b49e86d99d109bf7866f2baa3d9c99346174dad9", + "0x7b9fb6a8d32f956fe50bec11e142cbfc320221a89e25ea1f579d76b4b2c9bf1a", + "0x01bacc1068711052a28f3e4f7e9fd80b996fe89a0a2bac647ecdc9d9b83e8b1e", + "0xd24d7c8b06dbf1db024c250d7ac4c8d2bfc8be39a0e8990de46b0ddd79aa4cec", + "0x422fd18a2b8735f348c092ca2bda2b69c676613b595f3906944f869e28070d23", + "0x938a51069120a3b4f3081fe083d9246d32b811d9f2e37a0fe6e1cef0e7ff4792", + "0xa9116e660bfc36372df2d1b87c309781403b48116c95f2f73669048bebddf81b", + "0x858728b26fcc100ae1a2bf373e2cac05537fc347790a9169710974efea7be830", + "0xe17c0bafaf4a96427becb15242bed29534970937cebbf3b6759bf470a9884b4e", + "0xe40f175756e1815e0d514af34a8da49518173c7f0b9fe1ef24b1a46d2aeb1ee9", + "0xc29562af361c92883d4ce12f04170e189eb62f473c2a24ccef7145a26e1de030", + "0xf8d3f3f63b252b8bd0a7ec90d5694c36cc1472c261bd45382bb485d11ede5a56", + "0xfcf7d3ab6cc4ea23882638e9de6531459ee27a3140ab491f756c723a52378ab4", + "0xe74cf40070946b562555a93e868313d46613164c5e23236851c8c35a7258947c", + "0xa79ccf4a86e8a34faa518079edabfc8884c52aa41571c45e05b171acb2c53f15", + "0xbcbc83dab8dbcf748bcad7f14c08340ca4f07318a09c9a32399f47dab5e60a47", + "0x51dd90b2af2f1766134ae9b2a82d885a4a194bce1213369ebf3e315d03ebaa73", + "0xcf18e42db84f9501927d969e9a7e4b42553473c63c3995d8e761b76f79c6d3f4", + "0x95d14b250f97721031748210fb7845f4ec78e05804a87e1ddd1269a220758643", + "0x1c73593545255b2bea59520ee29d30291b4731112d39f507ccb8c98252a8d39e", + "0xf6d582117cabecb8408ae4e9520369d72dbca7eaab8ce6842d2febb5a1b22354", + "0xa2c0b519f6b635f06e64f697948248e57eddcdc5919be502ec1a53e7501297b6", + "0xf2268cc03cba0244623a414fc7550f868157deef46a8c424bc1e6f4b70595975", + "0x16f40825d69784d4299039d7b361f075d1336f29b93947e57ae963f119de68aa", + "0x7d63f07c24dc55307dcfc3160433e7d382272ea411b931221ae30dcebc3068c2", + "0xe469c2b1e0a2370b5a9fd6db791e0ffc5bed870df922684706fc6dd425176c02", + "0x13c52a53e3d7d5524f163d70de3be5dc4a5c8bc95c64041aa21fbd14fc0bddb4", + "0x094a9ed475b0cf2c3d845cfbed5104adbb97b8e233c860470bd9c2f967fafc81", + "0x15f1e7ff285656c4b445af048f4c95224345c4879ebe4c753f3f7b3ba4e625c1", + "0x58128af04dd68678ec8a9cdc54183f495fea8353a89fb304ecb674d1312dbc2e", + "0x32081afac331a70b6174ec52c776de2ec27369136dee0a25b58985a4607a7935", + "0x7f48dc400b525c33b2ea17d47260032965a03b6d076ab4d02cebb7b571d82549", + "0x3321b772ad4ffbb3466734db9ab81e4aa749916ce8ae56349698dcc0834dfa1b", + "0x79846e34b081b22517d5514f26bd67190812501c430042b28e510d5fea386442", + "0x8fa6d5ca4cd3b175ba6fee940a941bd149b050c46a0661ac52774652fbef045d", + "0x506db869b12f2c0b153f314477ecaffa9b7c53df20d5b2dbcdcd073a3c76141b", + "0xe69339d7a63e25eac8dcdd9a70c621561bf32ccc1f89624e235819d39cfe5ca4", + "0xd506504ddbcfd1f91ec9d5d71fb5eb6c05566da7c4631f58cb99d20e7bc1d846", + "0xf20c78eb7a7560c9933d6a583ea23f403e6cb9176e0fc9807752633fce2bff7b", + "0x16392a1f31ba9f84eab7172705e01567853808f17748c87d3d2b112bd297696c", + "0xf55d43b56a371be8e174d3f617d662e7b45eb1326c8cc878409180cb516abb00", + "0xf9df7d04c863b1aa10e03c68dee16d0e17f7e514de9847a20a63affc6e1211ba", + "0xef814a0a1681df3972a6b20187ffbf58ca58f9fea6df0de32c1036723164d9fb", + "0xf8b49fffd0ffb70ff19c3c3781ab43e121f90c447d73ce242dd0a0e2bce56336", + "0xa6e89a02913d0e909104b67e7422339d3c93a564b97171db0260c3a8540be2ab", + "0x5216d9be46b9697a34181ca7b0d4627ad99311fe84c8fbf1da4e804bdd91d39e", + "0xd30d40124a55222fd69799407da38503c04f742b45f0127fc273be3fd5cb35ee", + "0xcf121f66227509e3829949153738f6cd1eba7210a4f4b960510a86d999cb9118", + "0x2e1f8a60fc9427a0325fd8150a8ea6fdcde91a13b40e999400c586c672798a49", + "0xb014af1c33675b75ff8c965b0f7f8eeb32320e42ba14db790a5c60896d774282", + "0xbc4867d1c344c81c33554abdf3384b544ee616f5909143ddb6b2bf4a0ba3d41d", + "0x0079e37734bb661b5bed93acfaa18179fda2617c4c37bedcee6654f79f0b2d9a", + "0x2d3cc57aff3730fcfb2e5552376cdff7cbd452842e5256dbe115aa3b1ad18dee", + "0x15288da0a82c6d0146bd29b8d31aa31b6f516f9997156ce91fdb367399e5b81d", + "0xb344ac87a84a52e90de58bab979ec4a2e5fd935836405880dd1151e5683085e4", + "0xde8156dd2e7abb20044a23844a06ddc1590c9ac6732923c21269dabc36bb246a", + "0x6580171454e664a67c320e63ffe7b950df9173af211983c730f40888db58643a", + "0x5ad58caa9bb6f379dc30ef06b339d724a91000acc92a15486c86b2271396bb3e", + "0x0479a5fdaf588b170bc2d8c11301a463448249c848a4f2ecd39cdd5f6fd94a09", + "0xed9335181e2fefe38459807029ae5614e98d1ed80fc5bcad68046d63fa7bd965", + "0xacef0d3fad5cc33c98daff6f5580a7e843c5445007b3edd4508372f221992901", + "0xa147d774480b83904768d78b654f01de94c50d54c2112900b23cc18df088c14e", + "0x620ce3590e2996f10089121597a6c05f2f8ccc94dde95fda12a194492f4a96a0", + "0x606815f9dcd9fc31a2485fd5bb82ab9c4e9edf31c7e31770e89365d643f32a71", + "0x0a8b6fc63adbc84796423326834fb9876a91b585300310964119019182d420b1", + "0xded997869b600c4fcc61119595da1b8574027d64f9c678f442e9f7a33ac90fef", + "0x448ee745b1cab75979a3ac3f99e941ec291c921af8f65f10cec4707fab2aa97c", + "0xa3c7a6580857935652f73fdfdffc5a315020a22a778e584e0b78eddd70a6f59c", + "0xd56555316bb971bcd4ed2dc26b53a667e0def14eec160230b3bc18cd03a3c65a", + "0x030f8abafc222277b1c9e39e2b75ca6c09afeda33517d8cb5fbba73af7e1e1de", + "0xce35fea1dbc514f8d540a72295e2457863d7ae2afb76ee3bf1cfae1a8ef91fcd", + "0x8d890590196c7af780fdd854989e2c776d472a6e04c82b4fc3c3bd3e30d01aa1", + "0x7fbdddf9f6d14fbd3e6217b184e9b43450ac3109da621c919a499db6575dd34a", + "0x41e0a2e9ca2781a6722b1ea5b302e1f01d1b34c80c6f494e248c030f375ba1ec", + "0x7991a805d4f1237190f5b28a55fa603dd5c7a7cf3325024bd2eaad981ca0d70b", + "0x27537dd0a5d7084451cedb82bbba192fc59dfb60bee59bfecb5f26c49019396f", + "0xd3e67cc97c90c09f19b528908d9a60fef68fde3335c041434960405210ccf860", + "0x68b51ea61f57127d3a75b46e44c97d588904bfb880f5774e21440b902c1b7831", + "0xce0b41fa28c47f7a420ea5efe6ec77e413f22b6f67e9fd8f6728ddd73e5c6baa", + "0x9e7b2c49c92a224a444f4f91221ac2173993decf40b21118ff5962dea3969fd1", + "0x6a611eaca85f609f1f79bfce34df97fb975f450e87e1f24d9a93b59ee0b0083f", + "0x70ec7e2b800c43d093f7b1dec60e6743244b4516394ff861e8fa9f265efdd28d" + ] + }, "accounts": { "0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 6aad92505d9..065e3364438 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -52,6 +52,1528 @@ "extraData": "0x3535353535353535353535353535353535353535353535353535353535353535", "gasLimit": "0x1000000" }, + "hardcodedSync": { + "header": "f90214a0e11154bd22ac6a45e9569882d75fca57d12e44e5def1050de0a7b99452fb80d9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794006b2b96ab71a8df73dfabc11ae790f9c8c259a1a0d6216dd88ad006659c6214fd81887150e1bd1f87b248316d3a58cbfe40f521eea026802d5f81a58db8519436e768eae8b11f7de071d7f274487e5b5dd9e6954d7fa03ab8cae24350c9290ed5bb29777ae22498e0b8aa87f0ca85f2bfa74fd95c61b3b901000000000000004002000001000010000004000000000000010000001060000000000000040000000000000000004000040202000c0000000000000421002681102000000001000000000000080010000000010400000410900000000000000210000000025040080000000100000220100010000010000000200000100048008000000000000400800420020004000000208010000000002000000000800000000000000000005000800000000100200000100000000000000000000000000220802180020000000100040000010200000200000000000000000904000000420000008000000022000000000000000000001800000000100000000000008000108412d5f8f8832f60018347b78483449c5b845ae0127896d5830109058650617269747986312e32342e31827769a04a1c4062b2593568cf5fe861cd1b9b9024189927a3c75d09471efa029f7483b08863e584beff5c7905", + "totalDifficulty": "8154014315272113", + "CHTs": [ + "0x614648fc0a459451850bdfe353a932b5ff824e1b568478394f78b3ed5427e37a", + "0x1eae561c582dbb7f4e041998e084e165d0332c915d3a6da367638a8d24f3fafc", + "0x6fdc50234f74fd6eb5b8bb28378583da28963d26c7226e1254e04b676951c4b4", + "0x0d40b71e8f08c4d93a0f62d93eaee4c6ba92ee1ff6e46dab57dc64c992873245", + "0x7f129d232456d600332b59fb30434e4c71aa95b0e3a4f9328c74ec5b97102ecc", + "0x0aff522a9d28bb1a32af4524d049ce9b3e66149e8d2644efbad5736c9fa044ba", + "0xf9adf08eb7bca9237babc37df559297c6e1b54b585867867a2aed7c10cd191b9", + "0x5b90ca8fa35cad63ad662e3696f41c4159fa871e5f77637e018595a626282150", + "0xf33aa648935eb7dd99906d0855c71893b4c0d0c9b32ab8c8b7ae316e503ba35f", + "0x79946d20c81f7aae18f427d991f21888169c96424813461d04a61758bbe9f214", + "0x80950805fc209691ddaea24e8afecd0096e84e3c465940508131f41f569d559e", + "0xd58de59cb3b7f0323ff3edaf9e3af56843258c457f490346cf25a73a35163ed1", + "0xcf52cf0f195caa769e2d5857231f31bf17efed369c358e7ade257f6278b1df0b", + "0xce570fce622e9f3bd03942c63537417f96250bb3605d2182e5a567e961739e46", + "0xe6add695b25d4b06bfa08a80e9e9295c84948fc34202cf24b42c1cc325075d04", + "0x4699a5f1df0d7b2dab8ba282b6e83af0d0b31b604443e13ccf097fd46f346bcb", + "0x1a16f27083787c5dc1dd8f0be868338c78ce147d0cc043b299870f568de20a3b", + "0x2dc5c4538c1812e892e0a53c112e8e4c3fd9f6f60d1e8531a9df5419df86d013", + "0x40de720fa5ec3b58b3be838f189ae59bc4f21bc8d8f406e569339ff054f93459", + "0xc7274c13bc7462d09cbe60044ea6c9e92622204c41dfddfe864d388f830ab35e", + "0xfb6b099472c5457a813698944d4901b766b4bb8a177c4d357897f1974ba6c431", + "0x9e6104a79f7bbf96d117607ec87be8604417d80af11f558ef1e74067168dff0d", + "0xb8deb38b0b58be7b3eb89a5a3ca1eedc5726ab14186baba17ac520a592f68827", + "0x59a58beef1250fb3315291f0b84480b947672deb331980cda261c94ba544e22f", + "0x0fa4b28513f4a3639b427b5abb87902273fdc4077cc0a51361c3dddc264871f5", + "0xf9e1e92a1de2346fbd8b54987960f08a8b21cb0a8a6c561edcccd6cdfacb46b0", + "0x89f4a9590d0865e126622cc47ce2a1ba50aad880161335e8c88c8a24af709fd9", + "0x5f014ca414e0663c92fcbda0c7250153445a04808c7d062859d000c970003834", + "0xbdfc2347806fb9641788978b5d0a6bccc81b11203cd751dfae45a8dfd3bde7ea", + "0x41420d311b7b527ec68770306d97ce3352d7fee50fdba3b05bb54e70c7250459", + "0x3ad7001f1b2b2635266141327ed45b017f334fc3a5f410e3e99624492c489def", + "0x2beb717939cc0404dc173e50dfbe1477ff32c1ccb59f40d7900c2337021e2d6e", + "0x558b53c5eda0866f7515f113ea3254cb85424b739a5dd6ad48bd4d9221006985", + "0x294c62ce078bf950361111adbca5ebc963d5f12c7014b04e3d86d3cc95c6faba", + "0xec18a7c338bbebfdfbd03f1896d726dbb1d21a29e32e92fd9949478078bb19d9", + "0x6e61bb0641c13be0e0858bc3da3a0b06f6a8ac462301a33fab7425e99d6ae14e", + "0x7a4378c70cb339cb4e3805d013f6ecd66ebcfed3dd1df972c8124bd7b888c8e3", + "0x5911bdce0868655abb581c9ce87a51b85b449101d6d52350c05ff1db30deb900", + "0x081f65d017c48967f02efec9781ac4bc124f42a31ad20104cf4ac6553fe788e4", + "0x89a055c33ecf13f71637fc1dd818c6c26e86f4751c2e09c5b8970195b39ddcfe", + "0x83d33e35f31824d849e27d2cd1d4d02812cb84c8508bbb391ba563264ba2a429", + "0x144d66cd98cbac72f3dd9af9b2656529a00fe7fda8f70e02d0ee025fdf2de9d1", + "0x35d44c6849d379e58398189d06b149eee34a267e94230ae5e24a0c58ba3b7d30", + "0xe4d67e58b9be3711015ac016983bcbfeaf2ec71ee85bc08fc2e53e6d173ff348", + "0x67f7bfc9457f1a1566d9acd3700c399a2fbeb2e1071b3f5c908eb56f2bbb9716", + "0x2546b96a4a88411aa7b3aaffd71a0e22484cf526a099d58f1dd330b3209e4aca", + "0x91f9c4aa8357a4835ae2fc913ff21eb4790b711d2a813e94b38fbf52ced0c4f6", + "0xb4623b136bd01bbf2dfe3ccdcda850cdbc6da79b69324a582d3e1c29703a70ac", + "0x68649bddb9b142d43905ef85df986ccc35c5b0796d860b367c21085c9f1d0220", + "0xa007ebec8e3242c209a178e01eb7aac3666fe09370dc1064bfbc46651c5c4e01", + "0x614125ba7478c7ba2ecd062eb8014ad3b50f4d9a7ba546c932e3f0a3c43c13c9", + "0xfa579127b6d13731bddb5c27cff6bea2d0ec13bb6d17679d4d9e1ffce8d7dc2e", + "0xdb11e78fced06b1bd768da0d345f19c023d5708e7b57bf09c37009887e0bcde8", + "0xda9a47b636cebceb2f378d9149a4a5bdeb6841746e7f677942c26629d3d1d4ba", + "0xeaf7cf3816297b48236ea2cf3f60ece988ca7cc97f5c8efaac1433d23c3a5ae2", + "0x1b7746aeeeb0651a867a3f1d34eb0662660aa667847c04d6761507f043d0eb71", + "0x4e6a1631fc6702fef39cc0e383f4fb5608e8a1f0c721b1622c8f25ea14aa86ce", + "0x9e96f3b348c2170685fbaa99c968fadb4bd9dd621f6e913784851ab1bcad60a2", + "0x65df62cc768c87ec256f7308d9f199040aafc24c03d5c6d527bdaef9da365e4e", + "0xdf067410f903d878471fc3b53d020bce9d0b672ebd51df16ad65f4a3468be124", + "0x358cecbaca6506567a60b08d00c888c7b1dd66ccc292ba7c4c9aa3e37b018391", + "0x5102782ac246337226e6527ce651294bb5c3787cc68219208d6dfe6ce398f0b5", + "0xe6a48cff6189dc26c3d7242eacaf1e34c81503327b18087840a755c322665ca7", + "0xbf599651ec19034ca45bec20673f41813b43387ebbc596a57384a813eb6a21b2", + "0xa5a5242eb4e6fecf1b497a62de8138401cae35cad4a9c136d9efdfc12fd53d60", + "0x05eddef47694a7dfc61e79f78b65bcf9c5e0e65513cfadd2957ac3a324f54b55", + "0xa4b5589bca8121c6bc00a846ec459faa99441d0ffa4b577a45984c32d63128ac", + "0xc8a2f9d7974a1aa77b35188d9dbb3fd56d5a2f6c796d2a665360374886c5a386", + "0xe9d430f782c0275eab831108f934ea3bd589c6c72f9da930e9fd392de833e486", + "0x71e85321e2d1a4b0eb48d8493a97ee3634fe153f30a85d1dd55fb0f5f8c82b91", + "0xfed03a8dffe6cb8043a11ccad791096151f0803b020e4dcf33adc4b180551fa1", + "0xaf1beb7795169537916bf4c9b1515effd365cc0e3988cd3e296fa075831fb63d", + "0x06ffb84050198793b580803a41e78d4a6fbcaaba0901a6f938a5ac5f9982f1e2", + "0xb416bb6b94d5076df719edfd2e2bb9237eb2171b9ebbcdb082e1bb1016244371", + "0x60d6170c0fe77eada1dd85af74079ea0387a167341df0ee8ae110d0047c00fef", + "0x15f03d5f617db0bbf963d2daa06816a768b21794d05873131deb677bc3ff2a07", + "0x0b9fa1e7fb11e3c0b33cc609a87dba8c1acca7476a15da2116518d72ea019e0e", + "0x9bba5ba8b88b76613a52504bdde96ccc1064f3e868881cfb4b155d24d237e093", + "0xa8a77eb3fa43914feb609274d1ed96d51ae29028fa59e7f0d174b085d106fd27", + "0x142d2e126b1faaa6997553835ce1933083a5c2cfc9818ae71d559c8571757fab", + "0xe9241f795bd887173fa93f9e72bd7f07ee58d69dede512fc31f9faf0ddea8e29", + "0x526d5379c00d1a318409ea42ceeb7fa9d33a4bdb71793c940e0d1b42cc848d36", + "0x2045cd5b32670fc4c36fd32e45437db69f468aab51e10e32da423ad28bdf85b1", + "0xf0d0bdc64abd76e66be96239efbd0f25ae30bcad096a4cf28b8b5bd9658c8c3c", + "0xfa5cf979a921b2c5ba8fddc330cf1df7a445936f7bc990553c578dc3ca45de49", + "0xdf2ccce3cf15b30d7bef7ca83b45875e96f02e41c6aee9a1a97025f0dc75585a", + "0xb61fe42d47707d473a2ba8483dbd4b9a40c1e7b79c2bff15ff52aec560d505a6", + "0x068ce2cc3d65a152aa574be6f0617ff7e2f688db97b020d8ba84e81ae9037f57", + "0xef3c631c846ef30f6dfdaa901d8d1424cd100710335805e14226976e719cc2b2", + "0xd582c2e6adb0d112786bdf27dbf1c77fc7bd002511e53d0a10f4dbe780156478", + "0x8a028e29f728e414cf7e3d403bce9de7766feae6090ae0f7f787944569f2b001", + "0xafa8f78b22031dfb0b06004d32b6699421586ae779624fdb7153854d1ea5bd4a", + "0x7ff5e562415a97c4f731c7f8a6b82e401705e34a78751a6e8039b0930eb0dc59", + "0x4cff7c84dfe821e917e48089d3a25a88a84983fa5836d7a78fe050915ea86374", + "0x2ba7416bb329d81424f9fb12b43a285eb3077799e71cd21f0095845d2d165c87", + "0x613ca539b0ec3a5819424d8df2f4ee08e03e5e95a2607503bfaa8574270d163d", + "0x3f6ce1315b8feca300da0bd990b582c647b4440d4a218fb4bb6c841a789da37e", + "0xba8b0c45d55e44cec801c724ad6b6b699fa78505d87a5f356f6ef054628f0e0f", + "0xed1069e471b099408ceb19fdca42cb57bca2389dec54b8fd283db0a53ebe2c30", + "0xcbb375230e9aa4f7aa8536f42f4df3a6bd7572f603c03e716a934b0d3bbe475e", + "0xa8954ae2e84ed2c0f45db6e41731a09ebffec9b064cbd12e020e66b7575d2c9a", + "0x9229f2300310a0675f281f76c695b06214960621aaa4592e3bba558c23b5bad3", + "0xe821e771c08bd42b6d926bc1ecef87dd846110693f59d71cc79a55d7bdec4cf4", + "0xa7e54537a3a01524894a0f602bf010043a52c8c7ac7f6cba10a6ebf86ca11820", + "0x3ef166570a593e608afe6b848ab8543957963e63448b7a1d0febb8127003b527", + "0x1308ea66fbc0fdf84680f227d6425e63dd850286de1783300b64ce77deb696ce", + "0x14676109d2f68c5cee4f58c27f40579cc04663dcd01017963402aa2f06fd315b", + "0xfb9434241629e83ec929e1f3feeb1943945e8ce87590eb69a9ae44e3fdbdcb4e", + "0xb695c39514548fe5240723355a6a2eb2d233a48018485435b2d9a63a1097ef55", + "0x9caf7a3660201b0118736033e479b74e488f64a07a79e33f4782048af424840d", + "0x82f188de672c6e1826d70aa5f7d54f499aac011139ecde9d4d05360cd8b9aed7", + "0xdf7367edfa34b79be80c06aab16a54e7d1f74eb9f813a080a8c4af916e3a61c5", + "0xbd7cf6ed130f745c853777d762706e9050c2a45d01839b124d517e3e73206c6f", + "0x474b7557c158d93d732fa0b8829b40c2d9e593206c3c36d7743b6eadb0067689", + "0x1ff6d56aa85903b2a9710b56ad4760825edc5343cab855bc966cad9bd11aef7b", + "0x52c4c3990413706a86714b1dcac8d9c4e55a36eddd176dc55066cc39e308175c", + "0x7a63b6427abc9780a14a4826c45a313fa2d020ea33ae91d48e4cea28ebda51a5", + "0xfa7ec58ce730e3d66c79b2616e14f11b87077c5d911db6bd89cf7c69f9fb2559", + "0x58f1b88f3ae0b76dbaae0ac58673ab38118f5253b07ee2a309cffa1c3f9f3a30", + "0xca98407f9cbb2911422f5a0716c325e1c2ef053355796e47eb619094790da45f", + "0xad072d0b4fcb8ab2662e3d27f6c6baa2f914bedcb91d178a9ab02b9646e6203a", + "0xd8319f885666fd19a5a9801005530e4a490fe29765f9d60c38b60c5b9ea92d5e", + "0xe95daec9ea36ec00b4f9f7478ae136c1453bbbc3530f839e93483fdef4a61cc9", + "0x6eeb1a044cf3cddaa87f70dbca704fe9cad675e82659380fb733153ad452761d", + "0x89c53801a896ebb9cb6c3a881269a93f610122fe9c3132ec19d64a6f22e9f7bf", + "0x81e57e25ce8817d0cf3ca17d099ec20e75f11d32464c2480d2f63a53a22dbe47", + "0x42ddde6c79ae71e64ab091b24e3db68c0c3b560669aeda58107d07f61d9bd39d", + "0x6936a2002771717810dacc23da43097c7c1bf5c2619975f55132b5f450c03047", + "0x0dbc448620312bdf04e118caad4ce1fc5058d0c14b1bf655b650677a2d1eaaa6", + "0x108dc62f87065752fb77f6a3f00e9141e1fd170b9c0538124739bc75d5632b4b", + "0x9b555f75bbc6b9fa5ab1b63b5e7a4f6efc7e9c659a8829a69ec591b968133478", + "0x3f31b6d6e18c7afa96a95ba0855b52a2b0e3158d338ce3a20f14c14078abbeff", + "0x78940ccb7637be74bf6f1735c615054e632ce53410b77e9b1d9f256699a54861", + "0x71b5505cf3b75c328113ffdc94e8ef89b673838a26bee4bd7ce582049592e54a", + "0x68ecd3b26c50447e6483aa0adfd4187a4f99bd1b8517772a9b90f939b322687e", + "0x6c291cfad552325bb806ce314f066f3a7af0ccb5950fede839023b8140b3d06a", + "0xa32f442c4134ff4559c3411aafc87649ba6776f54e0148469b7538c243c19787", + "0x06ab81f6da34fadcc2d1b52982cfc69e20d9451801da18672dbbabe4abfb6983", + "0x8ad902710d008f2b7bf8dc50b66a11045c7e10f80be12f6c5e622c05ad48f2dc", + "0xb85a2abe729f4f7bfebc6a7eddf085c99992d6af700f487a9a2a64164dd14abe", + "0x11039611b2f406125519fa4d3f1cc7f4a89a284be02f0d23971b2990883b4b1b", + "0x69e21960b1ed6da34778848a92b200c8275ec8ae1763e07b8edab481cbd5c1cb", + "0xab4a7ffbe54a07e8b1af0eccdd1fda88d72a25d61bf6b12c9f5022afae936fc1", + "0x8d8fef9f7b0df3e2cbe6cd99ae3ec231c3bf7a583028c0f6accc38d2ac294019", + "0xf8c75352c289c74a797e8673193c505600611433730e415ed877087cad99d3fd", + "0x28b756fe2c8e5c6cfb5df29e8c4f3a9ae149c9d7408efc31c57e5164e9333da1", + "0x3912bfa54cdcb8e6eb1900d7b8d464fab0aa97593b9795802d8a084d66d82288", + "0x0db191d64e9a75039a2fe0817308692f3a163bcd1cd6b476fb5e04cdc8af7808", + "0x7df00cf34abc055979b1dd70e38b364f0b1f9b6ca8a2cdaa8e72dc1c30bf5471", + "0xc4ebe3625665babdf6b8862da0ab84be8fd7b5c1e4849e9c0c2277df99c1ce4e", + "0xd6b86c60afd43553bced67a5e202b5dfdd62e668359eb25e29c4768328136fb8", + "0x46be2d0335c8157496ce74edc96bba09b3873acbe46c285c54e6985615519fb7", + "0x876940ef8cbf54dfda6ffe0d469ac0fc9adb375fdfeaafe3da8345a9db0c964d", + "0xde7c02533643f05dcefdefa9c7cce1f0583a655fa2a9b4a5040ba6a7489c650e", + "0xdfb9bea572e6a60edf6406a5e87ef3fe60f5e5884ff2fdbd9ab5ccc7f0bc602b", + "0x56b30ee04caa1d1e8367f58855c361b43c2c17361e5b242e3b6dc1e53778df5e", + "0x5da53224eafabe23f1a5637ae74cac54adffca2f18fb4a2f506a617370f06378", + "0xe1f7ba27cc89f68862c9cdefcebd4b63419d01e6cc49122f7e6187912f3298df", + "0x67d0b1d84379e0f67466a6ea295a94cd55ed67392e51a6012994218be921d805", + "0x9db5e16e54e0f9310e578d5dc943a5e45ef5b3f5e66bf758d99eb8a7528d2013", + "0x4e0b154a0b06d6544950634de6bbdf511735226649bd694b4194c43aa7e89bc6", + "0x8146ae0e77da83a036ed8b78046f204defbc771ae61bff4016cda3ccb6597cc2", + "0x00cd2da8855d464a368ccbd92907baef0fd0fe2aa8c24e48e4bb6854a011d746", + "0x261fe32ea2985be3ac260b68aea223c4b8e4db240e5fb182490407a062acea5d", + "0x65eee7ac2b1b90a0f5a4e0950b2a0f3a9b32e0928aad7f4243d4bea2f056641a", + "0x7d9e7db3a97919ff2204736eb3920587d8fdbdc97d91f14049f1d41a1eeb78d7", + "0x9c2edb4a5bb85fe484094b0e033cd7d31408a2e2d4b801a001f6f886b92e73ef", + "0x1e191b4674a3a80e09b68efe4c4dd4f38d344ac0b42a1fa152aa1242a5b53e1d", + "0xf498295a3d4e3b72ae1a11fc1d1f031cdcb68aed705be3fd698b5b92bcdc8cf3", + "0xcc89f9c163149bc17d5b0a1d79bf5538a86c4aaa3374e202a7b41cd4a562c6e1", + "0x11b5219b9b2daa6832f206bba106c64a2b9c3aba39f7dbad1feaefd788c9ee42", + "0xd936254f54f45c34c79c8a1ded63133c9437e82c99a26a8bf3efb95ad9b5cf54", + "0x8e8b502743a0ea7075c89a88bd149b8f97846dd915918ab8cb21c7b7b710a4da", + "0xdf0e67381564465619d90165d5677c19a396674d832530c18cef2a348f9671bf", + "0x6481f7abc12e1a5655b0c88a693ecbbe5ab2685c776eb5a9a3485167eeaf95c2", + "0xe9ebad32fa87a2a77c82a6d276a18b0efd6f615361f0d6e72c0a037b35bb396a", + "0x3e052b0aed9cee87f4d70626837c1a49ec169b2e8e03c37fc5616bb0573fe35a", + "0x15245833a84147b5df07f999c6baf27655bda682a5a4db93879f41a2ea023f31", + "0x4820d25f27aec110817a81bea0d7b9bedeeb8d9af55ace79de81380093a02176", + "0x4e156aedc00095dfff29092326b02fe2863a6aba3ebf8add79485096f20267ff", + "0x3b63cf9b1decf710ac331a5db829a5fd2eb0a7da6724c0a90b9525334092d6e9", + "0xb54145d2b41dd0142f5d2487b0db7fa96f42621c08d63edc036dee4b072eda08", + "0x8084c6690651740db4e67dbb0623b5d1342cec0ce95b6349058d7051fbf186c9", + "0x9c6b1c3b15784111ae80cdf7398e1283f4d68a9c2a6a2cd95b8594e0acee752d", + "0x71322541265c9b5d5404e9f089e505ef1814fcad641a81ba3e1bec009abcb920", + "0x1e028666b6fe44f8c8b2c9f3fa8c8ae5f062a7e117d79d661446fcb8a72b5db7", + "0x3a6cd5395b4be2aa1ee4f7d24d1d1433f46db1307c7ae823803ca1df7843ac6c", + "0x64b8b040c6c0cc2ebb2f011039dcb091d4c8f4d338b82fc1a68235c6eeb8c8a1", + "0x89f98b1f7e78b539f83d45c5ce8cb455e8ad7686f42d39f9c195d37ee9cf5fe4", + "0x14abc82071dae6f563f272da9e1ba7f9ac6f0547544cf9cdec088ac6283eb464", + "0x6aa6490aa64733dab57d954b9907f421c6c571ab2b2cebbd833d59d74ba19be3", + "0x62e4524b07b9b8d8a53cd29e457a58dd9f940141797f847b889023c22330db0d", + "0x534a4c4ffd28cc8c3f9823826644138c9207255958f3dac5d0a5f279d57508d5", + "0x3e7f74f25707ae6686334c585603253a21764cc1adc730353c02a56f6b7f3e81", + "0x59cc225b1c9cee2ece86b3093a8bf6ad3ae0260ee760384f1299b5af75eaa1ff", + "0x15ee9a6c566674f1f7742d1e07015fcd66e22d7648ba25be50428006efccd026", + "0xc0668ec3f88e6a9f1097050e999f0082e9a39ba43fccb194790e51a41602e704", + "0x03b0cdd4ca4ca3d8b1270eb9b73dd28f22ce5681c3e0dd5d11107719d2614de5", + "0xffad54056c851b02f83948e7d665980f623643ef40aebe91936c3bf0d24a3a2e", + "0xdd587650149a81f7a5e92739c18af1216bf32ff2cd7b1c908a6d3100c052b0b0", + "0x1fb346da4fa3c0b7d1acf87e4e8b9c0b05cf41d21794d9db58b14e321f9b6bbb", + "0xc15a230b3105e4c549291228b28a3ded073e7061f56bd31a8bbe4570e2e11910", + "0x9c01dbeda0dd9cfb4e70e8b63551c590edf5be26c879d319781154c44520aba9", + "0x8b418cd11db8823868c9495d213b9e5c5e0d8b25d5f7c262f21b3d2b9f591ea2", + "0xff7cbadcb60f8e9574e1a1ca57c0cf1b5b26725a7683a870b581734ce906df73", + "0x0efe88c68a8404cf9e1cee6d4b863c48ba502c5b5f504dd8a6f251122138e651", + "0x87994dbe88b7749a347e438c76273ba5a7b8835449d32ba75bbc877979e5a3b8", + "0x366779f7f70fc10da80427ba5f0f6af0e1b5d60c37c0c7e524e408a1e2f261eb", + "0x616c1a9eeb13a026372b099a101eece0cf0d1715dddf192147d401c722b6a6f8", + "0xb35494e9758f3bd7bb23fdd9c86f60a8bc73e3422cc9be80c7f592fbcef26b9e", + "0xbfcf52fcbd301f4b5d32e62f284f95d01bc545e16f806ab64038d11be74f8638", + "0x3f155939a40b556e30ccc4b32273a3586fd5aa89c4209337da1ecf145416c6f6", + "0xc23227be04320beca30ce9ee2b9f74bc8802414ee78754d7af1bc887e1e260f0", + "0xbc45e7b6bab510e72479ed0a675a05217244a9879be26d24780a39537c233f10", + "0xf651ff7ae3c7570a95245216c9461fbf90293a3962f8883d502a92277f0e4ecc", + "0x92b1b6ba3f6bb8a949225e51a480dd63152147e98d96ff5aca2ddc81eadac6c5", + "0x368b2b21a1411fd2d651c12cba2f2c3d4d9dee020e98a63aeea861e4b6837e12", + "0xe52565a7d159275cbe9e024130faeec3ddc3c3e27507d35d92565c8a56e13c64", + "0x3252703f9e4b7ba715810126ba57d87bf585fbec8e5928aa598c577f11daf792", + "0x6283fbe3a436d7860c0b564f2c7a32814c189093c775a8d800ae24160dd3e72e", + "0xe76378b3adf8f756728c553a5d822afa016d8117cb04a24b1c2a1eadd62421a3", + "0xc0a2504fcbb69d1adce70da836a73fe8e8fd74aa7aa4cb7d22bf844e7b91aa89", + "0x4d3e70bd5f122962b3cf64de57c69d85194126d71e79c964fc4397afe252da25", + "0x7efda1eb1564ba1d295eb6d403d9900b3336f081f2bb6de2c375889883f64097", + "0x6bdce19bc957c2bfc7e49f91d436367374847fdc6daae2e621f00aa024f78094", + "0xf42d152632eb0a55173ce7ce4cca3a91c7d7971a7456eb6ffe88dea54c3182df", + "0xa6a2353ab4a3bda46687cfd3ec8e349f2ed61e449875b9d1580d9a2370ccd54d", + "0x3aa4b80ff21dc79fac0b4f913d46687c4f991e5005fa6af731c9b2d10dad9c81", + "0x7d1022dc5a7fad9c0291448c56eb99283e1e64c37f6a55431843644102959d6b", + "0xa918366830e62330c423ce2f03f99206f6f3c1bf7660e01fafdddc40c8a0b650", + "0xace8ee8ad7fb40d481f20b165ac8012f3ff69f0bd8fd3ee290d894236549d065", + "0xb03858a13f584d7128989a47ae71d945dd67a3c2f54ecb3368ab76371d944c6d", + "0x56c78acc4c4dab9994018a969c3d3451300f8229d018f6af2de91fa4da6d4230", + "0xfb4313d83488e1003d38869fd8e8788d7e74c124542774ad7fa75971bdc61131", + "0x1decf505cb4473ffb91dc428710d2a2188d57bbcca71b7b5e277eaba0c7252cd", + "0x9db499b44cf0bd96713ec99cc769c8454fba3729014d87b67c18b55f0b4b9fc0", + "0x3cc717a489465b21a09c3fa19453d2a8cddb914b7d2789c21db6c311386e0f80", + "0xce4868287d923f8b22aca7a1df1ee11685d7c50c6384994ded2e99fcd2c01906", + "0x06b502cc70d1ae3c79e44a421b6ffb9a1a6f0bc647b4421cb375ab5d8474c713", + "0x4803b5e78af29ff140e37b23bd2f3de9fa6cda3a1bea2361e838061490708d0f", + "0x874051f592d34ea3684460f094a78d0e1be3bcf49586b1467be0386f1f9e3d94", + "0x8b66caf3a57d9998e2d88b0e4ff296825b6dbafbded01e384fd87bf4a92c5bbb", + "0x61f6244709692f492cf345586212374f4b209f1d2f92d3ba0e4000ad0634bda2", + "0xc58788c015dda34717586db2395a654f49ef0bfb4642459cc0ac5a5d74a2fb67", + "0x5161b49a84d5c614d72bb3e220878afa94d9acd30cdeef78873dcd91233de390", + "0x5e358365657197bab7481eab0dfbf8a6d66eec8dc62aa345c5364f75c07b8675", + "0xb358c9e7d218bdbb42f91752d03365945a474d49e84dbb15982e368def01cffc", + "0x908bf24327cfa0001d13fb5a0a73b536132e7ecf66d47f2c77215b03bb5b1693", + "0xb041e9e1a1087afbf41d87aa9e56195cc548527c81023d43416720c025b896ef", + "0x48ff5fcf252fa38a00aaf887e108928755932f45d7cef5a8fa0b72d711789f66", + "0x16f99b5d528b9ea7a92e5f7ac59e60d4305b71c9b20485c7911f84e3ddd1802a", + "0xeadc395d16b240b8412e14d5065a33847fcf8ae122d22f24438d7f79d8cfc40f", + "0x560faaf4e0471cfe39aafa10c9660d61c8489d2c5d49eff2a8e62ab31b7ec08d", + "0xf1c8bac46e0764d0faf89556b0080cc7b16433070e1e945e83f1ae36595da7fe", + "0xcb7409cbd3d3104a4b5d856887fe6d390643b4c433de855644f2184218631662", + "0x6eec345c4baf4e699f0ea48bdf54b2e74f98020395759e275e7cda0138424ab0", + "0x48a8bb061ad00561541b4e19009d3e8c2e2b9064337ef431fde45fb2988136c3", + "0x458b21c6ca362ec731487499486c4c0ea69905c8f36617810009edac608b9e20", + "0xb338584ad517b679ea52ea9abfc8d786ce1eb55cd3f221782de658f75b23ed47", + "0xdfe64bd8632a87d995972376311f78a0fd390fd2635e002e3dcd7838a3b28516", + "0x49d9ca4420847c21e2969911b7b5f321fbdac5037d0d8644d6f357444f91238f", + "0xd654571d72fc11d7a86ed2408cd1f78e8009dcd117323c8970614ed8731d66d4", + "0x2133c8e084efa57df6e1b4f1af5515a4662809d722ec002676eaa99987a2607d", + "0x5bc530b5fae32bc84127fbe7feb7eb07432313915e2d579a668f46fdbe46bd1d", + "0x8070890263bff747db0122240249361f5aa66cf121c3b6c4ac40deff6e42af5a", + "0xecd7aef2e4b4419539fa40570a61a967a0f296f524c25de9cdbb012b03d8d837", + "0x4376d56fa5e09c64156c6d1371151a33f7ac1e46635afb37823ed75287083bf1", + "0x50d32b39873466597d5fd29a2bc3596f54051d064559c46510f643f2c24e6319", + "0xc44c4284e5cb873846761cd012e0d221763c972242c0c4a161f3fe0e2da74026", + "0x141d2894e4cebe94df908cf463d5aa6a95e22624f5183d03cb60011c0677eaab", + "0x1bb68700d0f6e052ca64c983352731ccb0c3947ec73d67ecbbcb72c5ae3791e5", + "0x73095bc9acdbad7044390e72ae6c471c8636dc0116e2ec322198bc080af7fb11", + "0x66bbec6ab32528486c3ad89c36fe750d9c6e5bec862ea683988ba578302db503", + "0x979820d20c32a076297e3a940ef4b9f3ef02c9ed551996fa106b6db778852e52", + "0x4da1d4babd26763bb29976f0f2c439d3cdc06089951d0eeab7df2da59c128454", + "0x4c70dd6d755e7fe3da5f94dd2af53d037bda9d7b1eabb68bdb75111ecd190e04", + "0x87ff13d01ebf46a5a45f5b29e7026117e8b41d135829457d80918dc00a325f0b", + "0x78d573b16ad8a3c3b0a704a01fa79915907fbddeaca6c7e189c5c586855ea882", + "0x95b9c87ed9b7365b1ac15b02a388d47f75ae8036bf658850ebbd8b829ded9186", + "0x812fb8d5c2d962725245a182d0d267fbf97358d5c236cfece3fb398fe641f78b", + "0x31db1fe9db91df6684660f1eed0928bbdac477bd1bd376399e27a53ce760ffd8", + "0x4bb0cc2765ae336b21fd1f983f21464e907c6fa4831b047386f64e021550b2e7", + "0x7f6317d849a40784edf0d2c7b32f57569e561efcb4fb3c5f857b30319a93e2e6", + "0x5921a9e8ccdb11e574a012cafcb05a6dcf86ff8006595837fce805675202b8df", + "0x5357bc6834cde24334aa697f050c51c0456f7b03f938819baaf8c5be1dc10df5", + "0x8fb8b01b64eab496c9496179016adac0dae5ff6793970b3c307202fb17a93af1", + "0xd4ad4478bee0d5bb0852461107c3bef946f147f66a478789b39f7efb517b3bea", + "0x630bd6a0422ab626b28f205ec9bca83c499462556cd8116556bb40ad0cdf0e66", + "0xb2d07716e5e20312f314cde99480110794d3cf70ccc786828fa25ebf97ffdcad", + "0x87fc5c3371e3ed8f9201f61768fb2683bdadf8c3f6a3039c3504107b07b508d0", + "0x9e67bf7118e42faff0aaf8aae3118867c692b27c35efcbfd057d562e8d4390d9", + "0xd96833f813ac20074274531949bce0637e06636b6ee8b875b4811f09cbc8c116", + "0x4e9f29f98bee2fdb5c5692d94bad8f87b6b2904258549a937603da0ab5d36b65", + "0x77c3b0bee822bab79529cbe96d6847649d9528399a488ba9e94484f7059c46c4", + "0x948d3eca01db52a52679fbc33ca30aceb7e3ff6449463a2748fad0982b75313b", + "0xb3084fdf4a2ea5228c35adb20017039f4ef01e97d99aae08d4adf591b96330c0", + "0x5bfb4369df41aa75c957c1fffd6b498be3e7ae858cd53f67c1c688b9c78afc4e", + "0x6a2092f54cfb6c26b0d5c8f559e5e9995c79873db7631a8f6397ef5ef815352c", + "0xb286ce1787331698f1f860e1232f6766a658d27390b7623d460136a6be90a444", + "0xf84ba9ae60fe7bae5d3eb5be6c6b85aa564f8d0a7ffc479d4b0d1c8bd69a2adf", + "0x467550339dad58cba021e3fe967bd5d81be04e6670488adfcfeeb0dab07d6b2f", + "0x5150476eb3075df5b6ab3fb54ded34ce76e06660ee401951652e484e9a3fbd62", + "0x80845f54e9c21ee96f4aebacad6d199416a6b30fd741d6e6c9966f58c54f1364", + "0x8264045a020782a7dfc047efdfaa103bc186e88c920f2c25a016911fcf33fa2c", + "0x52399e942b721929b9875c274ec6b5034c26f7749f6d26eddd99972370dad3ca", + "0xf03d8bd2bdb8ea0b6ae2e7bb55703520cff714143501f291a3e7199be5d466a8", + "0x40eed1aa25f1a87c849f5e02f846c991e7473af9fa0985e3d61bdee01cf0a5b8", + "0x3d18c888cc8729f63ee415348121e10b5d990c8f091fccce7e2d8f5c0132a20a", + "0x2e72d969de06d28196506263e6dba8310b6854b5069fdf94317a6d3e90752560", + "0x2bf249dd628dec9d4cb267a9013e050f0710daa2915e468a623748dde1a036e1", + "0x91c578ed45a55d0108656d1533d209de851f77d9abdb58265bf867d7aeeac5e9", + "0x88dabe83eea11db59d67db99a159c623498cbc648c79d829a317719b836540bf", + "0x5fac0c3efa49004a1af631263097978f16f7e6710ee7a1557432aa727e44e09d", + "0xa8506487d3c54e70b3d6e83eb72af7858f583527ba6f6a6aee6a3eb33750e538", + "0x62641830df38adc76a043baad1fbbdd8e49356c11b6565ae0b04429743011b08", + "0xf053195e1bc2db0d0451ab69471520d0a03370a8f27a4f62a1885702a36d583d", + "0x7197d7a7897505dde22c7a518054d9df7f3368fcbd109cb596872d92f6a86fcf", + "0xa5092fedfd64b4985e70ffbcd7b4522eb45f9bcabe4c478b1f1452b063d6d551", + "0x027251c22748451514c27aed0f091e7589600bdfe816ffb0a5ba99d55265b65e", + "0x590271f52852c220ae38b56cca9960a1fb94d5343a0090bfeca5e8b5bf82b2c5", + "0xf8df310ab62fd52c452122deb0f2e79bfb85bbcd0bcba7e6aa5a99a541233431", + "0x5d313f0071f2d885da1b1b5d104b8d78ae49842ff9a636ad2613ad9e90b4ea52", + "0x2672988155e5c27a3af3ae26e74d164d9f52b4c71b74905ae90466113e991692", + "0x330c8cb081da0372f6dded08c0036199e11aa8ab51f6f9869995cecd3eb16f24", + "0xd65721d9678bf4667c6688af76d2dba106fc51e8396b0af78bcc80bf4149629a", + "0xf5019f4da39e5ca6102679e5a0388a3850eae7bcd91c632d26515caef12c472f", + "0xe9c747dfd6af4dc29b5836495be42673a20bb2475264a2f9bed00eb8250fea7f", + "0x2486ab886ced7bbdd774371aa0ed1c177d6d187bda235a4a8fa390b704eeee8e", + "0xa91824527f5a40050aafe359817594b43cfddbe3977113207a7d5868507caa19", + "0xd44591357b62e80b8f5606eebd4cac5052efddfc3e6a8c5689660d6617f93b33", + "0xfe5628e6d9dc75f413cb12ee1004e1514769ad7085b5434f762e93db9115b78e", + "0xd0393986e30a8961e01ede613787fd2e6fab42db329d0e57bfd16b42cacc4045", + "0xbe40cc6ffd2d51f7658f48359d4b726c64a354a9d1becf189ed83775f8fb4086", + "0x1d06de0ea61fd233ed701c9520f18012143277ca9b379d39db62fcd0a4e7681c", + "0x463ffe1d54544945f4abd7e35cb7c90a4a809c25e1919215207b7d2a8d3b4fe9", + "0xdf128c4d6c4048d4fb0f7db6db091ce4de10d509c45736f5521ebc4ac93a7ddc", + "0x5ed827eae4b7e95cac552d60b60fa209157f1a8c6e3611c1a5f6f7a49e8a6a92", + "0xd7fd28964beb50a410de115f290a0140fbc78d0d4c47ba02afe9f47d80df5e53", + "0x1996f9b8f7efa3d860233141774f46c00b63f207219c2eac5e61318a9464d7a7", + "0x4cfccfc8a9623fc9b5ab38c991999f8a52c6537d984ecbb0c490ff37559cc51b", + "0x4aeec05c7d47781008273281bd01b36c5ce21916cf7fc9dbf79aa2c477923c1f", + "0x96cb38c2449f97c92c81f5f4317b15267c9c2f4ab62240885280ced5f54bbc53", + "0xab5e6b9e4c4a27aa725183699ae30a6f8bc8148bfe85d1e4d0bb8565502e6e73", + "0x23fcdee9cd75706e640aa55c4e8acccd7ba9591e724bf351a7070104cdc698bf", + "0x5f3433fb2aff1e3843785b2f2cba22811cac84061803a2c5fd045b1983c8ba81", + "0x5613366fa3c323b091a44d10ffdfb1f485160fb45094cbd52707484f820cdae5", + "0xfc43bffcd36963706e2bac564dea4d593c35c5156de02eb747bc557988d628cb", + "0x4f23fab93388bc79a879f85c3efe0f15606828e6034cdc6b66810a90cdacb793", + "0x62ebc41d0592d1569001358ff3f1641c0a6ad89e66b0fd1e784f060c9101dee3", + "0x12bc43cf16c8965f106f3749bb6b5d9ff3936a205d2ef5719ee637308f81ea24", + "0xe991829e5d9c26cd365f6907de1fe2f2153cd88a7d7e8e56224c9dacce442fa8", + "0x55679ce947be929966abf9953031fd172480b7da8be0b34344512406d93764ac", + "0xae1f80cf386c6cbdd1ee0a1241e738c245eb12665f2fd1a614391ba54c741847", + "0xad12a941df30e25584f19f5aa65069d919a2e0dcbcce73de8724f975abdceef9", + "0xb3478980a68ed409b58d35759d4648ce21ed97758a1eaa0d0f1ce6b059b6da41", + "0xbec5fc3e9184d2e46bf0ae39c408a7cc243a41b69a923fb2d1224638153b3ce0", + "0xec95c1df965aef7e6061a770e0c82b6dab0027dccca5ea3791ed207b868098ed", + "0x2bd64bac83283cbb0bb5f7c1d461261a089a40904574e2daaee97110425092cd", + "0xeed53a58f04a07af388b098bb8c1e49abab852736c84d69bcbb78b945f23b86e", + "0x2c2c81b8a0c362105ccd0251119ddb406b65562611b2c3b3fb9825dba0cf6ac7", + "0x91c93ff5548a0462f1cc7cdf0a5c57dfc1f21932dee38e25759c9e5719036fbe", + "0xbb1c1bea058893b30e38cf0ea2f53b943fd6bcafb86b0eb647ccd152aa42dad8", + "0x079da567e28f61687250a49aa9fca4c465245cb0ce02ff075b500b203c459605", + "0x691de81b04aab67b3276168be7dc43e220114005a4d66a1ce9ef2665cd2bc867", + "0x3deccfb1fdf3e57aa2d63d0692cb37f375aa457da52d88cc9cf277c32021bf45", + "0x6cd1a84bb6976f2599898aa46fc67627663738cdeeb815ef1f45762cbb14dae5", + "0x29c96ea5d11a5a761ff7c64b24a0892daeed506b8f7ab33e93d6eb6023b9b37c", + "0x0bd8890f06cc6187a1d1a029cb319df75018b067bf796591b0b0a07a2c33c008", + "0x6a3d0b949241a493d2eab974adb173daee1e3c791c2dce6bfe59b127f8557ba8", + "0xd102ccc0476081c8d399083930dfa59486a51f83d33096ce77897b9b0fe41b1b", + "0xf9ddd66ee324bc7f06544cd53f792dba6697c1ecfd4c40a44733944f7e7ebc91", + "0xc14b245a2f2d02ecb944acb218d76e311659cfabcf72f9eb49db59541550b6d9", + "0x190781209df0cb64a4ed6ceb15428699e6b67f3cff28b7a987988a8e29829171", + "0x46605aba1cbee0bfdf90b57e320823ad4607d9ea1d6698005820021128c472b0", + "0xfac04645717514b9ec56f85cf0e6cae5aab46e25e69e3cd010513d9598d56609", + "0xfd0c9f959513a72149bfa23b32c5006ea766ba2e41edd47f450090568d44cef6", + "0xf0560a14936e66cced54d4002599808b127f9e56260f04f144fe9da412577c61", + "0xc9448c9e8a3b09fd51ee93b77feecb8a8ba03e1781a3f5bccc93b4d1815232fd", + "0x3c41d49f2aa53e90f5fed6f372c620fff5a80f442894c71bd7b6c2f55ed76f47", + "0x0d9517fddbd945294c72ed49bf6bcbd88d84c9b3b2e257c05f64bb69c4d7815f", + "0x1a67fe64cb906429f47250e1a30858366e0204c3f39b7d4b3f121a46a51566a4", + "0x9833e385110465d72ab133f02348cb33433f38454f6e985b022720a9836e5015", + "0x89f653efbe7bdc469e2896aedb2a22ce5982b919a7c6dd14046db4eee3950b6d", + "0xe92427a7878630f65cd4f38dcee4c5d87ea0dc3d0ba1720c0d9f53cd84411b7f", + "0x1f692c127e4d0e37f55f24f5c20516c804dad968b5dfcfa000595b4682aabab6", + "0xa3557041302da75734accb2e95db335abb208626e1b9d20a54ec0e0d23a5e003", + "0x96bfe30b54d1f39b5693272ec7cea523e0531cb7fb805e69a820888ea747b3ba", + "0xca8f5d8fdd17be423ad5bf84d7f591466137a54388b65f5d853aa83ef25e9b42", + "0xafd729d01c437b299b29da02e34eef0b8a762a24447b96c0499231a17a84fe7b", + "0xf95f528a8abcdc0eeb66250fc3d1df11d0831a08b30d11f0f6f0f96b02f7ef82", + "0x483de90f340fd0035676305359fb8c83b709374676796c86c4d4b615ac779b5e", + "0x433f6ce08d28351388ef6310847d7949f4e92ec99d585c3cbb5fd7152baa507f", + "0x77dc56a6b802ffae812c3e4d8768fc3d80bf96b95a55b1b9736a9073ed0093ab", + "0x5c3c2bfb8cda1218a08084c4645e2a84fde3aad03ce00c3310b3ae5d80e25be2", + "0x3321f6475c8ed111a1373bdeb68609f52c4740f22e4f13952e8a6d98fbfae542", + "0x7a0c172b717acba8a7b874e6c88257cfe68d41855506ee909d84d23b028a7ffb", + "0x7ae3757e9cb71b9063d79db76109af96ff1a5e6aa1183b1b70150757243a94e1", + "0x4ce794f4c0c9273c14e6faa680e8837247c6a0ab503a82432f69529d4f5530b0", + "0x8a0ff3d87111ac19f2d95d813e384a96dae3cb15caf12e50b99816393db3a374", + "0x35adc4577b9532f5e821d6a39029cb898886ec9a8b938bde92ccb1df67d2dc2c", + "0x84976050b7ccc3c953976162a6406d125edae798bc1bf850b8867b3242076a30", + "0xa64d9c9681b1192185c9570a6512d8b21483534bf0ca7f457acc96f91070358d", + "0xb27f0ed2428dde6c5506770651e3cab0fc62b71be0f245a8f6a84c326ebdf327", + "0x4f71b19b200ccaf3d359eee3ad5d7c155616b86495a43e2a7c18d0740304aa2a", + "0xf22988f8c5443f4400af9895f655a84b31e871a68e74a396ea5334297c0fa190", + "0x37dbed2e2f7408ce439ab0ab09af040972021ecd606f517af45c195a80e3f3f6", + "0x5165c41b008baa5fdd010a9a17f0c2fae2a0f16b4d230c21bdcfc737e9279c23", + "0x96ebfdbfbc02fbf12acdf622ad7ffb8dc10299ee66c4ca956eacebc6073fad75", + "0x47ff8c523b69bd123ebc4ee8a81240f2bc1c4e8dafcf9b9cb5db5b7a8f4c884c", + "0xcc3a09c1108d216199d7b3412f86d73d4fa7585c393dd3ed95ef0320f0f9bba6", + "0xa79133fa77c790f4f12a9bebaf21531c831c72db93e4a36a8f2ea672260d74a6", + "0xfaaa6544245fbf22f3016befbd4acf93135e64f69a7aeab07599af3a52f6323a", + "0xf489992872d1dddbba3c6b2fee1eed0f604f02e7350d747398944bcf4fac3171", + "0xb49c4387382e339ed00cba9469275920e116ea556bbefeecfc9c154d2f1c1f77", + "0xfff493a58d86d6160d9bdaf60504b07d6f33412fee522af09c1a7de8ec9fcb05", + "0x584d1e0a2569cff0fc1b71c850eee0c1f680037cbb678bbaff035c49ea5a6275", + "0x91682c3606944042c10a5fed5e6b5662c39cf980471b8bc603042cf0d455842c", + "0xb979f301dc2bed6c7e60bafb112b92b22b5f173f1d9e8fd665415bace1a580e0", + "0x71d439075aede2a781f1a872dcb8c89846056f5317be5df5dbf47904d106938b", + "0x9c2353de49861c4d10309f99457e6f6d9e5b7a57360837aaf0a1942c0440fe9a", + "0xc2c08c3e2d8741a4b4bb180fee1b1d0cb54f87f2739aa3881d534a9c73fd2d1d", + "0xcd75923a659ed6e79c9a1e22201374bada6bb2e030e3664763dda54552bddb15", + "0x60749dd09da7517a03cf6baa9b4623198f4209f1274c00bfb234c61d467da12d", + "0x11b1893d89913c9c57f32ab875ed403fd9802475e3c861472dab770d4882192c", + "0x26ddfbfde82876e17d6872f31aca7f233f790b3ec0618d6b5c51871c9700039f", + "0x8c9ceba1e4cc81ee6103acda0bceebf5b0413023966dd5c3c5641453c96c29b4", + "0xf30e9e6f8456fb427f96f356eac399fbee64dee3ec4a2806701c3484608c0edb", + "0x7773f80e3cadcae69cabda956228cac8cf774bfa84e2ce92ab2872ed19946858", + "0x4d510670cd4036f534fda9c7b4ddc14aba28ac985b90a0bc831483621d44996b", + "0x4e7d6a0fef6ac54f4f0336961561398600d0c6a04862f613ed6eb648d45bd348", + "0x55c0bb04ee6e1aa15ae55e1de229ab5a4b553864c43cf527f2ee42d441bb0bd6", + "0x92a9c4000171a6534d7546749d7392a9a18974be969bd773b4ff3f5c39c91a17", + "0x892daebee1b6c833ad425d5606ac7562c135688ba8e83178c0f8438679e84e7f", + "0xfb1438e6e00a88a26dc46bdb1ff1696cfac94bebd02f16891c08b52de7accd84", + "0x46404590a94fdd59cdd4ce607c1ba016a78be8bfd8dac361b8cccf6191aa0bdb", + "0xc1a63495f12681da588396c2d30096cdc8c52fafbc0bb0d6f11de5ee2c5a7c51", + "0x86ce595e0805026d106024d9d13e0fca7b208155901b67cb0011138b31bd947d", + "0x7bd81277da5da97359e67e2d5c12cb238daa009f4220166e13ba1f067125888e", + "0x2dbf4b23c2178c8dea6066d43b5f1285894d9e74a8b1056d0ee02091b84dee50", + "0xe983e1211c5b12ccb547dffe850e4adff01eadbb6717adb150248900332482ae", + "0x2f42bd119e06fde6cf7e95c59caeb189afcec85ee9968196f7a15917f98962c9", + "0x1e54e7e17e28b7c2de1c8391684a938e1adc2011fdf8f4a6da900f3664f2f25a", + "0x657e31fe41599356929abc24f7d751e49aa769ef9a4b9d5b37e6bf019dd567a7", + "0x33de4f2776dcd8b17b846816e02c4dd1694891b6827f87a80b31ed37ac0c6048", + "0x2b3b692269fd869b7797c78de9a521705aa223d78652dfbb32c1b8b612bc4351", + "0xa57d205b64565acb103e962a83d300a302efdcd96a13f4c79e80e2733341a70c", + "0xbcdcd2d22c7e21d24e48d28c43d09186a15568feaa24f44f126e5bb96ffbde99", + "0x3a6de68513eb363878604d054f46224e8567f2654cbcc0d9f81fd37fda804a65", + "0xb762285a5d8172a6df584ed15e954f432ddd8f41ca342db7d1d14c54af21e420", + "0x97702988d087056b85f9046bb8d3e37365f4e5811507c1e2daf544af76f1825b", + "0x8d1dbce8efa6eeb4269e22b45c2a9e7c53f7ecafb83e8219b14d43f66b6fa68b", + "0x54a2b87cc430e350eba1271a9161fd08157e196a4d4a7ea29a7461dfab6370a1", + "0x253d68032f383891fbf9c1898fe7d41c6362ebf759b3e3216bc14bad63250181", + "0x175102f1ccd3712675505c3d74609f2c46053c2501998a91b69b2eac9e1e476b", + "0xb07dfe916a1c61b07571327de80a478aeccd3f6f26aa4ecd7081a5f16556e946", + "0x0c87d079935642a1d3673d9b41ed2d3da33ef124acc081e236b23c50d78ac968", + "0x0f3718936f3be6ac78445fe56dc92e4806032d67e014cbe0a92e3193999c8acf", + "0x88bc8add9c916ec21c2f83e398bee626533eb038900c787eed34cdc1ef273a2c", + "0xccd4eebce003d0415c0ecf2d40916651b5f336e5ac64652b69a2ef653d777995", + "0xb9bbc12a4b92aad64875c00d7536c7dee7d62b87813b99a9a77bdc066c169a89", + "0x9ec43027a7229ab550391eb6dfd0cd5cc9b3b103eeb0b79dc9d2f4d8ce3c0aa3", + "0xb4e8c06e7424fdeee2f241365828d9a407f117a0811cced5ac35dbe9abe70a81", + "0xa5a9149f1002457f7c9c3dc2a4aebf7d5453f20c1d7e3a3a732ae92b04b8c00a", + "0x28d20d654b1e7a024956a6c8f53bd1c097d1df3a6de91036092c88c8070474f4", + "0xa11eebe47ce50f4076209307fd58c75b0ff725469ea0875c658119f7abc644de", + "0xfff2020661ecfbb50cd6263686f903127b9d1e5f43dd8bd2d5ecb09eccf6090c", + "0x253576932466ee619cbd3f012915380f1e7a79972864fa0e98a755f902f1199c", + "0x554258855ef348fa770e3af434da722350e998e930f234b5b8c33d3d2f806595", + "0xad11b76ad542ca1e825b251a6cf410b6f86c8c4b42b3c8690a2871e7cfb27882", + "0x3c3d7cddca90448af6119481e08b388df75389ac3c7dcc26ac532680b23ce2a3", + "0x94c4ede45ad5b27c5a6b051fca3b055d548e4c29d2541a9cb4c37bcfff4f19a2", + "0xabf8f7c1b9828d61e3aa72ded1ceeafd6ad539b79b5d56c5eb93c3327b9d83ee", + "0x6e2aa49e5942f19f19181ae911e7951534aec1a7fe295bbf921d8f28a4b7c0aa", + "0x0f49df5c80ca4ff33623bcab40e9ded6159d3f167f7754c3dfaa2eea0ccc368f", + "0x070b14922cfbdf78ead68019e520a08b987ad203db005f4085cd25e6ab587016", + "0x8501cdc568d6c64cef9b87e639d5a0e3f5a4b7d77e8510df07bf0fc50d89d020", + "0xacb70d4cd2010d149f382dbc0f7fc1b74f0fa6bfb5e770017fad960aeb7c80e8", + "0xf49878d3473b21f4ff2c331fe48074ba47ff78198f839dfc7d1d69abab81e499", + "0x9a11ca4ae2a7a68bfdbf54d7f0978150176aa4012ccb8d1781c10b58e01b851c", + "0x58729c03b10b2ec8b4abd91b876ab57a2c0bf05ff02218bae9765a90037562b3", + "0x3b5b033d76798ad041842b9ecbe223dbcfc2d5babdbe864480126dd932d29fa5", + "0xe08ce9149dae8cbc8968dbabbd97624f917148f26f45b858e49c2c389bb22f20", + "0x6b532db41ccc7cdd970d5cb0166dee2272346f23e0acfd8d751491d0c3ecaec0", + "0x99fbdf39928b3f855b2390bb845a96478221330b7c350e83e7b4dbf7a35e2685", + "0xd2a2a108c0a4dfe5ba0d0488da0de7f6d15994f6c14b511712dff4af33bbcf8d", + "0x75ddbc2ad15fc25c2ae71750f1d5bde5e825b40d29d631a27d8801590d5e1321", + "0x226995d806f5d03722266554109395921f63ba1f66f5ed1ece7341bd860a635f", + "0xf78d4178efcc128e86b2e1df767e59c76a4bc9db0ea294bec79b08448133568c", + "0x160e1fa8fde835d6e91187a3da5caee245d4d0b9ee30894170617b680d275166", + "0x361d71c972953283f8ddbab4a45a01b39f30290dc1dbf1b6b744af5afb2e70d0", + "0xb8394cc0d42a0b60ec40984f753b8eb5b9175022bc2ca7f80d64d26106ce86b5", + "0xa0f6ff5ee727a3106e045468b5ed9ee8ef387eb9a0355f2249a71441819b7bd8", + "0xf441bc00d94f06485368e043f933ec9f8e181b11ab0212d728d83e2d039edfb6", + "0x1da12d2213cd65f5fce71c06e44b40a487d5e676558e6f617372244f8e98d549", + "0x7d988011d5c7da97b37c6a6936aa499a70aee8b38f8ed60959f576c108c54d1a", + "0x3d5ff693e4ec163fecbfffc95024cdddc4d2c561297124bb69c8d6aad4ae85b9", + "0xf7db67de101d00409e1ce3430445fe3d38a073e1c81e1453d63f4228a51615ce", + "0x335a94506606e70ca259348ae7157066b55faf09a4ac11bcc34a0b865f4a8057", + "0x137d0de6cfa1e475f6d94248c1e30bc10c17b98d40829974ed4ccfd7de0ffec4", + "0x1d63a7c1c54bc740875f3b5d8750aa6bc85d1c10e3caa4c9d67b4b010a83c29a", + "0x04e0208220bd1218b6180dcdfada95b3a8391bb380b0b0ad5a1a8a02f1a3687b", + "0x02a3dbb2d221bb8e8be58e12982445246928b9965caee73383e54edadc017315", + "0x549dfa1efb8c32071dac220aa4c76ccc038cde6ec9a39e2745a2d55e92bc0890", + "0x1f9bec0a6b3415194528a23443c9904f578d57d7024ceb964ab09a9e8e3d9c03", + "0xbfb25a68c40fcc0dd996e992b18dc73a48525a323995a0eee03a0a04c572b68f", + "0x7244057fe32846105479bf704b871bd1a081acefc57b37aea76116442805a70d", + "0xe6a48159dc041cc9a0d8eb124aebcffad394a400724410e956f8f46e1d89e8b7", + "0x812d9147b6661f54af0c39c1f4de79588ad9cb62b25befd4334ef5f3ebbc2cff", + "0xf9aa945fe2eb3d1e2a01db68d4502a4f33afcfa967fc06944e035c582dbf383f", + "0x63a437b920c6b916eed44003b8d35872acbd0d1859b6596b4f45e39d04057e0c", + "0xffbaa46c582530498f30e51d18deb6973824b850d09bf4a4535699890a548eca", + "0x6ab7423011299d3a82d2037cfac752bc0e88a82696f6aead69ae940bf202792a", + "0x2fc6f5dbcccf16340f2b3a5e341e364c3cb1dbb3e899c7acd6e50e7ab333f45a", + "0xd354b48b2d3cf13487ac8138caca0740408b42613b50f056ea595741ba275d7c", + "0x8e1cbf4bb7a83b1e47f69c08f3fbb133bd36d8fbce923db79a248c21e9657f8e", + "0x414c7f4d86ecf78c3988723ab584ff735633a37267b1f5986d0c2e6375f878b8", + "0xe0b0dc519fccf20ef45b2b185d791575d88f93011bcf5205f4880f7ed755a54d", + "0x528a7ac7c6a17775d207a983b76ff54f8fbb84b8ceb3f6fbb60a80d9f306c497", + "0x458bfe441e32d15fd95a33de1665a94ff4f2a4c357f4fdef5c9e7c82013f59be", + "0xd478a55408477b3559d50bcc4b5c4cc2713e0666f40d87c5faa7328c5b7db489", + "0x9977a36db4a48e7e1f4029efc494a341b8eb2e40c73fa9ed3be2f16065df8900", + "0xe2cb22eaad423da374bbe1cfb8f4f353eab0f9874084aac4f42578525e26586c", + "0x0225069114efef02e188a1a35320d6522c115706c7b87b3b54805aeeb9e60db7", + "0xf82e17b405c2e19957b63706c0d7405e09be93b129ecf850e1941d62f1c309eb", + "0xe26f6f439b0d33f00a973b12f5d3c619bc4cae8662ba25173fa3398b8fa19d02", + "0xeec38666a51fc161736b7b48c8befc98cf9683975abb8432cf735edb907b05d7", + "0x8d8c5ec1f83108372f361b0679a65bc72f1b5055a3b9a12f01855a61437c9ebf", + "0xb53f85551f811c60b17b48df2125648aacef9a74af403cbd877c1e539c045ede", + "0x498d608f0ebf85809b9f5a9270e481d03f4e26cfa38600e50347b968cc05b13c", + "0x8e6d9c2693bb876101c2c0ced0976fe71db31b0a725fcccc88cf9a69b47cc9bd", + "0x5ac71d4859c028d90da98406f2c739ce6280cc227529ef8f1be3d3547ef84da0", + "0x5e72e33c2d66fb9b31bfd4d423aa1ae7d4aa88a30758e29610eaaee778ad75ef", + "0x97345508a573bf5036243f384e1584dea6a723ae342a876b572526cf992f956e", + "0xccb2773ad04c605e9b4a6dede3cc41d69f43439f19e4cd97f54de3a28052d0e6", + "0x0d48cd6317b72fcdd315a6f912646831ed52257ebeb03fa70576a918282e43ae", + "0x688754d57dc88205d6223c88e802461852c5f930252bf74e08b73a79e4f0ebd9", + "0x2860c5f26b4eb0896b4ce041582a8d38b1c8aa21b6c163784277df2658d7e191", + "0x35257fb9aa6c9e8ac16068786fda9c06ece1cb2219106da3216ef4648d28be29", + "0x1b81179c25932e14098aad725e59bcb8da8867dc4a5d145e90103beff868f2ca", + "0x60309b91add03a291fce9fc3f8804eeb993508d7cd5ec4c13a41d31b71d09997", + "0x04d2e5e78c8d8c0059d829c16ea7397834cff5914a5c0618e5904a9037338deb", + "0xd6d345d35827336d086eeb801e331fe77491d47f0df668234e05c3755e413e13", + "0x7f29ddcbfc971fa8ec8e73ed1e77301310e99f677c17320a62fa32ca225e3e97", + "0x036d5fdecca68a54be820fd086e1185312bc9d434b332db547d65d9fd0adc5d8", + "0x07d7ebf143ec977f4134d782bbb3da778b1add224fc3617987d9b21c7bf7d09c", + "0xf27fcee747ad3f1acfee97988403537b85f51ac1157aba723ace11945bcb5115", + "0x5cb6c6cf872823930abb5798d4f1db9d0ae200d21ca3716445fcfe675432cb68", + "0x8226cce1ff6639ac646ec09fd71a0de3d6ffd323df6ea24446dbae7eba66a69c", + "0x6e07367cd7df8d5e756e9e4c535f0933df76941640a7bee501f8af8b653543b0", + "0xa60f86078624b3c727784d4a95bd6dee72210c801e7cd0a4fb01a2ef5f7e24e5", + "0xe3ff30fa3e754fec8605305377cf6a3842d2cb323950db58e5bf02794135bb2a", + "0x74203c76eba1b90e3e76fd493f66fe46130e13359547ce4c94919e9c8909ddec", + "0x4ad657902a564df2f15d7fcad6e4171c96c65798d8b49d3976c7d77869c06ab9", + "0x043cf965b0b5b2dae096d8c73190ad9b834b665097e6b77212359c5029fe8f1a", + "0xb370bc64167f8c6be57238f35a56b840688138e860b08c2c8694401ca32d22ad", + "0x1c242203268f4d543b7087b0b4506f4b5e5e6fa4f4b495c6bd15f94c7ccad31b", + "0x1250c4ef1fd54888a4e377127c9f27889fc5bae3455010733e8f48d7aef65c99", + "0x83bd5c6109c0937f109307dfae9b347fe7da69fceac9444da2d6394d26911956", + "0xbc25fde0522d9ded3c69f9ce8233145b5b15242a8f5d6d6feb2b7aaf0aec5cc8", + "0x0b7fd860e34f21a54293ba2dbd61b28fe5ea3399a29ff7af4f577e681ed579c5", + "0xb2d96f1f4fd0f26e226386aa94e306d8a4a2a3be2860951e0c2e39c77dc31bb8", + "0x4b9794e3a3fa08b8a71f55afd71f2c5ba34fc9d773c32242246c721c87e4b14d", + "0x01d6ab151bd597e2681e9c67a0c3f445c85bfca4f8cd73e3d088f49dd669ed2c", + "0x686280902ed294c99c49b8c2366686af45b9c6ad0e7bfdb1c52f1c901a6be2b6", + "0xe0a05a29c78f04794b3957ccb343be88cf11b00f5d2454a6003e2b363f88d5aa", + "0x798aead8eccab3a4d4dc1283cda04057038bbf80944a87c9e796fa7565e34ad8", + "0x866ba6664beb3b953f5b5524190685eacdd1830248bcb5b0cdcf686101be0ab0", + "0xf31b7929f0cd73d652d1ded75d5ac19d95720b386fdc660e0829d122e66a576f", + "0x20fb041619114e9beb6d70ed0a488a1ed8aa149ab506e7bf62244934441fe0a2", + "0x91f9dfc54ea16eea1700cf1d729e77408d037f43238545136f6cd9c72bb2d260", + "0x7f633029a0d96a3e4232ca3b02189b59b10e6edeafa9756f8db1e8844e9cba44", + "0x0b4f8a2e3547fb13fb7ee5555281ee325d068a76a67ddb1dcef60a6ae4b41597", + "0x35b3e9e377449e7b1a023573123f5d132b50a829091183d279590edc73df67a3", + "0x8ac0d74f10c0f6a60d2e5729d150ffef0467934f8c3e0b37eb7112eaff246a60", + "0xa8f65245b7fea166560a0d775db32688a0249ae3df937a42847f4f0f358af085", + "0x6d5812337f22e0e436ee2dee8bd3a45b237df7e045a4bee1458c55a1a269cfbb", + "0x6f79965282b544af683f2cd74cb056c092d5aeadea1d16e34382cd97113f4436", + "0xf91f555495a762ed98f946487f9aac89b4485c71fde9d700cf562164773b119f", + "0x92397cb86fcd4bdfd448fce9e3fd6fcda60586482217ab74884182d91f3a33e2", + "0x3f694bc4515ce3389bb57feb21ffeb3078e67c3a13bb53a345f7d837d92e91d4", + "0x81694d138eb5afbb7137ed7de9e4fd7010528da30014d06feded8cb2db307994", + "0x56d59ea9f640664f6a1ea3d92860f15ac38ec313d520b24b0ff4e365dff53b4b", + "0x5056000d0e11cf10bf36c57b44eff8fe9560e261264ba2b29e97323c3fdda5b6", + "0x427230af29e403291fed2784ea8852a68d4bb0c07a514dba4797644c8150ddad", + "0x21d5f70bde1ffe09c38545103cb9e6a349e62c1316f1e7e78c2f93e577a6dad1", + "0x385df64391152fe6e1f574efc1be371bf46606ba571420c601877dacfc3d1458", + "0x4076eeac8e1b22684b6fd996a11db49ef6b52539e481c1dbee3f1ad3f59d4872", + "0xa8239c7d2d32a3ef6f887799bef8b470dc52d0c82af8de31bf3a8e4a6bdf3535", + "0x52a6ab7c89019f8fed6761845f9071bed1748aa461b87b0a587b7f59489b2dbd", + "0xbf80c8df3c0202192d1b888f80668c5ebb9d4f8c7d168570afc54276af4de578", + "0xddb5784df235570dcbb1a08fd293d58f63b7afac494b1f8f947677f2dd36a87d", + "0xa741791df39f377bec8cede1f1c491eae35a710de095b5ca5c56d77f4431e87b", + "0xb119d39b47e1cdffe5a4f912d7bb19c6e7776803a386ef62226f08ac1fa0f4ad", + "0xf71e68699da769cf06d77c0432ecff635cedbed284256336c682d542e33c96ac", + "0xb600381fb3bbfa7f7c3b555c51999446b148a1507bd6279752e7059e2e0052a9", + "0xa596f51a92c38e63a7172461962834dd700bc847b1e29c03e27b8e49cca19b4a", + "0xee28f2ef5162f0dedb5de1c4b38a1049e98c82a34570b8bfa19735e915909579", + "0x1672d010862647d074aeddc4189a5bc3a128b8084eba6d011046b11ad23f445b", + "0xc99102d4079edccd947367846ae35e2b40ab3f0e1aae8d68885b1753c2c64177", + "0xcd1003ed721269cc94a0736f70714394c191e7a663191268e2daadeeae2790f9", + "0xd33a0f2338d2d95eff701d0bd287e70e0093c6954455bbc63be7de7c39f6d9c1", + "0x97fb57fab06fee889ca8db09d5dad12007024c3dc59f867170d65540d64808e5", + "0xc4a6963627634d4baf5697343904c4c803b2f875f05260602d9ecd45e0e34d4b", + "0xdf3bafd9380eda31fa5f606fa915253ee8b9a41cdbc0ad12e2dc1cbdb76ccf88", + "0x141dc873ceca100df1127451dbd96e117ffefd054076327b68b1c76a4651cb92", + "0xebcfc5da5a1e1882637b9714fd899d59fb957dc9e4afdaac199264e8d29fe5a3", + "0x087504ed686f8e598560ba1f70dbfc72eeefb7cbee9559927a98bbb31b7bb9fd", + "0x767d65e905169fc44546a7c7828c2f1b76898d93df663291db08a0a6f0fd8610", + "0x0ce5170b5c9ec6377c3ef465d986159f12e65c32ad577d8005fba498fc6e5d9f", + "0x76a78e8c3799f93f1359313a6b42f3a4bf92a9c52c7b495b8d82946d471ca965", + "0x1b5006aceffd1d61936cb327b7420f3a88ecc4ed8808db9f245cabdcf3da6fe0", + "0x5588ef96fb1e960284211b143bb5b5a1e431a015b5ae8aad1a86ba1b49fad459", + "0xce5cf0c647eadd6de376cfa52e4a3008bdc0ea3e09beef3be5e2369978bdadf2", + "0x2e55c31e3dec040cbf0f2bd0816bcf6d41ea29376b9958a40bd799c7c788d8d5", + "0x871c62991b05eaece3ac9fd843c62f6a635230d885b075df28f3421c64fafa55", + "0x36004f4df1cd2809aa89c4edfe3ce3df7a70c1cea1b99d906a64491f002b0374", + "0x91ce82776a39a4a32979f0df16d17c4ca0544e7086c90562c66868b588058106", + "0x23d8c25e9c94779c445bc7aa84ed86189617463e3a9e62dd974a23a29eada969", + "0x249e41cd4fd36f6bd6860286bd29945bb98cf66c0348f73b26bb4a28c3103a52", + "0xf158ef6bbe5a54a85f11c58e5c569dc927089ebb641c9d0f6a4641770e551cca", + "0x4e30a215bc185573c02cddf66c40a1c829b86dc639c2eca7e6a4026fd8a27933", + "0x15f0ad2cf92788cf0905aa6f8d092b1350e3f1530f1b06e07ffd8f37d9d867ee", + "0xe7d081057d6d3f5d85be6e28cff22e4f4e2c842d31599885f4e3f1c96049c101", + "0x342f966910c67104f934395a34ffddb97260920bd9043e2f1aace5062520ceee", + "0xd09b337b1ec7e7a3188b2a8981d14dfb89bed807807a6fc40a21ce82a3814b63", + "0x5bfcb62ce51ed31f94636e5e55a4fbbb8d63342818814d9167d690f96ebd9153", + "0x9f46f879a2b469812d61674250053eb01ff91b3d61b66ccffcf8b0566bb0ab0a", + "0x9e7c1698af64e08be4d5d2bc9262a7e0d2ddbab9b5c9499b505245869a1e791e", + "0xddc3dde6d397fdc437fc95bdc98b1bac052a1b4fb1bd81b90d18d63093bc0efc", + "0xb8180ff01aa196209573375a70c590e9ca8fb5eb94c921436c534fa57b93c802", + "0x795c03cb817afda30f993770ee0718774aaec6d0c9c01cb91ab2061539ab7349", + "0x45cbd728f2329f5bca7f7d188e64b9b307eabbd816365d0352e2ea661d923511", + "0xbc1e8acc0b620fe7c44f4d661950981e8388e3f8bbd58546157a1dc716d43414", + "0x4e796ee801061efacf4d84372f6daab14a98c3e91b569a0d580217442e1b821f", + "0xda432dc7a649547983d6ccba6ad31b7cf97ba3c7eebb5eab05f34561759e6090", + "0xd51b0632c736b3403bcc07399e9be4e40e04928ee4e63e87710002b066e462ff", + "0xa3076a6242b4e2e450f227294940d5aaef5b62ad68d63affc390f874958c0c0a", + "0xeed1d4e115039d92f2d82401aa631248a9c5b8de06bcf784adb918ff28d70bd2", + "0x6267b83c5d6acf41cbe965d1bbb8871228a060e46435a29c6a7ade18e44f3ce7", + "0xbe79880b453639b576dfc891353dcabbff3d16479ceb74ad2184a1dc89daadeb", + "0xd5356e5ff86c455718ddc8527750b69b3658c9746c0e47ac93291b039bc2db8a", + "0x079545539cfb2ab2b1d5341de50c6c71b8725cbf3a6ef168869d392c2e6f6ad5", + "0x0e3aaea1d36e3945580c3cd8e26456260a19ec0630476dc3ed444c517baaf5dd", + "0x28d6d2c1e9e4080e0bfdfa907f6d7c9f533cc477a729eb83ffd0f96f6d6f5018", + "0xebb8535debdfb417acf2c13e3ce6107d7e286cc573ec1c06ea28ef4cf3729c8c", + "0x96440ac46648fcf69de403e4c146dd1a37eecea957370f223753ec93f32298e3", + "0xca28ae763d5602c91d437349aebdb5cf9dbc89e6cfc53c124370b67e31fe8f9f", + "0xe27ba10642ff994e47ab1fc5a29ce071d80b82d6f584eaa56ac1a62a771eb21a", + "0x34e7db6c5ad2d646e6791b58ec4d429b8bfd69f76b1d9bf71f860b1faa4911ad", + "0x0b83663dee1daa173203e106ee4996ef147a9940f2318b912364bcfefcb07271", + "0xb164c1d879ad665dafe81929e0db557cf2c573f188cd86fe35ef24271cfd9b26", + "0x6587efc2bfa2ebd6da9816538e3abc5f03c75b5bc425f7e5e9c676f97b1449ff", + "0x668316bbac3e4cfd0c4fee48957d9c8fda962bc556c5ca35246b88b6c43fe291", + "0x264917f66c2d927b7f632744f9dd7b844514af80bf3729f30832b222410a08aa", + "0x38b162eecc129bb2e1c82e65d785e84b5a4a9822bf1e6506492a25b082309bf6", + "0xeaa3ee39cfaed2aca6c1560608bc1a2ae32805812d792471c9c6a9ebc80aabe2", + "0xd7738ea58e4319f98250874c16bc4ba12f2362a8f09a7158ca4e2ecacd954d99", + "0xd26d6e2dd1b62f7086673cf153c3249b15c652a7bd43a4ef7b796dcc2bc44a96", + "0x11a9a4f1f8d10712e79a219eac2fc81b3360c60aaa9bf179e720ec04d69956ec", + "0x6ea3422e40bbd52abd6660d9ee8ff351ccc61d997082e470197a474509ae1383", + "0x1ab854452eb96365cc3ab33c6c45b296864ee61b3a477716dd9eb715529787b6", + "0xeecb8949e3be53db9ab660c71d1bf702d8e919ae6487812181858992e7668c8b", + "0x2a2ee4c33009656e5e38e44a7314c40254639bd46e32cb09eb1b9643d92f9ffb", + "0xa14c5b1993fb968f7e1dfe4ad24716e8d9a5be662cb0af13f43e174e0bc2c5b6", + "0xd5603250b1933ef1cd1b27932627f27599f81ca29c9f02e3627eb621f613c935", + "0xcca950815341af147085a53b4108ce368db1a634f204ad75f3c687b5b7ea3985", + "0xe14e1ce237fe627e8047d5d8f8153157ff1ff3d2650e0e2ba870ece940421470", + "0xfe2bd09d81d1525b996c67fb8407636e06723b4327803a106c19ee60a4a960ce", + "0x995cd4b1f16450b64098fda2e678b14833a3b382f76e14cea71a0d297ade2080", + "0xefbf5dfa769a1e6132741600fa9459b8a1d11b11c3b2563b22c79cddb34b2ff3", + "0x1618c918d173a9af0daf3af314d576a6419456636a46e2c6b8126f2365d627ec", + "0x3b9a773b1c0e16037a429ab42fa3883803f320beb9a34c8e36c80b2b7b814331", + "0xbe3b816b72cc63cdb63e2897064965c1b4e9cbca1ae26c770a20508be1d9695a", + "0xc57f2c5ff8087d6cc2039910f00323a90a0bdc3d2164e0f52bbfa920d62a15a0", + "0x0f11a1d5bf509afb2694bc08584718bb93288355a7bf0f801e478eeb9ef52da2", + "0x829bcd6a2392c957300253f7e9abcba7513908d3013a74387e918dc57053c035", + "0xae4d9d51eabed53e9ba4dcfecfc449bc165b3bd40d87830fe044811f4056580d", + "0x2a8a21d59547009a533695b5808d928992547937478ff9a61fa4388e9afc1147", + "0xcca2ff6985f20f7d1633c35447f45a5b27fd5a93802688e2afe494a2c350917f", + "0x2b8a2080fdcdafddc5d94292ab4fde01d91e7ad2c1b5b5a2f04dca9a729c3778", + "0x211074e33dcaf13183115f89252435b4efd8e1f01c38ed484ca69c14bac72eaf", + "0x5de84a9ddb48a4e2134be8cdd5c274471055234d428daaa1039ae2500e59ebd3", + "0x3f71bb8768f5c8d0db2ec8360278279f4382f3a50a939842d80be98685c536df", + "0xd26b7cf7c6f987f4975010eb9e77becf7c0c93ace9eb53d289beab868ab5c93b", + "0x889d8c294f942cc322a197b4f746c688a15e1692cad0d2d9fa9a125f4998a6d8", + "0x7a0c807c41e209d12128445df83dc1931d5a24923b38d259a7bb9e8e4459db43", + "0x564e904caabec0630b52e056ef9ac08a2fd276ec99d81644bf38dc0b09eaf820", + "0xd5804d2547786f7d26282726d3f9f22e53e0ee2390ff0de8b97c33a4e4237535", + "0x5999f87486f0c721b038c659831c836980a2f7ee9c887c759710d62691588670", + "0x9fa08ce53c180bb53d5352dbb2312603a0c3a5087cb32f81bcff368c457a498b", + "0xb1279296a8cef2e6b80117a48db7291169ad35b39140debe3ee71465b2a93f85", + "0xd3ca8ebe2a6ce6db208b4bf1853b8625e8b12f7792df1ece14f696d1694addbc", + "0x7fea211ff413b60098ababd9e3077f58325ec14d9fe23bbb1cea0025d95896dc", + "0x270f61667793c26f67cbae50931919b8370c0b395704640837d66aba90a393b3", + "0xe81214151eae79a310d5bd8fbee6358a3d897b2b9ed1282337b71a653db17384", + "0x5f2928cf34dc3da9a559ab89d7496510b3c2b5d00d8de730b6df083d03103abd", + "0x619e0c1627f0802d660f1b06bb55c39c0b570514e71c69d5de41232fc6bca961", + "0xc8384233eaacb714f29163a0a9b507b9c9d0ad537dd64c25bce91cec6fa6c2c9", + "0x54c2e035312faaff2fd08fea36df91f2add2ce39298a1987f4286f3592405e8d", + "0x32bd9a7d486a43926319510505b5018b9ae951f4ff0837f8b9058e93bc303876", + "0x6df5062af0c06aed44dc45026fd74a287e15f5a60f122e49343e5a1d10e5f371", + "0x6b3ffbe23bec6a576dcac6756375e6420123ef1eb39750aa6fdce9d874ab790b", + "0xcdd08aecaa642133a9b93ef888c5a808cb2c84c48943e7ffb6d531dfc1c6c205", + "0x563f9e429bcfdaca1ec2ee7007f286b1b3e4358b76d12d94015d9989dd50b2da", + "0xd3a709568bc87059c1a11909396d655c2f107c999bd75ff5104449f53d590f99", + "0xaadf85b25fd426d50f3a22404616141211dbe541eb116b71c6ad960fa453e172", + "0xc411d65a0dd44d5725a401d4a479f9b5aec10334938bbec7ec216572bddd84fb", + "0x4ba49c0fcf4dc7858eb6b77c942b528a349ad39859a2a1f8995593f04ae8cb2e", + "0x17f327906a7bcee96532e912374523b88f474beca4e40661113121ea626a209f", + "0xb0fce9690ee2a2cd55a0e088c0e96fa0e922b4119df230d4b903c4b18cd6da7d", + "0xf7070d16a82595a5782717429dc6d00b1f8abf6778db1836a23954cf66bcdac9", + "0xceae3600d842c5d03611dcdfd0a0231e469c65b151e247b2205cba2916324707", + "0x6d1e0d4ef9387d070ccfb68f0866937d44ffe7d9c4059a21bbb4b0c87b7a6461", + "0xa7c125405cda699de778318152df327cfe79cfbd999c5cc45db15bfed216b146", + "0x5d90e851ff50eff60b8c92d63274c9f9b5efec6efec3c2a412b003693ff014c6", + "0x03efe16b91c66ac58204c952a9cd24818ca61fc6b1ce4d81a31263a7c045aabb", + "0xfe9324d99b23bd0502d6c1020564a850c932a0d010593e1894ae21641ac5c248", + "0x969138be8e3cf0bf9bd0963d2cc6467d8690fc40797bb2c2950de0df1a8329bd", + "0xdefc0e0c25782165aeca15723fb74d95d96d1ed7420be7f3c85ce7cf7440322e", + "0x0bf69f52b595f75df550078e4293602593e3bc2d7ac528b7be44f556435d9e42", + "0x142f2883383cb22f5aa8e863756bcdd154ff3ed8a02d5cde8fc1572db65003bf", + "0x0fc8980e2ce7498656aa9012eff375b6b32216a3142fb974c357a553bc9b248d", + "0x2714b77d484d7639adb40e1158734058dc02dc761c7349c4f3818c70347b348d", + "0xaac5d4ca615ede62571ea4150e4c01cf31dc410b06d5b443267117197e60478a", + "0xcf9f45357d06955730a934d2de24b859d39ac0ac40c8b29430ffe061e3bbe4e7", + "0x52330a846f5d2fbfc26c48a5a95c9d2e3c88a654ee8f5fcb7f9eeed39b2eeb17", + "0x807c2b8bbeec7e6d43bb781f2d7405f9389cef647751c1fd30fccde0f004aaaa", + "0x8cceb13ddcdb1b080075083091120c394a94d6f8f00a2eb4c4498a3b1a7d2f5e", + "0xef770e4d62f2912430987ad5ea59974aae40a81771295fa1380e417b3df88562", + "0x92cefcd22fbf95dbfa766e7c49a4e211596cc6d997976b04efd818ba8ab49bd9", + "0x809d91cdc51f42438312ae27ea1fa94fea4bcb2c9341c274ea18513ba20ec931", + "0x10538534fabee44df110346114f62797a31cf363d4979f881b721043b2250e82", + "0xe252558398e892e85351274a5064fff650f0323f38b0a4456b14a435c9a40d82", + "0x7d313335d362826f589dae0164a04ea681cfcd54f10d8e339ad1978ee63d7045", + "0x713414b22fd3719c42775449895089e6122064b90258a1b495704fbc4677d92c", + "0x748b6883462e9706a8fcab3b0c71272fb0bedac622144d5d81fe710562b8dedd", + "0x2945d4809258eba164089c2a5605a7c9e72759bf615bdce0aacf96ceb7d6ec12", + "0xfd89a991d0e20bc05d484b9cab61d27a0406fa741e0be6c8c1c2655d1310cdf6", + "0xaa296f6295ade70466ed9c185480e186596f2183947f65bd04fb5644dec93d33", + "0x5286efb4ae287693b85bb3eb47ac0b697ceb72ed6331aaaa521d58ad7dcd7974", + "0x6b3a5802ba251becdf8ba2508a6fb1d3db0b5b99646465b12844b8bc23f062fe", + "0xfbeff1e7cea22e0563407d57d9b16518a0355b676c48605adfb13945d7bb2f60", + "0x7c0764932e56518167f4ee45d912c1a7c78f30271b41ee16038f358d9865258b", + "0xfcb998af040eb99c3393b165dbc904a197341fb7dec2d8430346b7772935dfd0", + "0xe46aec72c95d0accef6ebf564e9264de932458fc1143570ddc28eef3801430c0", + "0x08f97afe124dfb2a18c6c624d9d1bac4cdb5dd102da6bec9c676e7fa000a43fb", + "0x50a62c4cd65e3591651f8fa56831ddb37ff966cba87c12d83708aba72591a060", + "0x1abe248da61411aa6b6801dc188e3f834c3fc4600ccef36ad9d7bc517441a61d", + "0x07e38e7dee4062c20f4b3f221df72590c0838619617e051243087250defd0028", + "0xbab90921cb56563d69347a4197b869a8c8bc34d01d753b509eeb5895e77eac81", + "0x620404dca85a89624483cdd7e2b143b12a38b737c0eb783f5e4b378fa1d578e9", + "0xd70f44dbb657c8fcdb90bcc24a47485fdc99c35ce746d8eb2302d529be43bdf0", + "0x425c47cba9cde3b337c451eb7828b0789a76bdbe1f86757292e7c3768cc51b6f", + "0x11b521b56aecb173dff0358678298ac7f55015dd8b217d81dfe52129d03b54b7", + "0x98ef31c7277a68ba0a2a2809f8e7b4099c0e50cd47ab030f5e1c3ea38b92d39e", + "0x82ae5ef4f71c43cc296f1f6279eddc71766102997b0534ca737c0c1a63b0b3cf", + "0x44e2f38922e64f0aaf27607673724e5c91ed5a8176899e935c73c0fc09826355", + "0xa0361b8e3d7709c4a68ff24623856c54d16ead1762578eb562c295f86f453b14", + "0x91726ead73260dcf30eb478615968be91e4e2b6aee522ff6d814bae4aa595c64", + "0x8afe8954bd7cf7a6c40e3903015830f516ecb1a98c1b028b6799e1605892b49c", + "0x142bfadd2c9e988cb07d36bab795231b9582fe424a62de129a24fac85fc47b88", + "0xe369b5c6a44aa592c1d2c55a6fb9e2a0ec3274be74fea84d2e05451db7ff9b8c", + "0x10030041949c30aed18afceb0b6ba1b9bf58c338e275ae6ed9f2dead02a1b6d1", + "0x993fb9325d7be082347cf9361f665efd4d38466de4234233f272b1c09854657a", + "0xe2cdddac0a6984c0ed9d4232d8b58bc2c61e404c3e60b58b90b5876640e8e19d", + "0x4adb2f59c6704b8be33a046a07d2585328465dc1b45a41bf30fba1ebf6b2f7a4", + "0x2c47e906f61c60bbe994a54e3d0a68ba8dfb519928cf350b6cf8421e5c1779f2", + "0x4b712c7fc97f4784b2f562ffad648d29884ce68c505644e2eb4195fc43c00d9a", + "0xcc0fd5276fae744a1ebf274df70eeefbf301ca7e3d1bdd6cbaf425fe0d400758", + "0x0d3e81f37d9d96efad22ded24f6cb7174606c3b2d294259f37e4f754b28fa2e1", + "0xf80aae34aff371a9911fefdcae1289c126c5876b3e4d2477784196a4ed6dc156", + "0x916469d84a13c2971d02ceb166dbe0c9cdaa88c23e57772cd3c260db7d2f9ea0", + "0x37a5b98e5934c2bf16b048f76c06b4ab17945c1f549a20b76ecbf99ac99c3698", + "0x1dcff6c4816141355ac06f9e31a73f31e4b1cd947de42a078eb60ae828d5cf58", + "0x099bbbaa5915dcbc3f975ef1ee1e5da2bf248e96e87856323151a08dee9b5e7d", + "0xd0f2f3478ed51f2454d21cb838b89a3569b3b2704af4d702526af646b42dfbfb", + "0xd906aac9b70f76522bdaff3840df5d9714d352c8a632f44e52370786ab631167", + "0x7f99f6d3add64e2381d7ddbdee1306e6f6749ce116642f993bc4c06970295663", + "0x58988b3a6a1437814e0057b08ce6e86f58cef845f8df78a6ec563d056592b81f", + "0x7476333d9709b4295a63b55e1d5eeb7c23a752c4211bc8696016b70a4c13dadf", + "0xcbe4bdbaa8e34a22b883371b21d5e7cd474368ef0df5ccfeea3edcb377e071ac", + "0xffc358eec58c4c6cc0031562809154edc13b9aa091674e473304682dcc4c2c1e", + "0x9dadda32c544767bd65dce5804a695b8e5c35d2f96c203c350001e5be78c044a", + "0xce2a6bb7c0bceedce3111d97294b8672d0f6ae8eb537ea785398fdf06d6ca2a8", + "0x5ed79a31acc649619c09c9b5df4d595c806a02e93e92c4fdbe882899832f3cff", + "0xb3e94be6cf733ad114b1c1fe76565c448faa9f14131b30aa79aa36a0edc615c8", + "0xeb33e3a43cc5068b611f7a95fef45d5a83d0219906515a9ff02e31c0f1aa4e39", + "0x63a2f545af614f075469aa9f8d4e49fcac12336722936def26c0a4cd01a31b6c", + "0xa6d5ba412c63ff5903e2f30bdf2d1e93118514a8c82b532fda0259b5c3c21986", + "0xd170edc5d55910ee2671397a9b04890faf8b4a3aed0e98852d5732af897989d5", + "0x508e7b9e80ea2fee221ee8a527ded1d480d6bda70d7fcc2d8d521e35c184deec", + "0xeb07494e1b639b09c49b145d51ecb9c2f8b98ea596779d1a14a71e2eed22975d", + "0x50b37a16f4233ba9287fcda52030e2a7d92db254746bc42f7358c9fa0d4e3116", + "0x447b12ecbd02d12bc80c990d632cc2032b72a441b418b74dcbcf3a76ad8d69a0", + "0xdfa6b21b930c94454ae6845041fb6f4e345a11440077c905b4f3386bf4824ecf", + "0x7eab803353df60fa522a5c1c7d155939e1059ce4d6c83d7e4e3ca756bd0fd9d0", + "0x25a35bba3fb585339e9c9df30a10246774a72f47e99fc329d64d36c67df4fa59", + "0x17ca37df7ec4f94f41dfa272553fd5dd3d641a986fa5a9dbb262fc395dac8ea2", + "0x766bb71133abdf384d8c24aac3f663f858bc8283817ec2dc082bb008739eeb37", + "0x5748e015a55f336461f5b1c4bfc80e5d76dcd9bb3c72d583cb7e585c35d67111", + "0x39909825449948d25a7f9346dd07d83f087e50c82e9fe9b9d474c10eb7bab0ea", + "0x441bf9c03a11ecb3b0472fcbed6aff62ce1c44b237c3357a4c3f5e8ca190dba7", + "0xa0456b6f725f0c4cd0917cc463ad42e8d7ac9496cb0c34f067b691d89dc1f2dd", + "0x6571a9b298c2180c91a8436c7ed81da8a69cde6c1a20c78f8327e9cb7bf9d929", + "0x152f3642af6d21630770d739d3f86b5a0a8b8ae5806be4e1b568499349d36882", + "0xa7dad74a9ed1bde34b6cb0baa940b7d565afb8dd6c4e2bb7fabcc30673f255b5", + "0xaa829dc659ea777c2d84851ca7eeaf8fa1e1409df8ec151ff9d9a87bbc8cd848", + "0xf70ff1f39678b75cd7e9c7cf7de35bab6d54997cce23b769ae452cbaf13db690", + "0x2ebfa2e52ab6f68c8b7f2a8d656c1fd997df4cb680ab4106cacbc50c4f1beec7", + "0xdcc2ac91b7ba5294b3de1eb7db158cfa53db057a4956d403732be9aee6899fbb", + "0x65dd99a245b52befb5099b69afa332a9a529bdb5c3b57dedb3fee52bc11ec426", + "0x83f08c95ecaee8710f687b9ef06fdae143fb7581ff1498bce187acdcc1af566e", + "0xffd22fe4049110b55b117b38f5ea4c268737db4fe92b9b5fe691630b39092dfc", + "0x7b4dbfce2925a674b0de23746b226bd901b7aa49140e400af6209e9877d11617", + "0x8c8d8762e05effacf2e70742f9c563458065f7a0abcf9cb6d6f605450aef08bd", + "0xb97df188cf546690574e316b144c8db55c7fee2d241ebfdba1424739b96a4197", + "0x83cb74821c0295a9d11e4be54cb7f2fd4fdcdeecf9a61a3cf7d168338194342e", + "0xc05d2a626a448cd6b89824fc6ceca1b2295361d7e94ce86005f7d527a0bbf10c", + "0xd0fb8122dfe38416a100bbf00ec04cfb14526296e746da85dc4487f2c7597efd", + "0xdef0c26f8ac9f6704a016635dc46386a95e014a8637733f054cbe87e59e0089b", + "0x084e741565cde3ad7fb2c60e0cb1244b1f8f6b87b210993abf2959fd380127c5", + "0x7986d8c793b5bcf0977260c761f5ab4af1d0bdec8a5dc49230f63258f6a0f403", + "0x584a5726cfe9772deb22093a30ff2b9b30ebc018cf861b8aa0fb28bed97ee0ed", + "0xf046b4649898fbdce79870896dbc2752050b5f654faeff320ed2184c7bab659e", + "0x744c1495610301a14d82e49dafbfce8c70f7f78bc0679f2c6fb964a476fcbecf", + "0x4edf5a73306621d2c4966d4aa6cb2935cd9484f1f0ba709ed5d5b91160a5de2c", + "0xb5faa128c00d7f97a3e5204995065e99aebc76706e2e96ccf4b37d7641690045", + "0x729bbb468965401fbb0f2ad1ba0b8ffc7072f9b18ef63e95f47cd98285b89854", + "0x0550d90dc0f6e8d2017e14324d404ec8a200c45ab4a17ac24cb17ca9b68881c2", + "0xdbc02a7ebd9bf74121fa2b4b05c1abf4bdf00a973b43e27faefd095d6cf80390", + "0xabd6ef9629eaafe2d8170d511a39ea29c30d9ca0f071d5ea0b80fcbaffbebabd", + "0xa9dad7abbf1bdbc32d229a67dac65cb5a14cb0e25e8dc57ef7538122471909fb", + "0xd1e063a59f032a9e0ccd9b926bcd6639e197fce15e28dc6b1bb1a4aae5862e75", + "0xe3187db1ce4e4faf95ae3b2136c34ec2ecf028e4054995fa59aacb94d0e16d75", + "0x4aaff2417ccb6bb6be1e3bb759f745053a3d45ce144db0fb627edd9900000276", + "0x3b108aeee36e6fef8d74ec08c937143facb90cfa5616ab7af6d37c00b3a4f1b1", + "0x1ad317c91fcc12235526ed9d6a45c3854f2fd421ce36a2d475fdf92d8afcb524", + "0xe39f66c3ab33ddb0d1fb51b969bacda7ce0f0f53af7012dcd4530435666b7dae", + "0xe071c158a9c418c34270cf27035afb0896251616ebbc57e7e5a2fbd503cb30c2", + "0x41dae0f056d18719bb5568f0893fae512f623e16effae772d35398da2bd8931f", + "0x426b1e3b67fb576cca9a180523ef9979aaf4d14649637f69347ad3876bdb6fee", + "0x2678a16324ded3abcc20b8545ad9a4155184e63b12d1d3a1959fc9d08dda781c", + "0x3f18f5def267a73abf0543135da57d752c57e4344ea941199055a38a46758ae3", + "0x031b50935a859999c1de5b772eb4363615388dbb9d12bfa6ca72111a069052a2", + "0x57bfecf554524f9dee811f59e9ddb287b04338323e4932c44b208913611533ea", + "0x870b1bf5feb1bb5297f34a80b058c81db9c97cb79609c537641f02753f665b68", + "0x3bcadf9d3dba81c74a178f533c75f1e77c64baa6ae274bd25a0cee762da43a26", + "0x38cb775e5437c113ad72ee04f0721390b7b8fdec2efd0eeae24d22cfd3f0abb0", + "0xc6b545762e567ad0fb73b49e3af783035e77e252f5f26fb56c39f2ba280e4937", + "0x922ba1cbae3ae6beb2e01ce1ac2b3a73383aeda9cd3825cdc6206d04fa04cbf4", + "0x9e5899be114b856b51e0de7a25cc1c5c6247fd2c06f0381d5cedb2c26c2081e4", + "0xc7c57fa4cfd2f5d2df0bbca134f48d152d8e284f1c0d946fcab4fdfde9235b22", + "0xf35e4daf46b5b181b6c6adb53f5d2f93acc93b76b422ad82ad996fcf95d5a942", + "0x0cf08cbe8ab573727328f5e5809baba6b8620536053d023dddbb9cc310df3246", + "0x6ab0f99c1cb99bd763af36647d29d6caafafa4aa119ec34527999f992de25104", + "0xa8aabd97d98e4a657980b581b26abbc9280a288301c33c45961f5e35303c31fd", + "0x3c92814886acb8f2af1342904d0b2688be4f269a24849507ffc0a7fd0d67584d", + "0x582781b1bfd4cd4d619ee98db64eed9a11c0562565fedb6613accc03670dc376", + "0x832c0574c81bc58cadbedff928fd08fcf1b4c80d7b323670bf67a29e312f4151", + "0x932b7bd4b919fdd18acaad39228563d65d19da6c7e8737f9c34fa3d58a57c7fe", + "0x153059b97cc89de7bdf0171150670085b850a63125d3e51525bba6765be313b0", + "0xba341526b613c0f3927d604bac37232dcd5ac104bf256720c62ed14ab05370a4", + "0x2b015d7a5486e2023aa93a00261be3ab97d38a1e7e1b14d8878e6c109d28ba51", + "0x554e29e53bd94dfe253d703050d8f54c703a009b412232847fe01e1b138f64db", + "0xfc603400b18e2570276dd994aa168b7ebf2fa9c8a3d7f4edcc8bd6bf5c008109", + "0x66e1cb6677eb595cad35fd028a36aa416f698b6366c73d179b8bd451b0dc3ce2", + "0x9219571b2c2860cfd4bf49b92439dd76304c2b5b2542f036392566b2b431db86", + "0x84c510b2dcbadb5562a66a1312b6016a4d6fdba205b5ee698978f2570fa191a7", + "0x483e7d9599fe6da557b4f5e35bc66b9d4bbaee82e2bcf29aa245c4aa679918e8", + "0x84dddf3ab9a135de68eb188476c23d1460c45c377e9a62c14015b2fcae515d94", + "0xe03b4b8470073abefcb0d4db364624116a046e85be9a28a52bd6fa5b4d2264a9", + "0x342a467e79121dae9c3d203615f772383d1e700fb05ff8ccb5a48961b423ec9e", + "0x025c53fc663b8cb0bae6a439bc0d4f3996618926337bd80797510b67000c6f94", + "0x0ebcae3ede50801c88b517af406fec7a3922b4876f28b3096425d4dec3f2ec1c", + "0xff78e7b509fbac13400ebbb8955bfadc0f35a4b568549dae44b55d15bdcf2a9f", + "0xe19e3bb2648377f25d4a190fc44b14e80b3e2c8dd17427fdcf50451af8b5a8b9", + "0x50ad2c5b2732b7f2c34fc0e2e103884effb23f7672a5290c7a3ee7f7c4609fd7", + "0xe5a000a849f39efb9bfa550d959e86d2d0d92b6f4034a3e75a84a4bcd34b647a", + "0x56fe17466ab440baaa576898ffb22735f4fb680db4ccb9a7dc6f19a060fe81e0", + "0x1ba71ed6a71d823c35464cafd2f4b35a047de73666f0bddc272398d1758b4aa0", + "0x801ac73a07eb37ee08ec538f723dcf2c41ba8f0f0e553c740a73c1b486b29567", + "0x732703b2b96778d10970cd6f90634e8e383d41f3b863c424a71aacdf3d567ef0", + "0x5295a9cea073059a0c806b5d84e95dd449bd15e081ec1543f04709737e12665a", + "0x25aa778a07dfa614a7554d7b00ed9c5360e1bda16df694279d45fb4c0a4ce11f", + "0x3a9e9b5dcda51fd92f8dbd18caa817f53f096f3b66f953a1f731adf41577eef9", + "0x554d4c03a8f7f4b16bee2ecc809a4a03b3e6bec0b0dfeffb45acbeac698241cf", + "0x567f2220013d4694394b054b9f93fd33f9b24d165ec92eb86eb216f2658a35a6", + "0xfec8e9f64cbf08d5dd3e19ecf7e685ac89e8430221f05166f84eed16e6e42935", + "0x1398f794bb66f9bb26eb2a17b32bcff6c6c8796df52e7a5f8c2b58a94e2d8912", + "0xd32d51d30aa51d571b89bea7eadbb3d32792c5971832880053e6da18a6644f77", + "0x753244cb3d3813f9a59b396fff82253ecafa836b37dd4f4572d2ae033142436c", + "0x74077018c89bbebdba21b096ddeb988a40943985fd479a4a95b172d6d89b3f12", + "0x20ca619770c23b5522ee50b629697763767a61f17652ae06f3f30bef7f300605", + "0xbe0de8f6eef387c01546944519c3bd9761c69bce0e9620d9995dfd4dc66e10ec", + "0x101bc2c69d14c170de6b3ecab9208f68b7b1b8ff0001a400f7373b77454113a7", + "0x8cf7437d2474278b2646a71baf196c21994f640e9baf0be059d820f57e0c66cc", + "0xc5751a0d6f9f5b859382b9840127d837a015a7b33d0a775e935ac2f2e57b1488", + "0xbabcfa88c03ae1d413a6165c7dfbf204d5511999a4fc74ea33a694aabb55e054", + "0x66b70f7c56c40e818fb1cb842a13be3e44d864d9ac5f1a4336dd00330685cb80", + "0x790a401845ed04ea517fe4721da3cda115adba8cbd28775e8fdc9bbe7a5bc670", + "0x2696bb11d905914f93ed07d71b99a6a4f2e90aa7bd5eca5e32275bd4870ac95d", + "0x5aea5a8a2b8586491f85ba8a387e6a6cfe8970c5f47a77f517afafef9a009fc1", + "0x7ccf035e2483a2dfdf068c0cbba769d25e21347dbb40302dd2a5c396cc082237", + "0xc7cfd5568e4d9769465645a1726b4889656c99befb7aa02a5b8ef8daaa8b03b4", + "0x5d5436654bf6c9b428c8ad12645ea5d5fe95aeb5e639ec46d4324dd54b0e7e8f", + "0x82f4a8a018dffaa850312b375503a6325562e75786393810a383498e71dc2c6c", + "0xcb82be0f881fb2794314fc3e2cfdd57ea5e12fa7105a824ed033615c4ae22f34", + "0xefe0e3f97c4e6b5be518d58f398ded35421d54c33e0c93e3ca0b527ca50e927b", + "0xe6ebb787f18f2d0d042eec05f2886020262ac20f3c14e8c03885e04136028823", + "0x1e41e40d2da6017775457223d1cdfb06bf41762b8bf47040357592315f627dea", + "0xada6d7bcc5013069b5d0676df3b067110db631d07020104a556b61423a26d3b3", + "0x8e0840f9e38908e49fd12635be7735c7293833c65929d5aeb5035d45942301d0", + "0xb01ea85a249d3c640f5e2ae43b340a5f0455350719b13cc8bf1a50c8941a8ad3", + "0x4e5524cca029a2729d27a3d2a712979f35e07cf9d436ca7dfc8c414eaf5d5a52", + "0x72208f2a837b1fe9e7445a72f7d57e414db9e0bd87f7e5daa8de14752a2a87c2", + "0xfcf05de95385cee5449c1ffc63cff009b585ea5896b2ad96d43e747bed4aec71", + "0xb9ba0e212f4dc38e5a0c2b62bd0c1bda73459e72233ea38cae8f4a91f0a6d764", + "0xa8946ec7aef9ee1402442e7cfb4363df529b915c96698110ec1e3c15d445299d", + "0x07349344fc0ac74be9acd9f616a08b3d1bcfbb08c2f95d079c235f52a0322fcc", + "0x223fbcf9b3a552057f728cc0e4dd283176735668beabba942f62006a902249b3", + "0x0e28903b5f5db741536eaff97cca54fb98357ffa69b84bbe365312d77374e47e", + "0x6588620c06642d029a1f8dc0b95a14c198b7af2648acdf1c8d73c80d87cdfda6", + "0x021f66c28e1fc7678af4f05726d8670bd88a143e749a96edcf7cf8239607e9f3", + "0x339ca9feebab8de1672036fe85ef63bb591f5466da074793436a07919a7740d5", + "0xee504bd35830555e345301e108b4ee3698c9a0739a8d4210ac975f1aebdfb944", + "0x61a020081cf4fd487b0e9b694465b94016d461897d4e18990e2d34a26e6a6541", + "0x539ed46b92da9b97e94f0bb089b034af3e6c85b9812f5ac18b64026906ef4f33", + "0xd244eaa108e905c9160cba9f75b3d4f46e428749c0a2de7b165e95992e63caf5", + "0xd88315191813c72230222f636d5de64bf5ed7bbeefd574b1d0c2fa61e16d5919", + "0xd428f280ca6b4ba0ff8bdc58a1b5c8ca5991f9d2dcb8522b17b3c09647a9c8a4", + "0x0744cac8522e0366aa470de75f1dc92e307f82e2e300fac1f8adb359e7f5d9ef", + "0x6e504ac6d3e63679f9db61c3e37bc9416d687156354d1fe82f7f434c4e43708a", + "0x34a5c50161a9b06229234a23f210458cf64fbb5531298735826599bc46179e87", + "0x03a94978bc793490395c9cbbae9fba0f7a725f5de2737e65f7e4f55763631585", + "0x183f981a62d19c3a4edc055aba9d04e642f89f203381a4e63ed7496ba7a1074c", + "0xae5492ed7758112e7fd6c21582df31dfe0b1d6b3fcece4d2e8bcb7d5bf56a00d", + "0x8f5062a00e823791785fac6c0eb7c1aa732a70cb1fdd23d4336b2323a99d9f5e", + "0x74584b0ad5236526dc1a4dce8f4e65f87ba3d529749a702217f46ac9a6acef7d", + "0x06f7debcf4fa4511a1182d992fb0ee265714e70354a08fd496f2550a9e268b70", + "0x8a6b101b16aefa233c158e0392f0897efea6b4144a98ab3050551f8f530ffc94", + "0xc65d3267fb49c21636e1cee8d39c515b9028058e8b9e0ec5c2d6e7adc9293e45", + "0xb9286dcd79def251104af4f3b68de8b9e5717ad5275665b6c079f49afab7770d", + "0xfa735c22373482f2017aea5547def3bbe6f0b8f08b7054b775dcd04c3a3b8597", + "0xe3d360213b5720573864c6a1d9204151491bad4235e56c35b340b22e8c29f5c4", + "0x87ee0e69a5db0bf2dcf753e2e1dccb92725f9d1d597aae378743038121071b9b", + "0xda446379789bac65f03bc0d2bddf4da37867069743ddbc4f2e846c90db8ab568", + "0x553465cc2c0ab7fca15424c8507d216d95f53a25e053657fd8eaad58efd45346", + "0xd3eda9aac5e84aa9cb845cbbaa180854868f497fb79c5053becd16f6d9ff13a2", + "0xf8bff7af9e6fc79a875bd7cc4c1a0a347572c5f83c8a6864313e5f182a8bcd96", + "0x3d49c1fc6ca0f9eef57064a5c125c24464d1ae6f29989f2e7f4942c50128f31c", + "0xfa78f4fff3ce4c2b34935ec5692b9bb0f326a65ec6b14299f990e697ceb89a34", + "0xd7de5c5c86a0ada9f328e8b67393f4002714c5d5f0d1ff68129c68b882d5c6d3", + "0x89f2fb3dc33363365ce597c0e5c4d14c0f66b60a8c6ae3f6d45d72af301cef4b", + "0x218c78843492895ae5ab088ed80e82eed320cb6f98595a211340b19428d94985", + "0x5380a88382839684d7d9fc7047eca486ec0383966b262e5e46b9aa0859ec1547", + "0x19cc514f0518b3cedbe31529f8506fe60c93122cc7da49ac6f855abdbb729e9d", + "0x93e2d29e5c272ba8dd20f621132c60ddeea7779309a4d14fde6e6d58b0643f98", + "0x3158d8140bea277184329a7f2f2bd7e956725dc80573ccb169c40bfdcf3f2c70", + "0x7505475407491f5a4619a25b97b1d5cc1e1ba38764be61b694b6c1d3ca51c216", + "0x40c556618336fdf46e581183b7e57a2f6e2665d8adf0d44b39d9a5150a56a13c", + "0xe8d0da5275d1280e0906d62421bd64a3397b5fade799a701e0a37111d13602f9", + "0x28fc4cfdd74093fc78d100681b770d7aead4d57552c9366d56bee6e7776653ce", + "0x81eb57db158fe3ae4e62785ab8a5c4fa07bf5a7815f1dcbe25bb997b89392691", + "0x361a76dda932befd901f101507a238fe1dd43ab563d09e5e3c6ca43e6de48f19", + "0x9931f8e7444209b91572ff581bee13380706e6d6de933ad96f185f71eeb1ca9f", + "0xf9b544a3c3090c494eda2657a527288e48b5f4c9032ed26eba3dcc6558508d79", + "0x16936de0caabfbe2e395583091c3b90305cd1fa734a5ecacc8db0ba8c40fa89b", + "0x998492ec7efc0178ad691288e36758800b139a26aa493bef28f2e96c460be402", + "0x626f93a0163fffb94c1cf227e6a0ef125f7930f3a21971dd3a9d443162a0b176", + "0x64a7ed78b519d1f04b5b3b46c6804c0647889475d4fe991c8a7e405a4a2334f8", + "0x4aedeb8f7470b9c97c2fec75b4c44252a855d36b73c6a4550d15368dbee9d0c2", + "0x17095f0fb67a7d24910c086ad4cac72e493bd7276afef463d05e26fec1f39381", + "0x05b5fc483f428f6c854403b365ad11f4cb170a2229ec66ba671b94ed50686858", + "0x76bd14300b8f845500b2991e8a78df8dca3054016ef6b5069b77ef05b806caab", + "0x718aafdcb0223d7010c9b6c012c38aaf82e02c8737488bace9a7f8db15c60047", + "0xeedb09efda45baaa9034a18259f1aae1275a86fc81a218d9982e0b17f8d743fe", + "0x2608c1d2f2f8513ff1ac6e33d21659624c16e00218f984ce971eb9bee4825101", + "0xa5331637e8221d95d318cd4f32d5d37698731f569c4879c151086974e2cd4e95", + "0x2f9faaf3d219ae56a94fb4ab12f940d63a1d86776aef6541d40ed63d03d44682", + "0xd91d881ed4fd4b6197d77713d2c42758d9e550343ab67fd761c7c3e7a3724fe5", + "0x2404c00a40e6d67254ded0ff5a5413776351b8587ab1fdc4cde74c316435a9df", + "0x8591c719906e31c2150ff3183382f665f756c9a324ed470d0916deaddc240edf", + "0x8d670ef59f2237573019bb60cceb14f7198698773b572f6acfe3d3bad6c33d3a", + "0x3631004b8ebaff324494cc7320bb3c0deca53480a21d2d7fdd516271af7c97ab", + "0x4dc37b8650d5e49ab1a87a9e88912a98a60099cdcfc33a5c21627f0bb05ff124", + "0x95a8b189f6335a7d1523c470aedd2fd41f66043019da9a1ea46b379372ad4d6b", + "0x7219f1318a197b919a83dd51417803c752c24dc3a005cd08c091b0339634e806", + "0x81d850ed79388dd32265463d5283b02b11f012e08eddddfe389d55790cd1ff52", + "0xe170a7511431b18ed7330446569a253047f4fd0653915e107104380ac40affb3", + "0x9c38e78c1851edfe159971a455a70e1d61b1ae71ea0cf828ef40d4166741fad4", + "0x1ee49fd6dc9fc4f6e8bdee61a3e010a0eb9d06597c256200538ec73580c42bec", + "0xc0e415e7a108c241fe301e6ac22c81738470b499aa65317fb9344d59ed763a09", + "0x4fd8e4224aa6f2863ec655c10e829e113882646230a3dc753d80c111093ba167", + "0xcd7f4ab1b3900488068618eca688f2fbf85e58b265ec0dc4c0ea55f8892be5a4", + "0xddcfaa6613a08b4d0a5f4259abae86cbe95fd5ec5ec77fad9ff2c5662efd4025", + "0xf8bc573cc98ace8805ea12e49c664d8d9cccd650038a4c6ad559780d1d2392cc", + "0x65d8dda84a5666f872d4a744a7c98b6dac5e1082e06625d49d32212a37bb1291", + "0xffc19cd76943cd82bd7aeb8d25d6dc4bb71f834cafe50a5ca2ae257d76a93db2", + "0x3efd8f977e31b77007ae5f290a63c22cb417b52d9bb36899baf826049d169785", + "0x9e225513beea6034be1edc5c51a3f12718713578a2a69bafe7af00bdfc477d02", + "0xebd0e1994eb8dc81f7ed767aa664ee7fc0514caf96fa5080c1ea120bc9803ce0", + "0x340d016d76c6f0db1853ef43ac32c2ebcca11a936c19f0f6814d64aff8d63ee7", + "0x57ba48a6bee7cc99a609f5ec1c9dc2aa1ad26589b292d0e913bbb7e6700895f4", + "0xb0b3f638edd6161784754f858844e77f9dc13a52943120680171deba7272e9d4", + "0x901ab47b6f412b57c0b09020defa44b5375c4e80749199c084f6ce0ecb89ab0c", + "0xb8c7e255dffdbe496fa3d949ed552e36ebdd6d14acc4049491ec6a033c086616", + "0x2f1780d8df1d77937e6dc3ec8483d39e3722eee9b102d84cb412b6765e1de74e", + "0x88712075a1174fbe444b715cad257d16547968ac267142ef293897332feac87f", + "0x6287016bcf8d4d4b67412f0b94b080d6b09b35d2a969d333fec03a114f49852e", + "0x7bae2942ac4d0c98a53feae67f5486415b9a59305b6adb3c7fdbf78642004eb7", + "0xe2dcb80caabe834c0897449540154ba5102f7c7a534c40f05dad77d42e26c571", + "0xc1856ba8c970c81104603472986449d9a6ad17f56cf67dd243c707c689e2faf0", + "0x3dc698054a61289b4b39f89c7f09dfdcf72c4a5a54276e508b095374cbbdf69a", + "0x0b27594e85ee0393ee4b16ac44751b9a1d8a9e7d704f42cc7c46bc1cb30dda54", + "0xfd47f64c6b87363b36d1de4950c72a7ae7fc61d941d6d046f89eec5bd63d863d", + "0xa420ed29af2c8a076098250c29704638476fd014558fdc68524d7a1c9b4043cc", + "0x20e516a19060c4f95559484dcff148812ba875407c1e0548714b630439985f65", + "0x779971f5b6aeb2717e6e336f91b3babc6b96621fd93352f0444b96043c34c1f0", + "0xa57891c1f318ee62a989a151b1be70176b8a86466e3f1669a87b3131b3f7190f", + "0xb09340884952e9fce0a543bd8e98617caacc63d4c87485da51cdb906aefd479f", + "0xff2c2dc309fb4c05b90a80a3fc715427f540be0788b33525a5ea00f0376ecf8a", + "0xaff098da407d643f4d60ce864184a0cd2001301833da3f379659ea4462da737d", + "0x0650daa5593e4d835532cb1cc353bd2e93fbae818e1f334491539ef4d363c2c0", + "0x1d6e8666bf720b0cc1fab78d8ea982ecd2b44305dac8edb2f5b9b9881722399a", + "0x673a6337982d71675566e7e6acf703f9c5b18718856bfae59edac11f4cf2ad3a", + "0x6f68da412db64aea7ea33dd930e145f45b36cce9d285ccb878d33594bceafdb7", + "0xbcc221ad6460fb4066d8c630720a519557064183fd3ff3feffce36b0d80b8da3", + "0xe671736f8a72834e5944c296f64a0d35743edaf75becef65203409bd369615d0", + "0xe4b50f9724453eef07bb00e56c32f6e056bddf38fed0cc80d3d9d2f86258810e", + "0xfa0594818b10ecd7be1deba272ee23b3cce007382e6974645a505df7d289ca39", + "0x35cfa0772e326b9325a613ac39ec350241a62d9f51cc0a1b0de4875d2ce48059", + "0xb6575e9d2cdfe08b13fce3badd0a991f5d331cff4444821932973767677ca13a", + "0xd4821ae28196784c066b254b2fb3b6230d5f4a0e769d8b85fc7ba453d3e93f1a", + "0xfd9f762aa42f1eb43e75c3c00d292f9afe393a14e272037d072872f820e710a8", + "0x9f78b0168eddb9acecaeb07fea85080fb638aca8874a9ff15d3bca7e3e4f9e73", + "0x8c2f0986e10039e96cc6695884401991d714adf5c445e9bb0f90a14cb4a12477", + "0xb7059b47417c4a06bcb11c6ab78221835279d130f52f5cfc316e80f87977b87a", + "0x56fcf49a8a7a69d4f8604190d79eae7e2957a1d129cfd813c9447249ace909fa", + "0x9401c3ee1a458253b3da8820c1e9b8945710839a826582f3a86e8a482dbca0f2", + "0xff3f9e5724cfbba1f837a10f3844cd437c0f1b5e31ddf61c4e56ec504fafac55", + "0x8787e48bce6ac94e62c13b82c544c2265b42ec08d959c18722c3f722cc8ff2d4", + "0x18cfd60669f16555f0b0a429a6b98bb64e936863d5524e23c3d263dce8177866", + "0x33a19dfb8f79494cd2b1b5983884992f637099735e67b2197ff48b00fa28ed0a", + "0xcd2d1272d5982579a63f951c3678c5ec440dcbdc2a5fe4ee8c765fd16ff07353", + "0xa7bd53be4ffe9029d5bf0c15051158d4fa1d9857861d9b3fa63dd0d5052ac98f", + "0x6e039f06324bfe8b9604711719bee4c840526f8c3ce9bc5c3c5584315362f0e8", + "0xafd6c666917c47aeae4d44703d891a3498211054535295178903665328d24291", + "0xc0f0dcd1102ae4eb932e3ee71f1417dc852f3f1ba6a8f2b12cfd8b86ceb3c335", + "0x6845dbf33355716e4161cd3e03ad296a4bec741255d91bcdb6e36950c7010c75", + "0x832d9dfedc39989c97066d465f256ceb8922f99e01c730865f62bba3a0aa786b", + "0xdf99981c644b3dd68728aa9801d5ae41579cc499a534d5213797b3fc35bb64d6", + "0x0115b4118eaf40a9f0fc1cdb8f26ed41e88de8c99e572f72d79dffad9a776e20", + "0x8b09da2fa7f9bd66158c3d469cd22d3f8ade9d86d0cfbc49ccb48335eac53df1", + "0x1edaf123ca42fef6c94b334ab5584c2837949abf3b3ad0b05de4e1da16a5fdeb", + "0xa7bf42422c1beb01742120f78b46ac1eae595f442b0f246f53a919343b4b3b37", + "0xcf72cd32a99afad5a5d9db18819131219a92c1404b57f64215a9e9e891c9428c", + "0xb0d4dc75898e16ff0c4b8bb317669eaba1e54f8d1a1cced03e6565ef3063fde2", + "0xde58a7597969ab3d35a4269d0623ba77254fa140ee0dc00f85e1d256f515c26c", + "0xc0c52dbd3d1febd3e5b4a59d9a6c1a4023d612160bccc5733f2006738baeb149", + "0x42759b763eef5c70b4fbb982cd247c29b0570dcfcba9649084622bc93bf0440b", + "0x02b44944241f25120667fd0c83797915239018c4b370378719be93a809d0fe31", + "0x176572271efc8297d8472120996569abdc26e0b2695cc1c69f72d8e27fd927d6", + "0x2c2f7eb653428b3a5329b339094caeeb4924d322b4362546ade060f8ce89ba65", + "0x3b548a06156cb3ce3ee222cd68a95ecd69bce5914a699b020f0890719a5f97fe", + "0xe74cc69a92f69d63c16a4baae5cb692e57f2e2efde17e0c46fc4cb338eadf215", + "0x9b2a05590bcfc56c432ddda8607b7902c1195ac72fae25c7f18e547a20fc1654", + "0x52f4d9509d31fa6100c7fa8d644dbfe2122581e8a277c6fe80b68aec78035ce6", + "0x380c3d4f876907fed243d11a8caf436445ac5ec55bfb3596091791bfd80ab8d3", + "0x386a91979bb6c8e42d282132f6903e517204fb9ce1379fe5f2a90b66b1f708c2", + "0x333d6dcba02dc8418059d95d43e22b9bc33539bda31f424c762c5b62676b04b1", + "0x50b91f399926865ca64ef68dfa540257f660759ced1276da1033bba6c2500da1", + "0x78266d3dde661a3b10f43d31375993ff002a7b49717a075c6367259baaa58fb1", + "0xb5066418dc050952f056082ef0f6d6b47fb423e9e5458176296aaa6edb7e7af0", + "0x3b8320734691ac54f2a231b296b889c9c8511843984a9ad80f3c43b8fdfb2391", + "0xf85d88e47f6b7ec5f5107785f80fd8b51ad6d5488be9b147e03b5697567ec932", + "0xc352f5af398bf837c89b42eeb48c322ac8eafdbf57af5c1c33ab0880623c7599", + "0x450a16022ae364a4f3ffd5e554aa9a324ebf8b9e6e635e753f4872ed6f63051f", + "0x0438e9c7d357912b1527a7fa5d6e30ec428e472a617d30e33946e47a1f648dac", + "0x4cea137040ab131bca9c9cdd41760c181244c736ca1d9d19370012935de0de6f", + "0x757728e69874bcea324af5348e76db22c3eaf8348843f61b82271570a5a96a93", + "0xf45bd1383b1d53e95dd4d0515f20035cecfb0707442c525c0f06b55e7ff52a61", + "0x156d898c3abc5a55d9860d679d97c36b2e48f833c1342bbf455b13874743b1bd", + "0xb3e80e0fe51cd1ab5d8ef201a011bf6a0a5878d070eabfdb4a6d7c77d06dfbe2", + "0xf7302c6bf2d04fff65957a18c8b988bf0e3dd7f3933229a6f1700e6447560d5f", + "0x73ad7c6627035301b9815d82626fe958ec0ddae62060f0c7f431865dc1b9f6b5", + "0xf10b5b53d915c1bb2eb9979dabd2e917dfbcfff17f1d09cb616b2a5179014ce8", + "0x93570e1d259272e6b825a5ed34a103fffcd27f792fb5b09a2442cc83a3bd172a", + "0x8c5538b8ff9ce17625018bc309af258e4f5acbf9c7c2d4e948cee8b30b336f92", + "0xe9a6cf047c81e965dd32c57edb680c2aaffe2e367976eaf49da5dfc957fac2f4", + "0x7b972cd72e31473b463ae197e30b121afdda7878b9bf0e1961d3813734663435", + "0x9690c83cc3a1b1b8649a89a9bb1e1fed606e4c949d46ab8f66f16c8320ff5127", + "0x8326afe249d762313e5e089474f174825821099a5e9136a7783c3eca7a160d05", + "0x240410eba6ddc5b60a0bdc83fca59d615d95c64b0afaed0a7f17b96ea65684b4", + "0xc48969c8f72df638ef2e8b98f0d67dc6d9eae1d5bfba2b02e584ac2dab51f3e9", + "0xc4fa4b201243c20d35df1ba466a4c40139471ec86bb55f872d54f6404d4bb05b", + "0xfd085495f4ebfd30f7ee4ad9f122ff3da3932fb87ee9aeaa7c8103602671b96d", + "0x17ef24bb8c605d6a27b3b44744353bfcd127488be96ac77a3d8c706015889040", + "0xfc2fa0f9a8aabf5fe515cb5b4a4ec6047f08e6140e81bab8624b02dbb3f99d71", + "0x3ea5269fd6cc38f8a2167cb1619d643ec9de3deb9ece6c19542626f7284b7b0d", + "0xd6ae9f4d8afee0374c662a86b489c603b4e16fb82dee3f57ddfa971e68531fbc", + "0xcdc97e7c7aba5cc5939382dc37142c9d59683d3188d642009edb492ccba1ed77", + "0x847886244064d2edd6791561638b63acd09336b4c88eecdb09493e8ee5324dc6", + "0xc3695209de581e3e3ee849b3dfd93d8102c9e047edc1596aa332d8137d0bc3e4", + "0xdf1399b24c2588519cbf19e2e7218d0fdd793cae1eeec52f9fda7c729a0d4e02", + "0x9718b2e289feaf4a2acff80f5d1c61400e917200fe97b5b9b6200d4c48e7a526", + "0x6fbd4948fdbf124fd0a9c958953abf372854bb6e29adfe9190b0101b97a342f9", + "0xb54aabb1fcf4c8b701734624fb68c842b500f5e71c39dd04083f8a3eaf7d7c51", + "0xc3710e6042dce5652464ec6891ec5b9f436208c12afeda5fd3f454edd8b5d79b", + "0xb6e3d629f78477b79bb9368f1611b62d717b3214675c64f1eb737dfa17b03b04", + "0x6fa6a372c4f33ec50d56a4039c0eb7d6652fb934b24ca468c1fa8f034aa043f5", + "0x51ae789b75938201ca463bd4e7c36152aeafc4b63544293e689e15ec80ed94a2", + "0x4fbb4816f1ea23ea83a425969223be5b9cbcd69113ff43e622ba9753a3a25901", + "0xb2df755c413220d7b684b063f81a800072f2f552e37fc057f555b252f70e858d", + "0xb5d01c218c65539914a8b01c40bcf629c83bbb4ef0c6289c127f583b133aa4ca", + "0x1489588ee88b1922296b2ba27abdd0d393a774009941f4779a63d3ccc015c34f", + "0x093c64995cd670084f2a908be6d6a508f490641474bfc722eb8605e0600d246e", + "0x9addbfaec75c7de95a89691ac3c23ac7c557c278155ba6026aa73258870847f4", + "0xedc09711042a5e3e94a1fff57e7d00e0193f1fb292e3625c6c230c66bfadf1e5", + "0x99a935be3a0aeeef44a096fc8b18ed302bf7224b6b7abcf5e897ad7fd44ad9b5", + "0x00d804cff32284e41ec123482da2a86019ad97d8b36c0b743873438e0cc7438d", + "0x669eabe8771c02c109a7d46ec07b346be0901078f5cd4419b05f3f62442f0b1d", + "0xbf26eeacefd0dfe498f7672aab4a5262d75af5a7e8f5a5dbf0a3e9cce3573b1e", + "0x9b43c92edad88c5825f99c8490b627b68602701a8358baa22103d2b11ced2d77", + "0x8e8988d54263d7e2d9692ad884d44575d3fcb7bfc37333a814ad19328df3c690", + "0x208d671c12795da6d89847247d9707cade2dad378a840d281a637e2af57d137e", + "0xfe83e593e005e58c47571fa00075d440286e02674394eb46956a25ac2e2d3622", + "0x41a61f08717bcb479edd0ed1fc9d8bcc13b9ca3ddede35dee6e0d0fc347c4c45", + "0xe9fa1018977dcb1a2dd82ef24105dcd827bf815985fa97afc0d294711997f686", + "0x7deebf65689aefa15a6d15f7b6e4818547f56b01f622f94fbc42ef968762ebf4", + "0xa8fad9841e2c5d7c1131c16145c57829f22b62566b5a7366d6653157dbddbc83", + "0xe0614431ceb7f622aa4f43c03fae28318aa726dc1ce0f95d69aae011eb62a017", + "0xc731b4b0341ff915979233c76f3562e8a28f268b5d3e531d8d4f3c927837f123", + "0xef265f9c899303b2afcf6cf2418cfc8f9c71d4254321aed87827c0c749f51546", + "0x40edf9f2122834fdbfa84483c376a6bd8b67eac8b8bf454258dc7810f8e849e9", + "0x63093778c25926c58ca06014bd1b668b4d89e641acbb94bcb13c9ca0519fdcc6", + "0xd8b930be700bbc53228755ecb5074d16308f8dd3187cd3a0efe0c2414001458e", + "0x75b0cc9e892313d9c1ecfef4bf4b3f5976f1c830a7283a82fc331277a4a97eb8", + "0x4f102fe9ed705a74524f2598ee6f22adfc1d4186e2ebcc7331bb48e900795cdd", + "0x48a257229a0e91207cc31ef82f00532ec12cb605abaeabf1235676dc57306357", + "0x9ed64622acf60a2bc6fdb2bb738517aae8dad9cffa738ed4f95b02d3be04176d", + "0xd23a29871a1fe22d8bb7e7749aadf6d77c0140fd383cab55b099714af617a371", + "0x79c92002b2077df1c7127a4c49575d7caea872ca1175011d47e019ff14ed8535", + "0x9a9434b2d09c181c7d9f8ce3e10fafd8c3b1e27b807243d74075e747570fb391", + "0xd3c946d1ed5a76e6e17a599d06bbae3319dedfa047e8443f9df3c4b09aca3b88", + "0x4f3ef090e35ccddb78598a581800ea6f2709c691e3024c2f5d13635d3fdba27a", + "0xf958691aa9a520e8e399e466e390679ce3781b82f1d0dfc62bb53d0b3f640176", + "0x4a7faaf47a5031e0a798dc00ab8248aae16866cf74935ac0703d3f1730617d79", + "0x6d350d1568d7db6c029f32d7c8fe47cfbe99984d5d24a9470800f4b70207f653", + "0x6553729bf5616496d7d3ff3e120ddf1c4e64857c53303003e4c9c2546f8458c2", + "0x05491ee727fefe4ef46b9922856a5282c4ba27a90150b967a04e62d85cb3dce4", + "0x61e8d5b5143c0c532adc9f466dde430afc1d1755775dd39095a51a5aa2d4422a", + "0x2b5a26a051940c5f804db637ca77a835ab50f6c62648adb5da7ea05b39b04b38", + "0xbc391789c853b9ed06fa0d2533f1f56b55937a49061f1cd1a102fbe88657a764", + "0x4206d3b075128ba118dd06bc273999ab5ec097f1690c2abfdab351efcfddaca8", + "0x78075f3f0420f490386d419fe2b187d8c6a3b0bbb2158e0f9bf04071ad235bb2", + "0x0cf1b70db8922a59f11eb3a40ee22264a231905cabcb270dc3df11d22c8cb780", + "0x093ca9659cfc716634b38ccc97cb8193baabdb6569f4b33e56e3d8ec1157dbbb", + "0xfb17fcc35e7609264b5dde51f3847f98f555808c693fc345e6b4da55dec4fb9e", + "0x7b6ff07aa7bd0decf690c24d510a2d08ec07fa78276311205004b521f15a161f", + "0x2323e4a69094bff2e821a49caf30ccd91717bfd9eef8609331621071d4fcca2d", + "0x9f05738aa053bd67194099d8bf7baf3166c4cc18b76aaf7cc1a197d4af911765", + "0xb46c0513fd784d2ef4029eb3352e4423d627861431c160988bdc901c01957114", + "0xe1b5c3328267a91718980d369530a7ce76c6f7e404030e880c5dd57508abb03e", + "0x66d908a91b10d229bd478a9ae64021757a22edebf9d41e4a58e2168e8445d137", + "0x9de8289dc95f5b61cdea4a32c7064750adaf034123380c68251df2b816790893", + "0xf9de4b4229f1d152bf4d00864d8d5c37e8cf38264b2fe304931392f848fbe8ec", + "0x356654f74408077036e642d6ae98d7d3893190f6169110c682bbeffad006e33c", + "0xe5a731364889cf98c6136de7365fc53b3f8cd622ae7480fc35a9aca8f4e615fc", + "0xecb8b7af4e850d0854aacb48f034d96a74a81e588f900e1acf0f421e8ea2e59a", + "0xd3d25554bfe2217268be1364b9f74ece500ba8e49260218f22bdb86558edeea2", + "0xee9e40ade104510e4d04b9141864d3d14ddf947f7dd8d05ca29fb3b4d4efce7c", + "0x440556c74bba8c2d89d9eae72f713529f0694a72a741951d5144f7f977ba745a", + "0xfb63981c40b30bc7675280cec8063e7f64f44eb60d983b462cbfbd923a18c46f", + "0x666810ed3d8a8cb87b9d3d908285b7428380cbffeaa2ac9f50b9acfe3727a334", + "0xf87e07add78b9ff8c8b8c4e81b1086ae1fc9f97903a0b8d5e30442781abf5747", + "0x7919d5dac99d403b646b4785205c3ec2635023816e534eef9f14aefe01a0c8e5", + "0x99e1935acf142897bcc10ca07285849b08e5d8f0f8ab73bfb5b6f79cc65f4919", + "0x182a38b8286b5a6ecc93b431a20356a178cba89ac025327e28b7bab5e815ae1c", + "0x666d49f7785b6d3db5ad92f1403e2e447743351bfd31f1b3b61665a79037a1ea", + "0x898f91e453cb2349f6a222f23aa848bf01426fb40fc7c00fea3015847da37edd", + "0x6919143735b6f85a9d0e37bc4b81a92d664b5ef75e40be58fd1b269f5627fdc1", + "0xb854a51fa1ac7182b6f92d48cd90d8a576e75f769147916565acfbeeead664e7", + "0x3924e051c439c6a49a7af5d5a07d3b9b193eb1a6c1511ef406aee6f8e94b2f94", + "0xc6a2b425de2dd99bfa1c0970d29df185045a56cfd3b4021a3eaf630d4e87c6b4", + "0xe66104bd368ce9ce40920c6a0a1dace7be55bdd5ec594cb9169e42cf07282168", + "0x876d3a55345136b3079c260cdb312f8c708f9ae8afd3a6a90f8c018ba58be19b", + "0x5c0849ab35f38121bfceec816cdcc2525e88530ad874086bfa4056c8dedb1e77", + "0x3028fba2e7ff0c70acf12e33e744a881b94865d6f373a50d5d5eef23202568f5", + "0x9ac128a61197f07dd4b0fbac847b864a6496f1047a085e9a26f1618e9ae83406", + "0x55c9428bc7a5017957e025f046231005d4199c8e92627074923280cc3f6e3cc1", + "0x474004a4237145fc86484ae385c21523250746c662e791d5c366441c3b9d2189", + "0xa53ff4b977a2417289f9b532a20b758a2b0bbaa84e71c82e783c7ef045f16eec", + "0x0418a7320d961c5dede728027a0be6f4979211ec600b564edd408a1e9377d5b9", + "0xc8ed8d992f2b75be024eafc15ff7d7c5c0b0599cdd6b603437b4e737a60993e8", + "0x3f5e222d8b28b38a8c7b190448286d4a14afd1b0cb2697fd9356158f5215a0e8", + "0xcfc961c5ff3b8615089248635d900fbea9ae9f7b4d86ebee3703453567a67485", + "0xcb88b820997d440812da7192f44c6debd27da3a41f04b595f515e65cf8a80d50", + "0xce6f3fa44aa7a177ea56d97f00ba344852f614951e665e3742429a6aaf698c37", + "0x21bee516e3366f5770dc4f6af36f799a5c967eaf398f2b70c3a8ca694096a9d5", + "0xe5a99d3fddf70f8e732f7f4a14fe81de8cf1ffc945a47d9eaa7a28c5eaf6ef84", + "0x0d9e3847d768c28783981c6313bc9b0e60ef4c2a8693cc25d399e9db50f393da", + "0x728f54d10e7b531b464ec7e86f3320a4e853967c14061e727f58ee3c115cf65b", + "0xe1a0b9237f50b5e47c98190589842f0b72be2acb3b6a57c075b0c9933ee23100", + "0xe42d8bd36eb740ad018367109ad59f8a74ab017eee893be54a4d1b04b7cf37f7", + "0x72bd0949deab66aed968e725b4434158741c70007855105dd17ab9cec2cb1a91", + "0x450177933434050053831a4c162399286a92c18f9899c413d1c579ef95379fad", + "0x8c950374baef552acae9affd2238ce1b0a1c27e463a03e518b99f23f269f805c", + "0x7a09cddc74127b837571d245fc039489cd0be46ef3618460013de17c2bbf7933", + "0x6ad520bcc098e50d371d504a1e4f4e37b63484066606556debb14c1341880f9d", + "0xca0232939f26cf17430ab3299f1970c334f8dc132724c6e6b01a2467f4dbc149", + "0x9edc115c3af74d77a3267df2b87a77d82b825d07993b74fc31668a09915ae070", + "0x0147d798bf772842ca2e33c28b65fc6934e41e8775b5cfd566dd2f60641da26a", + "0xca005d851a4c27070a0706bfb3b95303b7d79008f49a681f052700c1b4275c57", + "0xc365df99690cb05b89c7efc60a7af3bb4e01c22e5f6d51c9631cf737717965c6", + "0x80aac988930e5f1de8d1db964645abb114e145f301db96925bb02cae2f6bbdc2", + "0x7c67c1aa7d047bbb20131ba231a55d0b596394b06b89c574d23b8aee7231b65d", + "0xd2e03510fc847b2890ea18eba3ed90ebdaaed83b55bf9cb5eb37b9fac10517bf", + "0x4047b15bafa722bf1f5ed69691e671a64c54eda20f11d25143ac7e5dd4e9ccad", + "0x746ab5985f0ef9bc18cf60d1216c69d1fd40df2c1bec2262bae7438acdcd42b2", + "0x7fdfec7be4c42f0d16b66818334e49c97d7b06ea6a2befa361a4aba3c511cb7f", + "0xaedb8c3201c978069b5b2b562252cf617e2a0b0cdae62dabef3a04badce1a084", + "0x24dc7b367353aa7ac0c386f4f5768ef1212fa2cb0de8317300ee54b6b8e420fc", + "0x6bf5c551d97c93ed425eefb8f2998b5fb3735f96bd71b1384799a3330347074b", + "0x9d0be98f9e31ad94e6badd0bbaeb85dc69322649b825f8c41dccc8f9a8d0b4a0", + "0x0d1e4ef567e933a591dd361bb254c080f91351b04ded52e022ed296c2c06580f", + "0xb80d22650285ec257007fb6ff1de2c209cc6be02303b3e2bac43c6a57c0d7004", + "0xe2cd2f349288db25e7315e3c8b4257367f082a377ba4384275a506e814940caa", + "0xf56100200b9fee76191568e49bbfa0eba66887f24cbd6cfc0145db6f31da07b9", + "0x13beb775c7a572d1c54631405b45f3e96938af0d5c740c4762d5ebe5f7ceb1b6", + "0xb5b20d1527a14d733fdb3a94f178dcbecfc9f4312e2c3c0dbfe57996e143682b", + "0x5153bf8c2d061de36ebbc21a31c3755f96296936e79584d03ea169d7450700f7", + "0x8d59bf8350b7eb84d5cceecbf735db04270e4d76b66eb9961243af61317a30e3", + "0x90e0af4b3a2806ea91799ee9d973fe9a2a3c7c07574acb7c72665af11a515bc2", + "0x171fc19c2c2e6fa95af7789a01078a34a628f998ed882884e6f514d45642cd6e", + "0x5f73cd024051e26bf239f11b35b757e896dffc144a2cfabb50aee58e2b4c8afd", + "0xdb7401010dd1db0e8af735200f9bfea39f868425afa01bcc404e5136db7cafad", + "0x809dfd2cc6df05328ef813bc5ab86b6ae90bfadf37107dade647e5a49fbda950", + "0xc731c27a9d048ff7ac2f08d1d68d46fa57e61e620e044b929dcd7d076d157eb6", + "0x1d443d7c2a3974ce9d3211aa39efb84d779dde08e132628c77d72cf092ece1ec", + "0x71410564b523d40ccd091e3e19deaad26d74d97963a171cd6e2f739abfacf63e", + "0xab33110fe291f5cc2f469cec31c7d21409345545446ac33c0f49e1e004542f6d", + "0xa775e97c8fb2b70449066c1d33efbc44a10ed6c931b7d4a193e649b853f23794", + "0xf07dd49b627af4aa3253f0403aeef8a3bb452dc2c69a1227325a1c88731ada5b", + "0xfc648f6b75782491734b7d24fde9c7b4bd939d0b338a74a0b36daab26ca3555e", + "0xaa88a296c0cd44bbaaf8148c005f180d7a2757b4ddcc623a43a88a43deeee936", + "0x1ee2fb788d4dc943f726b8455957bc175ebac3e4b8427177a053d7f299a3598b", + "0x13e7c4da8f8982f0ad250a425a24ea8f8b8574abe033e236dfbf596fe2efac0e", + "0x8acdcc6356fc748e03c06ff4878d0fa96f18e4f03272ce01f02ad29d8211f611", + "0x230d99e6323448f1ebcf7e6792e2978a5d74ef654234be97ebaec5c56a684457", + "0xad35598f4bcf7bfa1852a9265a59d0f9914b3b6289a7aa3015e3d808d504aca6", + "0x4d9956ec8c5887e8cce4bab5b6819cc13a8703cb527f14a5e9db99cbfd83b665", + "0x99a277612b78515fd153c88e0060c274b1ab4a60202b575a9b9892420ae657a3", + "0x656acdfdfdf9b76d499176bc3a259aa9722b31c7f3f4ae5c2da8bc3833c12d66", + "0xd06448c98e529a17170aae72cf359a1e2808ff529ca9f37df3360b92790f925e", + "0x9afd24c01afe4856a47db81a6818899d93a5096853b395a24cb9edd693bd24e0", + "0x03b7a5d8eb6ae24ebe158e411df31514229a2f302108984597317196f6226ccf", + "0x6f97a76567724eecec6c55e811085e7a83cd5f6551924f6f8de590b16cd255cc", + "0x5fa0d567d50e49df1d24f243a2ff97feecaacacb6a5d7e34620a9f7e18cb3f84", + "0x727b25a1d44fa0eaea544ac593fd8bbde356a71a48162160feace5596251f1e9", + "0x3d8340ffdc8e124785dcbf85d3b12a65808c49d91a77ed7a1ef54e404acb56cf", + "0x9057ce97cd01e362ac771d04ecdc45b10cfd45d0c3a1070e2c0fbbc81fcdcbd4", + "0x016b166a2ff70c7beec4ecf9a408a8fa4c556e0e4382911057a984454fd9ab45", + "0x9c2a27134a95f9f28d9f313ed2ff1dba33d5a080cd2d00626b8b6efab87d6957", + "0x66f3583ab4095411135af58756f72480d888a24aeda166136e18e25f42d56e39", + "0xf2cbde4bb5fef74ce2342be3f2178a7ec92ec819721456687705025708a2ddcb", + "0x5ce0fddd2a1a63fbe9bb28c01ba7d1c120f2eab2eacb0dc6200fea8c170e5d2d", + "0xeee2051e5b3a37bed40c32e05f141ea33283556a20e42cac05e5efded1b046a4", + "0x0a38951aeda2ad0227d5db28597901dd2f15fb8a53027241941f705f84f3462d", + "0xd532a9afec12700d8a6976dd148621347df54aa5f78fd64581835027a88ef6f1", + "0x2e328120b2bdbe717d673b04c9fe2c66d9320f668798b9fa11c257a5719c12ca", + "0x46a2cc57ba5798731135b891a9cb9af4b1f780a168d91a9d745f5eb39bdf72f8", + "0xe350043ef30f36168e8f68da553667cccd2eaaa4a1ef85c187163b9e5ab243a0", + "0x183ba0d0cdc68e3ac433eae5822bf39e1e351bac9faa4ec279fe9d3304bc6dd7", + "0xdbbfda6ab37d6b32188cbfa975f513f6024e84364bd6c59d513357598c92f80f", + "0xa44361a80cd53311a9e2de8e244013ea6a926cbd5854920ae3e162bd25d8ea21", + "0xd832af8bb66b36e85828711a95a77a2b6f4b42a5865bebbca59209e6585e8c9b", + "0xc7f64dc286ba1f7b6ddb15638662314813113bf058c7a9065597aaa4452c752a", + "0x178b152e9820020d4245e8a997deb02767796841a0220ac22544aa1250f84296", + "0xa182cbcf24b7d477c0efb568a8b120ca341c4b82ff0fd0d6d0b856a65dcf1083", + "0xb1f0f8c06b2743e1f8149ce4dc215f5dfb89f8f1da9718f3f312e500ef06aacb", + "0x5027caa12ed653330800d4de4014e24fe9251ddbcafea58e2c27012dac58c371", + "0x35a7801cd57644a1df91656b0566c62265159106b963368cdaf429472913c189", + "0xe80e4e8f12abcd5a79aeca6efc64bafe1893075bbec001338f625642fc047bee", + "0x994fb4f27b15427028aba87c42b08eb0919e12870a05405e0ef8f2458cc2b279", + "0x67cc00cc4591d984d9c2270fbdadb8c0d4ec9b40c6879aad8176f9cc7131e31b", + "0xd73e02e0c536cabfda569a8da06c99a28f3314d2761e7c0271aa5480dfad3246", + "0x8d709e7a8435b1d5507859d0e4406589b03d1b3ca646f9f26ec3004c6b2d973a", + "0xd5b64c36bc4614f9ee9bdfadab6c095ad183a8cdfa87a9e6858c4b12d9067aac", + "0x9d1d6d5c1eedbffcfcfc2af6aa9a6df958897cd81cac630dcb998f41a6b14638", + "0x39a3945ad321e02ffda18c8072e74f0dae525a57c7197dfeb86453ad208ecd98", + "0x878708a865debc222b72daa2611b7cb8368313c05f7f41e7f8fbbf33f602a582", + "0x305cf1edcfb804a104d777371850939c7c028f50d45f2fc4791524e24b6adfa7", + "0x6f5dac19867a9f14de66769c9a8f0813d7ac7fc4590eb3a862cd14ef63381491", + "0xdd7d64e12a1391437a07fa88b6ea7184676cacfc7cc8db544ab1808dfae8c87e", + "0x1e97a0e1992b75202522362a4edd8004a430f99c024a6503105cc55bcc7b843a", + "0xcc78f11a9f6996cf742875333c8274c68800658fd5a7465bdbf9c13cf2cf72f1", + "0x1fcfc22ea13dc96c9f8f3546f3f1b8f458bf7d1d46445c92deadd848bfee0c09", + "0xaa5d6969d152ebbb075a97c4a051195db68d90a75c37c104321131c073fdd843", + "0xf4f6e0c5bd269c7de9d1473c5074b3bd4d42b207742b918ab1481c633d05a38a", + "0xbba5eb96150613be2e45e1ea8ecad915415cb1e091a85b6858a7d1d5a8a005f4", + "0x1cdd61d797c519d6295196df06cffd0c9819ce0d9315c66e5309f14eacab63ce", + "0xb49771b39eefe9791d25ff5a1c94f0dc7d560a90cd9ca9c997625c05c0299783", + "0x5232fc02627cf406984a2f4f2e3813ad6260c1b07da797c2d1b7218d7eb05ad3", + "0xecc5ee2ea8e3956d964bed681f61323f608bbfe52397b5b28ef26f660e3c214b", + "0x49ce943abece2026b0c51a5ad5bd35613c92f480027bc47954eb9bc7cca5bb0b", + "0x27f731e278a0221daf21ab225b0297276db74ab79edc4806aa6a794e730f615e", + "0x55a9b21ac8387ad6aff87660d889be69d8b506a5de230043fe5937d0bfa53771", + "0xdd2ba4ff24bd512d48b553d031130799e46f3812c4b782c9423235ccebd7e655", + "0xffff9cc54e4484d4e70a6b3770d11fb9e13e583522ab4bc376cd6c7498021d65", + "0xb4bfa3c62b210ad81177faf4f6a170dd801713e5f9e3e4bcb7301c81cf60d083", + "0x5c3f5d4c0836dc02a32d7059c9598bfe46a813684f3576ec24aa8215a5de6270", + "0xd6d8e57c79dc17f19eebdce62de1adc0940d881d61c4a1099d51e6cf0b1009b4", + "0x2d3b6873546a1e6d026249e0cc45ad822fbdbb2ebcbb13832b7862ba9bc09982", + "0xd0d2b37a28cd798dd9d1a1e0892e86d90ebd54e6be912ff122402f6d923becb1", + "0x0345ca4471a47d8d12421bb39b0b0f7e8475d04181abfaa9050b95cde9aa4a8e", + "0x78a603e3f62c47845e657de355bc40d877612062b2f42b63c50645f3c12c4b15", + "0x1e973f2f79722999a5caa72528d1920917d7e7eb6839976ca19165c3a8bd26fb", + "0x3f5242f783e2336e5cf0cfee1427fbb15a833930b22187b3659367563a529039", + "0x181667e480e8017caf91681eb04cfaf0560254028a903b620485cb9771cc26d1", + "0xeaf92b93fcc996d886bca5fec1f6a7dcdb58cd7acd8033637a8fd9d4bda169b0", + "0xe5164f795fac046d3106dd707c4628d731bb73a3fed8d15ecf915de5b2f0a48a", + "0x556f9c42a01e441bf0e74c4a89323bdea6ce402dbbc1f500d5b00146be5439fa", + "0xe59b25cc5415f5b84b41ab7085b854f64f6d839085e85e6b2a30c41e6f689494", + "0x9e2c804effa40cd7a92ac8901798c03a5e66f47496cd89fd3b8314e7973f3d06", + "0xad4eec2bac36a3ea837c95bef538000dbc75374a4c4f8ffa7d2705ba300aebd9", + "0x12212ae8872a77a5d57a4f5fd91797c2fbf64ac2fa5af09aa55742b3950d8e88", + "0xd987ccc0c413e4390b5b5b69370f54b5d35f79c9cf4c1c534598a7e383399ebb", + "0x8d30d2dc8afe7f50e160fb4d3cfc5c54a962f31ae5b4f65c2362ceb7b8cc4733", + "0x617cb9b3cab2b8c43b11bc3412cab6f889197ba608c068dba2eaf1fa051b0f26", + "0x75bf3d53043c8375f1e51194be0942f3ec73ffbd61926d33910fdd00dddf5b87", + "0x72bd67478fa033abe7905125b728485f401aaa31694bf9ae7eb1184adff2db12", + "0x23d7a73706b970688eac1e8affa5524f0f563228aa7601fe7d790f844c186bbf", + "0xea350aacae57df34a533519b3448435879faf637e3f4a7cd3bbc891489d31caa", + "0xbff826ed9cc685de15275d59a299f5272cfab31750d39141e5ceb8f5d3645741", + "0x020ecefd03dde3543cea261d265a265898f6804230e95f044360d4aedfe031a6", + "0x71645432ccbc0826c83dfdf044ad7e3b2df4bc979e68513ca382ff93e24d1d77", + "0xfcd3731fa2259ace8cce5eb1a3fd74c723f997cfd8d4192105c41f2874d22d55", + "0xf13985444c5a6873217da182e9784fa87576829b9e841dc209a2592f0f5522ad", + "0x0e065da66efc90bd88217d6e9a5721280c4037de294d9e6ee8c1207b664217af", + "0xc6f893863ef60cf57991974de8edfa93c28c55c3af96f94cef9360be9a3a05b8", + "0xae2bfbe04bfe046166f0d6871d689a809fe443c9a6cdebdd5b2e32a36d7fa67c", + "0x733fbd82f21056a2e402ab050e32cc83aae96a67dfd3fa9c50732a3fd576e7d5", + "0xf4e29375a5f989dfebdbc9101d411f062c1090a9869058f6b87fe19b3a259489", + "0x95f902f47c21700bb030841890c47d759dbeca59983f1f2d5353674a4f45088f", + "0xb02a6050eaa94106ee9d4577b10f6adbfe7705a3ef9c3019412c4f60ee8d0e1a", + "0x20d64b55c9e4c2eb51e5af544ed068ce9d323c194c5b18bebea4bb0182344ea2", + "0xb6e40dd521e524b30139719580bd7441a35a1bc304c338c426b706673e179320", + "0xc54752027833b57236b5f043fed133b2461f199b75d52da8578c6e98dc2fc5da", + "0xfd3f9c65d1b05ccbf980a35cd433da01443ff8fc7be680892ea3185914d86727", + "0x7175b164364820f36d10f9e079707a40b21004d0687f90bab1b132c9c34ee2a9", + "0xe4c4df954bf0d3d0eff516775d60cfd29d0e780da4f07589ece3f11ba8925b2f", + "0xa927f17776d750c0b6996f1d8d0db22547fffdb006c0cff367d0a0edc41ddb01", + "0x27050f4807ec856a205518e9d13821b2cda0231cd8959f47ee34832181eaf8fa", + "0x4ebe3a5760406a59770cce09a0a44225dd5a2fade1d877b219558029e30ac4e1", + "0x290c328e60c366b0d18e55c5578b9b3bd83bf1b0600faf0822a1f6f1ae85edb5", + "0xd7bab11bbd83da583e3fcceb0f84bb551cda363c33c67f93e02800176c29bcee", + "0x3cdcfb49d11cfa3ba1809271869fdd9071017e5498f8acb01c595dedcd3ff109", + "0xc75582264ee66717ee40ff52a6689d03121ce0f1abb2c354cff6d92e532a81e5", + "0xe7004c5a4d09fc89e8737a5535221b552e67c3a0fb5851021e9f9a0de4672ab1", + "0xd6b8f94deccddb6d4f8b066c0302faa4b562f7a04e3a092b7d87b3a08485d933", + "0x2e726cd7212cdfd26cf0d928932b05ac8258003254e6558c87eca8a82cf6bb02", + "0x6c8786a64069e3f422dc5000e6a614adf14215ebce0aa8ab8e22c5f239a3714d", + "0x2f736729adc62370324b478cacfc6256fa0cb9119219a2a000d2c34c3293f6c8", + "0x8afc8743b959ab340dc86c6ddd9ca1726cf4bbd13054616b3d1d64bf656e0827", + "0x661832363afb109885055ee90663ea7514059a2c6d69144f8892138e89ed037f", + "0x2279ecda37192639297242d97723c6b635456cb2c98266493552e618067fc5ea", + "0xec7b510975a50daf40effbc94c977f508c84a9712cdb28d60c80b30adb3fd24c", + "0xcaea827e123419fe48b7f72dd67eb8c3965a4504f13e4ad7443bc8e87bd7c832", + "0xff012579799171dada6dc819977c222836b9cbb4f521142e74e9ef0762f73131", + "0x70ec4b383c92a8bb37f733825d60e76e75469a71b1d5361a84e37b38e3b8a34b", + "0x4dc584e8bce8efed0a55021d334b87dc5973de45effbc43e84acbfc03592532a", + "0x0fdabd0093aaf388fdc53d49570d3304c8c583415eadabc98635dc472f366b90", + "0x1b29d10d1443bb37e47668c9b6a124a1964a3f12075ab9be1620891579d8db31", + "0x3d350137648ba1e593182918a4ddb6b5983001356d6e406bcb88753449ea55f6", + "0xfc3911c59399e8c329db2dadcb5f7a58855f19401f513b9f6bdeca01e73edbcd", + "0x89a4277d6bf214c50fc0a7219ae59bdb719b71094d6a02c4ef5e07b50501e74e", + "0x7158b6d3debe3b6ef5dc0d40616691c804581d5614714f2284e63df42b5ea578", + "0x46d73cd458ee5a26724a68b2f8186930104aa9674fe4d94ce75215c61d0ede81", + "0x100c71337ae5379ca5d43f2177f2f6e6e57c628bbae4bfb70abdd1f23279787c", + "0x3c9e2e0161341c82207498608091846726ee4dba0fe1fe69c07a92a0ff7675c2", + "0x5c4885fe3f85ee61e50378943a48732843d47184619f40954daf24a165f2ba9b", + "0xce300dbdbc2c8eb91c75f7e0e8e91dc03ba8894478a9e65529241ff462abf713", + "0xebcc160dcb2f38f4607cfd3ae74a15286eb0aae05c8fc4f87abb751ca88a699a", + "0x91aa4f2af47471ac51160d0d1c81137c7c6a22ada295356668427a45d21c6a07", + "0xf30c1a0842faa5df4ef896e192d5902445ed7b01cfc83dc287492b1896126310", + "0x0e069a0772dd736ea68fbbef47302ed6e802868d0847518ea5ea2eb34a79705a", + "0xb49c6e624b584d49ba226f31611a0c4f3ff0033a746b370890533b209da2ac3f", + "0xf2a4cb9c4877795e0ee2964e5aec8828941bef07777ff4db07423b4a2eae5a31", + "0x2e9cee7389233b6b4937f5997be0a6f37a8c347c58886b75e3013060c10c4a82", + "0xd2318412b7dd0eb4f6b3da69c2c3cb7d8a6b7028ea8f0a39bc3bd513ec7c6d3c", + "0x74c00a1f66bbe517e7166993e18a1564d43877110c54be28053321721e619e86", + "0x37de40b83aff733b4792e27dd6211687ad891f8d95e397e3a3e07d481a5c44a7", + "0xb607adc39f83da6b0a7da38893a95cf33582d836c967496ea7636e61c6cb7191", + "0x518708d6d86b3a15dfd50d0003c340998be42ff59d533703be30763aa080c547", + "0xc9cc7282488774cbdb9d6511ebae8f6eb9947cc5360585d75197532e37e9c7ae", + "0x9c73d1c1a937f888d29da748772785d1a8269282003e7cbab2af4140039312ed", + "0xadc5c8b549e56222f6634a308348eda613afa171b5991ede1b127f241d25c570", + "0x0bcab0832ec43772bb1aa95f8ba9eac83b4b47bfa776876276b47722aaf5c3c5", + "0x8b37849d079adedcba7ed2be598a6d84464ccdd807ccdef2d711e5ef7bdc003b", + "0x8e2e677e5f20a78caa0ab3726528209bca791551d0d33346144c5e7b1c8c6bf7", + "0xda0666298d3184c66e54af103e988fa0c9a80a12e32921e5bea0233a8638e23a", + "0x1ffb4873b85e71b067e3ac99bb26e7f5ee5e036bba4835989f1477ac8b03466f", + "0xfc89d4900e3e7a475b8923bad15bf68f4cb967cb50fae648c2efb3d90cde84f9", + "0xb62eb8ea8e54ed6358a752943acd7a2a1fef9553533b56ca17f3cfc0ba719ec8", + "0x795e2eecc65f357e0b7a9c97d2c028b7503524809adc6e783f05eb0423362980", + "0xdb06a90870bce8df7a88118d485eb691a0043c695ceb64af565ed62d37770c98", + "0xa28bb65d12c4875edd64e643da53c1b65a154d9e40a4cd37c6f770940235740f", + "0x136902f6e7104043a9d828a027df5f23c61a7d085e49907042c55d99d72c16d7", + "0x058424a9554f7a52bb6516ee51653aee32ea09d96247fce31dd8b31af52a07aa", + "0xcce2dbdca699f427d620870ae23b96b38da3414c57e71990ba8af36a58e6b936", + "0xd1feadaa1927f77eae9bb7260fe84ada5d524bdf1239a6e688080da9f7b71af0", + "0xebe906165c9808c0b368392dd2cd950b55e1f95394d28255d7cb9848bd4f3839", + "0x639198f58b4712fde6064dc49f73b3db52726e76ab9bdc00f6ef9a0487fd6d5b", + "0xe9e2f1d0afa3d3b0883fc7269618ca1a50ea5aa828ea07f92fae48b2b2fc54fd", + "0x811ee53510a20a012a10ed6a02407dcaf98099823a35e54849b381d4a6e5b5e8", + "0x221c81c3c384717eabd545830b62427d11fc62bd1df260921a8e121456d719e0", + "0xdc62196c03031dfd983ad4a211a514e25c4c97c9cd9ca62ac18b44cc0da4e0ea", + "0x3f60edc7443b2ae2a4ede7f52c2c4de9d58f90d6be2f0fb25772b51c352aee17", + "0xb5cdbf0eda83613a613ea26b14401361a2de1be89412367f39d4ab01449a87f5", + "0x10d0156c9a828e9b8d61e615079beebbaa525a07f32d792e5a67d4f03846bf4c", + "0x4be38f1cac74f26e2e5bed0d2b416482a74aa425564ccfd3e0ef10b5f57a7d59", + "0x814aa2e560adae5e7192ada4ee11567bfebf3ff8a2a93aa8dd432df30c77f44f", + "0x187c004ce45887043188c222842da10e062a9be8a3db326d3ebdf860209e723e", + "0x60036829b2cce1932f2d4198b5207d70a2e0634c929a63df122ea38f620f89eb", + "0xc323959ae94b9d4e5246a35ccb887b8fcdd2b5de43ab581e53fd3090b4dc88b8", + "0x37a114fb8c7c973708d5dba9c37df501db5e0d074c757954e52ef716299239ec", + "0x8cb29fadf7071a43d8208036d986abe64a1974786c4ab573f4dcca88f8db83a9", + "0xfc4485a7b2ddece8cefbc0f45c949920b9412a47b3e21efa9aa381e0cba0ee72", + "0xfdd52d72e5f42cc1cf1bdcbdc97b15f623b78d78425c338fe588e890be995597", + "0x92e26312a466aff28597bf3444b0bd298b12872f099885ab10949c0d263446a5", + "0x420d6f0581dc5c914b0da7339fb69bb5c9094ea8715c778e9dccd922317c36da", + "0xdd8641edece5a0ab2b024b4ceefdc3f524cb0cc9549c200528962eb0fa341310", + "0x740c0963ec5c29ca9fa48445ddc604bec138df538edb18844182556924d09fa6", + "0xe66653af6368613260ba344cc051d6086a2e08331e8bc5ddc2d25ab06ead9eec", + "0x86e1aa0ab7a4e47828216a25073d6c355e2f4ac4773cf1d2d859f62fd8fb8a24", + "0x3be2cdbd947172907f5605beb7863e2edc5f176e0960904550358ed6c2670704", + "0xc7d4869adae5a7593dbea4f802ab068044dab40fe0063d5b7c7727a3bf288525", + "0x620611d92e256bf7cc471c8883801be5d64fc8b77c1f39682bf840031e0dcd3e", + "0xd89f0456b5a3d041d5309ef623e259003383277f7f509096ae5dd02d312543d6", + "0x7d91689ff4e212d6f2c7d62cdef0593686ba04aaf455c576535d097120f1353d", + "0x568a6763698a23b4b2289b851b46907ec5777284741d3a7304d7df297fa4129e", + "0xb9dec1f84c9b71d5939f40982fe5c88d15f868e265d4fd9fa0560c2b64191998", + "0x6620f3e9e7fae45ca0178116a9e478f95bc0a69fab3a8341dca673453741bb6d", + "0xbb418a7f8415e5378cca2ee7056c6c78641b085e30bb9f9da033ea193bbfc77f", + "0x002fe11d761d3135edbb3dcb50533a1b143593145f7b4cd914d84494b1df652e", + "0x5f76ba2c72c3e4d93d98668455def3d335b03f517648c6cfde1d0a37178a0ec1", + "0xda49060ebc8b7963a9ff4095c9777d902075967d75c47ee3e9f86f03031b0a3e", + "0xde325b667d85828b7416d437a91c19a14b0217323650dd5880a8a40ea85f451c", + "0x9c14e5953fe56c60599dea8284b0948603334fc7aa795cae80308eff4cbd67da", + "0xa9e82869a1be8247c665d86f52900784005853c5249393fadabe37d08752ac9b", + "0x3feff38ddc1917cd5cace417b4e86762126997a5420ac2cb32abafa769f91ac5", + "0x01144f9a6fa0b4396560cdee8bc6e873bdf3ec5c3ab3f7409e59884e6d2dbd05", + "0x96778169c9f2b805e67cf18324c292c8b67c57db72aeebfe5369d91aca0983b3", + "0x373f81dd55fb3bdc9de4c42028a5bdc970cfda825723b6f0f7804b50a1754bda", + "0x3af64226f4eb3ea6bd6d0dae027bce6b361b30c50b4a65a4e1661577268953d0", + "0x35b96aa54e1c50049a0c91281c75d3d06c4b609a2d3d92cb22d1328369adcdc6", + "0xb02c9650fc610b3f5a0b547e8bc505b4a840e1dea123b4cb2c8af6232ae1359f", + "0xae53d65eebce31c14b787f1df5b021334312e8d5b8302b84f6a56b6608e25d97", + "0x4901a419abac1937602d98c21e937a03db8a48d088e56895788da845829225cd", + "0xf5636fb8f3a381476267e6713f10763cef51071b6d981a8f661a24ff6d368e71", + "0x059e8319866374d8eb8372e71998cc9277c5f5e5968c126a81d87d0d7a6fe8fa", + "0xd5fbcd3d7a4387000e014e67ef61d4a7ce09a70374ad4fcdb6ca0b6b50b13ea5", + "0xc37ef88d74d307090a0dd49b69d5705c8e65ad606548b0880eef33b8346c2af8", + "0xa316c8a8ac949af5957fc905ba39c247a477224cd9c4cbabccd0671dbc1e17e7", + "0xdb313f10f0dfb56b8684e6ded5e89c4d5a3cd958a99b1773680db8682645b9f4", + "0x0c81ab956b95426f5c327c6ac6db2fbbaa8fd0f41cc9f58971d5089a0f3c52c5", + "0xb09827a7c1bfba1fb7e5c7acee1da5d8fda1c10da19046151f55ef7fefb784b9", + "0x4332b07750799b436dc5b8521feb0927d7e59b25832ac83876da4eb9df333aec", + "0xdf6895278968d74b85e4bb2c53d70772a6176322200f864b004ed914bcc3cf2c", + "0x9a4a6427c038efbb77e255b8e74df6f897590f734328e5be0ab6b16a6ca58e46", + "0xcf683bc5fd50f6c444a84a5524b3e6ba381fe62c39828650f8c70d9b5b6e8d47", + "0x3282bab4eea18b9a8147d6dbf26073882e7f859b498b2d17608cc96548f5ba7f", + "0x04684c3e47911134ccfa142c85d283f26ed315b5818a523a79e9be31c17b4dcc", + "0xa8efff633914b0ed52a2eb3b75d6efbe1efb0f640136807db13d8809289e40a4", + "0x4502554b0b48e3230e24efafc4f8eef7ff50347cea1a27a15ba46187ed0fb2a9", + "0xe0d6508774e4d8772bfed391286d5f13b986518dfe49d6cc9fd55c415e2382f8", + "0xeefb070835b6cacf8237566bfbc77b177ad0e3e6293587d76904f5cf56cfe62d", + "0x06162414a2b278bf48122286cfd04e83ab148c91ff45d5b90bb3a55d374debb1", + "0xf87fcab4bf30f560c5359ee594e263859f1160f3ddd4186918093275e271d520", + "0xf3ea8332782f88dfa789e42eebba3ec9672589d090c557e36e05c7eda9c7372c", + "0xf05f9c5ec95884e6da30f95d56ad58a025dd696215ff57683d6946ebce25d497", + "0x6738c17f58a1e7d41a634984b98a5efa47e910640da0fcd80d2ad0603c0ec9f9", + "0x8c2029217e14a9bd4dd88eefbe6ddf886d30c56df42035464a5acfe567406dcd", + "0x5d0434b926b112a81e7276b96d1dcff0391e782dd68003173a5d11701a8fc190", + "0x4d9a5c9209364544eddbc545822bea83af527fa1f7b24dbedbdda61b69e18250", + "0x3e5800a59c58a56bd2cb7659db0705f45b6b8e827cf06eb0fe98586abfc83368", + "0xbc3f4d3a46d5fe6df5ded66fc47b5b73baa878c9b8fc3798e87a17995614c515", + "0xf715cbf347c5308a4d50c99eeb4882c6244a03ca77349d126337ed3861e454a0", + "0xe831c5b327832f9440cfc795e7f703cae82648704d05f7bd41b2acd4e07b2c1f", + "0x46c6926581d617ac8384583726ec7088f1e0df60bb075a1b43ab51fbdaa108b7", + "0x236eb9d731c98bc8407bcb9954e3297c51ed6a116f90f6d1ccdd8f4c89bf5dd0", + "0x6ea6994bc6b93be59e0e8f48e32f2afbbcc653d4c1b845625b8a5e280db809bd", + "0x3af35cfbcdd184c7579a273a73361271ae9e1a97ef89fb1f0e6dfe89a776c237", + "0x7553093da896b06cda700a41c0233274a089e633dcb5fd8d81ff0393491db2c6", + "0xc555ae61e8f86c775768be4a07045042a8d5898ca6dac14687327b89303d9ad2", + "0x4fc388b57b8d35c704e8c03be70f1c9ba03e638ffac704791c0aeec6d3dd8e2c", + "0xfd0ec61b6a525012d03781c254697a98ac0d4b1e55f46e3aa1ab819e7a90436f", + "0x1d7e68aa18a225ddede2856f421613f88872e89a7024919590930c43326a5bf4", + "0x37865c43f2db20bbfd51a1440e7cf95923c6b980ac6b7e3173d3f867d60d9b32", + "0x44de3419b85216c1d2ab63cf3a002c28835dd084c2e3ee0eb4ba92dc49d5a1b5", + "0xd5fd4d94d504e021eb7865b8aff7ed53c6afa96970fbacd678c2b78fd8c5badf", + "0x479043958f7b84ee3c20a9503fb10b3ecbb895b2b4eb4f69b3ea0b5243f881c8", + "0x683669e82fd55e4162c00a97b2af897395e3a1d3dc51c7f12f4e01e4e3cc3ef6", + "0x9dfc309c9a3382fad72a40825cf621e1dfe095aa77e3b00bd5a0f0c5445d6a34", + "0x63def4af1a927f696cf1abaeba3c172de583cdff6278d8db46e23ac8063ac042", + "0x682e98b0482b1282c896bc2920ce48328246d8d3301b5059988325950f19e0ae", + "0x929abbe6a8ebc0ac32f5ec6a8c1f728d733284e81c02477f606163521d86f642", + "0xd3deb41a543048541beb8b96a1f5b029da6ddb513327d025a5176e95dd4ab1ed", + "0x886432bd185ec9c30a459182ac4467aa9c0f590de8825712c8fe3d9cf7bef9eb", + "0xcc9f64743d0672261a614e9e5c09e9f8416d754f9c536e456a08ef885569a39d", + "0x55bd4b7d2d2ffe8ffd7054d1c8f912119ae793a23dd2d9a10f0ba94ee4b8ac9c", + "0x00a86e2d5dcaec027c9c49853eba467e910f39b4cae50bee85c40b48d34313c6", + "0x89ebc269c4a123f9622e89fd221d22776def13c4a9637a7f69176504ed48ac2e", + "0x808d7a4793aa0afd91d35a6a46eb4f3ed522c77716fbd27765ad2104d2638d75", + "0x5766e58d79181a27639e4e2b1c141de7825e6abe3996d3d06a518bc87044abb0", + "0x53e304b2ae212fac8b059d283f8f97553cb16fb3332e8833305a32db18abb5fa" + ] + }, "nodes": [ "enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303", "enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303", From 50a46431c7b19afea1789dfa206f3a881b81b7b7 Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Thu, 26 Apr 2018 15:00:42 +0300 Subject: [PATCH 046/147] Update wasmi and pwasm-utils (#8493) * Update wasmi to 0.2 New wasmi supports 32bit platforms and no longer requires a special feature to build for such platforms. * Update pwasm-utils to 0.1.5 --- Cargo.lock | 19 +++++++++++++------ ethcore/wasm/Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb7936297e5..4587085dc0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1770,6 +1770,11 @@ dependencies = [ "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nan-preserving-float" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "net2" version = "0.2.31" @@ -2586,7 +2591,7 @@ dependencies = [ [[package]] name = "pwasm-utils" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3625,18 +3630,19 @@ dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", - "wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmi" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3888,6 +3894,7 @@ dependencies = [ "checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" "checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3" +"checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "143149743832c6543b60a8ef2a26cd9122dfecec2b767158e852a7beecf6d7a0" @@ -3928,7 +3935,7 @@ dependencies = [ "checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786" "checksum protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40e2484e639dcae0985fc483ad76ce7ad78ee5aa092751d7d538f0b20d76486b" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" -"checksum pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54d440c3b56eee028aa5d4f18cbed8c6e0c9ae23563b93f344beb7e73854ea02" +"checksum pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d51e9954a77aab7b4b606dc315a49cbed187924f163b6750cdf6d5677dbf0839" "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" @@ -4033,7 +4040,7 @@ dependencies = [ "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb" +"checksum wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46df76793c28cd8f590d5667f540a81c1c245440a17b03560e381226e27cf348" "checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2" "checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index a39e6ee5292..a0362955d1d 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -12,4 +12,4 @@ libc = "0.2" pwasm-utils = "0.1" vm = { path = "../vm" } ethcore-logger = { path = "../../logger" } -wasmi = { version = "0.1.3", features = ["opt-in-32bit"] } +wasmi = { version = "0.2" } From c94f1be8b04aeb74ad1c399bf80d61d12855b0b0 Mon Sep 17 00:00:00 2001 From: David Dorgan Date: Fri, 27 Apr 2018 14:01:47 +0100 Subject: [PATCH 047/147] Remove three old warp boot nodes. (#8497) --- ethcore/res/ethereum/foundation.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 4438718711a..6658b5e5227 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -2873,9 +2873,6 @@ "enode://00526537cb7e1aa6cf49714f0635fd0f608904d8d0693b949eea2dcdfdb0abbe4c794003a5fe57aa662d0a9215e8dfa4d2deb6ef0101c5e185e2617721813d43@40.65.122.44:30303", "enode://4a456b4b6e6ee1f51389763e51b80fe04782c762445d96c32a96ebd34bd9178c1894924d5101123eacfd4f0fc4da25b5e1ee7f18832ac0bf4c6d6ac81442d698@40.71.6.49:3030", "enode://68f85e7403976aa92318eff804cbe9bc988e0f5230d9d07ae4def030cbae16603262638e272d19875b7e5c54e296ba88ab6ec6e98face9e2537346c4dce78882@52.243.47.211:30303", - "enode://dc72806c3aa8fda207c8c018aba8d6cf143728b3628b6ded8d5e8cdeb8aa05cbd53f710ecd014c9a8f0d1e98f2874bff8afb15a229202f510a9c0258d1f6d109@159.203.210.80:30303", - "enode://5a62f19d35c0da8b576c9414568c728d4744e6e9d436c0f9db27456400011414f515871f13a6b8e0468534b5116cfe765d7630f680f1707a38467940a9f62511@45.55.33.62:30303", - "enode://605e04a43b1156966b3a3b66b980c87b7f18522f7f712035f84576016be909a2798a438b2b17b1a8c58db314d88539a77419ca4be36148c086900fba487c9d39@188.166.255.12:30303", "enode://1d1f7bcb159d308eb2f3d5e32dc5f8786d714ec696bb2f7e3d982f9bcd04c938c139432f13aadcaf5128304a8005e8606aebf5eebd9ec192a1471c13b5e31d49@138.201.223.35:30303", "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", From f47c533bc71f3fa7916f8d11b807026e2397cba6 Mon Sep 17 00:00:00 2001 From: Anton Gavrilov Date: Fri, 27 Apr 2018 15:02:45 +0200 Subject: [PATCH 048/147] Return error if RLP size of transaction exceeds the limit (#8473) * Return error if RLP size of transaction exceeds the limit * Review comments fixed * RLP check moved to verifier, corresponding pool test added --- Cargo.lock | 1 + ethcore/src/client/client.rs | 3 +-- ethcore/src/engines/mod.rs | 5 +++++ ethcore/src/machine.rs | 11 +++++++++++ ethcore/src/miner/pool_client.rs | 4 ++++ ethcore/src/spec/spec.rs | 5 +++++ ethcore/sync/src/chain.rs | 5 ----- ethcore/transaction/src/error.rs | 13 +++++++++++++ json/src/spec/params.rs | 3 +++ miner/Cargo.toml | 1 + miner/src/lib.rs | 1 + miner/src/pool/client.rs | 4 ++++ miner/src/pool/res/big_transaction.data | 1 + miner/src/pool/tests/client.rs | 14 ++++++++++++++ miner/src/pool/tests/mod.rs | 10 ++++++++++ miner/src/pool/tests/tx.rs | 13 +++++++++++++ miner/src/pool/verifier.rs | 7 +++++++ rpc/src/v1/helpers/errors.rs | 2 ++ 18 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 miner/src/pool/res/big_transaction.data diff --git a/Cargo.lock b/Cargo.lock index 4587085dc0e..48a0ab0d945 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -684,6 +684,7 @@ dependencies = [ "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "price-info 1.12.0", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", "transaction-pool 1.12.0", diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 6ec318a03f9..ebc8961cd06 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -62,7 +62,6 @@ use ethcore_miner::pool::VerifiedTransaction; use parking_lot::{Mutex, RwLock}; use rand::OsRng; use receipt::{Receipt, LocalizedReceipt}; -use rlp::Rlp; use snapshot::{self, io as snapshot_io}; use spec::Spec; use state_db::StateDB; @@ -995,7 +994,7 @@ impl Client { let txs: Vec = transactions .iter() - .filter_map(|bytes| Rlp::new(bytes).as_val().ok()) + .filter_map(|bytes| self.engine().decode_transaction(bytes).ok()) .collect(); self.notify(|notify| { diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 8556879f95a..a17ae356e6f 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -426,6 +426,11 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> { fn additional_params(&self) -> HashMap { self.machine().additional_params() } + + /// Performs pre-validation of RLP decoded transaction before other processing + fn decode_transaction(&self, transaction: &[u8]) -> Result { + self.machine().decode_transaction(transaction) + } } // convenience wrappers for existing functions. diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 7d488e0d0c9..e3bf7d340ca 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -34,6 +34,7 @@ use tx_filter::TransactionFilter; use ethereum_types::{U256, Address}; use bytes::BytesRef; +use rlp::Rlp; use vm::{CallType, ActionParams, ActionValue, ParamsType}; use vm::{EnvInfo, Schedule, CreateContractAddress}; @@ -376,6 +377,16 @@ impl EthereumMachine { "registrar".to_owned() => format!("{:x}", self.params.registrar) ] } + + /// Performs pre-validation of RLP decoded transaction before other processing + pub fn decode_transaction(&self, transaction: &[u8]) -> Result { + let rlp = Rlp::new(&transaction); + if rlp.as_raw().len() > self.params().max_transaction_size { + debug!("Rejected oversized transaction of {} bytes", rlp.as_raw().len()); + return Err(transaction::Error::TooBig) + } + rlp.as_val().map_err(|e| transaction::Error::InvalidRlp(e.to_string())) + } } /// Auxiliary data fetcher for an Ethereum machine. In Ethereum-like machines diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs index 61153be0256..dfcdec684f8 100644 --- a/ethcore/src/miner/pool_client.rs +++ b/ethcore/src/miner/pool_client.rs @@ -145,6 +145,10 @@ impl<'a, C: 'a> pool::client::Client for PoolClient<'a, C> where } } } + + fn decode_transaction(&self, transaction: &[u8]) -> Result { + self.engine.decode_transaction(transaction) + } } impl<'a, C: 'a> NonceClient for PoolClient<'a, C> where diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 7f6d650dd4f..156ab8f15a8 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -48,6 +48,8 @@ use trace::{NoopTracer, NoopVMTracer}; pub use ethash::OptimizeFor; +const MAX_TRANSACTION_SIZE: usize = 300 * 1024; + // helper for formatting errors. fn fmt_err(f: F) -> String { format!("Spec json is invalid: {}", f) @@ -123,6 +125,8 @@ pub struct CommonParams { pub max_code_size_transition: BlockNumber, /// Transaction permission managing contract address. pub transaction_permission_contract: Option

, + /// Maximum size of transaction's RLP payload + pub max_transaction_size: usize, } impl CommonParams { @@ -238,6 +242,7 @@ impl From for CommonParams { registrar: p.registrar.map_or_else(Address::new, Into::into), node_permission_contract: p.node_permission_contract.map(Into::into), max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into), + max_transaction_size: p.max_transaction_size.map_or(MAX_TRANSACTION_SIZE, Into::into), max_code_size_transition: p.max_code_size_transition.map_or(0, Into::into), transaction_permission_contract: p.transaction_permission_contract.map(Into::into), wasm_activation_transition: p.wasm_activation_transition.map_or( diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index eaab13b6f4b..25d9a09f6bc 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -140,7 +140,6 @@ const MAX_PEERS_PROPAGATION: usize = 128; const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20; const MAX_NEW_HASHES: usize = 64; const MAX_NEW_BLOCK_AGE: BlockNumber = 20; -const MAX_TRANSACTION_SIZE: usize = 300*1024; // maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; // Maximal number of transactions in sent in single packet. @@ -1517,10 +1516,6 @@ impl ChainSync { let mut transactions = Vec::with_capacity(item_count); for i in 0 .. item_count { let rlp = r.at(i)?; - if rlp.as_raw().len() > MAX_TRANSACTION_SIZE { - debug!("Skipped oversized transaction of {} bytes", rlp.as_raw().len()); - continue; - } let tx = rlp.as_raw().to_vec(); transactions.push(tx); } diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index e38dc3ac675..eeeba4e53a9 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -18,6 +18,7 @@ use std::{fmt, error}; use ethereum_types::U256; use ethkey; +use rlp; use unexpected::OutOfBounds; #[derive(Debug, PartialEq, Clone)] @@ -74,6 +75,10 @@ pub enum Error { NotAllowed, /// Signature error InvalidSignature(String), + /// Transaction too big + TooBig, + /// Invalid RLP encoding + InvalidRlp(String), } impl From for Error { @@ -82,6 +87,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: rlp::DecoderError) -> Self { + Error::InvalidRlp(format!("{}", err)) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; @@ -106,6 +117,8 @@ impl fmt::Display for Error { InvalidChainId => "Transaction of this chain ID is not allowed on this chain.".into(), InvalidSignature(ref err) => format!("Transaction has invalid signature: {}.", err), NotAllowed => "Sender does not have permissions to execute this type of transction".into(), + TooBig => "Transaction too big".into(), + InvalidRlp(ref err) => format!("Transaction has invalid RLP structure: {}.", err), }; f.write_fmt(format_args!("Transaction error ({})", msg)) diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 4a1efe2a7f9..ce47086df17 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -113,6 +113,9 @@ pub struct Params { /// See main EthashParams docs. #[serde(rename="maxCodeSize")] pub max_code_size: Option, + /// Maximum size of transaction RLP payload. + #[serde(rename="maxTransactionSize")] + pub max_transaction_size: Option, /// See main EthashParams docs. #[serde(rename="maxCodeSizeTransition")] pub max_code_size_transition: Option, diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 95dd888dc9a..707352484e2 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -28,6 +28,7 @@ log = "0.3" parking_lot = "0.5" price-info = { path = "../price-info" } rayon = "1.0" +rlp = { path = "../util/rlp" } trace-time = { path = "../util/trace-time" } transaction-pool = { path = "../transaction-pool" } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 197823aec79..08ea7d204fb 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -30,6 +30,7 @@ extern crate linked_hash_map; extern crate parking_lot; extern crate price_info; extern crate rayon; +extern crate rlp; extern crate trace_time; extern crate transaction_pool as txpool; diff --git a/miner/src/pool/client.rs b/miner/src/pool/client.rs index 4243e8d26bf..622e9a84927 100644 --- a/miner/src/pool/client.rs +++ b/miner/src/pool/client.rs @@ -62,6 +62,10 @@ pub trait Client: fmt::Debug + Sync { /// Classify transaction (check if transaction is filtered by some contracts). fn transaction_type(&self, tx: &transaction::SignedTransaction) -> TransactionType; + + /// Performs pre-validation of RLP decoded transaction + fn decode_transaction(&self, transaction: &[u8]) + -> Result; } /// State nonce client diff --git a/miner/src/pool/res/big_transaction.data b/miner/src/pool/res/big_transaction.data new file mode 100644 index 00000000000..15703f893ad --- /dev/null +++ b/miner/src/pool/res/big_transaction.data @@ -0,0 +1 @@ +6060604052341561000f57600080fd5b604051610b0d380380610b0d833981016040528080518201919060200180518201919060200180518201919050508260009080519060200190610053929190610092565b50816002908051906020019061006a92919061011c565b50806001908051906020019061008192919061011c565b506001600381905550505050610204565b82805482825590600052602060002090810192821561010b579160200282015b8281111561010a5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906100b2565b5b509050610118919061019c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061015d57805160ff191683800117855561018b565b8280016001018555821561018b579182015b8281111561018a57825182559160200191906001019061016f565b5b50905061019891906101df565b5090565b6101dc91905b808211156101d857600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016101a2565b5090565b90565b61020191905b808211156101fd5760008160009055506001016101e5565b5090565b90565b6108fa806102136000396000f300606060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806317ac53a21461007d57806324c12bf61461019a57806335aa2e4414610228578063affed0e01461028b578063b7ab4db5146102b4578063c19d93fb1461031e575b600080fd5b341561008857600080fd5b610198600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506103ac565b005b34156101a557600080fd5b6101ad610600565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ed5780820151818401526020810190506101d2565b50505050905090810190601f16801561021a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561023357600080fd5b610249600480803590602001909190505061069e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561029657600080fd5b61029e6106dd565b6040518082815260200191505060405180910390f35b34156102bf57600080fd5b6102c76106e3565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561030a5780820151818401526020810190506102ef565b505050509050019250505060405180910390f35b341561032957600080fd5b610331610777565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610371578082015181840152602081019050610356565b50505050905090810190601f16801561039e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000806040805190810160405280876040518082805190602001908083835b6020831015156103f057805182526020820191506020810190506020830392506103cb565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200160035460010260001916600019168152506040518082600260200280838360005b8381101561046657808201518184015260208101905061044b565b5050505090500191505060405180910390209150600090505b6000805490508110156105d55760008181548110151561049b57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660018387848151811015156104ee57fe5b90602001906020020151878581518110151561050657fe5b90602001906020020151878681518110151561051e57fe5b90602001906020020151604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f115156105a057600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff161415156105c857fe5b808060010191505061047f565b85600190805190602001906105eb929190610815565b50600160035401600381905550505050505050565b60028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106965780601f1061066b57610100808354040283529160200191610696565b820191906000526020600020905b81548152906001019060200180831161067957829003601f168201915b505050505081565b6000818154811015156106ad57fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b6106eb610895565b600080548060200260200160405190810160405280929190818152602001828054801561076d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610723575b5050505050905090565b60018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561080d5780601f106107e25761010080835404028352916020019161080d565b820191906000526020600020905b8154815290600101906020018083116107f057829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061085657805160ff1916838001178555610884565b82800160010185558215610884579182015b82811115610883578251825591602001919060010190610868565b5b50905061089191906108a9565b5090565b602060405190810160405280600081525090565b6108cb91905b808211156108c75760008160009055506001016108af565b5090565b905600a165627a7a723058200ae0215fae320b646a22fdd58278b328f46d915bd65ddbfeb5b4a09643d6e0220029000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000007ffbe3512782069be388f41be4d8eb350672d3a500000000000000000000000000000000000000000000000000000000000000e88b98f0e95488c3849ba24320a00a047c39b3ca3af8f066d82d849104eb0218150baf61620b321c8d2db0c8e351fd17826cd2cd13296287fb02cab742db410ba4346b4c13c1f81cc52dd5ee3dd7773e23842fe5d8e29db6da6f8f6f42964f118486b0c8d7971cfb8ed4926622774c92e495ae47dd481eb03090ad09a1fb4a2cd0ad4b108efeb408f160f34fae6f6d9843574f3e37dd11ec54dd69fa7dfa919257e760a78d6cccec92785381f9554b3da1249c4844e259b0f57180034fb63bd6136132f822f6472a31c68b8a60646bcbddfa4ddd3be0fe4457a4f691a6542bf798a4fa6b0990284166000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001056e81f171bcc55a6ff8345e692c0f86e000000000000000000000000000000006060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d83398101 diff --git a/miner/src/pool/tests/client.rs b/miner/src/pool/tests/client.rs index 7f7be64cc8d..a00cc541ebc 100644 --- a/miner/src/pool/tests/client.rs +++ b/miner/src/pool/tests/client.rs @@ -15,17 +15,21 @@ // along with Parity. If not, see . use ethereum_types::{U256, H256, Address}; +use rlp::Rlp; use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; use pool; use pool::client::AccountDetails; +const MAX_TRANSACTION_SIZE: usize = 15 * 1024; + #[derive(Debug, Clone)] pub struct TestClient { account_details: AccountDetails, gas_required: U256, is_service_transaction: bool, local_address: Address, + max_transaction_size: usize, } impl Default for TestClient { @@ -39,6 +43,7 @@ impl Default for TestClient { gas_required: 21_000.into(), is_service_transaction: false, local_address: Default::default(), + max_transaction_size: MAX_TRANSACTION_SIZE, } } } @@ -116,6 +121,15 @@ impl pool::client::Client for TestClient { pool::client::TransactionType::Regular } } + + fn decode_transaction(&self, transaction: &[u8]) -> Result { + let rlp = Rlp::new(&transaction); + if rlp.as_raw().len() > self.max_transaction_size { + return Err(transaction::Error::TooBig) + } + rlp.as_val().map_err(|e| transaction::Error::InvalidRlp(e.to_string())) + } + } impl pool::client::NonceClient for TestClient { diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 340cb751586..0d8e38a6e11 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -755,3 +755,13 @@ fn should_clear_cache_after_timeout_for_local() { // then assert_eq!(txq.pending(TestClient::new(), 0, 1002, None).len(), 2); } + +#[test] +fn should_reject_big_transaction() { + let txq = new_queue(); + let big_tx = Tx::default().big_one(); + let res = txq.import(TestClient::new(), vec![ + verifier::Transaction::Local(PendingTransaction::new(big_tx, transaction::Condition::Timestamp(1000).into())) + ]); + assert_eq!(res, vec![Err(transaction::Error::TooBig)]); +} \ No newline at end of file diff --git a/miner/src/pool/tests/tx.rs b/miner/src/pool/tests/tx.rs index ee0a7390eed..c0f8751ebba 100644 --- a/miner/src/pool/tests/tx.rs +++ b/miner/src/pool/tests/tx.rs @@ -87,6 +87,19 @@ impl Tx { nonce: self.nonce.into() } } + + pub fn big_one(self) -> SignedTransaction { + let keypair = Random.generate().unwrap(); + let tx = Transaction { + action: transaction::Action::Create, + value: U256::from(100), + data: include_str!("../res/big_transaction.data").from_hex().unwrap(), + gas: self.gas.into(), + gas_price: self.gas_price.into(), + nonce: self.nonce.into() + }; + tx.sign(keypair.secret(), None) + } } pub trait TxExt: Sized { type Out; diff --git a/miner/src/pool/verifier.rs b/miner/src/pool/verifier.rs index 92d2eb9c86b..0a89a784b11 100644 --- a/miner/src/pool/verifier.rs +++ b/miner/src/pool/verifier.rs @@ -27,6 +27,7 @@ use std::sync::Arc; use std::sync::atomic::{self, AtomicUsize}; use ethereum_types::{U256, H256}; +use rlp::Encodable; use transaction; use txpool; @@ -222,6 +223,12 @@ impl txpool::Verifier for Verifier { Transaction::Local(tx) => tx, }; + // Verify RLP payload + if let Err(err) = self.client.decode_transaction(&transaction.rlp_bytes()) { + debug!(target: "txqueue", "[{:?}] Rejected transaction's rlp payload", err); + bail!(err) + } + let sender = transaction.sender(); let account_details = self.client.account_details(&sender); diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index acff796646e..4f3289a116b 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -338,6 +338,8 @@ pub fn transaction_message(error: &TransactionError) -> String { RecipientBanned => "Recipient is banned in local queue.".into(), CodeBanned => "Code is banned in local queue.".into(), NotAllowed => "Transaction is not permitted.".into(), + TooBig => "Transaction is too big, see chain specification for the limit.".into(), + InvalidRlp(ref descr) => format!("Invalid RLP data: {}", descr), } } From bde4bf58a12ff6d07a546b9dd1c1b1e087c6c2d3 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 27 Apr 2018 15:04:27 +0200 Subject: [PATCH 049/147] `duration_ns: u64 -> duration: Duration` (#8457) * duration_ns: u64 -> duration: Duration * format on millis {:.2} -> {} --- ethcore/private-tx/src/lib.rs | 3 ++- ethcore/src/client/chain_notify.rs | 3 ++- ethcore/src/client/client.rs | 24 +++++++------------ ethcore/src/snapshot/watcher.rs | 9 ++++--- ethcore/sync/src/api.rs | 6 ++--- ethcore/sync/src/tests/helpers.rs | 3 ++- parity/informant.rs | 4 ++-- rpc/src/v1/impls/eth_pubsub.rs | 3 ++- rpc/src/v1/tests/mocked/eth_pubsub.rs | 12 ++++++---- secret_store/src/acl_storage.rs | 3 ++- secret_store/src/key_server_set.rs | 3 ++- .../src/listener/service_contract_listener.rs | 3 ++- updater/src/updater.rs | 2 +- 13 files changed, 43 insertions(+), 35 deletions(-) diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 12028ddf121..26a31fc7ae3 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -66,6 +66,7 @@ pub use error::{Error, ErrorKind}; use std::sync::{Arc, Weak}; use std::collections::{HashMap, HashSet}; +use std::time::Duration; use ethereum_types::{H128, H256, U256, Address}; use hash::keccak; use rlp::*; @@ -667,7 +668,7 @@ fn find_account_password(passwords: &Vec, account_provider: &AccountProv } impl ChainNotify for Provider { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !imported.is_empty() { trace!("New blocks imported, try to prune the queue"); if let Err(err) = self.process_queue() { diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index ccfb2558d61..a1f84d2a139 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -17,6 +17,7 @@ use bytes::Bytes; use ethereum_types::H256; use transaction::UnverifiedTransaction; +use std::time::Duration; /// Messages to broadcast via chain pub enum ChainMessageType { @@ -40,7 +41,7 @@ pub trait ChainNotify : Send + Sync { _sealed: Vec, // Block bytes. _proposed: Vec, - _duration: u64, + _duration: Duration, ) { // does nothing by default } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ebc8961cd06..8d305fc0572 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -18,7 +18,7 @@ use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; -use std::time::{Instant}; +use std::time::{Instant, Duration}; use itertools::Itertools; // util @@ -32,7 +32,7 @@ use util_error::UtilError; // other use ethereum_types::{H256, Address, U256}; use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; use client::ancient_import::AncientVerifier; use client::Error as ClientError; use client::{ @@ -120,7 +120,7 @@ impl<'a> ::std::ops::Sub<&'a ClientReport> for ClientReport { self.blocks_imported -= other.blocks_imported; self.transactions_applied -= other.transactions_applied; self.gas_processed = self.gas_processed - other.gas_processed; - self.state_db_mem = higher_mem - lower_mem; + self.state_db_mem = higher_mem - lower_mem; self } @@ -331,11 +331,7 @@ impl Importer { self.block_queue.mark_as_bad(&invalid_blocks); } let is_empty = self.block_queue.mark_as_good(&imported_blocks); - let duration_ns = { - let elapsed = start.elapsed(); - elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64 - }; - (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, duration_ns, is_empty) + (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, start.elapsed(), is_empty) }; { @@ -1434,7 +1430,7 @@ impl ImportBlock for Client { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } let status = self.block_status(BlockId::Hash(header.parent_hash())); - if status == BlockStatus::Unknown || status == BlockStatus::Pending { + if status == BlockStatus::Unknown || status == BlockStatus::Pending { bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(header.parent_hash()))); } } @@ -1497,7 +1493,7 @@ impl Call for Client { } fn estimate_gas(&self, t: &SignedTransaction, state: &Self::State, header: &Header) -> Result { - let (mut upper, max_upper, env_info) = { + let (mut upper, max_upper, env_info) = { let init = *header.gas_limit(); let max = init * U256::from(10); @@ -2096,10 +2092,7 @@ impl ImportSealedBlock for Client { retracted.clone(), vec![h.clone()], vec![], - { - let elapsed = start.elapsed(); - elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64 - }, + start.elapsed(), ); }); self.db.read().flush().expect("DB flush failed."); @@ -2109,6 +2102,7 @@ impl ImportSealedBlock for Client { impl BroadcastProposalBlock for Client { fn broadcast_proposal_block(&self, block: SealedBlock) { + const DURATION_ZERO: Duration = Duration::from_millis(0); self.notify(|notify| { notify.new_blocks( vec![], @@ -2117,7 +2111,7 @@ impl BroadcastProposalBlock for Client { vec![], vec![], vec![block.rlp_bytes()], - 0, + DURATION_ZERO, ); }); } diff --git a/ethcore/src/snapshot/watcher.rs b/ethcore/src/snapshot/watcher.rs index 841fa1982ac..936feaefba8 100644 --- a/ethcore/src/snapshot/watcher.rs +++ b/ethcore/src/snapshot/watcher.rs @@ -24,7 +24,7 @@ use io::IoChannel; use ethereum_types::H256; use bytes::Bytes; -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; // helper trait for transforming hashes to numbers and checking if syncing. trait Oracle: Send + Sync { @@ -107,7 +107,7 @@ impl ChainNotify for Watcher { _: Vec, _: Vec, _: Vec, - _duration: u64) + _duration: Duration) { if self.oracle.is_major_importing() { return } @@ -136,6 +136,7 @@ mod tests { use ethereum_types::{H256, U256}; use std::collections::HashMap; + use std::time::Duration; struct TestOracle(HashMap); @@ -158,6 +159,8 @@ mod tests { // helper harness for tests which expect a notification. fn harness(numbers: Vec, period: u64, history: u64, expected: Option) { + const DURATION_ZERO: Duration = Duration::from_millis(0); + let hashes: Vec<_> = numbers.clone().into_iter().map(|x| H256::from(U256::from(x))).collect(); let map = hashes.clone().into_iter().zip(numbers).collect(); @@ -175,7 +178,7 @@ mod tests { vec![], vec![], vec![], - 0, + DURATION_ZERO, ); } diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index c66a1c6a625..5e96f11cf37 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -413,7 +413,7 @@ impl ChainNotify for EthSync { retracted: Vec, sealed: Vec, proposed: Vec, - _duration: u64) + _duration: Duration) { use light::net::Announcement; @@ -452,7 +452,7 @@ impl ChainNotify for EthSync { fn start(&self) { match self.network.start().map_err(Into::into) { - Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), + Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), Err(err) => warn!("Error starting network: {}", err), _ => {}, } @@ -625,7 +625,7 @@ impl NetworkConfiguration { config_path: self.config_path, net_config_path: self.net_config_path, listen_address: match self.listen_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, - public_address: match self.public_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, + public_address: match self.public_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, udp_port: self.udp_port, nat_enabled: self.nat_enabled, discovery_enabled: self.discovery_enabled, diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 086dc503bba..54467adb775 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -16,6 +16,7 @@ use std::collections::{VecDeque, HashSet, HashMap}; use std::sync::Arc; +use std::time::Duration; use ethereum_types::H256; use parking_lot::{RwLock, Mutex}; use bytes::Bytes; @@ -538,7 +539,7 @@ impl ChainNotify for EthPeer { retracted: Vec, sealed: Vec, proposed: Vec, - _duration: u64) + _duration: Duration) { self.new_blocks_queue.write().push_back(NewBlockMessage { imported, diff --git a/parity/informant.rs b/parity/informant.rs index 896e80ec53d..29f732e0853 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -351,7 +351,7 @@ impl Informant { } impl ChainNotify for Informant { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, duration: u64) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, duration: Duration) { let mut last_import = self.last_import.lock(); let client = &self.target.client; @@ -373,7 +373,7 @@ impl ChainNotify for Informant { Colour::White.bold().paint(format!("{}", header_view.hash())), Colour::Yellow.bold().paint(format!("{}", block.transactions_count())), Colour::Yellow.bold().paint(format!("{:.2}", header_view.gas_used().low_u64() as f32 / 1000000f32)), - Colour::Purple.bold().paint(format!("{:.2}", duration as f32 / 1000000f32)), + Colour::Purple.bold().paint(format!("{}", duration.as_milliseconds())), Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)), if skipped > 0 { format!(" + another {} block(s) containing {} tx(s)", diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index d7e6112a93a..1a872f5600a 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -18,6 +18,7 @@ use std::sync::{Arc, Weak}; use std::collections::BTreeMap; +use std::time::Duration; use jsonrpc_core::{BoxFuture, Result, Error}; use jsonrpc_core::futures::{self, Future, IntoFuture}; @@ -227,7 +228,7 @@ impl ChainNotify for ChainNotificationHandler { _sealed: Vec, // Block bytes. _proposed: Vec, - _duration: u64, + _duration: Duration, ) { const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; let headers = enacted diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index 15b178d504e..fb28ba31274 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -20,11 +20,15 @@ use jsonrpc_core::MetaIoHandler; use jsonrpc_core::futures::{self, Stream, Future}; use jsonrpc_pubsub::Session; +use std::time::Duration; + use v1::{EthPubSub, EthPubSubClient, Metadata}; use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify}; use parity_reactor::EventLoop; +const DURATION_ZERO: Duration = Duration::from_millis(0); + #[test] fn should_subscribe_to_new_heads() { // given @@ -53,13 +57,13 @@ fn should_subscribe_to_new_heads() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x1","extraData":"0x","gasLimit":"0xf4240","gasUsed":"0x0","hash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","number":"0x1","parentHash":"0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x1c9","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","timestamp":"0x0","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); // Notify about two blocks - handler.new_blocks(vec![], vec![], vec![h2, h3], vec![], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![h2, h3], vec![], vec![], vec![], DURATION_ZERO); // Receive both let (res, receiver) = receiver.into_future().wait().unwrap(); @@ -125,7 +129,7 @@ fn should_subscribe_to_logs() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications (enacted) - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) @@ -133,7 +137,7 @@ fn should_subscribe_to_logs() { assert_eq!(res, Some(response.into())); // Check notifications (retracted) - handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 58d9bc47756..6399660aff3 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -16,6 +16,7 @@ use std::sync::Arc; use std::collections::{HashMap, HashSet}; +use std::time::Duration; use parking_lot::{Mutex, RwLock}; use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; use ethereum_types::{H256, Address}; @@ -75,7 +76,7 @@ impl AclStorage for OnChainAclStorage { } impl ChainNotify for OnChainAclStorage { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !enacted.is_empty() || !retracted.is_empty() { self.contract.lock().update() } diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index 7697408557e..cb324dbc9ba 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use std::net::SocketAddr; use std::collections::{BTreeMap, HashSet}; +use std::time::Duration; use parking_lot::Mutex; use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, CallContract, RegistryInfo}; use ethcore::filter::Filter; @@ -162,7 +163,7 @@ impl KeyServerSet for OnChainKeyServerSet { } impl ChainNotify for OnChainKeyServerSet { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !enacted.is_empty() || !retracted.is_empty() { self.contract.lock().update(enacted, retracted) } diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 2975eaa134c..1e17be8e557 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -17,6 +17,7 @@ use std::collections::HashSet; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::time::Duration; use std::thread; use parking_lot::Mutex; use ethcore::client::ChainNotify; @@ -428,7 +429,7 @@ impl Drop for ServiceContractListener { } impl ChainNotify for ServiceContractListener { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { let enacted_len = enacted.len(); if enacted_len == 0 { return; diff --git a/updater/src/updater.rs b/updater/src/updater.rs index 3b5ce01a935..c5f45c7658a 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -660,7 +660,7 @@ impl Updater, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { match (self.client.upgrade(), self.sync.as_ref().and_then(Weak::upgrade)) { (Some(ref c), Some(ref s)) if !s.status().is_syncing(c.queue_info()) => self.poll(), _ => {}, From f58dc73afc80a0e9ba67c92dc10ce2ddde21dd98 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 27 Apr 2018 17:46:17 +0200 Subject: [PATCH 050/147] Remove unused dependency `bigint` (#8505) * remove unused dependency bigint in * remove bigint in rpc_cli --- Cargo.lock | 13 ------------- rpc_cli/Cargo.toml | 1 - util/memorydb/Cargo.toml | 1 - 3 files changed, 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48a0ab0d945..3176c3ab3d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,16 +102,6 @@ dependencies = [ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bigint" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bincode" version = "0.8.0" @@ -1634,7 +1624,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "memorydb" version = "0.1.1" dependencies = [ - "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", @@ -2806,7 +2795,6 @@ dependencies = [ name = "rpc-cli" version = "1.4.0" dependencies = [ - "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.12.0", "parity-rpc-client 1.4.0", @@ -3783,7 +3771,6 @@ dependencies = [ "checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4" -"checksum bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5442186ef6560f30f1ee4b9c1e4c87a35a6879d3644550cc248ec2b955eb5fcd" "checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" diff --git a/rpc_cli/Cargo.toml b/rpc_cli/Cargo.toml index 0bda94ab674..7d4652c38cb 100644 --- a/rpc_cli/Cargo.toml +++ b/rpc_cli/Cargo.toml @@ -9,6 +9,5 @@ version = "1.4.0" [dependencies] futures = "0.1" rpassword = "1.0" -bigint = "4.0" parity-rpc = { path = "../rpc" } parity-rpc-client = { path = "../rpc_client" } diff --git a/util/memorydb/Cargo.toml b/util/memorydb/Cargo.toml index da832278146..41c41bb628e 100644 --- a/util/memorydb/Cargo.toml +++ b/util/memorydb/Cargo.toml @@ -6,7 +6,6 @@ description = "in-memory implementation of hashdb" license = "GPL-3.0" [dependencies] -bigint = "4.0" elastic-array = "0.10" heapsize = "0.4" ethereum-types = "0.3" From e5832e41f4716cdce989adad3876c7c04c2fb406 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 1 May 2018 20:16:03 +0800 Subject: [PATCH 051/147] Show imported messages for light client (#8517) --- ethcore/light/src/client/service.rs | 7 ++++++- parity/informant.rs | 29 ++++++++++++++++++++++++++++- parity/run.rs | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/ethcore/light/src/client/service.rs b/ethcore/light/src/client/service.rs index 3d13be16b4a..a3ec8a36866 100644 --- a/ethcore/light/src/client/service.rs +++ b/ethcore/light/src/client/service.rs @@ -30,7 +30,7 @@ use kvdb::KeyValueDB; use cache::Cache; use parking_lot::Mutex; -use super::{ChainDataFetcher, Client, Config as ClientConfig}; +use super::{ChainDataFetcher, LightChainNotify, Client, Config as ClientConfig}; /// Errors on service initialization. #[derive(Debug)] @@ -86,6 +86,11 @@ impl Service { }) } + /// Set the actor to be notified on certain chain events + pub fn add_notify(&self, notify: Arc) { + self.client.add_listener(Arc::downgrade(¬ify)); + } + /// Register an I/O handler on the service. pub fn register_handler(&self, handler: Arc + Send>) -> Result<(), IoError> { self.io_service.register_handler(handler) diff --git a/parity/informant.rs b/parity/informant.rs index 29f732e0853..5c2e0ab89d3 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -33,7 +33,7 @@ use ethcore::snapshot::service::Service as SnapshotService; use sync::{LightSyncProvider, LightSync, SyncProvider, ManageNetwork}; use io::{TimerToken, IoContext, IoHandler}; use light::Cache as LightDataCache; -use light::client::LightChainClient; +use light::client::{LightChainClient, LightChainNotify}; use number_prefix::{binary_prefix, Standalone, Prefixed}; use parity_rpc::{is_major_importing}; use parity_rpc::informant::RpcStats; @@ -395,6 +395,33 @@ impl ChainNotify for Informant { } } +impl LightChainNotify for Informant { + fn new_headers(&self, good: &[H256]) { + let mut last_import = self.last_import.lock(); + let client = &self.target.client; + + let importing = self.target.is_major_importing(); + let ripe = Instant::now() > *last_import + Duration::from_secs(1) && !importing; + + if ripe { + if let Some(header) = good.last().and_then(|h| client.block_header(BlockId::Hash(*h))) { + info!(target: "import", "Imported {} {} ({} Mgas){}", + Colour::White.bold().paint(format!("#{}", header.number())), + Colour::White.bold().paint(format!("{}", header.hash())), + Colour::Yellow.bold().paint(format!("{:.2}", header.gas_used().low_u64() as f32 / 1000000f32)), + if good.len() > 1 { + format!(" + another {} header(s)", + Colour::Red.bold().paint(format!("{}", good.len() - 1))) + } else { + String::new() + } + ); + *last_import = Instant::now(); + } + } + } +} + const INFO_TIMER: TimerToken = 0; impl IoHandler for Informant { diff --git a/parity/run.rs b/parity/run.rs index f07f67caa83..fdb32293b9c 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -412,7 +412,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result Date: Tue, 1 May 2018 20:47:04 +0800 Subject: [PATCH 052/147] Directly return None if tracing is disabled (#8504) * Directly return None if tracing is disabled * Address gumbles: release read locks as fast as possible --- ethcore/src/client/client.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8d305fc0572..bc20de3dd86 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1868,6 +1868,10 @@ impl BlockChainClient for Client { } fn filter_traces(&self, filter: TraceFilter) -> Option> { + if !self.tracedb.read().tracing_enabled() { + return None; + } + let start = self.block_number(filter.range.start)?; let end = self.block_number(filter.range.end)?; @@ -1887,6 +1891,10 @@ impl BlockChainClient for Client { } fn trace(&self, trace: TraceId) -> Option { + if !self.tracedb.read().tracing_enabled() { + return None; + } + let trace_address = trace.address; self.transaction_address(trace.transaction) .and_then(|tx_address| { @@ -1896,6 +1904,10 @@ impl BlockChainClient for Client { } fn transaction_traces(&self, transaction: TransactionId) -> Option> { + if !self.tracedb.read().tracing_enabled() { + return None; + } + self.transaction_address(transaction) .and_then(|tx_address| { self.block_number(BlockId::Hash(tx_address.block_hash)) @@ -1904,6 +1916,10 @@ impl BlockChainClient for Client { } fn block_traces(&self, block: BlockId) -> Option> { + if !self.tracedb.read().tracing_enabled() { + return None; + } + self.block_number(block) .and_then(|number| self.tracedb.read().block_traces(number)) } From 4ddf13a453b1f9a3085b35d11dc2c9dd67038b99 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 1 May 2018 15:01:49 +0200 Subject: [PATCH 053/147] Hardware Wallet trait (#8071) * getting started with replacing HardwareWalletManager * trezor and ledger impls the new trait with some drawbacks * Everything move to the new trait * It required lifetime annotations in the trait because [u8] in unsized * Lets now start moving entry point from HardwareWalletManager * rename trait to Wallet * move thread management to the actual wallets * Moved thread management to each respective Wallet * Cleaned up pub items that is needed to be pub * Wallet trait more or less finished * Cleaned up docs * fix tests * omit removed docs * fix spelling, naming och remove old comments * ledger test is broken, add correct logging format * So locally on my machine Linux Ubuntu 17.10 the test doesn't panic but on the CI server libusb::Context::new() fails which I don't understand because it has worked before * Additionally the ledger test is optional so I lean toward ignoring it the CI Server * ignore hardware tests by default * more verbose checking in ledger test --- hw/src/ledger.rs | 397 ++++++++++++++++++++++++++--------------------- hw/src/lib.rs | 132 ++++++++-------- hw/src/trezor.rs | 344 +++++++++++++++++++++------------------- 3 files changed, 473 insertions(+), 400 deletions(-) diff --git a/hw/src/ledger.rs b/hw/src/ledger.rs index e7d616d4f9f..e31d49f1304 100644 --- a/hw/src/ledger.rs +++ b/hw/src/ledger.rs @@ -20,8 +20,11 @@ use std::cmp::min; use std::fmt; use std::str::FromStr; +use std::sync::atomic; +use std::sync::atomic::AtomicBool; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; +use std::thread; use ethereum_types::{H256, Address}; use ethkey::Signature; @@ -29,12 +32,12 @@ use hidapi; use libusb; use parking_lot::{Mutex, RwLock}; -use super::{WalletInfo, KeyPath}; +use super::{WalletInfo, KeyPath, Device, Wallet, USB_DEVICE_CLASS_DEVICE}; /// Ledger vendor ID -pub const LEDGER_VID: u16 = 0x2c97; -/// Legder product IDs: [Nano S and Blue] -pub const LEDGER_PIDS: [u16; 2] = [0x0000, 0x0001]; +const LEDGER_VID: u16 = 0x2c97; +/// Ledger product IDs: [Nano S and Blue] +const LEDGER_PIDS: [u16; 2] = [0x0000, 0x0001]; const ETH_DERIVATION_PATH_BE: [u8; 17] = [4, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/0'/0 const ETC_DERIVATION_PATH_BE: [u8; 21] = [5, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0x02, 0x73, 0xd0, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/160720'/0'/0 @@ -64,8 +67,10 @@ pub enum Error { KeyNotFound, /// Signing has been cancelled by user. UserCancel, - /// Invalid Device + /// Invalid device InvalidDevice, + /// Impossible error + ImpossibleError, } impl fmt::Display for Error { @@ -77,6 +82,7 @@ impl fmt::Display for Error { Error::KeyNotFound => write!(f, "Key not found"), Error::UserCancel => write!(f, "Operation has been cancelled"), Error::InvalidDevice => write!(f, "Unsupported product was entered"), + Error::ImpossibleError => write!(f, "Placeholder error"), } } } @@ -100,157 +106,43 @@ pub struct Manager { key_path: RwLock, } -#[derive(Debug)] -struct Device { - path: String, - info: WalletInfo, -} - impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>) -> Manager { - Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Manager { usb: hidapi, devices: RwLock::new(Vec::new()), key_path: RwLock::new(KeyPath::Ethereum), - } - } - - /// Re-populate device list. Only those devices that have Ethereum app open will be added. - pub fn update_devices(&self) -> Result { - let mut usb = self.usb.lock(); - usb.refresh_devices(); - let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut num_new_devices = 0; - for device in devices { - trace!("Checking device: {:?}", device); - if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { - continue; - } - match self.read_device_info(&usb, &device) { - Ok(info) => { - debug!("Found device: {:?}", info); - if !self.devices.read().iter().any(|d| d.path == info.path) { - num_new_devices += 1; + }); + + let usb_context = Arc::new(libusb::Context::new()?); + let m = manager.clone(); + + // Subscribe to all Ledger devices + // This means that we need to check that the given productID is supported + // None => LIBUSB_HOTPLUG_MATCH_ANY, in other words that all are subscribed to + // More info can be found: + usb_context.register_callback( + Some(LEDGER_VID), None, Some(USB_DEVICE_CLASS_DEVICE), + Box::new(EventHandler::new(Arc::downgrade(&manager)))).expect("usb_callback"); + + // Ledger event handler thread + thread::Builder::new() + .spawn(move || { + if let Err(e) = m.update_devices() { + debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e); + } + loop { + usb_context.handle_events(Some(Duration::from_millis(500))) + .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); + if exiting.load(atomic::Ordering::Acquire) { + break; } - new_devices.push(info); - } - Err(e) => debug!("Error reading device info: {}", e), - }; - } - *self.devices.write() = new_devices; - Ok(num_new_devices) - } + }) + .ok(); - /// Select key derivation path for a known chain. - pub fn set_key_path(&self, key_path: KeyPath) { - *self.key_path.write() = key_path; - } - - fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { - let mut handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let address = Self::read_wallet_address(&mut handle, *self.key_path.read())?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); - Ok(Device { - path: dev_info.path.clone(), - info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, - address: address, - }, - }) - } - - fn read_wallet_address(handle: &hidapi::HidDevice, key_path: KeyPath) -> Result { - let ver = Self::send_apdu(handle, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; - if ver.len() != 4 { - return Err(Error::Protocol("Version packet size mismatch")); - } - - let (major, minor, patch) = (ver[1], ver[2], ver[3]); - if major < 1 || (major == 1 && minor == 0 && patch < 3) { - return Err(Error::Protocol("App version 1.0.3 is required.")); - } - - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match key_path { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; - let key_and_address = Self::send_apdu(handle, commands::GET_ETH_PUBLIC_ADDRESS, 0, 0, derivation_path)?; - if key_and_address.len() != 107 { // 1 + 65 PK + 1 + 40 Addr (ascii-hex) - return Err(Error::Protocol("Key packet size mismatch")); - } - let address_string = ::std::str::from_utf8(&key_and_address[67..107]) - .map_err(|_| Error::Protocol("Invalid address string"))?; - - let address = Address::from_str(&address_string) - .map_err(|_| Error::Protocol("Invalid address string"))?; - - Ok(address) - } - - /// List connected wallets. This only returns wallets that are ready to be used. - pub fn list_devices(&self) -> Vec { - self.devices.read().iter().map(|d| d.info.clone()).collect() - } - - /// Get wallet info. - pub fn device_info(&self, address: &Address) -> Option { - self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) - } - - /// Sign transaction data with wallet managing `address`. - pub fn sign_transaction(&self, address: &Address, data: &[u8]) -> Result { - let usb = self.usb.lock(); - let devices = self.devices.read(); - let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; - let handle = self.open_path(|| usb.open_path(&device.path))?; - - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match *self.key_path.read() { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; - const MAX_CHUNK_SIZE: usize = 255; - let mut chunk: [u8; MAX_CHUNK_SIZE] = [0; MAX_CHUNK_SIZE]; - &mut chunk[0..derivation_path.len()].copy_from_slice(derivation_path); - let mut dest_offset = derivation_path.len(); - let mut data_pos = 0; - let mut result; - loop { - let p1 = if data_pos == 0 { 0x00 } else { 0x80 }; - let dest_left = MAX_CHUNK_SIZE - dest_offset; - let chunk_data_size = min(dest_left, data.len() - data_pos); - &mut chunk[dest_offset..][0..chunk_data_size].copy_from_slice(&data[data_pos..][0..chunk_data_size]); - result = Self::send_apdu(&handle, commands::SIGN_ETH_TRANSACTION, p1, 0, &chunk[0..(dest_offset + chunk_data_size)])?; - dest_offset = 0; - data_pos += chunk_data_size; - if data_pos == data.len() { - break; - } - } - - if result.len() != 65 { - return Err(Error::Protocol("Signature packet size mismatch")); - } - let v = (result[0] + 1) % 2; - let r = H256::from_slice(&result[1..33]); - let s = H256::from_slice(&result[33..65]); - Ok(Signature::from_rsv(&r, &s, v)) - } - - fn open_path(&self, f: F) -> Result - where F: Fn() -> Result - { - f().map_err(Into::into) + Ok(manager) } fn send_apdu(handle: &hidapi::HidDevice, command: u8, p1: u8, p2: u8, data: &[u8]) -> Result, Error> { @@ -285,7 +177,7 @@ impl Manager { chunk_index += 1; } - // read response + // Read response chunk_index = 0; let mut message_size = 0; let mut message = Vec::new(); @@ -303,7 +195,7 @@ impl Manager { let mut offset = 5; if seq == 0 { - // read message size and status word. + // Read message size and status word. if chunk_size < 7 { return Err(Error::Protocol("Unexpected chunk header")); } @@ -321,7 +213,7 @@ impl Manager { return Err(Error::Protocol("No status word")); } let status = (message[message.len() - 2] as usize) << 8 | (message[message.len() - 1] as usize); - debug!("Read status {:x}", status); + debug!(target: "hw", "Read status {:x}", status); match status { 0x6700 => Err(Error::Protocol("Incorrect length")), 0x6982 => Err(Error::Protocol("Security status not satisfied (Canceled by user)")), @@ -365,18 +257,166 @@ fn try_connect_polling(ledger: Arc, timeout: Duration) -> bool { false } +impl <'a>Wallet<'a> for Manager { + type Error = Error; + type Transaction = &'a [u8]; + + fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result { + let usb = self.usb.lock(); + let devices = self.devices.read(); + let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; + let handle = self.open_path(|| usb.open_path(&device.path))?; + + let eth_path = Ð_DERIVATION_PATH_BE[..]; + let etc_path = &ETC_DERIVATION_PATH_BE[..]; + let derivation_path = match *self.key_path.read() { + KeyPath::Ethereum => eth_path, + KeyPath::EthereumClassic => etc_path, + }; + const MAX_CHUNK_SIZE: usize = 255; + let mut chunk: [u8; MAX_CHUNK_SIZE] = [0; MAX_CHUNK_SIZE]; + &mut chunk[0..derivation_path.len()].copy_from_slice(derivation_path); + let mut dest_offset = derivation_path.len(); + let mut data_pos = 0; + let mut result; + loop { + let p1 = if data_pos == 0 { 0x00 } else { 0x80 }; + let dest_left = MAX_CHUNK_SIZE - dest_offset; + let chunk_data_size = min(dest_left, transaction.len() - data_pos); + &mut chunk[dest_offset..][0..chunk_data_size].copy_from_slice(&transaction[data_pos..][0..chunk_data_size]); + result = Self::send_apdu(&handle, commands::SIGN_ETH_TRANSACTION, p1, 0, &chunk[0..(dest_offset + chunk_data_size)])?; + dest_offset = 0; + data_pos += chunk_data_size; + if data_pos == transaction.len() { + break; + } + } + + if result.len() != 65 { + return Err(Error::Protocol("Signature packet size mismatch")); + } + let v = (result[0] + 1) % 2; + let r = H256::from_slice(&result[1..33]); + let s = H256::from_slice(&result[33..65]); + Ok(Signature::from_rsv(&r, &s, v)) + } + + fn set_key_path(&self, key_path: KeyPath) { + *self.key_path.write() = key_path; + } + + fn update_devices(&self) -> Result { + let mut usb = self.usb.lock(); + usb.refresh_devices(); + let devices = usb.devices(); + let mut new_devices = Vec::new(); + let mut num_new_devices = 0; + for device in devices { + trace!("Checking device: {:?}", device); + if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { + continue; + } + match self.read_device(&usb, &device) { + Ok(info) => { + debug!(target: "hw", "Found device: {:?}", info); + if !self.devices.read().iter().any(|d| d.path == info.path) { + num_new_devices += 1; + } + new_devices.push(info); + + } + Err(e) => debug!(target: "hw", "Error reading device info: {}", e), + }; + } + *self.devices.write() = new_devices; + Ok(num_new_devices) + } + + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { + let handle = self.open_path(|| usb.open_path(&dev_info.path))?; + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + match self.get_address(&handle) { + Ok(Some(addr)) => { + Ok(Device { + path: dev_info.path.clone(), + info: WalletInfo { + name: name, + manufacturer: manufacturer, + serial: serial, + address: addr, + }, + }) + } + // This variant is not possible, but the trait forces this return type + Ok(None) => Err(Error::ImpossibleError), + Err(e) => Err(e), + } + } + + fn list_devices(&self) -> Vec { + self.devices.read().iter().map(|d| d.info.clone()).collect() + } + + // Not used because it is not supported by Ledger + fn list_locked_devices(&self) -> Vec { + vec![] + } + + fn get_wallet(&self, address: &Address) -> Option { + self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) + } + + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Self::Error> { + let ver = Self::send_apdu(device, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; + if ver.len() != 4 { + return Err(Error::Protocol("Version packet size mismatch")); + } + + let (major, minor, patch) = (ver[1], ver[2], ver[3]); + if major < 1 || (major == 1 && minor == 0 && patch < 3) { + return Err(Error::Protocol("App version 1.0.3 is required.")); + } + + let eth_path = Ð_DERIVATION_PATH_BE[..]; + let etc_path = &ETC_DERIVATION_PATH_BE[..]; + let derivation_path = match *self.key_path.read() { + KeyPath::Ethereum => eth_path, + KeyPath::EthereumClassic => etc_path, + }; + let key_and_address = Self::send_apdu(device, commands::GET_ETH_PUBLIC_ADDRESS, 0, 0, derivation_path)?; + if key_and_address.len() != 107 { // 1 + 65 PK + 1 + 40 Addr (ascii-hex) + return Err(Error::Protocol("Key packet size mismatch")); + } + let address_string = ::std::str::from_utf8(&key_and_address[67..107]) + .map_err(|_| Error::Protocol("Invalid address string"))?; + + let address = Address::from_str(&address_string) + .map_err(|_| Error::Protocol("Invalid address string"))?; + + Ok(Some(address)) + } + + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result + { + f().map_err(Into::into) + } +} + /// Ledger event handler -/// A seperate thread is hanedling incoming events +/// A separate thread is handling incoming events /// /// Note, that this run to completion and race-conditions can't occur but this can /// therefore starve other events for being process with a spinlock or similar -pub struct EventHandler { +struct EventHandler { ledger: Weak, } impl EventHandler { /// Ledger event handler constructor - pub fn new(ledger: Weak) -> Self { + fn new(ledger: Weak) -> Self { Self { ledger: ledger } } } @@ -402,27 +442,34 @@ impl libusb::Hotplug for EventHandler { } #[test] +#[ignore] +/// This test can't be run without an actual ledger device connected fn smoke() { use rustc_hex::FromHex; - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap())); - let manager = Manager::new(hidapi.clone()); - manager.update_devices().unwrap(); - for d in &*manager.devices.read() { - println!("Device: {:?}", d); - } - - if let Some(address) = manager.list_devices().first().map(|d| d.address.clone()) { - let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); - let signature = manager.sign_transaction(&address, &tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let large_tx = FromHex::from_hex("f8cb81968504e3b2920083024f279475b02a3c39710d6a3f2870d0d788299d48e790f180b8a4b61d27f6000000000000000000000000e1af840a5a1cb1efdf608a97aa632f4aa39ed199000000000000000000000000000000000000000000000000105ff43f46a9a800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018080").unwrap(); - let signature = manager.sign_transaction(&address, &large_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let huge_tx = FromHex::from_hex("f935e98201048505d21dba00833b82608080b935946103e86003908155620d2f00600455601460055560a060405260608190527f2e2e2e00000000000000000000000000000000000000000000000000000000006080908152600d805460008290527f2e2e2e00000000000000000000000000000000000000000000000000000000068255909260008051602062003474833981519152602060026001851615610100026000190190941693909304601f0192909204820192909190620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b5b50620001009291505b80821115620000fc5760008155600101620000e6565b5090565b5050600e8054600360ff199182168117909255604080518082019091528281527f2e2e2e00000000000000000000000000000000000000000000000000000000006020918201908152600f80546000829052825160069516949094178155937f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80260026101006001871615026000190190951694909404601f019290920483019290620001d7565b82800160010185558215620001d7579182015b82811115620001d7578251825591602001919060010190620001ba565b5b50620001fb9291505b80821115620000fc5760008155600101620000e6565b5090565b50506010805460ff19166001179055346200000057604051620034943803806200349483398101604090815281516020830151918301516060840151919390810191015b5b5b60068054600160a060020a0319166c01000000000000000000000000338102041790558151600d80546000829052909160008051602062003474833981519152602060026101006001861615026000190190941693909304601f908101849004820193870190839010620002c157805160ff1916838001178555620002f1565b82800160010185558215620002f1579182015b82811115620002f1578251825591602001919060010190620002d4565b5b50620003159291505b80821115620000fc5760008155600101620000e6565b5090565b505080600f9080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200036557805160ff191683800117855562000395565b8280016001018555821562000395579182015b828111156200039557825182559160200191906001019062000378565b5b50620003b99291505b80821115620000fc5760008155600101620000e6565b5090565b5050600980546c01000000000000000000000000808602819004600160a060020a0319928316179092556007805487840293909304929091169190911790555b505050505b613066806200040e6000396000f300606060405236156102035760e060020a600035046306fdde03811461034b578063095ea7b3146103c65780630b0b6d5b146103ed5780631b1ccc47146103fc57806320e870931461047757806323b872dd1461049657806325b29d84146104c057806327187991146104df578063277ccde2146104f15780632e1fbfcd14610510578063308b2fdc14610532578063313ce5671461055457806338cc48311461057757806340eddc4e146105a057806341f4793a146105bf578063467ed261146105de578063471ad963146105fd5780634e860ebb1461060f5780634efbe9331461061e57806354786b4e1461064257806354e35ba2146106bd57806358793ad4146106d25780635abedab21461073f5780635af2f8211461074e57806360483a3f1461076d57806360d12fa0146107da578063698f2e84146108035780636a749986146108155780636d5f66391461082a5780636e9c36831461083c57806370a082311461085e5780637a290fe5146108805780637e7541461461088f57806394c41bdb1461090a57806395d89b4114610929578063962a64cd146109a4578063a0b6533214610a09578063a9059cbb14610a2b578063ab62438f14610a52578063b63ca98114610aa9578063b7c54c6f14610abb578063c4e41b2214610ada578063ca7c4dba14610af9578063cb79e31b14610b18578063dd62ed3e14610b3a575b6103495b60006000600c546000141561021b57610000565b600354600c54670de0b6b3a764000091349091020204915060009050816001600030600160a060020a031681526020019081526020016000205410156102c557600160a060020a033016600090815260016020526040902054600c54909250828115610000570466038d7ea4c68000023403905033600160a060020a03166108fc829081150290604051809050600060405180830381858888f1935050505015156102c557610000565b5b600160a060020a03338116600081815260016020908152604080832080548801905530909416825283822080548790039055601380543487900301908190559154600c548551908152918201879052845190949293927f5a0391f2a67f11ed0034b68f8cf14e7e41d6f86e0a7622f2af5ea8f07b488396928290030190a45b5050565b005b3461000057610358610b5f565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103d9600435602435610bed565b604080519115158252519081900360200190f35b3461000057610349610c58565b005b3461000057610358610dbc565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484610e5a565b60408051918252519081900360200190f35b34610000576103d9600435602435604435610ef9565b604080519115158252519081900360200190f35b3461000057610484610ff3565b60408051918252519081900360200190f35b3461000057610349600435611002565b005b346100005761048461105a565b60408051918252519081900360200190f35b3461000057610484600435611061565b60408051918252519081900360200190f35b346100005761048460043561108d565b60408051918252519081900360200190f35b34610000576105616110b9565b6040805160ff9092168252519081900360200190f35b34610000576105846110c2565b60408051600160a060020a039092168252519081900360200190f35b34610000576104846110c7565b60408051918252519081900360200190f35b34610000576104846110ce565b60408051918252519081900360200190f35b34610000576104846110d5565b60408051918252519081900360200190f35b3461000057610349600435611174565b005b34610000576103496113b5565b005b34610000576103d9600435611407565b604080519115158252519081900360200190f35b3461000057610358611549565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103496004356024356115e7565b005b346100005760408051602060046024803582810135601f8101859004850286018501909652858552610726958335959394604494939290920191819084018382808284375094965061167e95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610349611c13565b005b3461000057610484611d46565b60408051918252519081900360200190f35b346100005760408051602060046024803582810135601f81018590048502860185019096528585526107269583359593946044949392909201918190840183828082843750949650611d4d95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610584612303565b60408051600160a060020a039092168252519081900360200190f35b3461000057610349600435612313565b005b3461000057610349600435602435612347565b005b346100005761034960043561252f565b005b3461000057610484600435612941565b60408051918252519081900360200190f35b346100005761048460043561298d565b60408051918252519081900360200190f35b34610000576103496129ac565b005b3461000057610358612a13565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484612ab1565b60408051918252519081900360200190f35b3461000057610358612ab8565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650612b4695505050505050565b60408051918252519081900360200190f35b3461000057610484600435612b63565b60408051918252519081900360200190f35b34610000576103d9600435602435612b8c565b604080519115158252519081900360200190f35b3461000057610349600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350612c3c92505050565b005b3461000057610349600435612f38565b005b3461000057610484612f90565b60408051918252519081900360200190f35b346100005761048461300c565b60408051918252519081900360200190f35b3461000057610484613013565b60408051918252519081900360200190f35b346100005761048460043561301a565b60408051918252519081900360200190f35b3461000057610484600435602435613039565b60408051918252519081900360200190f35b600d805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b601a54600090600160a060020a03161515610c7257610000565b600160a060020a0333166000908152600a60205260409020541515610c9657610000565b600160a060020a0333166000908152601d602052604090205460ff1615610cbc57610000565b601b54426212750090910111610cd157610000565b600160a060020a0333166000818152601d60209081526040808320805460ff19166001179055600a8252918290208054601c805490910190555482519384529083015280517f475c7605c08471fdc551a58d2c318b163628c5852f69323a1b91c34eb0bb09339281900390910190a150601154601c54606490910490604682029010610db857601a5460068054600160a060020a031916606060020a600160a060020a0393841681020417908190556040805191909216815290517f6b8184e23a898262087be50aa3ea5de648451e63f94413e810586c25282d58c2916020908290030190a15b5b50565b604080516020808201835260008252600d8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b600f805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600160a060020a038316600090815260016020526040812054829010801590610f495750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b8015610f555750600082115b15610fe757600160a060020a03808516600081815260016020908152604080832080548890039055878516808452818420805489019055848452600283528184203390961684529482529182902080548790039055815186815291517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610feb56610feb565b5060005b5b9392505050565b600160a060020a033016315b90565b60065433600160a060020a0390811691161461101d57610000565b600c8190556040805182815290517f0bbd501ef336990995d82b5e3fd82a15abe1ff10c982757a1698ac5d1c3e79579181900360200190a15b5b50565b600b545b90565b6000601882815481101561000057906000526020600020906007020160005b506004015490505b919050565b6000601882815481101561000057906000526020600020906007020160005b506001015490505b919050565b600e5460ff1681565b305b90565b6013545b90565b601c545b90565b600d805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600654600090819033600160a060020a0390811691161461119457610000565b60008381526014602052604090205415156111ae57610000565b60008381526014602052604090206005015433600160a060020a039081169116146111d857610000565b60008381526014602052604090206005015460a060020a900460ff16156111fe57610000565b601154600084815260146020526040902060040154606490910460370292508290111561122a57610000565b60008381526014602052604081206005015460a860020a900460ff16600181116100005714156112eb57600954600084815260146020908152604080832060058101546001909101548251840185905282517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810191909152915194169363a9059cbb93604480840194938390030190829087803b156100005760325a03f1156100005750611389915050565b60008381526014602052604080822060058101546001909101549151600160a060020a039091169282156108fc02929190818181858888f160008881526014602090815260409182902060058101546001909101548351600160a060020a0390921682529181019190915281519297507f2648a7e2f9c34700b91370233666e5118fa8be3e0c21fed4f7402b941df8efdd9650829003019350915050a15b6000838152601460205260409020600501805460a060020a60ff02191660a060020a1790555b5b505050565b60065433600160a060020a039081169116146113d057610000565b6010805460ff191690556040517fb48c7f694f0a3b9b22d7e61c60ff8aebbb107314b6b698fc489ff3f017cb57e090600090a15b5b565b600060006000600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f115610000575050604051514210905061147c57610000565b60085433600160a060020a0390811691161461149757610000565b5050600b54600160a060020a03328181166000908152600a6020526040902080549386029384019055601180548401905560128054860190556008549092916114e39130911683610ef9565b506114ee8282612b8c565b50600054601154600b5460408051918252602082018590528051600160a060020a038716927fb4d6befef2def3d17bcb13c2b882ec4fa047f33157446d3e0e6094b2a21609ac92908290030190a4600192505b5b5050919050565b604080516020808201835260008252600f8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b60065433600160a060020a0390811691161461160257610000565b60105460ff16151561161357610000565b600160a060020a0330166000908152600160209081526040808320805485019055600c859055825484019283905580518481529051839286927f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c3929081900390910190a45b5b5b5050565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a039081169116146116ed57610000565b60115460649004935060056016541115801561170c5750836005540288115b1561171657610000565b61171e612f90565b8811156117305761172d612f90565b97505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016000815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061182057805160ff191683800117855561184d565b8280016001018555821561184d579182015b8281111561184d578251825591602001919060010190611832565b5b5061186e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116119c9576007028160070283600052602060002091820191016119c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10611968575061199a565b601f01602090049060005260206000209081019061199a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701611925565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a90810204021790555050505060166000815460010191905081905550426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b60065460009033600160a060020a03908116911614611c3157610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f1156100005750506040515162dd7c00014210159050611ca657610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1600954909550600160a060020a0316935063a9059cbb9250339150611cef9050612f90565b6000604051602001526040518360e060020a0281526004018083600160a060020a0316815260200182815260200192505050602060405180830381600087803b156100005760325a03f115610000575050505b5b50565b6016545b90565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a03908116911614611dbc57610000565b60105460ff1615611dcc57610000565b6000611dd73061298d565b1115611de257610000565b6017546212750001421015611df657610000565b6013546064900493508360055402881115611e1057610000565b30600160a060020a031631881115611e305730600160a060020a03163197505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016001815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f2057805160ff1916838001178555611f4d565b82800160010185558215611f4d579182015b82811115611f4d578251825591602001919060010190611f32565b5b50611f6e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116120c9576007028160070283600052602060002091820191016120c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10612068575061209a565b601f01602090049060005260206000209081019061209a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701612025565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061214a57805160ff1916838001178555612177565b82800160010185558215612177579182015b8281111561217757825182559160200191906001019061215c565b5b506121989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a908102040217905550505050426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b600654600160a060020a03165b90565b600854600160a060020a03161561232957610000565b60088054600160a060020a031916606060020a838102041790555b50565b60065433600160a060020a0390811691161461236257610000565b60105460ff16151561237357610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421090506123e257610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663cdd933326000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421015905061245257610000565b600854600160a060020a0316151561246957610000565b6000805482018155600160a060020a03308116808352600160209081526040808520805487019055600b8790556002825280852060088054861687529083529481902080548701905593548451868152945193169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600054601154600b546040805185815290517f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c39181900360200190a45b5b5b5b5b5050565b604080516101008082018352600080835260208084018290528451808201865282815284860152606084018290526080840182905260a0840182905260c0840182905260e0840182905285825260148152848220855180850187528154815260018083015482850152600280840180548a51600019948216159099029390930190921604601f8101859004850287018501895280875296979496879692959394938601938301828280156126245780601f106125f957610100808354040283529160200191612624565b820191906000526020600020905b81548152906001019060200180831161260757829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154600160a060020a038116606083015260ff60a060020a820481161515608084015260a09092019160a860020a909104166001811161000057905250600085815260146020526040902054909350151561269d57610000565b60008481526014602052604090206005015460a060020a900460ff16156126c357610000565b60008481526014602052604090206003015442106126e057610000565b6000848152601460209081526040808320600160a060020a033316845260060190915290205460ff161561271357610000565b600160a060020a0333166000818152600a6020908152604080832054888452601483528184206004810180548301905594845260069094019091529020805460ff19166001179055915061276684612941565b6000858152601460205260409020601880549293509091839081101561000057906000526020600020906007020160005b50600082015481600001556001820154816001015560028201816002019080546001816001161561010002031660029004828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612801578054855561283d565b8280016001018555821561283d57600052602060002091601f016020900482015b8281111561283d578254825591600101919060010190612822565b5b5061285e9291505b8082111561186a5760008155600101611856565b5090565b5050600382810154908201556004808301549082015560059182018054929091018054600160a060020a031916606060020a600160a060020a0394851681020417808255825460a060020a60ff021990911660f860020a60a060020a9283900460ff908116820282900490930291909117808455935460a860020a60ff021990941660a860020a9485900490921681020490920291909117905560408051868152339092166020830152818101849052517f8f8bbb8c1937f844f6a094cd4c6eeab8ed5e36f83952e6306ffb2c11fffe5bce916060908290030190a15b50505050565b6000805b60185481101561298657601881815481101561000057906000526020600020906007020160005b505483141561297d57809150612986565b5b600101612945565b5b50919050565b600160a060020a0381166000908152600160205260409020545b919050565b60065433600160a060020a039081169116146129c757610000565b600160a060020a03301660009081526001602052604080822080548354038355829055517fe0987873419fe09d3c9a3e0267f4daf163e812d512f867abaf6bf9822f141a8b9190a15b5b565b60408051602080820183526000825260198054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b6011545b90565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b6000602082511115612b5757610000565b5060208101515b919050565b6000601882815481101561000057906000526020600020906007020160005b505490505b919050565b600160a060020a033316600090815260016020526040812054829010801590612bb55750600082115b15612c2d57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610c5256610c52565b506000610c52565b5b92915050565b600160a060020a0333166000908152600a60205260409020541515612c6057610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151626ebe00014210159050612cd557610000565b601b5415801590612cef5750426019600201546212750001115b15612cf957610000565b6040805160808101825283815260208082018490524262127500018284015233600160a060020a03166000908152600a8252928320546060830152815180516019805495819052939484937f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969560026001841615610100026000190190931692909204601f90810182900483019490910190839010612da257805160ff1916838001178555612dcf565b82800160010185558215612dcf579182015b82811115612dcf578251825591602001919060010190612db4565b5b50612df09291505b8082111561186a5760008155600101611856565b5090565b505060208201518160010160006101000a815481600160a060020a030219169083606060020a908102040217905550604082015181600201556060820151816003015590505060016019600401600033600160a060020a0316815260200190815260200160002060006101000a81548160ff021916908360f860020a9081020402179055507f854a9cc4d907d23cd8dcc72af48dc0e6a87e6f76376a309a0ffa3231ce8e13363383426212750001846040518085600160a060020a031681526020018060200184815260200183600160a060020a031681526020018281038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015612f235780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a15b5050565b60065433600160a060020a03908116911614612f5357610000565b600b819055600080546011546040519192909184917f17a7f53ef43da32c3936b4ac2b060caff5c4b03cd24b1c8e96a191eb1ec48d1591a45b5b50565b6000600960009054906101000a9004600160a060020a0316600160a060020a03166370a08231306000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100005760325a03f115610000575050604051519150505b90565b6000545b90565b600c545b90565b600160a060020a0381166000908152600a60205260409020545b919050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b9291505056d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb500000000000000000000000069381683bde924cef65f1c97f7c8fb769a20409300000000000000000000000014f37b574242d366558db61f3335289a5035c506000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000018546573742074657374657220746573746573742063616d700000000000000000000000000000000000000000000000000000000000000000000000000000000354455300000000000000000000000000000000000000000000000000000000001ba033230fce515bea9de982fe85e0ec8fe892984bc3070ad633daab20eb370864d5a05deb41870e2117197b84cb71110fc0508fa7457165cb8cb82cb8d4d801e6e3f1").unwrap(); - let signature = manager.sign_transaction(&address, &huge_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - } + let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().expect("HidApi"))); + let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).expect("Ledger Manager"); + + // Update device list + assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); + + // Fetch the ethereum address of a connected ledger device + let address = manager.list_devices() + .iter() + .filter(|d| d.manufacturer == "Ledger".to_string()) + .nth(0) + .map(|d| d.address.clone()) + .expect("No ledger device detected"); + + let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); + let signature = manager.sign_transaction(&address, &tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + let large_tx = FromHex::from_hex("f8cb81968504e3b2920083024f279475b02a3c39710d6a3f2870d0d788299d48e790f180b8a4b61d27f6000000000000000000000000e1af840a5a1cb1efdf608a97aa632f4aa39ed199000000000000000000000000000000000000000000000000105ff43f46a9a800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018080").unwrap(); + let signature = manager.sign_transaction(&address, &large_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + let huge_tx = FromHex::from_hex("f935e98201048505d21dba00833b82608080b935946103e86003908155620d2f00600455601460055560a060405260608190527f2e2e2e00000000000000000000000000000000000000000000000000000000006080908152600d805460008290527f2e2e2e00000000000000000000000000000000000000000000000000000000068255909260008051602062003474833981519152602060026001851615610100026000190190941693909304601f0192909204820192909190620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b5b50620001009291505b80821115620000fc5760008155600101620000e6565b5090565b5050600e8054600360ff199182168117909255604080518082019091528281527f2e2e2e00000000000000000000000000000000000000000000000000000000006020918201908152600f80546000829052825160069516949094178155937f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80260026101006001871615026000190190951694909404601f019290920483019290620001d7565b82800160010185558215620001d7579182015b82811115620001d7578251825591602001919060010190620001ba565b5b50620001fb9291505b80821115620000fc5760008155600101620000e6565b5090565b50506010805460ff19166001179055346200000057604051620034943803806200349483398101604090815281516020830151918301516060840151919390810191015b5b5b60068054600160a060020a0319166c01000000000000000000000000338102041790558151600d80546000829052909160008051602062003474833981519152602060026101006001861615026000190190941693909304601f908101849004820193870190839010620002c157805160ff1916838001178555620002f1565b82800160010185558215620002f1579182015b82811115620002f1578251825591602001919060010190620002d4565b5b50620003159291505b80821115620000fc5760008155600101620000e6565b5090565b505080600f9080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200036557805160ff191683800117855562000395565b8280016001018555821562000395579182015b828111156200039557825182559160200191906001019062000378565b5b50620003b99291505b80821115620000fc5760008155600101620000e6565b5090565b5050600980546c01000000000000000000000000808602819004600160a060020a0319928316179092556007805487840293909304929091169190911790555b505050505b613066806200040e6000396000f300606060405236156102035760e060020a600035046306fdde03811461034b578063095ea7b3146103c65780630b0b6d5b146103ed5780631b1ccc47146103fc57806320e870931461047757806323b872dd1461049657806325b29d84146104c057806327187991146104df578063277ccde2146104f15780632e1fbfcd14610510578063308b2fdc14610532578063313ce5671461055457806338cc48311461057757806340eddc4e146105a057806341f4793a146105bf578063467ed261146105de578063471ad963146105fd5780634e860ebb1461060f5780634efbe9331461061e57806354786b4e1461064257806354e35ba2146106bd57806358793ad4146106d25780635abedab21461073f5780635af2f8211461074e57806360483a3f1461076d57806360d12fa0146107da578063698f2e84146108035780636a749986146108155780636d5f66391461082a5780636e9c36831461083c57806370a082311461085e5780637a290fe5146108805780637e7541461461088f57806394c41bdb1461090a57806395d89b4114610929578063962a64cd146109a4578063a0b6533214610a09578063a9059cbb14610a2b578063ab62438f14610a52578063b63ca98114610aa9578063b7c54c6f14610abb578063c4e41b2214610ada578063ca7c4dba14610af9578063cb79e31b14610b18578063dd62ed3e14610b3a575b6103495b60006000600c546000141561021b57610000565b600354600c54670de0b6b3a764000091349091020204915060009050816001600030600160a060020a031681526020019081526020016000205410156102c557600160a060020a033016600090815260016020526040902054600c54909250828115610000570466038d7ea4c68000023403905033600160a060020a03166108fc829081150290604051809050600060405180830381858888f1935050505015156102c557610000565b5b600160a060020a03338116600081815260016020908152604080832080548801905530909416825283822080548790039055601380543487900301908190559154600c548551908152918201879052845190949293927f5a0391f2a67f11ed0034b68f8cf14e7e41d6f86e0a7622f2af5ea8f07b488396928290030190a45b5050565b005b3461000057610358610b5f565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103d9600435602435610bed565b604080519115158252519081900360200190f35b3461000057610349610c58565b005b3461000057610358610dbc565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484610e5a565b60408051918252519081900360200190f35b34610000576103d9600435602435604435610ef9565b604080519115158252519081900360200190f35b3461000057610484610ff3565b60408051918252519081900360200190f35b3461000057610349600435611002565b005b346100005761048461105a565b60408051918252519081900360200190f35b3461000057610484600435611061565b60408051918252519081900360200190f35b346100005761048460043561108d565b60408051918252519081900360200190f35b34610000576105616110b9565b6040805160ff9092168252519081900360200190f35b34610000576105846110c2565b60408051600160a060020a039092168252519081900360200190f35b34610000576104846110c7565b60408051918252519081900360200190f35b34610000576104846110ce565b60408051918252519081900360200190f35b34610000576104846110d5565b60408051918252519081900360200190f35b3461000057610349600435611174565b005b34610000576103496113b5565b005b34610000576103d9600435611407565b604080519115158252519081900360200190f35b3461000057610358611549565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103496004356024356115e7565b005b346100005760408051602060046024803582810135601f8101859004850286018501909652858552610726958335959394604494939290920191819084018382808284375094965061167e95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610349611c13565b005b3461000057610484611d46565b60408051918252519081900360200190f35b346100005760408051602060046024803582810135601f81018590048502860185019096528585526107269583359593946044949392909201918190840183828082843750949650611d4d95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610584612303565b60408051600160a060020a039092168252519081900360200190f35b3461000057610349600435612313565b005b3461000057610349600435602435612347565b005b346100005761034960043561252f565b005b3461000057610484600435612941565b60408051918252519081900360200190f35b346100005761048460043561298d565b60408051918252519081900360200190f35b34610000576103496129ac565b005b3461000057610358612a13565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484612ab1565b60408051918252519081900360200190f35b3461000057610358612ab8565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650612b4695505050505050565b60408051918252519081900360200190f35b3461000057610484600435612b63565b60408051918252519081900360200190f35b34610000576103d9600435602435612b8c565b604080519115158252519081900360200190f35b3461000057610349600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350612c3c92505050565b005b3461000057610349600435612f38565b005b3461000057610484612f90565b60408051918252519081900360200190f35b346100005761048461300c565b60408051918252519081900360200190f35b3461000057610484613013565b60408051918252519081900360200190f35b346100005761048460043561301a565b60408051918252519081900360200190f35b3461000057610484600435602435613039565b60408051918252519081900360200190f35b600d805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b601a54600090600160a060020a03161515610c7257610000565b600160a060020a0333166000908152600a60205260409020541515610c9657610000565b600160a060020a0333166000908152601d602052604090205460ff1615610cbc57610000565b601b54426212750090910111610cd157610000565b600160a060020a0333166000818152601d60209081526040808320805460ff19166001179055600a8252918290208054601c805490910190555482519384529083015280517f475c7605c08471fdc551a58d2c318b163628c5852f69323a1b91c34eb0bb09339281900390910190a150601154601c54606490910490604682029010610db857601a5460068054600160a060020a031916606060020a600160a060020a0393841681020417908190556040805191909216815290517f6b8184e23a898262087be50aa3ea5de648451e63f94413e810586c25282d58c2916020908290030190a15b5b50565b604080516020808201835260008252600d8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b600f805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600160a060020a038316600090815260016020526040812054829010801590610f495750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b8015610f555750600082115b15610fe757600160a060020a03808516600081815260016020908152604080832080548890039055878516808452818420805489019055848452600283528184203390961684529482529182902080548790039055815186815291517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610feb56610feb565b5060005b5b9392505050565b600160a060020a033016315b90565b60065433600160a060020a0390811691161461101d57610000565b600c8190556040805182815290517f0bbd501ef336990995d82b5e3fd82a15abe1ff10c982757a1698ac5d1c3e79579181900360200190a15b5b50565b600b545b90565b6000601882815481101561000057906000526020600020906007020160005b506004015490505b919050565b6000601882815481101561000057906000526020600020906007020160005b506001015490505b919050565b600e5460ff1681565b305b90565b6013545b90565b601c545b90565b600d805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600654600090819033600160a060020a0390811691161461119457610000565b60008381526014602052604090205415156111ae57610000565b60008381526014602052604090206005015433600160a060020a039081169116146111d857610000565b60008381526014602052604090206005015460a060020a900460ff16156111fe57610000565b601154600084815260146020526040902060040154606490910460370292508290111561122a57610000565b60008381526014602052604081206005015460a860020a900460ff16600181116100005714156112eb57600954600084815260146020908152604080832060058101546001909101548251840185905282517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810191909152915194169363a9059cbb93604480840194938390030190829087803b156100005760325a03f1156100005750611389915050565b60008381526014602052604080822060058101546001909101549151600160a060020a039091169282156108fc02929190818181858888f160008881526014602090815260409182902060058101546001909101548351600160a060020a0390921682529181019190915281519297507f2648a7e2f9c34700b91370233666e5118fa8be3e0c21fed4f7402b941df8efdd9650829003019350915050a15b6000838152601460205260409020600501805460a060020a60ff02191660a060020a1790555b5b505050565b60065433600160a060020a039081169116146113d057610000565b6010805460ff191690556040517fb48c7f694f0a3b9b22d7e61c60ff8aebbb107314b6b698fc489ff3f017cb57e090600090a15b5b565b600060006000600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f115610000575050604051514210905061147c57610000565b60085433600160a060020a0390811691161461149757610000565b5050600b54600160a060020a03328181166000908152600a6020526040902080549386029384019055601180548401905560128054860190556008549092916114e39130911683610ef9565b506114ee8282612b8c565b50600054601154600b5460408051918252602082018590528051600160a060020a038716927fb4d6befef2def3d17bcb13c2b882ec4fa047f33157446d3e0e6094b2a21609ac92908290030190a4600192505b5b5050919050565b604080516020808201835260008252600f8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b60065433600160a060020a0390811691161461160257610000565b60105460ff16151561161357610000565b600160a060020a0330166000908152600160209081526040808320805485019055600c859055825484019283905580518481529051839286927f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c3929081900390910190a45b5b5b5050565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a039081169116146116ed57610000565b60115460649004935060056016541115801561170c5750836005540288115b1561171657610000565b61171e612f90565b8811156117305761172d612f90565b97505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016000815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061182057805160ff191683800117855561184d565b8280016001018555821561184d579182015b8281111561184d578251825591602001919060010190611832565b5b5061186e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116119c9576007028160070283600052602060002091820191016119c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10611968575061199a565b601f01602090049060005260206000209081019061199a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701611925565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a90810204021790555050505060166000815460010191905081905550426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b60065460009033600160a060020a03908116911614611c3157610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f1156100005750506040515162dd7c00014210159050611ca657610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1600954909550600160a060020a0316935063a9059cbb9250339150611cef9050612f90565b6000604051602001526040518360e060020a0281526004018083600160a060020a0316815260200182815260200192505050602060405180830381600087803b156100005760325a03f115610000575050505b5b50565b6016545b90565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a03908116911614611dbc57610000565b60105460ff1615611dcc57610000565b6000611dd73061298d565b1115611de257610000565b6017546212750001421015611df657610000565b6013546064900493508360055402881115611e1057610000565b30600160a060020a031631881115611e305730600160a060020a03163197505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016001815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f2057805160ff1916838001178555611f4d565b82800160010185558215611f4d579182015b82811115611f4d578251825591602001919060010190611f32565b5b50611f6e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116120c9576007028160070283600052602060002091820191016120c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10612068575061209a565b601f01602090049060005260206000209081019061209a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701612025565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061214a57805160ff1916838001178555612177565b82800160010185558215612177579182015b8281111561217757825182559160200191906001019061215c565b5b506121989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a908102040217905550505050426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b600654600160a060020a03165b90565b600854600160a060020a03161561232957610000565b60088054600160a060020a031916606060020a838102041790555b50565b60065433600160a060020a0390811691161461236257610000565b60105460ff16151561237357610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421090506123e257610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663cdd933326000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421015905061245257610000565b600854600160a060020a0316151561246957610000565b6000805482018155600160a060020a03308116808352600160209081526040808520805487019055600b8790556002825280852060088054861687529083529481902080548701905593548451868152945193169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600054601154600b546040805185815290517f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c39181900360200190a45b5b5b5b5b5050565b604080516101008082018352600080835260208084018290528451808201865282815284860152606084018290526080840182905260a0840182905260c0840182905260e0840182905285825260148152848220855180850187528154815260018083015482850152600280840180548a51600019948216159099029390930190921604601f8101859004850287018501895280875296979496879692959394938601938301828280156126245780601f106125f957610100808354040283529160200191612624565b820191906000526020600020905b81548152906001019060200180831161260757829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154600160a060020a038116606083015260ff60a060020a820481161515608084015260a09092019160a860020a909104166001811161000057905250600085815260146020526040902054909350151561269d57610000565b60008481526014602052604090206005015460a060020a900460ff16156126c357610000565b60008481526014602052604090206003015442106126e057610000565b6000848152601460209081526040808320600160a060020a033316845260060190915290205460ff161561271357610000565b600160a060020a0333166000818152600a6020908152604080832054888452601483528184206004810180548301905594845260069094019091529020805460ff19166001179055915061276684612941565b6000858152601460205260409020601880549293509091839081101561000057906000526020600020906007020160005b50600082015481600001556001820154816001015560028201816002019080546001816001161561010002031660029004828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612801578054855561283d565b8280016001018555821561283d57600052602060002091601f016020900482015b8281111561283d578254825591600101919060010190612822565b5b5061285e9291505b8082111561186a5760008155600101611856565b5090565b5050600382810154908201556004808301549082015560059182018054929091018054600160a060020a031916606060020a600160a060020a0394851681020417808255825460a060020a60ff021990911660f860020a60a060020a9283900460ff908116820282900490930291909117808455935460a860020a60ff021990941660a860020a9485900490921681020490920291909117905560408051868152339092166020830152818101849052517f8f8bbb8c1937f844f6a094cd4c6eeab8ed5e36f83952e6306ffb2c11fffe5bce916060908290030190a15b50505050565b6000805b60185481101561298657601881815481101561000057906000526020600020906007020160005b505483141561297d57809150612986565b5b600101612945565b5b50919050565b600160a060020a0381166000908152600160205260409020545b919050565b60065433600160a060020a039081169116146129c757610000565b600160a060020a03301660009081526001602052604080822080548354038355829055517fe0987873419fe09d3c9a3e0267f4daf163e812d512f867abaf6bf9822f141a8b9190a15b5b565b60408051602080820183526000825260198054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b6011545b90565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b6000602082511115612b5757610000565b5060208101515b919050565b6000601882815481101561000057906000526020600020906007020160005b505490505b919050565b600160a060020a033316600090815260016020526040812054829010801590612bb55750600082115b15612c2d57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610c5256610c52565b506000610c52565b5b92915050565b600160a060020a0333166000908152600a60205260409020541515612c6057610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151626ebe00014210159050612cd557610000565b601b5415801590612cef5750426019600201546212750001115b15612cf957610000565b6040805160808101825283815260208082018490524262127500018284015233600160a060020a03166000908152600a8252928320546060830152815180516019805495819052939484937f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969560026001841615610100026000190190931692909204601f90810182900483019490910190839010612da257805160ff1916838001178555612dcf565b82800160010185558215612dcf579182015b82811115612dcf578251825591602001919060010190612db4565b5b50612df09291505b8082111561186a5760008155600101611856565b5090565b505060208201518160010160006101000a815481600160a060020a030219169083606060020a908102040217905550604082015181600201556060820151816003015590505060016019600401600033600160a060020a0316815260200190815260200160002060006101000a81548160ff021916908360f860020a9081020402179055507f854a9cc4d907d23cd8dcc72af48dc0e6a87e6f76376a309a0ffa3231ce8e13363383426212750001846040518085600160a060020a031681526020018060200184815260200183600160a060020a031681526020018281038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015612f235780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a15b5050565b60065433600160a060020a03908116911614612f5357610000565b600b819055600080546011546040519192909184917f17a7f53ef43da32c3936b4ac2b060caff5c4b03cd24b1c8e96a191eb1ec48d1591a45b5b50565b6000600960009054906101000a9004600160a060020a0316600160a060020a03166370a08231306000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100005760325a03f115610000575050604051519150505b90565b6000545b90565b600c545b90565b600160a060020a0381166000908152600a60205260409020545b919050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b9291505056d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb500000000000000000000000069381683bde924cef65f1c97f7c8fb769a20409300000000000000000000000014f37b574242d366558db61f3335289a5035c506000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000018546573742074657374657220746573746573742063616d700000000000000000000000000000000000000000000000000000000000000000000000000000000354455300000000000000000000000000000000000000000000000000000000001ba033230fce515bea9de982fe85e0ec8fe892984bc3070ad633daab20eb370864d5a05deb41870e2117197b84cb71110fc0508fa7457165cb8cb82cb8d4d801e6e3f1").unwrap(); + let signature = manager.sign_transaction(&address, &huge_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); } diff --git a/hw/src/lib.rs b/hw/src/lib.rs index 9bfec83410b..f51be356ae1 100644 --- a/hw/src/lib.rs +++ b/hw/src/lib.rs @@ -16,7 +16,8 @@ //! Hardware wallet management. -#![warn(missing_docs)] +#[warn(missing_docs)] +#[warn(warnings)] extern crate ethereum_types; extern crate ethkey; @@ -38,12 +39,60 @@ use std::fmt; use std::sync::Arc; use std::sync::atomic; use std::sync::atomic::AtomicBool; -use std::thread; -use std::time::Duration; use ethereum_types::U256; const USB_DEVICE_CLASS_DEVICE: u8 = 0; +#[derive(Debug)] +pub struct Device { + path: String, + info: WalletInfo, +} + +pub trait Wallet<'a> { + /// Error + type Error; + /// Transaction data format + type Transaction; + + /// Sign transaction data with wallet managing `address`. + fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result; + + /// Set key derivation path for a chain. + fn set_key_path(&self, key_path: KeyPath); + + /// Re-populate device list + /// Note, this assumes all devices are iterated over and updated + fn update_devices(&self) -> Result; + + /// Read device info + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result; + + /// List connected and acknowledged wallets + fn list_devices(&self) -> Vec; + + /// List locked wallets + /// This may be moved if it is the wrong assumption, for example this is not supported by Ledger + /// Then this method return a empty vector + fn list_locked_devices(&self) -> Vec; + + /// Get wallet info. + fn get_wallet(&self, address: &Address) -> Option; + + /// Generate ethereum address for a Wallet + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Self::Error>; + + /// Open a device using `device path` + /// Note, f - is a closure that borrows HidResult + /// HidDevice is in turn a type alias for a `c_void function pointer` + /// For further information see: + /// * + /// * + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result; +} + + /// Hardware wallet error. #[derive(Debug)] pub enum Error { @@ -144,70 +193,13 @@ pub struct HardwareWalletManager { trezor: Arc, } - impl HardwareWalletManager { /// Hardware wallet constructor pub fn new() -> Result { - let usb_context_trezor = Arc::new(libusb::Context::new()?); - let usb_context_ledger = Arc::new(libusb::Context::new()?); - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?)); - let ledger = Arc::new(ledger::Manager::new(hidapi.clone())); - let trezor = Arc::new(trezor::Manager::new(hidapi.clone())); - - // Subscribe to TREZOR V1 - // Note, this support only TREZOR V1 becasue TREZOR V2 has another vendorID for some reason - // Also, we now only support one product as the second argument specifies - usb_context_trezor.register_callback( - Some(trezor::TREZOR_VID), Some(trezor::TREZOR_PIDS[0]), Some(USB_DEVICE_CLASS_DEVICE), - Box::new(trezor::EventHandler::new(Arc::downgrade(&trezor))))?; - - // Subscribe to all Ledger Devices - // This means that we need to check that the given productID is supported - // None => LIBUSB_HOTPLUG_MATCH_ANY, in other words that all are subscribed to - // More info can be found: http://libusb.sourceforge.net/api-1.0/group__hotplug.html#gae6c5f1add6cc754005549c7259dc35ea - usb_context_ledger.register_callback( - Some(ledger::LEDGER_VID), None, Some(USB_DEVICE_CLASS_DEVICE), - Box::new(ledger::EventHandler::new(Arc::downgrade(&ledger))))?; - let exiting = Arc::new(AtomicBool::new(false)); - let thread_exiting_ledger = exiting.clone(); - let thread_exiting_trezor = exiting.clone(); - let l = ledger.clone(); - let t = trezor.clone(); - - // Ledger event thread - thread::Builder::new() - .name("hw_wallet_ledger".to_string()) - .spawn(move || { - if let Err(e) = l.update_devices() { - debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e); - } - loop { - usb_context_ledger.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); - if thread_exiting_ledger.load(atomic::Ordering::Acquire) { - break; - } - } - }) - .ok(); - - // Trezor event thread - thread::Builder::new() - .name("hw_wallet_trezor".to_string()) - .spawn(move || { - if let Err(e) = t.update_devices() { - debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e); - } - loop { - usb_context_trezor.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); - if thread_exiting_trezor.load(atomic::Ordering::Acquire) { - break; - } - } - }) - .ok(); + let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?)); + let ledger = ledger::Manager::new(hidapi.clone(), exiting.clone())?; + let trezor = trezor::Manager::new(hidapi.clone(), exiting.clone())?; Ok(HardwareWalletManager { exiting: exiting, @@ -217,6 +209,8 @@ impl HardwareWalletManager { } /// Select key derivation path for a chain. + /// Currently, only one hard-coded keypath is supported + /// It is managed by `ethcore/account_provider` pub fn set_key_path(&self, key_path: KeyPath) { self.ledger.set_key_path(key_path); self.trezor.set_key_path(key_path); @@ -231,24 +225,26 @@ impl HardwareWalletManager { } /// Return a list of paths to locked hardware wallets + /// This is only applicable to Trezor because Ledger only appears as + /// a device when it is unlocked pub fn list_locked_wallets(&self) -> Result, Error> { Ok(self.trezor.list_locked_devices()) } /// Get connected wallet info. pub fn wallet_info(&self, address: &Address) -> Option { - if let Some(info) = self.ledger.device_info(address) { + if let Some(info) = self.ledger.get_wallet(address) { Some(info) } else { - self.trezor.device_info(address) + self.trezor.get_wallet(address) } } /// Sign transaction data with wallet managing `address`. pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo, encoded_transaction: &[u8]) -> Result { - if self.ledger.device_info(address).is_some() { + if self.ledger.get_wallet(address).is_some() { Ok(self.ledger.sign_transaction(address, encoded_transaction)?) - } else if self.trezor.device_info(address).is_some() { + } else if self.trezor.get_wallet(address).is_some() { Ok(self.trezor.sign_transaction(address, t_info)?) } else { Err(Error::KeyNotFound) @@ -256,6 +252,8 @@ impl HardwareWalletManager { } /// Send a pin to a device at a certain path to unlock it + /// This is only applicable to Trezor because Ledger only appears as + /// a device when it is unlocked pub fn pin_matrix_ack(&self, path: &str, pin: &str) -> Result { self.trezor.pin_matrix_ack(path, pin).map_err(Error::TrezorDevice) } diff --git a/hw/src/trezor.rs b/hw/src/trezor.rs index 7db226718bc..044e5487b40 100644 --- a/hw/src/trezor.rs +++ b/hw/src/trezor.rs @@ -19,12 +19,15 @@ //! and https://github.com/trezor/trezor-common/blob/master/protob/protocol.md //! for protocol details. -use super::{WalletInfo, TransactionInfo, KeyPath}; +use super::{WalletInfo, TransactionInfo, KeyPath, Wallet, Device, USB_DEVICE_CLASS_DEVICE}; use std::cmp::{min, max}; use std::fmt; use std::sync::{Arc, Weak}; +use std::sync::atomic; +use std::sync::atomic::AtomicBool; use std::time::{Duration, Instant}; +use std::thread; use ethereum_types::{U256, H256, Address}; use ethkey::Signature; @@ -37,9 +40,9 @@ use protobuf::{Message, ProtobufEnum}; use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumTxRequest, EthereumSignTx, EthereumGetAddress, EthereumTxAck, ButtonAck}; /// Trezor v1 vendor ID -pub const TREZOR_VID: u16 = 0x534c; +const TREZOR_VID: u16 = 0x534c; /// Trezor product IDs -pub const TREZOR_PIDS: [u16; 1] = [0x0001]; +const TREZOR_PIDS: [u16; 1] = [0x0001]; const ETH_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003C, 0x80000000, 0, 0]; // m/44'/60'/0'/0/0 const ETC_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003D, 0x80000000, 0, 0]; // m/44'/61'/0'/0/0 @@ -94,12 +97,6 @@ pub struct Manager { key_path: RwLock, } -#[derive(Debug)] -struct Device { - path: String, - info: WalletInfo, -} - /// HID Version used for the Trezor device enum HidVersion { V1, @@ -108,102 +105,42 @@ enum HidVersion { impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>) -> Manager { - Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Manager { usb: hidapi, devices: RwLock::new(Vec::new()), locked_devices: RwLock::new(Vec::new()), key_path: RwLock::new(KeyPath::Ethereum), - } - } - - /// Re-populate device list - pub fn update_devices(&self) -> Result { - let mut usb = self.usb.lock(); - usb.refresh_devices(); - let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut locked_devices = Vec::new(); - let mut error = None; - for usb_device in devices { - let is_trezor = usb_device.vendor_id == TREZOR_VID; - let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id); - let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0; - - trace!( - "Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}", - usb_device, - is_trezor, - is_supported_product, - is_valid, - ); - if !is_trezor || !is_supported_product || !is_valid { - continue; - } - match self.read_device_info(&usb, &usb_device) { - Ok(device) => new_devices.push(device), - Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()), - Err(e) => { - warn!("Error reading device: {:?}", e); - error = Some(e); + }); + + let usb_context = Arc::new(libusb::Context::new()?); + let m = manager.clone(); + + // Subscribe to TREZOR V1 + // Note, this support only TREZOR V1 because TREZOR V2 has a different vendorID for some reason + // Also, we now only support one product as the second argument specifies + usb_context.register_callback( + Some(TREZOR_VID), Some(TREZOR_PIDS[0]), Some(USB_DEVICE_CLASS_DEVICE), + Box::new(EventHandler::new(Arc::downgrade(&manager))))?; + + // Trezor event thread + thread::Builder::new() + .name("hw_wallet_trezor".to_string()) + .spawn(move || { + if let Err(e) = m.update_devices() { + debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e); } - } - } - let count = new_devices.len(); - trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices); - *self.devices.write() = new_devices; - *self.locked_devices.write() = locked_devices; - match error { - Some(e) => Err(e), - None => Ok(count), - } - } - - fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { - let handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); - match self.get_address(&handle) { - Ok(Some(addr)) => { - Ok(Device { - path: dev_info.path.clone(), - info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, - address: addr, - }, - }) - } - Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())), - Err(e) => Err(e), - } - } - - /// Select key derivation path for a known chain. - pub fn set_key_path(&self, key_path: KeyPath) { - *self.key_path.write() = key_path; - } - - /// List connected wallets. This only returns wallets that are ready to be used. - pub fn list_devices(&self) -> Vec { - self.devices.read().iter().map(|d| d.info.clone()).collect() - } - - pub fn list_locked_devices(&self) -> Vec { - (*self.locked_devices.read()).clone() - } - - /// Get wallet info. - pub fn device_info(&self, address: &Address) -> Option { - self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) - } + loop { + usb_context.handle_events(Some(Duration::from_millis(500))) + .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); + if exiting.load(atomic::Ordering::Acquire) { + break; + } + } + }) + .ok(); - fn open_path(&self, f: F) -> Result - where F: Fn() -> Result - { - f().map_err(Into::into) + Ok(manager) } pub fn pin_matrix_ack(&self, device_path: &str, pin: &str) -> Result { @@ -227,61 +164,6 @@ impl Manager { unlocked } - fn get_address(&self, device: &hidapi::HidDevice) -> Result, Error> { - let typ = MessageType::MessageType_EthereumGetAddress; - let mut message = EthereumGetAddress::new(); - match *self.key_path.read() { - KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), - KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), - } - message.set_show_display(false); - self.send_device_message(&device, &typ, &message)?; - - let (resp_type, bytes) = self.read_device_response(&device)?; - match resp_type { - MessageType::MessageType_EthereumAddress => { - let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?; - Ok(Some(From::from(response.get_address()))) - } - _ => Ok(None), - } - } - - /// Sign transaction data with wallet managing `address`. - pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo) -> Result { - let usb = self.usb.lock(); - let devices = self.devices.read(); - let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; - let handle = self.open_path(|| usb.open_path(&device.path))?; - let msg_type = MessageType::MessageType_EthereumSignTx; - let mut message = EthereumSignTx::new(); - match *self.key_path.read() { - KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), - KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), - } - message.set_nonce(self.u256_to_be_vec(&t_info.nonce)); - message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit)); - message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price)); - message.set_value(self.u256_to_be_vec(&t_info.value)); - - match t_info.to { - Some(addr) => { - message.set_to(addr.to_vec()) - } - None => (), - } - let first_chunk_length = min(t_info.data.len(), 1024); - let chunk = &t_info.data[0..first_chunk_length]; - message.set_data_initial_chunk(chunk.to_vec()); - message.set_data_length(t_info.data.len() as u32); - if let Some(c_id) = t_info.chain_id { - message.set_chain_id(c_id as u32); - } - - self.send_device_message(&handle, &msg_type, &message)?; - - self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..]) - } fn u256_to_be_vec(&self, val: &U256) -> Vec { let mut buf = [0u8; 32]; @@ -400,6 +282,152 @@ impl Manager { } } +impl <'a>Wallet<'a> for Manager { + type Error = Error; + type Transaction = &'a TransactionInfo; + + fn sign_transaction(&self, address: &Address, t_info: Self::Transaction) -> + Result { + let usb = self.usb.lock(); + let devices = self.devices.read(); + let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; + let handle = self.open_path(|| usb.open_path(&device.path))?; + let msg_type = MessageType::MessageType_EthereumSignTx; + let mut message = EthereumSignTx::new(); + match *self.key_path.read() { + KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), + KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), + } + message.set_nonce(self.u256_to_be_vec(&t_info.nonce)); + message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit)); + message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price)); + message.set_value(self.u256_to_be_vec(&t_info.value)); + + match t_info.to { + Some(addr) => { + message.set_to(addr.to_vec()) + } + None => (), + } + let first_chunk_length = min(t_info.data.len(), 1024); + let chunk = &t_info.data[0..first_chunk_length]; + message.set_data_initial_chunk(chunk.to_vec()); + message.set_data_length(t_info.data.len() as u32); + if let Some(c_id) = t_info.chain_id { + message.set_chain_id(c_id as u32); + } + + self.send_device_message(&handle, &msg_type, &message)?; + + self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..]) + } + + fn set_key_path(&self, key_path: KeyPath) { + *self.key_path.write() = key_path; + } + + fn update_devices(&self) -> Result { + let mut usb = self.usb.lock(); + usb.refresh_devices(); + let devices = usb.devices(); + let mut new_devices = Vec::new(); + let mut locked_devices = Vec::new(); + let mut error = None; + for usb_device in devices { + let is_trezor = usb_device.vendor_id == TREZOR_VID; + let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id); + let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0; + + trace!( + "Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}", + usb_device, + is_trezor, + is_supported_product, + is_valid, + ); + if !is_trezor || !is_supported_product || !is_valid { + continue; + } + match self.read_device(&usb, &usb_device) { + Ok(device) => new_devices.push(device), + Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()), + Err(e) => { + warn!("Error reading device: {:?}", e); + error = Some(e); + } + } + } + let count = new_devices.len(); + trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices); + *self.devices.write() = new_devices; + *self.locked_devices.write() = locked_devices; + match error { + Some(e) => Err(e), + None => Ok(count), + } + } + + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { + let handle = self.open_path(|| usb.open_path(&dev_info.path))?; + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + match self.get_address(&handle) { + Ok(Some(addr)) => { + Ok(Device { + path: dev_info.path.clone(), + info: WalletInfo { + name: name, + manufacturer: manufacturer, + serial: serial, + address: addr, + }, + }) + } + Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())), + Err(e) => Err(e), + } + } + + fn list_devices(&self) -> Vec { + self.devices.read().iter().map(|d| d.info.clone()).collect() + } + + fn list_locked_devices(&self) -> Vec { + (*self.locked_devices.read()).clone() + } + + fn get_wallet(&self, address: &Address) -> Option { + self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) + } + + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Error> { + let typ = MessageType::MessageType_EthereumGetAddress; + let mut message = EthereumGetAddress::new(); + match *self.key_path.read() { + KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), + KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), + } + message.set_show_display(false); + self.send_device_message(&device, &typ, &message)?; + + let (resp_type, bytes) = self.read_device_response(&device)?; + match resp_type { + MessageType::MessageType_EthereumAddress => { + let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?; + Ok(Some(From::from(response.get_address()))) + } + _ => Ok(None), + } + } + + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result + { + f().map_err(Into::into) + } +} + // Try to connect to the device using polling in at most the time specified by the `timeout` fn try_connect_polling(trezor: Arc, duration: Duration) -> bool { let start_time = Instant::now(); @@ -412,11 +440,11 @@ fn try_connect_polling(trezor: Arc, duration: Duration) -> bool { } /// Trezor event handler -/// A separate thread is handeling incoming events +/// A separate thread is handling incoming events /// /// Note, that this run to completion and race-conditions can't occur but this can /// therefore starve other events for being process with a spinlock or similar -pub struct EventHandler { +struct EventHandler { trezor: Weak, } @@ -455,10 +483,10 @@ fn test_signature() { use ethereum_types::{H160, H256, U256}; let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap())); - let manager = Manager::new(hidapi.clone()); + let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).unwrap(); let addr: Address = H160::from("some_addr"); - manager.update_devices().unwrap(); + assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); let t_info = TransactionInfo { nonce: U256::from(1), From 066378beaebe5179e5b064d6b4add7a5cdd55645 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 1 May 2018 16:02:14 +0300 Subject: [PATCH 054/147] SecretStore: merge two types of errors into single one + Error::is_non_fatal (#8357) * SecretStore: error unify initial commit SecretStore: pass real error in error messages SecretStore: is_internal_error -> Error::is_non_fatal warnings SecretStore: ConsensusTemporaryUnreachable fix after merge removed comments removed comments SecretStore: updated HTTP error responses SecretStore: more ConsensusTemporaryUnreachable tests fix after rebase * fixed grumbles * use HashSet in tests --- secret_store/src/acl_storage.rs | 4 +- secret_store/src/key_server.rs | 4 +- .../key_version_negotiation_session.rs | 51 +++-- .../key_server_cluster/admin_sessions/mod.rs | 6 + .../servers_set_change_session.rs | 24 ++- .../admin_sessions/share_add_session.rs | 24 ++- .../client_sessions/decryption_session.rs | 29 ++- .../client_sessions/encryption_session.rs | 5 +- .../client_sessions/generation_session.rs | 63 +----- .../client_sessions/signing_session_ecdsa.rs | 25 ++- .../signing_session_schnorr.rs | 27 ++- .../src/key_server_cluster/cluster.rs | 36 +++- .../key_server_cluster/cluster_sessions.rs | 6 +- .../cluster_sessions_creator.rs | 21 +- .../key_server_cluster/connection_trigger.rs | 2 +- .../connection_trigger_with_migration.rs | 2 +- .../jobs/consensus_session.rs | 62 +++--- .../key_server_cluster/jobs/decryption_job.rs | 2 +- .../key_server_cluster/jobs/job_session.rs | 108 ++++++++-- .../jobs/signing_job_ecdsa.rs | 4 +- .../jobs/signing_job_schnorr.rs | 2 +- .../src/key_server_cluster/message.rs | 20 +- secret_store/src/key_server_cluster/mod.rs | 132 +----------- secret_store/src/key_server_set.rs | 2 +- secret_store/src/key_storage.rs | 4 +- secret_store/src/lib.rs | 2 +- secret_store/src/listener/http_listener.rs | 23 +- secret_store/src/listener/mod.rs | 2 +- .../src/listener/service_contract_listener.rs | 28 +-- secret_store/src/serialization.rs | 2 +- secret_store/src/traits.rs | 2 +- secret_store/src/types/all.rs | 88 +------- secret_store/src/types/error.rs | 199 ++++++++++++++++++ secret_store/src/types/mod.rs | 6 +- 34 files changed, 577 insertions(+), 440 deletions(-) create mode 100644 secret_store/src/types/error.rs diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 6399660aff3..50414eff26c 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -22,7 +22,7 @@ use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; use ethereum_types::{H256, Address}; use bytes::Bytes; use trusted_client::TrustedClient; -use types::all::{Error, ServerKeyId}; +use types::{Error, ServerKeyId}; use_contract!(acl_storage, "AclStorage", "res/acl_storage.json"); @@ -113,7 +113,7 @@ impl CachedContract { self.contract.functions() .check_permissions() .call(requester, document.clone(), &do_call) - .map_err(|e| Error::Internal(e.to_string())) + .map_err(|e| Error::Internal(format!("ACL checker call error: {}", e.to_string()))) }, None => Err(Error::Internal("ACL checker contract is not configured".to_owned())), } diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs index ea3a3c0a571..f11a157c00d 100644 --- a/secret_store/src/key_server.rs +++ b/secret_store/src/key_server.rs @@ -27,7 +27,7 @@ use super::key_storage::KeyStorage; use super::key_server_set::KeyServerSet; use key_server_cluster::{math, ClusterCore}; use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer, NodeKeyPair}; -use types::all::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, +use types::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, ClusterConfiguration, MessageHash, EncryptedMessageSignature, NodeId}; use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration}; @@ -238,7 +238,7 @@ pub mod tests { use key_server_set::tests::MapKeyServerSet; use key_server_cluster::math; use ethereum_types::{H256, H520}; - use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId, + use types::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature, Requester, NodeId}; use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer}; diff --git a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs index 15abdce89df..6c39fd8e7ed 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs @@ -143,6 +143,10 @@ pub struct FastestResultComputer { self_node_id: NodeId, /// Threshold (if known). threshold: Option, + /// Count of all configured key server nodes. + configured_nodes_count: usize, + /// Count of all connected key server nodes. + connected_nodes_count: usize, } /// Selects version with most support, waiting for responses from all nodes. @@ -185,7 +189,7 @@ impl SessionImpl where T: SessionTransport { /// Return result computer reference. pub fn version_holders(&self, version: &H256) -> Result, Error> { Ok(self.data.lock().versions.as_ref().ok_or(Error::InvalidStateForRequest)? - .get(version).ok_or(Error::KeyStorage("key version not found".into()))? + .get(version).ok_or(Error::ServerKeyIsNotFound)? .clone()) } @@ -236,7 +240,7 @@ impl SessionImpl where T: SessionTransport { // try to complete session Self::try_complete(&self.core, &mut *data); if no_confirmations_required && data.state != SessionState::Finished { - return Err(Error::MissingKeyShare); + return Err(Error::ServerKeyIsNotFound); } else if data.state == SessionState::Finished { return Ok(()); } @@ -266,7 +270,7 @@ impl SessionImpl where T: SessionTransport { &KeyVersionNegotiationMessage::KeyVersions(ref message) => self.on_key_versions(sender, message), &KeyVersionNegotiationMessage::KeyVersionsError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, } @@ -388,7 +392,7 @@ impl ClusterSession for SessionImpl where T: SessionTransport { if data.state != SessionState::Finished { warn!("{}: key version negotiation session failed with timeout", self.core.meta.self_node_id); - data.result = Some(Err(Error::ConsensusUnreachable)); + data.result = Some(Err(Error::ConsensusTemporaryUnreachable)); self.core.completed.notify_all(); } } @@ -431,11 +435,13 @@ impl SessionTransport for IsolatedSessionTransport { } impl FastestResultComputer { - pub fn new(self_node_id: NodeId, key_share: Option<&DocumentKeyShare>) -> Self { + pub fn new(self_node_id: NodeId, key_share: Option<&DocumentKeyShare>, configured_nodes_count: usize, connected_nodes_count: usize) -> Self { let threshold = key_share.map(|ks| ks.threshold); FastestResultComputer { - self_node_id: self_node_id, - threshold: threshold, + self_node_id, + threshold, + configured_nodes_count, + connected_nodes_count, } }} @@ -443,7 +449,7 @@ impl SessionResultComputer for FastestResultComputer { fn compute_result(&self, threshold: Option, confirmations: &BTreeSet, versions: &BTreeMap>) -> Option> { match self.threshold.or(threshold) { // if there's no versions at all && we're not waiting for confirmations anymore - _ if confirmations.is_empty() && versions.is_empty() => Some(Err(Error::MissingKeyShare)), + _ if confirmations.is_empty() && versions.is_empty() => Some(Err(Error::ServerKeyIsNotFound)), // if we have key share on this node Some(threshold) => { // select version this node have, with enough participants @@ -459,7 +465,17 @@ impl SessionResultComputer for FastestResultComputer { .find(|&(_, ref n)| n.len() >= threshold + 1) .map(|(version, nodes)| Ok((version.clone(), nodes.iter().cloned().nth(0) .expect("version is only inserted when there's at least one owner; qed")))) - .unwrap_or(Err(Error::ConsensusUnreachable))), + // if there's no version consensus among all connected nodes + // AND we're connected to ALL configured nodes + // OR there are less than required nodes for key restore + // => this means that we can't restore key with CURRENT configuration => respond with fatal error + // otherwise we could try later, after all nodes are connected + .unwrap_or_else(|| Err(if self.configured_nodes_count == self.connected_nodes_count + || self.configured_nodes_count < threshold + 1 { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }))), } }, // if we do not have share, then wait for all confirmations @@ -469,7 +485,11 @@ impl SessionResultComputer for FastestResultComputer { .max_by_key(|&(_, ref n)| n.len()) .map(|(version, nodes)| Ok((version.clone(), nodes.iter().cloned().nth(0) .expect("version is only inserted when there's at least one owner; qed")))) - .unwrap_or(Err(Error::ConsensusUnreachable))), + .unwrap_or_else(|| Err(if self.configured_nodes_count == self.connected_nodes_count { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }))), } } } @@ -480,7 +500,7 @@ impl SessionResultComputer for LargestSupportResultComputer { return None; } if versions.is_empty() { - return Some(Err(Error::MissingKeyShare)); + return Some(Err(Error::ServerKeyIsNotFound)); } versions.iter() @@ -552,12 +572,15 @@ mod tests { id: Default::default(), self_node_id: node_id.clone(), master_node_id: master_node_id.clone(), + configured_nodes_count: nodes.len(), + connected_nodes_count: nodes.len(), }, sub_session: sub_sesion.clone(), key_share: key_storage.get(&Default::default()).unwrap(), result_computer: Arc::new(FastestResultComputer::new( node_id.clone(), key_storage.get(&Default::default()).unwrap().as_ref(), + nodes.len(), nodes.len() )), transport: DummyTransport { cluster: cluster, @@ -723,13 +746,15 @@ mod tests { let computer = FastestResultComputer { self_node_id: Default::default(), threshold: None, + configured_nodes_count: 1, + connected_nodes_count: 1, }; - assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::MissingKeyShare))); + assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::ServerKeyIsNotFound))); } #[test] fn largest_computer_returns_missing_share_if_no_versions_returned() { let computer = LargestSupportResultComputer; - assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::MissingKeyShare))); + assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::ServerKeyIsNotFound))); } } diff --git a/secret_store/src/key_server_cluster/admin_sessions/mod.rs b/secret_store/src/key_server_cluster/admin_sessions/mod.rs index 01655653a2c..11c01cac53e 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/mod.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/mod.rs @@ -32,6 +32,10 @@ pub struct ShareChangeSessionMeta { pub master_node_id: NodeId, /// Id of node, on which this session is running. pub self_node_id: NodeId, + /// Count of all configured key server nodes. + pub configured_nodes_count: usize, + /// Count of all connected key server nodes. + pub connected_nodes_count: usize, } impl ShareChangeSessionMeta { @@ -42,6 +46,8 @@ impl ShareChangeSessionMeta { master_node_id: self.master_node_id, self_node_id: self.self_node_id, threshold: all_nodes_set_len.checked_sub(1).ok_or(Error::ConsensusUnreachable)?, + configured_nodes_count: self.configured_nodes_count, + connected_nodes_count: self.connected_nodes_count, }) } } diff --git a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs index e9aacdfbb4e..698872aadc2 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs @@ -282,7 +282,7 @@ impl SessionImpl { &ServersSetChangeMessage::ServersSetChangeShareAddMessage(ref message) => self.on_share_add_message(sender, message), &ServersSetChangeMessage::ServersSetChangeError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, &ServersSetChangeMessage::ServersSetChangeCompleted(ref message) => @@ -416,12 +416,14 @@ impl SessionImpl { match &message.message { &KeyVersionNegotiationMessage::RequestKeyVersions(ref message) if sender == &self.core.meta.master_node_id => { let key_id = message.session.clone().into(); - let key_share = self.core.key_storage.get(&key_id).map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = self.core.key_storage.get(&key_id)?; let negotiation_session = KeyVersionNegotiationSessionImpl::new(KeyVersionNegotiationSessionParams { meta: ShareChangeSessionMeta { id: key_id.clone(), self_node_id: self.core.meta.self_node_id.clone(), master_node_id: sender.clone(), + configured_nodes_count: self.core.meta.configured_nodes_count, + connected_nodes_count: self.core.meta.connected_nodes_count, }, sub_session: message.sub_session.clone().into(), key_share: key_share, @@ -492,7 +494,7 @@ impl SessionImpl { // on nodes, holding selected key share version, we could check if master node plan is correct let master_node_id = message.master_node_id.clone().into(); - if let Some(key_share) = self.core.key_storage.get(&key_id).map_err(|e| Error::KeyStorage(e.into()))? { + if let Some(key_share) = self.core.key_storage.get(&key_id)? { let version = message.version.clone().into(); if let Ok(key_version) = key_share.version(&version) { let key_share_owners = key_version.id_numbers.keys().cloned().collect(); @@ -660,7 +662,7 @@ impl SessionImpl { if !data.new_nodes_set.as_ref() .expect("new_nodes_set is filled during initialization; session is completed after initialization; qed") .contains(&self.core.meta.self_node_id) { - self.core.key_storage.clear().map_err(|e| Error::KeyStorage(e.into()))?; + self.core.key_storage.clear()?; } data.state = SessionState::Finished; @@ -709,6 +711,8 @@ impl SessionImpl { id: key_id, self_node_id: core.meta.self_node_id.clone(), master_node_id: master_node_id, + configured_nodes_count: core.meta.configured_nodes_count, + connected_nodes_count: core.meta.connected_nodes_count, }, cluster: core.cluster.clone(), key_storage: core.key_storage.clone(), @@ -731,12 +735,14 @@ impl SessionImpl { Some(Ok(key_id)) => key_id, }; - let key_share = core.key_storage.get(&key_id).map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = core.key_storage.get(&key_id)?; let negotiation_session = KeyVersionNegotiationSessionImpl::new(KeyVersionNegotiationSessionParams { meta: ShareChangeSessionMeta { id: key_id, self_node_id: core.meta.self_node_id.clone(), master_node_id: core.meta.self_node_id.clone(), + configured_nodes_count: core.meta.configured_nodes_count, + connected_nodes_count: core.meta.connected_nodes_count, }, sub_session: math::generate_random_scalar()?, key_share: key_share, @@ -888,7 +894,7 @@ impl SessionImpl { if !data.new_nodes_set.as_ref() .expect("new_nodes_set is filled during initialization; session is completed after initialization; qed") .contains(&core.meta.self_node_id) { - core.key_storage.clear().map_err(|e| Error::KeyStorage(e.into()))?; + core.key_storage.clear()?; } data.state = SessionState::Finished; @@ -1011,9 +1017,9 @@ impl KeyVersionNegotiationTransport for ServersSetChangeKeyVersionNegotiationTra } fn check_nodes_set(all_nodes_set: &BTreeSet, new_nodes_set: &BTreeSet) -> Result<(), Error> { - // all new nodes must be a part of all nodes set + // all_nodes_set is the set of nodes we're currently connected to (and configured for) match new_nodes_set.iter().any(|n| !all_nodes_set.contains(n)) { - true => Err(Error::InvalidNodesConfiguration), + true => Err(Error::NodeDisconnected), false => Ok(()) } } @@ -1104,6 +1110,8 @@ pub mod tests { self_node_id: master_node_id.clone(), master_node_id: master_node_id.clone(), id: SessionId::default(), + configured_nodes_count: all_nodes_set.len(), + connected_nodes_count: all_nodes_set.len(), }; let old_nodes = gml.nodes.iter().map(|n| create_node(meta.clone(), admin_public.clone(), all_nodes_set.clone(), n.1)); diff --git a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs index 7da73543bea..abe34edeab2 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs @@ -155,9 +155,7 @@ pub struct IsolatedSessionTransport { impl SessionImpl where T: SessionTransport { /// Create new share addition session. pub fn new(params: SessionParams) -> Result { - let key_share = params.key_storage - .get(¶ms.meta.id) - .map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = params.key_storage.get(¶ms.meta.id)?; Ok(SessionImpl { core: SessionCore { @@ -257,8 +255,8 @@ impl SessionImpl where T: SessionTransport { let admin_public = self.core.admin_public.as_ref().cloned().ok_or(Error::ConsensusUnreachable)?; // key share version is required on ShareAdd master node - let key_share = self.core.key_share.as_ref().ok_or_else(|| Error::KeyStorage("key share is not found on master node".into()))?; - let key_version = key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = self.core.key_share.as_ref().ok_or_else(|| Error::ServerKeyIsNotFound)?; + let key_version = key_share.version(&version)?; // old nodes set is all non-isolated owners of version holders let non_isolated_nodes = self.core.transport.nodes(); @@ -326,7 +324,7 @@ impl SessionImpl where T: SessionTransport { &ShareAddMessage::NewKeysDissemination(ref message) => self.on_new_keys_dissemination(sender, message), &ShareAddMessage::ShareAddError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone().into())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, } @@ -714,10 +712,10 @@ impl SessionImpl where T: SessionTransport { // save encrypted data to the key storage data.state = SessionState::Finished; if core.key_share.is_some() { - core.key_storage.update(core.meta.id.clone(), refreshed_key_share.clone()) + core.key_storage.update(core.meta.id.clone(), refreshed_key_share.clone())?; } else { - core.key_storage.insert(core.meta.id.clone(), refreshed_key_share.clone()) - }.map_err(|e| Error::KeyStorage(e.into()))?; + core.key_storage.insert(core.meta.id.clone(), refreshed_key_share.clone())?; + } // signal session completion data.state = SessionState::Finished; @@ -851,7 +849,7 @@ impl SessionTransport for IsolatedSessionTransport { #[cfg(test)] pub mod tests { use std::sync::Arc; - use std::collections::{VecDeque, BTreeMap, BTreeSet}; + use std::collections::{VecDeque, BTreeMap, BTreeSet, HashSet}; use ethkey::{Random, Generator, Public, KeyPair, Signature, sign}; use ethereum_types::H256; use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage}; @@ -952,6 +950,8 @@ pub mod tests { id: SessionId::default(), self_node_id: NodeId::default(), master_node_id: master_node_id, + configured_nodes_count: new_nodes_set.iter().chain(old_nodes_set.iter()).collect::>().len(), + connected_nodes_count: new_nodes_set.iter().chain(old_nodes_set.iter()).collect::>().len(), }; let new_nodes = new_nodes_set.iter() .filter(|n| !old_nodes_set.contains(&n)) @@ -992,6 +992,8 @@ pub mod tests { id: SessionId::default(), self_node_id: NodeId::default(), master_node_id: master_node_id, + configured_nodes_count: new_nodes_set.iter().chain(ml.nodes.keys()).collect::>().len(), + connected_nodes_count: new_nodes_set.iter().chain(ml.nodes.keys()).collect::>().len(), }; let old_nodes_set = ml.nodes.keys().cloned().collect(); let nodes = ml.nodes.iter() @@ -1102,7 +1104,7 @@ pub mod tests { assert_eq!(ml.nodes[&master_node_id].session.initialize(Some(ml.version), Some(new_nodes_set), Some(ml.old_set_signature.clone()), Some(ml.new_set_signature.clone()) - ).unwrap_err(), Error::KeyStorage("key share is not found on master node".into())); + ).unwrap_err(), Error::ServerKeyIsNotFound); } #[test] diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs index c47dd26bad7..083acb64800 100644 --- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs @@ -154,7 +154,7 @@ impl SessionImpl { if let Some(key_share) = params.key_share.as_ref() { // encrypted data must be set if key_share.common_point.is_none() || key_share.encrypted_point.is_none() { - return Err(Error::NotStartedSessionId); + return Err(Error::DocumentKeyIsNotFound); } } @@ -290,7 +290,7 @@ impl SessionImpl { // check if version exists let key_version = match self.core.key_share.as_ref() { None => return Err(Error::InvalidMessage), - Some(key_share) => key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?, + Some(key_share) => key_share.version(&version)?, }; let mut data = self.data.lock(); @@ -337,7 +337,7 @@ impl SessionImpl { &DecryptionMessage::PartialDecryption(ref message) => self.on_partial_decryption(sender, message), &DecryptionMessage::DecryptionSessionError(ref message) => - self.process_node_error(Some(&sender), Error::Io(message.error.clone())), + self.process_node_error(Some(&sender), message.error.clone()), &DecryptionMessage::DecryptionSessionCompleted(ref message) => self.on_session_completed(sender, message), &DecryptionMessage::DecryptionSessionDelegation(ref message) => @@ -432,8 +432,7 @@ impl SessionImpl { }; let mut data = self.data.lock(); - let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?) - .map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?)?.hash.clone(); let requester_public = data.consensus_session.consensus_job().executor().requester() .ok_or(Error::InvalidStateForRequest)? .public(&self.core.meta.id) @@ -564,7 +563,7 @@ impl SessionImpl { match { match node { - Some(node) => data.consensus_session.on_node_error(node), + Some(node) => data.consensus_session.on_node_error(node, error.clone()), None => data.consensus_session.on_session_timeout(), } } { @@ -601,7 +600,7 @@ impl SessionImpl { Some(key_share) => key_share, }; - let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(version)?.hash.clone(); let requester = data.consensus_session.consensus_job().executor().requester().ok_or(Error::InvalidStateForRequest)?.clone(); let requester_public = requester.public(&core.meta.id).map_err(Error::InsufficientRequesterData)?; let consensus_group = data.consensus_session.select_consensus_group()?.clone(); @@ -637,6 +636,8 @@ impl SessionImpl { master_node_id: core.meta.self_node_id.clone(), self_node_id: core.meta.self_node_id.clone(), threshold: core.meta.threshold, + configured_nodes_count: core.meta.configured_nodes_count, + connected_nodes_count: core.meta.connected_nodes_count, }, job, transport); job_session.initialize(consensus_group, self_response, core.meta.self_node_id != core.meta.master_node_id)?; data.broadcast_job_session = Some(job_session); @@ -881,6 +882,8 @@ mod tests { self_node_id: id_numbers.iter().nth(i).clone().unwrap().0, master_node_id: id_numbers.iter().nth(0).clone().unwrap().0, threshold: encrypted_datas[i].threshold, + configured_nodes_count: 5, + connected_nodes_count: 5, }, access_key: access_key.clone(), key_share: Some(encrypted_datas[i].clone()), @@ -944,6 +947,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { @@ -976,6 +981,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: None, @@ -998,6 +1005,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 2, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { @@ -1131,7 +1140,7 @@ mod tests { let (_, _, _, sessions) = prepare_decryption_sessions(); assert!(sessions[0].decrypted_secret().is_none()); sessions[0].on_session_timeout(); - assert_eq!(sessions[0].decrypted_secret().unwrap().unwrap_err(), Error::ConsensusUnreachable); + assert_eq!(sessions[0].decrypted_secret().unwrap().unwrap_err(), Error::ConsensusTemporaryUnreachable); } #[test] @@ -1141,7 +1150,7 @@ mod tests { // 1 node disconnects => we still can recover secret sessions[0].on_node_timeout(sessions[1].node()); - assert!(sessions[0].data.lock().consensus_session.consensus_job().rejects().contains(sessions[1].node())); + assert!(sessions[0].data.lock().consensus_session.consensus_job().rejects().contains_key(sessions[1].node())); assert!(sessions[0].state() == ConsensusSessionState::EstablishingConsensus); // 2 node are disconnected => we can not recover secret @@ -1208,7 +1217,7 @@ mod tests { let disconnected = sessions[0].data.lock().consensus_session.computation_job().requests().iter().cloned().nth(0).unwrap(); sessions[0].on_node_timeout(&disconnected); assert_eq!(sessions[0].state(), ConsensusSessionState::EstablishingConsensus); - assert!(sessions[0].data.lock().consensus_session.computation_job().rejects().contains(&disconnected)); + assert!(sessions[0].data.lock().consensus_session.computation_job().rejects().contains_key(&disconnected)); assert!(!sessions[0].data.lock().consensus_session.computation_job().requests().contains(&disconnected)); } diff --git a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs index ca8bac38154..3c863d1cb93 100644 --- a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs @@ -306,7 +306,7 @@ impl ClusterSession for SessionImpl { &EncryptionMessage::ConfirmEncryptionInitialization(ref message) => self.on_confirm_initialization(sender.clone(), message), &EncryptionMessage::EncryptionSessionError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone().into())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, }, @@ -326,7 +326,7 @@ pub fn check_encrypted_data(key_share: Option<&DocumentKeyShare>) -> Result<(), if let Some(key_share) = key_share { // check that common_point and encrypted_point are still not set yet if key_share.common_point.is_some() || key_share.encrypted_point.is_some() { - return Err(Error::CompletedSessionId); + return Err(Error::DocumentKeyAlreadyStored); } } @@ -344,5 +344,4 @@ pub fn update_encrypted_data(key_storage: &Arc, key_id: ServerKeyId, key_share.common_point = Some(common_point); key_share.encrypted_point = Some(encrypted_point); key_storage.update(key_id, key_share) - .map_err(|e| Error::KeyStorage(e.into())) } diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs index 0afe618246d..c2effe6c26d 100644 --- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs @@ -354,7 +354,7 @@ impl SessionImpl { &GenerationMessage::PublicKeyShare(ref message) => self.on_public_key_share(sender.clone(), message), &GenerationMessage::SessionError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone().into())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, &GenerationMessage::SessionCompleted(ref message) => @@ -474,7 +474,7 @@ impl SessionImpl { // simulate failure, if required if data.simulate_faulty_behaviour { - return Err(Error::Io("simulated error".into())); + return Err(Error::Internal("simulated error".into())); } // check state @@ -592,8 +592,7 @@ impl SessionImpl { }; if let Some(ref key_storage) = self.key_storage { - key_storage.insert(self.id.clone(), encrypted_data.clone()) - .map_err(|e| Error::KeyStorage(e.into()))?; + key_storage.insert(self.id.clone(), encrypted_data.clone())?; } // then respond with confirmation @@ -790,8 +789,7 @@ impl SessionImpl { // then save encrypted data to the key storage if let Some(ref key_storage) = self.key_storage { - key_storage.insert(self.id.clone(), encrypted_data.clone()) - .map_err(|e| Error::KeyStorage(e.into()))?; + key_storage.insert(self.id.clone(), encrypted_data.clone())?; } // then distribute encrypted data to every other node @@ -925,23 +923,15 @@ impl Debug for SessionImpl { } } -pub fn check_cluster_nodes(self_node_id: &NodeId, nodes: &BTreeSet) -> Result<(), Error> { - // at least two nodes must be in cluster - if nodes.len() < 1 { - return Err(Error::InvalidNodesCount); - } - // this node must be a part of cluster - if !nodes.contains(self_node_id) { - return Err(Error::InvalidNodesConfiguration); - } - +fn check_cluster_nodes(self_node_id: &NodeId, nodes: &BTreeSet) -> Result<(), Error> { + assert!(nodes.contains(self_node_id)); Ok(()) } -pub fn check_threshold(threshold: usize, nodes: &BTreeSet) -> Result<(), Error> { +fn check_threshold(threshold: usize, nodes: &BTreeSet) -> Result<(), Error> { // at least threshold + 1 nodes are required to collectively decrypt message if threshold >= nodes.len() { - return Err(Error::InvalidThreshold); + return Err(Error::NotEnoughNodesForThreshold); } Ok(()) @@ -1096,25 +1086,10 @@ pub mod tests { assert!(l.master().initialize(Default::default(), Default::default(), false, 0, l.nodes.keys().cloned().collect::>().into()).is_ok()); } - #[test] - fn fails_to_initialize_if_not_a_part_of_cluster() { - let node_id = math::generate_random_point().unwrap(); - let cluster = Arc::new(DummyCluster::new(node_id.clone())); - let session = SessionImpl::new(SessionParams { - id: SessionId::default(), - self_node_id: node_id.clone(), - key_storage: Some(Arc::new(DummyKeyStorage::default())), - cluster: cluster, - nonce: Some(0), - }); - let cluster_nodes: BTreeSet<_> = (0..2).map(|_| math::generate_random_point().unwrap()).collect(); - assert_eq!(session.initialize(Default::default(), Default::default(), false, 0, cluster_nodes.into()).unwrap_err(), Error::InvalidNodesConfiguration); - } - #[test] fn fails_to_initialize_if_threshold_is_wrong() { match make_simple_cluster(2, 2) { - Err(Error::InvalidThreshold) => (), + Err(Error::NotEnoughNodesForThreshold) => (), _ => panic!("unexpected"), } } @@ -1193,24 +1168,6 @@ pub mod tests { assert!(l.master().derived_point().unwrap() != passed_point.into()); } - #[test] - fn fails_to_complete_initialization_if_not_a_part_of_cluster() { - let (sid, m, _, l) = make_simple_cluster(0, 2).unwrap(); - let mut nodes = BTreeMap::new(); - nodes.insert(m, math::generate_random_scalar().unwrap()); - nodes.insert(math::generate_random_point().unwrap(), math::generate_random_scalar().unwrap()); - assert_eq!(l.first_slave().on_initialize_session(m, &message::InitializeSession { - session: sid.into(), - session_nonce: 0, - origin: None, - author: Address::default().into(), - nodes: nodes.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), - is_zero: false, - threshold: 0, - derived_point: math::generate_random_point().unwrap().into(), - }).unwrap_err(), Error::InvalidNodesConfiguration); - } - #[test] fn fails_to_complete_initialization_if_threshold_is_wrong() { let (sid, m, s, l) = make_simple_cluster(0, 2).unwrap(); @@ -1226,7 +1183,7 @@ pub mod tests { is_zero: false, threshold: 2, derived_point: math::generate_random_point().unwrap().into(), - }).unwrap_err(), Error::InvalidThreshold); + }).unwrap_err(), Error::NotEnoughNodesForThreshold); } #[test] diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs index 02c20bc20e1..b0d465343bd 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs @@ -187,6 +187,8 @@ impl SessionImpl { master_node_id: params.meta.master_node_id, self_node_id: params.meta.self_node_id, threshold: params.meta.threshold * 2, + configured_nodes_count: params.meta.configured_nodes_count, + connected_nodes_count: params.meta.connected_nodes_count, }, consensus_executor: match requester { Some(requester) => KeyAccessJob::new_on_master(params.meta.id.clone(), params.acl_storage.clone(), requester), @@ -259,7 +261,7 @@ impl SessionImpl { // check if version exists let key_version = match self.core.key_share.as_ref() { None => return Err(Error::InvalidMessage), - Some(key_share) => key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?, + Some(key_share) => key_share.version(&version)?, }; // select nodes to participate in consensus etablish session @@ -311,7 +313,7 @@ impl SessionImpl { &EcdsaSigningMessage::EcdsaPartialSignature(ref message) => self.on_partial_signature(sender, message), &EcdsaSigningMessage::EcdsaSigningSessionError(ref message) => - self.process_node_error(Some(&sender), Error::Io(message.error.clone())), + self.process_node_error(Some(&sender), message.error.clone()), &EcdsaSigningMessage::EcdsaSigningSessionCompleted(ref message) => self.on_session_completed(sender, message), &EcdsaSigningMessage::EcdsaSigningSessionDelegation(ref message) => @@ -386,8 +388,7 @@ impl SessionImpl { let key_share = self.core.key_share.as_ref() .expect("this is master node; master node is selected so that it has key version; qed"); let key_version = key_share.version(data.version.as_ref() - .expect("this is master node; master node is selected so that it has key version; qed") - ).map_err(|e| Error::KeyStorage(e.into()))?; + .expect("this is master node; master node is selected so that it has key version; qed"))?; let consensus_group = data.consensus_session.select_consensus_group()?.clone(); let mut other_consensus_group_nodes = consensus_group.clone(); @@ -680,7 +681,7 @@ impl SessionImpl { let inv_nonce_share = data.inv_nonce_generation_session.as_ref().expect(nonce_exists_proof).joint_public_and_secret().expect(nonce_exists_proof)?.2; let version = data.version.as_ref().ok_or(Error::InvalidMessage)?.clone(); - let key_version = key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(&version)?.hash.clone(); let signing_job = EcdsaSigningJob::new_on_slave(key_share.clone(), key_version, sig_nonce_public, inv_nonce_share)?; let signing_transport = self.core.signing_transport(); @@ -744,7 +745,7 @@ impl SessionImpl { match { match node { - Some(node) => data.consensus_session.on_node_error(node), + Some(node) => data.consensus_session.on_node_error(node, error.clone()), None => data.consensus_session.on_session_timeout(), } } { @@ -970,6 +971,14 @@ impl Cluster for NonceGenerationTransport where F: Fn(SessionId, Secret, u fn nodes(&self) -> BTreeSet { self.cluster.nodes() } + + fn configured_nodes_count(&self) -> usize { + self.cluster.configured_nodes_count() + } + + fn connected_nodes_count(&self) -> usize { + self.cluster.connected_nodes_count() + } } impl SessionCore { @@ -988,7 +997,7 @@ impl SessionCore { Some(key_share) => key_share, }; - let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(version)?.hash.clone(); let signing_job = EcdsaSigningJob::new_on_master(key_share.clone(), key_version, nonce_public, inv_nonce_share, inversed_nonce_coeff, message_hash)?; consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false).map(|_| ()) } @@ -1099,6 +1108,8 @@ mod tests { self_node_id: gl_node_id.clone(), master_node_id: master_node_id.clone(), threshold: gl_node.key_storage.get(&session_id).unwrap().unwrap().threshold, + configured_nodes_count: gl.nodes.len(), + connected_nodes_count: gl.nodes.len(), }, access_key: "834cb736f02d9c968dfaf0c37658a1d86ff140554fc8b59c9fdad5a8cf810eec".parse().unwrap(), key_share: Some(gl_node.key_storage.get(&session_id).unwrap().unwrap()), diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs index ed7164ca3a9..013748827c0 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs @@ -246,7 +246,7 @@ impl SessionImpl { // check if version exists let key_version = match self.core.key_share.as_ref() { None => return Err(Error::InvalidMessage), - Some(key_share) => key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?, + Some(key_share) => key_share.version(&version)?, }; let mut data = self.data.lock(); @@ -313,7 +313,7 @@ impl SessionImpl { &SchnorrSigningMessage::SchnorrPartialSignature(ref message) => self.on_partial_signature(sender, message), &SchnorrSigningMessage::SchnorrSigningSessionError(ref message) => - self.process_node_error(Some(&sender), Error::Io(message.error.clone())), + self.process_node_error(Some(&sender), message.error.clone()), &SchnorrSigningMessage::SchnorrSigningSessionCompleted(ref message) => self.on_session_completed(sender, message), &SchnorrSigningMessage::SchnorrSigningSessionDelegation(ref message) => @@ -500,8 +500,7 @@ impl SessionImpl { .expect("session key is generated before signature is computed; we are in SignatureComputing state; qed") .joint_public_and_secret() .expect("session key is generated before signature is computed; we are in SignatureComputing state; qed")?; - let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?) - .map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?)?.hash.clone(); let signing_job = SchnorrSigningJob::new_on_slave(self.core.meta.self_node_id.clone(), key_share.clone(), key_version, joint_public_and_secret.0, joint_public_and_secret.1)?; let signing_transport = self.core.signing_transport(); @@ -564,7 +563,7 @@ impl SessionImpl { match { match node { - Some(node) => data.consensus_session.on_node_error(node), + Some(node) => data.consensus_session.on_node_error(node, error.clone()), None => data.consensus_session.on_session_timeout(), } } { @@ -717,6 +716,14 @@ impl Cluster for SessionKeyGenerationTransport { fn nodes(&self) -> BTreeSet { self.cluster.nodes() } + + fn configured_nodes_count(&self) -> usize { + self.cluster.configured_nodes_count() + } + + fn connected_nodes_count(&self) -> usize { + self.cluster.connected_nodes_count() + } } impl SessionCore { @@ -735,7 +742,7 @@ impl SessionCore { Some(key_share) => key_share, }; - let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(version)?.hash.clone(); let signing_job = SchnorrSigningJob::new_on_master(self.meta.self_node_id.clone(), key_share.clone(), key_version, session_public, session_secret_share, message_hash)?; consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false).map(|_| ()) @@ -851,6 +858,8 @@ mod tests { self_node_id: gl_node_id.clone(), master_node_id: master_node_id.clone(), threshold: gl_node.key_storage.get(&session_id).unwrap().unwrap().threshold, + configured_nodes_count: gl.nodes.len(), + connected_nodes_count: gl.nodes.len(), }, access_key: "834cb736f02d9c968dfaf0c37658a1d86ff140554fc8b59c9fdad5a8cf810eec".parse().unwrap(), key_share: Some(gl_node.key_storage.get(&session_id).unwrap().unwrap()), @@ -971,6 +980,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { @@ -1003,6 +1014,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: None, @@ -1025,6 +1038,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 2, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs index 26f0e7ef1fa..d782ccd035f 100644 --- a/secret_store/src/key_server_cluster/cluster.rs +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -109,6 +109,10 @@ pub trait Cluster: Send + Sync { fn is_connected(&self, node: &NodeId) -> bool; /// Get a set of connected nodes. fn nodes(&self) -> BTreeSet; + /// Get total count of configured key server nodes (valid at the time of ClusterView creation). + fn configured_nodes_count(&self) -> usize; + /// Get total count of connected key server nodes (valid at the time of ClusterView creation). + fn connected_nodes_count(&self) -> usize; } /// Cluster initialization parameters. @@ -160,6 +164,8 @@ pub struct ClusterClientImpl { /// Network cluster view. It is a communication channel, required in single session. pub struct ClusterView { core: Arc>, + configured_nodes_count: usize, + connected_nodes_count: usize, } /// Cross-thread shareable cluster data. @@ -554,7 +560,7 @@ impl ClusterCore { let is_initialization_message = message.is_initialization_message(); let is_delegation_message = message.is_delegation_message(); match is_initialization_message || is_delegation_message { - false => sessions.get(&session_id, true).ok_or(Error::InvalidSessionId), + false => sessions.get(&session_id, true).ok_or(Error::NoActiveSessionWithId), true => { let creation_data = SC::creation_data_from_message(&message)?; let master = if is_initialization_message { sender.clone() } else { data.self_key_pair.public().clone() }; @@ -652,7 +658,7 @@ impl ClusterConnections { let trigger: Box = match config.auto_migrate_enabled { false => Box::new(SimpleConnectionTrigger::new(config.key_server_set.clone(), config.self_key_pair.clone(), config.admin_public.clone())), true if config.admin_public.is_none() => Box::new(ConnectionTriggerWithMigration::new(config.key_server_set.clone(), config.self_key_pair.clone())), - true => return Err(Error::Io("secret store admininstrator public key is specified with auto-migration enabled".into())), // TODO [Refac]: Io -> Internal + true => return Err(Error::Internal("secret store admininstrator public key is specified with auto-migration enabled".into())), }; let connector = trigger.servers_set_change_creator_connector(); @@ -835,8 +841,10 @@ impl Connection { } impl ClusterView { - pub fn new(cluster: Arc, nodes: BTreeSet) -> Self { + pub fn new(cluster: Arc, nodes: BTreeSet, configured_nodes_count: usize) -> Self { ClusterView { + configured_nodes_count: configured_nodes_count, + connected_nodes_count: nodes.len(), core: Arc::new(Mutex::new(ClusterViewCore { cluster: cluster, nodes: nodes, @@ -871,6 +879,14 @@ impl Cluster for ClusterView { fn nodes(&self) -> BTreeSet { self.core.lock().nodes.clone() } + + fn configured_nodes_count(&self) -> usize { + self.configured_nodes_count + } + + fn connected_nodes_count(&self) -> usize { + self.connected_nodes_count + } } impl ClusterClientImpl { @@ -1125,7 +1141,7 @@ pub mod tests { fn cluster_state(&self) -> ClusterState { unimplemented!("test-only") } fn new_generation_session(&self, _session_id: SessionId, _origin: Option
, _author: Address, _threshold: usize) -> Result, Error> { self.generation_requests_count.fetch_add(1, Ordering::Relaxed); - Err(Error::Io("test-errror".into())) + Err(Error::Internal("test-error".into())) } fn new_encryption_session(&self, _session_id: SessionId, _requester: Requester, _common_point: Public, _encrypted_point: Public) -> Result, Error> { unimplemented!("test-only") } fn new_decryption_session(&self, _session_id: SessionId, _origin: Option
, _requester: Requester, _version: Option, _is_shadow_decryption: bool, _is_broadcast_session: bool) -> Result, Error> { unimplemented!("test-only") } @@ -1197,6 +1213,14 @@ pub mod tests { fn nodes(&self) -> BTreeSet { self.data.lock().nodes.iter().cloned().collect() } + + fn configured_nodes_count(&self) -> usize { + self.data.lock().nodes.len() + } + + fn connected_nodes_count(&self) -> usize { + self.data.lock().nodes.len() + } } pub fn loop_until(core: &mut Core, timeout: Duration, predicate: F) where F: Fn() -> bool { @@ -1365,11 +1389,11 @@ pub mod tests { { // try to start generation session => fail in initialization assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 100).map(|_| ()), - Err(Error::InvalidThreshold)); + Err(Error::NotEnoughNodesForThreshold)); // try to start generation session => fails in initialization assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 100).map(|_| ()), - Err(Error::InvalidThreshold)); + Err(Error::NotEnoughNodesForThreshold)); assert!(clusters[0].data.sessions.generation_sessions.is_empty()); } diff --git a/secret_store/src/key_server_cluster/cluster_sessions.rs b/secret_store/src/key_server_cluster/cluster_sessions.rs index e67458f766d..780c947fc37 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions.rs @@ -547,8 +547,9 @@ impl ClusterSession for AdminSession { } } pub fn create_cluster_view(data: &Arc, requires_all_connections: bool) -> Result, Error> { + let disconnected_nodes_count = data.connections.disconnected_nodes().len(); if requires_all_connections { - if !data.connections.disconnected_nodes().is_empty() { + if disconnected_nodes_count != 0 { return Err(Error::NodeDisconnected); } } @@ -556,7 +557,8 @@ pub fn create_cluster_view(data: &Arc, requires_all_connections: bo let mut connected_nodes = data.connections.connected_nodes(); connected_nodes.insert(data.self_key_pair.public().clone()); - Ok(Arc::new(ClusterView::new(data.clone(), connected_nodes))) + let connected_nodes_count = connected_nodes.len(); + Ok(Arc::new(ClusterView::new(data.clone(), connected_nodes, connected_nodes_count + disconnected_nodes_count))) } #[cfg(test)] diff --git a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs index 86e40853e22..a56f51f8fbc 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs @@ -115,7 +115,7 @@ impl SessionCreatorCore { /// Read key share && remove disconnected nodes. fn read_key_share(&self, key_id: &SessionId) -> Result, Error> { - self.key_storage.get(key_id).map_err(|e| Error::KeyStorage(e.into())) + self.key_storage.get(key_id) } } @@ -146,7 +146,7 @@ impl ClusterSessionCreator for GenerationSessionCreat fn create(&self, cluster: Arc, master: NodeId, nonce: Option, id: SessionId, _creation_data: Option<()>) -> Result, Error> { // check that there's no finished encryption session with the same id if self.core.key_storage.contains(&id) { - return Err(Error::DuplicateSessionId); + return Err(Error::ServerKeyAlreadyGenerated); } let nonce = self.core.check_session_nonce(&master, nonce)?; @@ -232,6 +232,8 @@ impl ClusterSessionCreator for DecryptionSessi self_node_id: self.core.self_node_id.clone(), master_node_id: master, threshold: encrypted_data.as_ref().map(|ks| ks.threshold).unwrap_or_default(), + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, access_key: id.access_key, key_share: encrypted_data, @@ -278,6 +280,8 @@ impl ClusterSessionCreator for SchnorrSign self_node_id: self.core.self_node_id.clone(), master_node_id: master, threshold: encrypted_data.as_ref().map(|ks| ks.threshold).unwrap_or_default(), + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, access_key: id.access_key, key_share: encrypted_data, @@ -324,6 +328,8 @@ impl ClusterSessionCreator for EcdsaSigningS self_node_id: self.core.self_node_id.clone(), master_node_id: master, threshold: encrypted_data.as_ref().map(|ks| ks.threshold).unwrap_or_default(), + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, access_key: id.access_key, key_share: encrypted_data, @@ -351,14 +357,19 @@ impl ClusterSessionCreator, master: NodeId, nonce: Option, id: SessionIdWithSubSession, _creation_data: Option<()>) -> Result>, Error> { + let configured_nodes_count = cluster.configured_nodes_count(); + let connected_nodes_count = cluster.connected_nodes_count(); let encrypted_data = self.core.read_key_share(&id.id)?; let nonce = self.core.check_session_nonce(&master, nonce)?; - let computer = Arc::new(FastestResultKeyVersionsResultComputer::new(self.core.self_node_id.clone(), encrypted_data.as_ref())); + let computer = Arc::new(FastestResultKeyVersionsResultComputer::new(self.core.self_node_id.clone(), encrypted_data.as_ref(), + configured_nodes_count, configured_nodes_count)); Ok(Arc::new(KeyVersionNegotiationSessionImpl::new(KeyVersionNegotiationSessionParams { meta: ShareChangeSessionMeta { id: id.id.clone(), self_node_id: self.core.self_node_id.clone(), master_node_id: master, + configured_nodes_count: configured_nodes_count, + connected_nodes_count: connected_nodes_count, }, sub_session: id.access_key.clone(), key_share: encrypted_data, @@ -419,6 +430,8 @@ impl ClusterSessionCreator for AdminSess id: id.clone(), self_node_id: self.core.self_node_id.clone(), master_node_id: master, + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, transport: ShareAddTransport::new(id.clone(), Some(version), nonce, cluster), key_storage: self.core.key_storage.clone(), @@ -435,6 +448,8 @@ impl ClusterSessionCreator for AdminSess id: id.clone(), self_node_id: self.core.self_node_id.clone(), master_node_id: master, + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, cluster: cluster.clone(), key_storage: self.core.key_storage.clone(), diff --git a/secret_store/src/key_server_cluster/connection_trigger.rs b/secret_store/src/key_server_cluster/connection_trigger.rs index e0172b89aca..66612f044be 100644 --- a/secret_store/src/key_server_cluster/connection_trigger.rs +++ b/secret_store/src/key_server_cluster/connection_trigger.rs @@ -23,7 +23,7 @@ use ethkey::Public; use key_server_cluster::{KeyServerSet, KeyServerSetSnapshot}; use key_server_cluster::cluster::{ClusterClient, ClusterConnectionsData}; use key_server_cluster::cluster_sessions::AdminSession; -use types::all::{Error, NodeId}; +use types::{Error, NodeId}; use {NodeKeyPair}; #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs index 91679928fb6..40a4b5028eb 100644 --- a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs +++ b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs @@ -26,7 +26,7 @@ use key_server_cluster::cluster_sessions::{AdminSession, ClusterSession}; use key_server_cluster::jobs::servers_set_change_access_job::ordered_nodes_hash; use key_server_cluster::connection_trigger::{Maintain, ConnectionsAction, ConnectionTrigger, ServersSetChangeSessionCreatorConnector, TriggerConnections}; -use types::all::{Error, NodeId}; +use types::{Error, NodeId}; use {NodeKeyPair}; /// Key servers set change trigger with automated migration procedure. diff --git a/secret_store/src/key_server_cluster/jobs/consensus_session.rs b/secret_store/src/key_server_cluster/jobs/consensus_session.rs index cc4ebc6d9f4..5d780a48ebf 100644 --- a/secret_store/src/key_server_cluster/jobs/consensus_session.rs +++ b/secret_store/src/key_server_cluster/jobs/consensus_session.rs @@ -232,38 +232,42 @@ impl Result { + pub fn on_node_error(&mut self, node: &NodeId, error: Error) -> Result { let is_self_master = self.meta.master_node_id == self.meta.self_node_id; let is_node_master = self.meta.master_node_id == *node; let (is_restart_needed, timeout_result) = match self.state { ConsensusSessionState::WaitingForInitialization if is_self_master => { // it is strange to receive error before session is initialized && slave doesn't know access_key - // => fatal error + // => unreachable self.state = ConsensusSessionState::Failed; (false, Err(Error::ConsensusUnreachable)) } ConsensusSessionState::WaitingForInitialization if is_node_master => { - // can not establish consensus - // => fatal error + // error from master node before establishing consensus + // => unreachable self.state = ConsensusSessionState::Failed; - (false, Err(Error::ConsensusUnreachable)) + (false, Err(if !error.is_non_fatal() { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + })) }, ConsensusSessionState::EstablishingConsensus => { debug_assert!(is_self_master); // consensus still can be established // => try to live without this node - (false, self.consensus_job.on_node_error(node)) + (false, self.consensus_job.on_node_error(node, error)) }, ConsensusSessionState::ConsensusEstablished => { // we could try to continue without this node, if enough nodes left - (false, self.consensus_job.on_node_error(node)) + (false, self.consensus_job.on_node_error(node, error)) }, ConsensusSessionState::WaitingForPartialResults => { // check if *current* computation job can continue without this node let is_computation_node = self.computation_job.as_mut() .expect("WaitingForPartialResults state is only set when computation_job is created; qed") - .on_node_error(node) + .on_node_error(node, error.clone()) .is_err(); if !is_computation_node { // it is not used by current computation job @@ -275,7 +279,7 @@ impl return Ok(false), @@ -312,7 +316,7 @@ impl Result, Error> { - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; if partial_request.other_nodes_ids.len() != self.key_share.threshold || partial_request.other_nodes_ids.contains(&self.self_node_id) || partial_request.other_nodes_ids.iter().any(|n| !key_version.id_numbers.contains_key(n)) { diff --git a/secret_store/src/key_server_cluster/jobs/job_session.rs b/secret_store/src/key_server_cluster/jobs/job_session.rs index 82f387d7b99..d3a765bf5bc 100644 --- a/secret_store/src/key_server_cluster/jobs/job_session.rs +++ b/secret_store/src/key_server_cluster/jobs/job_session.rs @@ -101,8 +101,8 @@ struct JobSessionData { struct ActiveJobSessionData { /// Active partial requests. requests: BTreeSet, - /// Rejects to partial requests. - rejects: BTreeSet, + /// Rejects to partial requests (maps to true, if reject is fatal). + rejects: BTreeMap, /// Received partial responses. responses: BTreeMap, } @@ -149,7 +149,7 @@ impl JobSession where Executor: JobExe /// Get rejects. #[cfg(test)] - pub fn rejects(&self) -> &BTreeSet { + pub fn rejects(&self) -> &BTreeMap { debug_assert!(self.meta.self_node_id == self.meta.master_node_id); &self.data.active_data.as_ref() @@ -201,7 +201,11 @@ impl JobSession where Executor: JobExe debug_assert!(self.meta.self_node_id == self.meta.master_node_id); if nodes.len() < self.meta.threshold + 1 { - return Err(Error::ConsensusUnreachable); + return Err(if self.meta.configured_nodes_count < self.meta.threshold + 1 { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }); } if self.data.state != JobSessionState::Inactive { @@ -211,7 +215,7 @@ impl JobSession where Executor: JobExe // result from self let active_data = ActiveJobSessionData { requests: nodes.clone(), - rejects: BTreeSet::new(), + rejects: BTreeMap::new(), responses: BTreeMap::new(), }; let waits_for_self = active_data.requests.contains(&self.meta.self_node_id); @@ -295,13 +299,14 @@ impl JobSession where Executor: JobExe match self.executor.check_partial_response(node, &response)? { JobPartialResponseAction::Ignore => Ok(()), JobPartialResponseAction::Reject => { - active_data.rejects.insert(node.clone()); + // direct reject is always considered as fatal + active_data.rejects.insert(node.clone(), true); if active_data.requests.len() + active_data.responses.len() >= self.meta.threshold + 1 { return Ok(()); } self.data.state = JobSessionState::Failed; - Err(Error::ConsensusUnreachable) + Err(consensus_unreachable(&active_data.rejects)) }, JobPartialResponseAction::Accept => { active_data.responses.insert(node.clone(), response); @@ -316,22 +321,26 @@ impl JobSession where Executor: JobExe } /// When error from node is received. - pub fn on_node_error(&mut self, node: &NodeId) -> Result<(), Error> { + pub fn on_node_error(&mut self, node: &NodeId, error: Error) -> Result<(), Error> { if self.meta.self_node_id != self.meta.master_node_id { if node != &self.meta.master_node_id { return Ok(()); } self.data.state = JobSessionState::Failed; - return Err(Error::ConsensusUnreachable); + return Err(if !error.is_non_fatal() { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }); } if let Some(active_data) = self.data.active_data.as_mut() { - if active_data.rejects.contains(node) { + if active_data.rejects.contains_key(node) { return Ok(()); } if active_data.requests.remove(node) || active_data.responses.remove(node).is_some() { - active_data.rejects.insert(node.clone()); + active_data.rejects.insert(node.clone(), !error.is_non_fatal()); if self.data.state == JobSessionState::Finished && active_data.responses.len() < self.meta.threshold + 1 { self.data.state = JobSessionState::Active; } @@ -340,7 +349,7 @@ impl JobSession where Executor: JobExe } self.data.state = JobSessionState::Failed; - return Err(Error::ConsensusUnreachable); + return Err(consensus_unreachable(&active_data.rejects)); } } @@ -354,7 +363,8 @@ impl JobSession where Executor: JobExe } self.data.state = JobSessionState::Failed; - Err(Error::ConsensusUnreachable) + // we have started session => consensus is possible in theory, but now it has failed with timeout + Err(Error::ConsensusTemporaryUnreachable) } } @@ -368,6 +378,16 @@ impl JobPartialRequestAction { } } +/// Returns appropriate 'consensus unreachable' error. +fn consensus_unreachable(rejects: &BTreeMap) -> Error { + // when >= 50% of nodes have responded with fatal reject => ConsensusUnreachable + if rejects.values().filter(|r| **r).count() >= rejects.len() / 2 { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + } +} + #[cfg(test)] pub mod tests { use std::collections::{VecDeque, BTreeMap, BTreeSet}; @@ -414,11 +434,27 @@ pub mod tests { } pub fn make_master_session_meta(threshold: usize) -> SessionMeta { - SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(1), threshold: threshold } + SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(1), threshold: threshold, + configured_nodes_count: 5, connected_nodes_count: 5 } } pub fn make_slave_session_meta(threshold: usize) -> SessionMeta { - SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(2), threshold: threshold } + SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(2), threshold: threshold, + configured_nodes_count: 5, connected_nodes_count: 5 } + } + + #[test] + fn job_initialize_fails_if_not_enough_nodes_for_threshold_total() { + let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); + job.meta.configured_nodes_count = 1; + assert_eq!(job.initialize(vec![Public::from(1)].into_iter().collect(), None, false).unwrap_err(), Error::ConsensusUnreachable); + } + + #[test] + fn job_initialize_fails_if_not_enough_nodes_for_threshold_connected() { + let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); + job.meta.connected_nodes_count = 3; + assert_eq!(job.initialize(vec![Public::from(1)].into_iter().collect(), None, false).unwrap_err(), Error::ConsensusTemporaryUnreachable); } #[test] @@ -528,7 +564,7 @@ pub mod tests { fn job_node_error_ignored_when_slave_disconnects_from_slave() { let mut job = JobSession::new(make_slave_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); assert_eq!(job.state(), JobSessionState::Inactive); - job.on_node_error(&NodeId::from(3)).unwrap(); + job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Inactive); } @@ -536,7 +572,7 @@ pub mod tests { fn job_node_error_leads_to_fail_when_slave_disconnects_from_master() { let mut job = JobSession::new(make_slave_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); assert_eq!(job.state(), JobSessionState::Inactive); - assert_eq!(job.on_node_error(&NodeId::from(1)).unwrap_err(), Error::ConsensusUnreachable); + assert_eq!(job.on_node_error(&NodeId::from(1), Error::AccessDenied).unwrap_err(), Error::ConsensusUnreachable); assert_eq!(job.state(), JobSessionState::Failed); } @@ -546,7 +582,7 @@ pub mod tests { job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); job.on_partial_response(&NodeId::from(2), 3).unwrap(); - job.on_node_error(&NodeId::from(2)).unwrap(); + job.on_node_error(&NodeId::from(2), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Active); } @@ -555,7 +591,7 @@ pub mod tests { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); - job.on_node_error(&NodeId::from(3)).unwrap(); + job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Active); } @@ -564,7 +600,7 @@ pub mod tests { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); - job.on_node_error(&NodeId::from(3)).unwrap(); + job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Active); } @@ -573,7 +609,7 @@ pub mod tests { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); - assert_eq!(job.on_node_error(&NodeId::from(2)).unwrap_err(), Error::ConsensusUnreachable); + assert_eq!(job.on_node_error(&NodeId::from(2), Error::AccessDenied).unwrap_err(), Error::ConsensusUnreachable); assert_eq!(job.state(), JobSessionState::Failed); } @@ -592,4 +628,34 @@ pub mod tests { assert_eq!(job.state(), JobSessionState::Active); assert!(job.transport().is_empty_response()); } + + #[test] + fn job_fails_with_temp_error_if_more_than_half_nodes_respond_with_temp_error() { + let mut job = JobSession::new(make_master_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3), Public::from(4)].into_iter().collect(), None, false).unwrap(); + job.on_node_error(&NodeId::from(2), Error::NodeDisconnected).unwrap(); + assert_eq!(job.on_node_error(&NodeId::from(3), Error::NodeDisconnected).unwrap_err(), Error::ConsensusTemporaryUnreachable); + } + + #[test] + fn job_fails_with_temp_error_if_more_than_half_rejects_are_temp() { + let mut job = JobSession::new(make_master_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3), Public::from(4)].into_iter().collect(), None, false).unwrap(); + job.on_node_error(&NodeId::from(2), Error::NodeDisconnected).unwrap(); + assert_eq!(job.on_node_error(&NodeId::from(3), Error::NodeDisconnected).unwrap_err(), Error::ConsensusTemporaryUnreachable); + } + + #[test] + fn job_fails_if_more_than_half_rejects_are_non_temp() { + let mut job = JobSession::new(make_master_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3), Public::from(4)].into_iter().collect(), None, false).unwrap(); + job.on_node_error(&NodeId::from(2), Error::AccessDenied).unwrap(); + assert_eq!(job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap_err(), Error::ConsensusUnreachable); + } + + #[test] + fn job_fails_with_temp_error_when_temp_error_is_reported_by_master_node() { + let mut job = JobSession::new(make_slave_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + assert_eq!(job.on_node_error(&NodeId::from(1), Error::NodeDisconnected).unwrap_err(), Error::ConsensusTemporaryUnreachable); + } } diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs index 561a8e0f87c..8f4ab1d68eb 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs @@ -108,7 +108,7 @@ impl JobExecutor for EcdsaSigningJob { fn process_partial_request(&mut self, partial_request: EcdsaPartialSigningRequest) -> Result, Error> { let inversed_nonce_coeff_mul_nonce = math::compute_secret_mul(&partial_request.inversed_nonce_coeff, &self.inv_nonce_share)?; - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; let signature_r = math::compute_ecdsa_r(&self.nonce_public)?; let inv_nonce_mul_secret = math::compute_secret_mul(&inversed_nonce_coeff_mul_nonce, &key_version.secret_share)?; let partial_signature_s = math::compute_ecdsa_s_share( @@ -134,7 +134,7 @@ impl JobExecutor for EcdsaSigningJob { } fn compute_response(&self, partial_responses: &BTreeMap) -> Result { - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; if partial_responses.keys().any(|n| !key_version.id_numbers.contains_key(n)) { return Err(Error::InvalidMessage); } diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs index 6246a728de9..54225a6cf57 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs @@ -107,7 +107,7 @@ impl JobExecutor for SchnorrSigningJob { } fn process_partial_request(&mut self, partial_request: SchnorrPartialSigningRequest) -> Result, Error> { - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; if partial_request.other_nodes_ids.len() != self.key_share.threshold || partial_request.other_nodes_ids.contains(&self.self_node_id) || partial_request.other_nodes_ids.iter().any(|n| !key_version.id_numbers.contains_key(n)) { diff --git a/secret_store/src/key_server_cluster/message.rs b/secret_store/src/key_server_cluster/message.rs index e08d6761a61..cc49e56fdb5 100644 --- a/secret_store/src/key_server_cluster/message.rs +++ b/secret_store/src/key_server_cluster/message.rs @@ -18,8 +18,8 @@ use std::fmt; use std::collections::{BTreeSet, BTreeMap}; use ethkey::Secret; use key_server_cluster::SessionId; -use super::{SerializableH256, SerializablePublic, SerializableSecret, SerializableSignature, - SerializableMessageHash, SerializableRequester, SerializableAddress}; +use super::{Error, SerializableH256, SerializablePublic, SerializableSecret, + SerializableSignature, SerializableMessageHash, SerializableRequester, SerializableAddress}; pub type MessageSessionId = SerializableH256; pub type MessageNodeId = SerializablePublic; @@ -346,7 +346,7 @@ pub struct SessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// When session is completed. @@ -390,7 +390,7 @@ pub struct EncryptionSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// Node is asked to be part of consensus group. @@ -509,7 +509,7 @@ pub struct SchnorrSigningSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// Schnorr signing session completed. @@ -662,7 +662,7 @@ pub struct EcdsaSigningSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// ECDSA signing session completed. @@ -769,7 +769,7 @@ pub struct DecryptionSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// When decryption session is completed. @@ -936,7 +936,7 @@ pub struct ServersSetChangeError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// When servers set change session is completed. @@ -999,7 +999,7 @@ pub struct ShareAddError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// Key versions are requested. @@ -1038,7 +1038,7 @@ pub struct KeyVersionsError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } impl Message { diff --git a/secret_store/src/key_server_cluster/mod.rs b/secret_store/src/key_server_cluster/mod.rs index 94386d0510a..d5ac85b3dea 100644 --- a/secret_store/src/key_server_cluster/mod.rs +++ b/secret_store/src/key_server_cluster/mod.rs @@ -14,14 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; -use std::io::Error as IoError; -use ethkey; -use crypto; -use super::types::all::ServerKeyId; +use super::types::ServerKeyId; pub use super::traits::NodeKeyPair; -pub use super::types::all::{NodeId, Requester, EncryptedDocumentKeyShadow}; +pub use super::types::{Error, NodeId, Requester, EncryptedDocumentKeyShadow}; pub use super::acl_storage::AclStorage; pub use super::key_storage::{KeyStorage, DocumentKeyShare, DocumentKeyShareVersion}; pub use super::key_server_set::{is_migration_required, KeyServerSet, KeyServerSetSnapshot, KeyServerSetMigration}; @@ -53,126 +49,10 @@ pub struct SessionMeta { pub self_node_id: NodeId, /// Session threshold. pub threshold: usize, -} - -/// Errors which can occur during encryption/decryption session -#[derive(Clone, Debug, PartialEq)] -pub enum Error { - /// Invalid node address has been passed. - InvalidNodeAddress, - /// Invalid node id has been passed. - InvalidNodeId, - /// Session with the given id already exists. - DuplicateSessionId, - /// Session with the same id already completed. - CompletedSessionId, - /// Session is not ready to start yet (required data is not ready). - NotStartedSessionId, - /// Session with the given id is unknown. - InvalidSessionId, - /// Invalid number of nodes. - /// There must be at least two nodes participating in encryption. - /// There must be at least one node participating in decryption. - InvalidNodesCount, - /// Node which is required to start encryption/decryption session is not a part of cluster. - InvalidNodesConfiguration, - /// Invalid threshold value has been passed. - /// Threshold value must be in [0; n - 1], where n is a number of nodes participating in the encryption. - InvalidThreshold, - /// Current state of encryption/decryption session does not allow to proceed request. - /// Reschedule this request for later processing. - TooEarlyForRequest, - /// Current state of encryption/decryption session does not allow to proceed request. - /// This means that either there is some comm-failure or node is misbehaving/cheating. - InvalidStateForRequest, - /// Request cannot be sent/received from this node. - InvalidNodeForRequest, - /// Message or some data in the message was recognized as invalid. - /// This means that node is misbehaving/cheating. - InvalidMessage, - /// Message version is not supported. - InvalidMessageVersion, - /// Message is invalid because of replay-attack protection. - ReplayProtection, - /// Connection to node, required for this session is not established. - NodeDisconnected, - /// Node is missing requested key share. - MissingKeyShare, - /// Cryptographic error. - EthKey(String), - /// I/O error has occured. - Io(String), - /// Deserialization error has occured. - Serde(String), - /// Key storage error. - KeyStorage(String), - /// Consensus is unreachable. - ConsensusUnreachable, - /// Acl storage error. - AccessDenied, - /// Can't start session, because exclusive session is active. - ExclusiveSessionActive, - /// Can't start exclusive session, because there are other active sessions. - HasActiveSessions, - /// Insufficient requester data. - InsufficientRequesterData(String), -} - -impl From for Error { - fn from(err: ethkey::Error) -> Self { - Error::EthKey(err.into()) - } -} - -impl From for Error { - fn from(err: crypto::Error) -> Self { - Error::EthKey(err.into()) - } -} - -impl From for Error { - fn from(err: IoError) -> Self { - Error::Io(err.to_string()) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::InvalidNodeAddress => write!(f, "invalid node address has been passed"), - Error::InvalidNodeId => write!(f, "invalid node id has been passed"), - Error::DuplicateSessionId => write!(f, "session with the same id is already registered"), - Error::CompletedSessionId => write!(f, "session with the same id is already completed"), - Error::NotStartedSessionId => write!(f, "not enough data to start session with the given id"), - Error::InvalidSessionId => write!(f, "invalid session id has been passed"), - Error::InvalidNodesCount => write!(f, "invalid nodes count"), - Error::InvalidNodesConfiguration => write!(f, "invalid nodes configuration"), - Error::InvalidThreshold => write!(f, "invalid threshold value has been passed"), - Error::TooEarlyForRequest => write!(f, "session is not yet ready to process this request"), - Error::InvalidStateForRequest => write!(f, "session is in invalid state for processing this request"), - Error::InvalidNodeForRequest => write!(f, "invalid node for this request"), - Error::InvalidMessage => write!(f, "invalid message is received"), - Error::InvalidMessageVersion => write!(f, "unsupported message is received"), - Error::ReplayProtection => write!(f, "replay message is received"), - Error::NodeDisconnected => write!(f, "node required for this operation is currently disconnected"), - Error::MissingKeyShare => write!(f, "requested key share version is not found"), - Error::EthKey(ref e) => write!(f, "cryptographic error {}", e), - Error::Io(ref e) => write!(f, "i/o error {}", e), - Error::Serde(ref e) => write!(f, "serde error {}", e), - Error::KeyStorage(ref e) => write!(f, "key storage error {}", e), - Error::ConsensusUnreachable => write!(f, "Consensus unreachable"), - Error::AccessDenied => write!(f, "Access denied"), - Error::ExclusiveSessionActive => write!(f, "Exclusive session active"), - Error::HasActiveSessions => write!(f, "Unable to start exclusive session"), - Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), - } - } -} - -impl Into for Error { - fn into(self) -> String { - format!("{}", self) - } + /// Count of all configured key server nodes (valid at session start time). + pub configured_nodes_count: usize, + /// Count of all connected key server nodes (valid at session start time). + pub connected_nodes_count: usize, } mod admin_sessions; diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index cb324dbc9ba..25651bb4cad 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -25,7 +25,7 @@ use ethkey::public_to_address; use hash::keccak; use ethereum_types::{H256, Address}; use bytes::Bytes; -use types::all::{Error, Public, NodeAddress, NodeId}; +use types::{Error, Public, NodeAddress, NodeId}; use trusted_client::TrustedClient; use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; use {NodeKeyPair}; diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index fee73c2ae1a..4f78bc338c2 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -21,7 +21,7 @@ use tiny_keccak::Keccak; use ethereum_types::{H256, Address}; use ethkey::{Secret, Public, public_to_address}; use kvdb::KeyValueDB; -use types::all::{Error, ServerKeyId, NodeId}; +use types::{Error, ServerKeyId, NodeId}; use serialization::{SerializablePublic, SerializableSecret, SerializableH256, SerializableAddress}; /// Key of version value. @@ -419,7 +419,7 @@ pub mod tests { use ethereum_types::{Address, H256}; use ethkey::{Random, Generator, Public, Secret, public_to_address}; use kvdb_rocksdb::Database; - use types::all::{Error, ServerKeyId}; + use types::{Error, ServerKeyId}; use super::{DB_META_KEY_VERSION, CURRENT_VERSION, KeyStorage, PersistentKeyStorage, DocumentKeyShare, DocumentKeyShareVersion, CurrentSerializableDocumentKeyShare, upgrade_db, SerializableDocumentKeyShareV0, SerializableDocumentKeyShareV1, SerializableDocumentKeyShareV2, SerializableDocumentKeyShareVersionV2}; diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 8e1278e425b..80b15318a9f 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -76,7 +76,7 @@ use ethcore::client::Client; use ethcore::miner::Miner; use sync::SyncProvider; -pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, +pub use types::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, Error, NodeAddress, ContractAddress, ServiceConfiguration, ClusterConfiguration}; pub use traits::{NodeKeyPair, KeyServer}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index bf293a44eb4..074052fae47 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -29,7 +29,7 @@ use url::percent_encoding::percent_decode; use traits::KeyServer; use serialization::{SerializableEncryptedDocumentKeyShadow, SerializableBytes, SerializablePublic}; -use types::all::{Error, Public, MessageHash, NodeAddress, RequestSignature, ServerKeyId, +use types::{Error, Public, MessageHash, NodeAddress, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId}; /// Key server http-requests listener. Available requests: @@ -271,15 +271,16 @@ fn return_bytes(req_uri: &Uri, result: Result, Error>) - } fn return_error(err: Error) -> HttpResponse { - let mut res = match err { - Error::InsufficientRequesterData(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), - Error::AccessDenied => HttpResponse::new().with_status(HttpStatusCode::Forbidden), - Error::DocumentNotFound => HttpResponse::new().with_status(HttpStatusCode::NotFound), - Error::Hyper(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), - Error::Serde(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), - Error::Database(_) => HttpResponse::new().with_status(HttpStatusCode::InternalServerError), - Error::Internal(_) => HttpResponse::new().with_status(HttpStatusCode::InternalServerError), - }; + let mut res = HttpResponse::new().with_status(match err { + Error::AccessDenied | Error::ConsensusUnreachable | Error::ConsensusTemporaryUnreachable => + HttpStatusCode::Forbidden, + Error::ServerKeyIsNotFound | Error::DocumentKeyIsNotFound => + HttpStatusCode::NotFound, + Error::InsufficientRequesterData(_) | Error::Hyper(_) | Error::Serde(_) + | Error::DocumentKeyAlreadyStored | Error::ServerKeyAlreadyGenerated => + HttpStatusCode::BadRequest, + _ => HttpStatusCode::InternalServerError, + }); // return error text. ignore errors when returning error let error_text = format!("\"{}\"", err); @@ -377,7 +378,7 @@ mod tests { use ethkey::Public; use traits::KeyServer; use key_server::tests::DummyKeyServer; - use types::all::NodeAddress; + use types::NodeAddress; use super::{parse_request, Request, KeyServerHttpListener}; #[test] diff --git a/secret_store/src/listener/mod.rs b/secret_store/src/listener/mod.rs index 2c4fbaf4cb7..0d1f3f26753 100644 --- a/secret_store/src/listener/mod.rs +++ b/secret_store/src/listener/mod.rs @@ -23,7 +23,7 @@ mod tasks_queue; use std::collections::BTreeSet; use std::sync::Arc; use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, AdminSessionsServer, KeyServer}; -use types::all::{Error, Public, MessageHash, EncryptedMessageSignature, RequestSignature, ServerKeyId, +use types::{Error, Public, MessageHash, EncryptedMessageSignature, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId, Requester}; /// Available API mask. diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 1e17be8e557..0e273b3eeee 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -315,7 +315,7 @@ impl ServiceContractListener { Ok(Some(server_key)) => { data.contract.publish_generated_server_key(&origin, server_key_id, server_key) }, - Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_server_key_generation_error(&origin, server_key_id) @@ -335,7 +335,7 @@ impl ServiceContractListener { Ok(None) => { data.contract.publish_server_key_retrieval_error(&origin, server_key_id) } - Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_server_key_retrieval_error(&origin, server_key_id) @@ -349,7 +349,7 @@ impl ServiceContractListener { /// Store document key. fn store_document_key(data: &Arc, origin: Address, server_key_id: &ServerKeyId, author: &Address, common_point: &Public, encrypted_point: &Public) -> Result<(), String> { let store_result = data.key_storage.get(server_key_id) - .and_then(|key_share| key_share.ok_or(Error::DocumentNotFound)) + .and_then(|key_share| key_share.ok_or(Error::ServerKeyIsNotFound)) .and_then(|key_share| check_encrypted_data(Some(&key_share)).map(|_| key_share).map_err(Into::into)) .and_then(|key_share| update_encrypted_data(&data.key_storage, server_key_id.clone(), key_share, author.clone(), common_point.clone(), encrypted_point.clone()).map_err(Into::into)); @@ -357,7 +357,7 @@ impl ServiceContractListener { Ok(()) => { data.contract.publish_stored_document_key(&origin, server_key_id) }, - Err(ref error) if is_internal_error(&error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_document_key_store_error(&origin, server_key_id) @@ -372,17 +372,16 @@ impl ServiceContractListener { fn retrieve_document_key_common(data: &Arc, origin: Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { let retrieval_result = data.acl_storage.check(requester.clone(), server_key_id) .and_then(|is_allowed| if !is_allowed { Err(Error::AccessDenied) } else { Ok(()) }) - .and_then(|_| data.key_storage.get(server_key_id).and_then(|key_share| key_share.ok_or(Error::DocumentNotFound))) + .and_then(|_| data.key_storage.get(server_key_id).and_then(|key_share| key_share.ok_or(Error::ServerKeyIsNotFound))) .and_then(|key_share| key_share.common_point - .ok_or(Error::DocumentNotFound) - .and_then(|common_point| math::make_common_shadow_point(key_share.threshold, common_point) - .map_err(|e| Error::Internal(e.into()))) + .ok_or(Error::DocumentKeyIsNotFound) + .and_then(|common_point| math::make_common_shadow_point(key_share.threshold, common_point)) .map(|common_point| (common_point, key_share.threshold))); match retrieval_result { Ok((common_point, threshold)) => { data.contract.publish_retrieved_document_key_common(&origin, server_key_id, requester, common_point, threshold) }, - Err(ref error) if is_internal_error(&error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_document_key_retrieval_error(&origin, server_key_id, requester) @@ -406,7 +405,7 @@ impl ServiceContractListener { Ok(Some((participants, decrypted_secret, shadow))) => { data.contract.publish_retrieved_document_key_personal(&origin, server_key_id, &requester, &participants, decrypted_secret, shadow) }, - Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_document_key_retrieval_error(&origin, server_key_id, &requester) @@ -511,15 +510,6 @@ impl ::std::fmt::Display for ServiceTask { } } -/// Is internal error? Internal error means that it is SS who's responsible for it, like: connectivity, db failure, ... -/// External error is caused by SS misuse, like: trying to generate duplicated key, access denied, ... -/// When internal error occurs, we just ignore request for now and will retry later. -/// When external error occurs, we reject request. -fn is_internal_error(_error: &Error) -> bool { - // TODO [Reliability]: implement me after proper is passed through network - false -} - /// Log service task result. fn log_service_task_result(task: &ServiceTask, self_id: &Public, result: Result<(), String>) -> Result<(), String> { match result { diff --git a/secret_store/src/serialization.rs b/secret_store/src/serialization.rs index 95f67909677..42209e0de4a 100644 --- a/secret_store/src/serialization.rs +++ b/secret_store/src/serialization.rs @@ -22,7 +22,7 @@ use serde::de::{Visitor, Error as SerdeError}; use ethkey::{Public, Secret, Signature}; use ethereum_types::{H160, H256}; use bytes::Bytes; -use types::all::Requester; +use types::Requester; macro_rules! impl_bytes_deserialize { ($name: ident, $value: expr, true) => { diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs index ea09a3d9067..04f2fa1294e 100644 --- a/secret_store/src/traits.rs +++ b/secret_store/src/traits.rs @@ -17,7 +17,7 @@ use std::collections::BTreeSet; use ethkey::{KeyPair, Signature, Error as EthKeyError}; use ethereum_types::{H256, Address}; -use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, Requester, +use types::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, Requester, EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId}; /// Node key pair. diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index b9940268144..bfc58779a6b 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -14,13 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; -use std::io; -use std::net; use std::collections::BTreeMap; -use serde_json; -use {ethkey, kvdb, bytes, ethereum_types, key_server_cluster}; +use {ethkey, bytes, ethereum_types}; /// Node id. pub type NodeId = ethkey::Public; @@ -37,25 +33,6 @@ pub type RequestSignature = ethkey::Signature; /// Public key type. pub use ethkey::Public; -/// Secret store error -#[derive(Debug, PartialEq)] -pub enum Error { - /// Insufficient requester data - InsufficientRequesterData(String), - /// Access to resource is denied - AccessDenied, - /// Requested document not found - DocumentNotFound, - /// Hyper error - Hyper(String), - /// Serialization/deserialization error - Serde(String), - /// Database-related error - Database(String), - /// Internal error - Internal(String), -} - /// Secret store configuration #[derive(Debug, Clone)] pub struct NodeAddress { @@ -136,69 +113,6 @@ pub enum Requester { Address(ethereum_types::Address), } -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), - Error::AccessDenied => write!(f, "Access dened"), - Error::DocumentNotFound => write!(f, "Document not found"), - Error::Hyper(ref msg) => write!(f, "Hyper error: {}", msg), - Error::Serde(ref msg) => write!(f, "Serialization error: {}", msg), - Error::Database(ref msg) => write!(f, "Database error: {}", msg), - Error::Internal(ref msg) => write!(f, "Internal error: {}", msg), - } - } -} - -impl From for Error { - fn from(err: serde_json::Error) -> Self { - Error::Serde(err.to_string()) - } -} - -impl From for Error { - fn from(err: ethkey::Error) -> Self { - Error::Internal(err.into()) - } -} - -impl From for Error { - fn from(err: io::Error) -> Error { - Error::Internal(err.to_string()) - } -} - -impl From for Error { - fn from(err: net::AddrParseError) -> Error { - Error::Internal(err.to_string()) - } -} - -impl From for Error { - fn from(err: kvdb::Error) -> Self { - Error::Database(err.to_string()) - } -} - -impl From for Error { - fn from(err: key_server_cluster::Error) -> Self { - match err { - key_server_cluster::Error::InsufficientRequesterData(err) - => Error::InsufficientRequesterData(err), - key_server_cluster::Error::ConsensusUnreachable - | key_server_cluster::Error::AccessDenied => Error::AccessDenied, - key_server_cluster::Error::MissingKeyShare => Error::DocumentNotFound, - _ => Error::Internal(err.into()), - } - } -} - -impl Into for Error { - fn into(self) -> String { - format!("{}", self) - } -} - impl Default for Requester { fn default() -> Self { Requester::Signature(Default::default()) diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs new file mode 100644 index 00000000000..6469585facb --- /dev/null +++ b/secret_store/src/types/error.rs @@ -0,0 +1,199 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::fmt; +use std::net; +use std::io::Error as IoError; + +use {ethkey, crypto, kvdb}; + +/// Secret store error. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Error { + /// Invalid node address has been passed. + InvalidNodeAddress, + /// Invalid node id has been passed. + InvalidNodeId, + /// Session with the given id already exists. + DuplicateSessionId, + /// No active session with given id. + NoActiveSessionWithId, + /// Invalid threshold value has been passed. + /// Threshold value must be in [0; n - 1], where n is a number of nodes participating in the encryption. + NotEnoughNodesForThreshold, + /// Current state of encryption/decryption session does not allow to proceed request. + /// Reschedule this request for later processing. + TooEarlyForRequest, + /// Current state of encryption/decryption session does not allow to proceed request. + /// This means that either there is some comm-failure or node is misbehaving/cheating. + InvalidStateForRequest, + /// Request cannot be sent/received from this node. + InvalidNodeForRequest, + /// Message or some data in the message was recognized as invalid. + /// This means that node is misbehaving/cheating. + InvalidMessage, + /// Message version is not supported. + InvalidMessageVersion, + /// Message is invalid because of replay-attack protection. + ReplayProtection, + /// Connection to node, required for this session is not established. + NodeDisconnected, + /// Server key with this ID is already generated. + ServerKeyAlreadyGenerated, + /// Server key with this ID is not yet generated. + ServerKeyIsNotFound, + /// Document key with this ID is already stored. + DocumentKeyAlreadyStored, + /// Document key with this ID is not yet stored. + DocumentKeyIsNotFound, + /// Consensus is temporary unreachable. Means that something is currently blocking us from either forming + /// consensus group (like disconnecting from too many nodes, which are AGREE to partticipate in consensus) + /// or from rejecting request (disconnecting from AccessDenied-nodes). + ConsensusTemporaryUnreachable, + /// Consensus is unreachable. It doesn't mean that it will ALWAYS remain unreachable, but right NOW we have + /// enough nodes confirmed that they do not want to be a part of consensus. Example: we're connected to 10 + /// of 100 nodes. Key threshold is 6 (i.e. 7 nodes are required for consensus). 4 nodes are responding with + /// reject => consensus is considered unreachable, even though another 90 nodes still can respond with OK. + ConsensusUnreachable, + /// Acl storage error. + AccessDenied, + /// Can't start session, because exclusive session is active. + ExclusiveSessionActive, + /// Can't start exclusive session, because there are other active sessions. + HasActiveSessions, + /// Insufficient requester data. + InsufficientRequesterData(String), + /// Cryptographic error. + EthKey(String), + /// I/O error has occured. + Io(String), + /// Deserialization error has occured. + Serde(String), + /// Hyper error. + Hyper(String), + /// Database-related error. + Database(String), + /// Internal error. + Internal(String), +} + +impl Error { + /// Is this a fatal error? Non-fatal means that it is possible to replay the same request with a non-zero + /// chance to success. I.e. the error is not about request itself (or current environment factors that + /// are affecting request processing), but about current SecretStore state. + pub fn is_non_fatal(&self) -> bool { + match *self { + // non-fatal errors: + + // session start errors => restarting session is a solution + Error::DuplicateSessionId | Error::NoActiveSessionWithId | + // unexpected message errors => restarting session/excluding node is a solution + Error::TooEarlyForRequest | Error::InvalidStateForRequest | Error::InvalidNodeForRequest | + // invalid message errors => restarting/updating/excluding node is a solution + Error::InvalidMessage | Error::InvalidMessageVersion | Error::ReplayProtection | + // connectivity problems => waiting for reconnect && restarting session is a solution + Error::NodeDisconnected | + // temporary (?) consensus problems, related to other non-fatal errors => restarting is probably (!) a solution + Error::ConsensusTemporaryUnreachable | + // exclusive session errors => waiting && restarting is a solution + Error::ExclusiveSessionActive | Error::HasActiveSessions => true, + + // fatal errors: + + // config-related errors + Error::InvalidNodeAddress | Error::InvalidNodeId | + // wrong session input params errors + Error::NotEnoughNodesForThreshold | Error::ServerKeyAlreadyGenerated | Error::ServerKeyIsNotFound | + Error::DocumentKeyAlreadyStored | Error::DocumentKeyIsNotFound | Error::InsufficientRequesterData(_) | + // access denied/consensus error + Error::AccessDenied | Error::ConsensusUnreachable | + // indeterminate internal errors, which could be either fatal (db failure, invalid request), or not (network error), + // but we still consider these errors as fatal + Error::EthKey(_) | Error::Serde(_) | Error::Hyper(_) | Error::Database(_) | Error::Internal(_) | Error::Io(_) => false, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::InvalidNodeAddress => write!(f, "invalid node address has been passed"), + Error::InvalidNodeId => write!(f, "invalid node id has been passed"), + Error::DuplicateSessionId => write!(f, "session with the same id is already registered"), + Error::NoActiveSessionWithId => write!(f, "no active session with given id"), + Error::NotEnoughNodesForThreshold => write!(f, "not enough nodes for passed threshold"), + Error::TooEarlyForRequest => write!(f, "session is not yet ready to process this request"), + Error::InvalidStateForRequest => write!(f, "session is in invalid state for processing this request"), + Error::InvalidNodeForRequest => write!(f, "invalid node for this request"), + Error::InvalidMessage => write!(f, "invalid message is received"), + Error::InvalidMessageVersion => write!(f, "unsupported message is received"), + Error::ReplayProtection => write!(f, "replay message is received"), + Error::NodeDisconnected => write!(f, "node required for this operation is currently disconnected"), + Error::ServerKeyAlreadyGenerated => write!(f, "Server key with this ID is already generated"), + Error::ServerKeyIsNotFound => write!(f, "Server key with this ID is not found"), + Error::DocumentKeyAlreadyStored => write!(f, "Document key with this ID is already stored"), + Error::DocumentKeyIsNotFound => write!(f, "Document key with this ID is not found"), + Error::ConsensusUnreachable => write!(f, "Consensus unreachable"), + Error::ConsensusTemporaryUnreachable => write!(f, "Consensus temporary unreachable"), + Error::AccessDenied => write!(f, "Access dened"), + Error::ExclusiveSessionActive => write!(f, "Exclusive session active"), + Error::HasActiveSessions => write!(f, "Unable to start exclusive session"), + Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), + Error::EthKey(ref e) => write!(f, "cryptographic error {}", e), + Error::Hyper(ref msg) => write!(f, "Hyper error: {}", msg), + Error::Serde(ref msg) => write!(f, "Serialization error: {}", msg), + Error::Database(ref msg) => write!(f, "Database error: {}", msg), + Error::Internal(ref msg) => write!(f, "Internal error: {}", msg), + Error::Io(ref msg) => write!(f, "IO error: {}", msg), + } + } +} + +impl From for Error { + fn from(err: ethkey::Error) -> Self { + Error::EthKey(err.into()) + } +} + +impl From for Error { + fn from(err: kvdb::Error) -> Self { + Error::Database(err.to_string()) + } +} + +impl From for Error { + fn from(err: crypto::Error) -> Self { + Error::EthKey(err.into()) + } +} + +impl From for Error { + fn from(err: IoError) -> Self { + Error::Io(err.to_string()) + } +} + +impl Into for Error { + fn into(self) -> String { + format!("{}", self) + } +} + +impl From for Error { + fn from(err: net::AddrParseError) -> Error { + Error::Internal(err.to_string()) + } +} diff --git a/secret_store/src/types/mod.rs b/secret_store/src/types/mod.rs index dc5bd3d8a08..9da7f6ef985 100644 --- a/secret_store/src/types/mod.rs +++ b/secret_store/src/types/mod.rs @@ -16,4 +16,8 @@ //! Types used in the public api -pub mod all; +mod all; +mod error; + +pub use self::all::*; +pub use self::error::*; From 314e279fcb66a25222db792e9e4c4168a43ac0c8 Mon Sep 17 00:00:00 2001 From: ellaismer <31844524+ellaismer@users.noreply.github.com> Date: Tue, 1 May 2018 14:41:46 -0400 Subject: [PATCH 055/147] Enable WebAssembly and Byzantium for Ellaism (#8520) * Enable WebAssembly and Byzantium for Ellaism * Fix indentation * Remove empty lines --- ethcore/res/ethereum/ellaism.json | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ethcore/res/ethereum/ellaism.json b/ethcore/res/ethereum/ellaism.json index 3650e68df52..96c2016e55a 100644 --- a/ethcore/res/ethereum/ellaism.json +++ b/ethcore/res/ethereum/ellaism.json @@ -13,9 +13,9 @@ "eip150Transition": "0x0", "eip160Transition": "0x0", "ecip1017EraRounds": 10000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "eip161dTransition": "0x7fffffffffffffff", + "eip100bTransition": 2000000 } } }, @@ -29,7 +29,12 @@ "chainID": "0x40", "eip155Transition": "0x0", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "wasmActivationTransition": 2000000, + "eip140Transition": 2000000, + "eip211Transition": 2000000, + "eip214Transition": 2000000, + "eip658Transition": 2000000 }, "genesis": { "seal": { @@ -60,6 +65,10 @@ "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } } } } From 22f691c99b71c14e3928fecd7d64df11f9ccfc87 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 2 May 2018 09:20:59 +0200 Subject: [PATCH 056/147] More changes for Android (#8421) --- .gitlab-ci.yml | 17 +++++++++++++++++ Cargo.lock | 22 +++++++++++----------- docker/android/Dockerfile | 2 ++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2c216496f67..347b5a57ba4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -180,6 +180,23 @@ windows: paths: - parity.zip name: "x86_64-pc-windows-msvc_parity" +android-armv7: + stage: build + image: parity/parity-android:latest + only: + - beta + - tags + - stable + - triggers + script: + - cargo build --target=armv7-linux-androideabi + # TODO: check that `arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/release/parity | grep c++_shared` is empty + tags: + - rust-arm + artifacts: + paths: + - parity.zip + name: "armv7-linux-androideabi_parity" docker-build: stage: build only: diff --git a/Cargo.lock b/Cargo.lock index 3176c3ab3d7..741cc3832ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,7 +70,7 @@ name = "backtrace-sys" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -432,7 +432,7 @@ version = "0.5.7" source = "git+https://github.com/paritytech/rust-secp256k1#db81cfea59014b4d176f10f86ed52e1a130b6822" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1203,7 +1203,7 @@ name = "hidapi" version = "0.3.1" source = "git+https://github.com/paritytech/hidapi-rs#70ec4bd1b755ec5dd32ad2be0c8345864147c8bc" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1436,7 +1436,7 @@ dependencies = [ name = "keccak-hash" version = "0.1.0" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1524,7 +1524,7 @@ name = "libusb-sys" version = "0.2.4" source = "git+https://github.com/paritytech/libusb-sys#14bdb698003731b6344a79e1d814704e44363e7c" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1678,7 +1678,7 @@ name = "miniz_oxide_c_api" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2723,7 +2723,7 @@ name = "ring" version = "0.12.1" source = "git+https://github.com/paritytech/ring#b98d7f586c0467d68e9946a5f47b4a04b9a86b4a" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2774,7 +2774,7 @@ name = "rocksdb-sys" version = "0.3.0" source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", @@ -3010,7 +3010,7 @@ name = "snappy-sys" version = "0.1.0" source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3782,7 +3782,7 @@ dependencies = [ "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" -"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" +"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" diff --git a/docker/android/Dockerfile b/docker/android/Dockerfile index 5769cd13bc8..7783781b4ca 100644 --- a/docker/android/Dockerfile +++ b/docker/android/Dockerfile @@ -75,3 +75,5 @@ ENV CFLAGS_arm_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID ENV CFLAGS_armv7_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID ENV CXXFLAGS_arm_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID ENV CXXFLAGS_armv7_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID +ENV CXXSTDLIB_arm_linux_androideabi "" +ENV CXXSTDLIB_armv7_linux_androideabi "" From 1f736e4c9031a0f40a22f5f3f96e31dc0e128fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 2 May 2018 09:31:06 +0200 Subject: [PATCH 057/147] Transaction Pool improvements (#8470) * Don't use ethereum_types in transaction pool. * Hide internal insertion_id. * Fix tests. * Review grumbles. --- miner/src/pool/mod.rs | 13 ++- miner/src/pool/queue.rs | 4 +- miner/src/pool/ready.rs | 12 +-- miner/src/pool/scoring.rs | 11 ++- transaction-pool/Cargo.toml | 2 + transaction-pool/src/error.rs | 16 ++-- transaction-pool/src/lib.rs | 23 +++-- transaction-pool/src/pool.rs | 113 +++++++++++++++-------- transaction-pool/src/ready.rs | 4 +- transaction-pool/src/scoring.rs | 34 ++++--- transaction-pool/src/tests/helpers.rs | 10 +- transaction-pool/src/tests/mod.rs | 13 +-- transaction-pool/src/tests/tx_builder.rs | 10 -- transaction-pool/src/transactions.rs | 46 +++++---- 14 files changed, 173 insertions(+), 138 deletions(-) diff --git a/miner/src/pool/mod.rs b/miner/src/pool/mod.rs index 7950510c6d0..45d28f3c121 100644 --- a/miner/src/pool/mod.rs +++ b/miner/src/pool/mod.rs @@ -105,6 +105,11 @@ impl VerifiedTransaction { self.priority } + /// Gets transaction insertion id. + pub(crate) fn insertion_id(&self) -> usize { + self.insertion_id + } + /// Gets wrapped `SignedTransaction` pub fn signed(&self) -> &transaction::SignedTransaction { &self.transaction @@ -114,9 +119,13 @@ impl VerifiedTransaction { pub fn pending(&self) -> &transaction::PendingTransaction { &self.transaction } + } impl txpool::VerifiedTransaction for VerifiedTransaction { + type Hash = H256; + type Sender = Address; + fn hash(&self) -> &H256 { &self.hash } @@ -128,8 +137,4 @@ impl txpool::VerifiedTransaction for VerifiedTransaction { fn sender(&self) -> &Address { &self.sender } - - fn insertion_id(&self) -> u64 { - self.insertion_id as u64 - } } diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index edc092a119f..8cf4534b763 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -282,11 +282,11 @@ impl TransactionQueue { // We want to clear stale transactions from the queue as well. // (Transactions that are occuping the queue for a long time without being included) let stale_id = { - let current_id = self.insertion_id.load(atomic::Ordering::Relaxed) as u64; + let current_id = self.insertion_id.load(atomic::Ordering::Relaxed); // wait at least for half of the queue to be replaced let gap = self.pool.read().options().max_count / 2; // but never less than 100 transactions - let gap = cmp::max(100, gap) as u64; + let gap = cmp::max(100, gap); current_id.checked_sub(gap) }; diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs index 54b5aec3a9f..c2829b34a9a 100644 --- a/miner/src/pool/ready.rs +++ b/miner/src/pool/ready.rs @@ -54,14 +54,14 @@ pub struct State { nonces: HashMap, state: C, max_nonce: Option, - stale_id: Option, + stale_id: Option, } impl State { /// Create new State checker, given client interface. pub fn new( state: C, - stale_id: Option, + stale_id: Option, max_nonce: Option, ) -> Self { State { @@ -91,10 +91,10 @@ impl txpool::Ready for State { match tx.transaction.nonce.cmp(nonce) { // Before marking as future check for stale ids cmp::Ordering::Greater => match self.stale_id { - Some(id) if tx.insertion_id() < id => txpool::Readiness::Stalled, + Some(id) if tx.insertion_id() < id => txpool::Readiness::Stale, _ => txpool::Readiness::Future, }, - cmp::Ordering::Less => txpool::Readiness::Stalled, + cmp::Ordering::Less => txpool::Readiness::Stale, cmp::Ordering::Equal => { *nonce = *nonce + 1.into(); txpool::Readiness::Ready @@ -178,7 +178,7 @@ mod tests { let res = State::new(TestClient::new().with_nonce(125), None, None).is_ready(&tx); // then - assert_eq!(res, txpool::Readiness::Stalled); + assert_eq!(res, txpool::Readiness::Stale); } #[test] @@ -190,7 +190,7 @@ mod tests { let res = State::new(TestClient::new(), Some(1), None).is_ready(&tx); // then - assert_eq!(res, txpool::Readiness::Stalled); + assert_eq!(res, txpool::Readiness::Stale); } #[test] diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs index b9f074ecb0f..eaf06983328 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -28,7 +28,6 @@ //! from our local node (own transactions). use std::cmp; -use std::sync::Arc; use ethereum_types::U256; use txpool; @@ -69,7 +68,7 @@ impl txpool::Scoring for NonceAndGasPrice { } } - fn update_scores(&self, txs: &[Arc], scores: &mut [U256], change: txpool::scoring::Change) { + fn update_scores(&self, txs: &[txpool::Transaction], scores: &mut [U256], change: txpool::scoring::Change) { use self::txpool::scoring::Change; match change { @@ -79,7 +78,7 @@ impl txpool::Scoring for NonceAndGasPrice { assert!(i < txs.len()); assert!(i < scores.len()); - scores[i] = txs[i].transaction.gas_price; + scores[i] = txs[i].transaction.transaction.gas_price; let boost = match txs[i].priority() { super::Priority::Local => 15, super::Priority::Retracted => 10, @@ -116,6 +115,7 @@ impl txpool::Scoring for NonceAndGasPrice { mod tests { use super::*; + use std::sync::Arc; use pool::tests::tx::{Tx, TxExt}; use txpool::Scoring; @@ -131,7 +131,10 @@ mod tests { 1 => ::pool::Priority::Retracted, _ => ::pool::Priority::Regular, }; - Arc::new(verified) + txpool::Transaction { + insertion_id: 0, + transaction: Arc::new(verified), + } }).collect::>(); let initial_scores = vec![U256::from(0), 0.into(), 0.into()]; diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index b8630781123..342c376f63c 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -10,4 +10,6 @@ error-chain = "0.11" log = "0.3" smallvec = "0.4" trace-time = { path = "../util/trace-time" } + +[dev-dependencies] ethereum-types = "0.3" diff --git a/transaction-pool/src/error.rs b/transaction-pool/src/error.rs index 2e8ac739897..4cf221a71e4 100644 --- a/transaction-pool/src/error.rs +++ b/transaction-pool/src/error.rs @@ -14,24 +14,26 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; +/// Error chain doesn't let us have generic types. +/// So the hashes are converted to debug strings for easy display. +type Hash = String; error_chain! { errors { /// Transaction is already imported - AlreadyImported(hash: H256) { + AlreadyImported(hash: Hash) { description("transaction is already in the pool"), - display("[{:?}] already imported", hash) + display("[{}] already imported", hash) } /// Transaction is too cheap to enter the queue - TooCheapToEnter(hash: H256, min_score: String) { + TooCheapToEnter(hash: Hash, min_score: String) { description("the pool is full and transaction is too cheap to replace any transaction"), - display("[{:?}] too cheap to enter the pool. Min score: {}", hash, min_score) + display("[{}] too cheap to enter the pool. Min score: {}", hash, min_score) } /// Transaction is too cheap to replace existing transaction that occupies the same slot. - TooCheapToReplace(old_hash: H256, hash: H256) { + TooCheapToReplace(old_hash: Hash, hash: Hash) { description("transaction is too cheap to replace existing transaction in the pool"), - display("[{:?}] too cheap to replace: {:?}", hash, old_hash) + display("[{}] too cheap to replace: {}", hash, old_hash) } } } diff --git a/transaction-pool/src/lib.rs b/transaction-pool/src/lib.rs index 33d17f4b0fc..4a1bdcde142 100644 --- a/transaction-pool/src/lib.rs +++ b/transaction-pool/src/lib.rs @@ -69,14 +69,15 @@ #![warn(missing_docs)] extern crate smallvec; -extern crate ethereum_types; +extern crate trace_time; #[macro_use] extern crate error_chain; #[macro_use] extern crate log; -extern crate trace_time; +#[cfg(test)] +extern crate ethereum_types; #[cfg(test)] mod tests; @@ -95,27 +96,29 @@ pub mod scoring; pub use self::error::{Error, ErrorKind}; pub use self::listener::{Listener, NoopListener}; pub use self::options::Options; -pub use self::pool::{Pool, PendingIterator}; +pub use self::pool::{Pool, PendingIterator, Transaction}; pub use self::ready::{Ready, Readiness}; pub use self::scoring::Scoring; pub use self::status::{LightStatus, Status}; pub use self::verifier::Verifier; use std::fmt; - -use ethereum_types::{H256, Address}; +use std::hash::Hash; /// Already verified transaction that can be safely queued. pub trait VerifiedTransaction: fmt::Debug { + /// Transaction hash type. + type Hash: fmt::Debug + fmt::LowerHex + Eq + Clone + Hash; + + /// Transaction sender type. + type Sender: fmt::Debug + Eq + Clone + Hash; + /// Transaction hash - fn hash(&self) -> &H256; + fn hash(&self) -> &Self::Hash; /// Memory usage fn mem_usage(&self) -> usize; /// Transaction sender - fn sender(&self) -> &Address; - - /// Unique index of insertion (lower = older). - fn insertion_id(&self) -> u64; + fn sender(&self) -> &Self::Sender; } diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index fa28cdcdfe5..5cb6e479b8e 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -17,8 +17,6 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeSet}; -use ethereum_types::{H160, H256}; - use error; use listener::{Listener, NoopListener}; use options::Options; @@ -29,21 +27,51 @@ use transactions::{AddResult, Transactions}; use {VerifiedTransaction}; -type Sender = H160; +/// Internal representation of transaction. +/// +/// Includes unique insertion id that can be used for scoring explictly, +/// but internally is used to resolve conflicts in case of equal scoring +/// (newer transactionsa are preferred). +#[derive(Debug)] +pub struct Transaction { + /// Sequential id of the transaction + pub insertion_id: u64, + /// Shared transaction + pub transaction: Arc, +} + +impl Clone for Transaction { + fn clone(&self) -> Self { + Transaction { + insertion_id: self.insertion_id, + transaction: self.transaction.clone(), + } + } +} + +impl ::std::ops::Deref for Transaction { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.transaction + } +} /// A transaction pool. #[derive(Debug)] -pub struct Pool, L = NoopListener> { +pub struct Pool, L = NoopListener> { listener: L, scoring: S, options: Options, mem_usage: usize, - transactions: HashMap>, - by_hash: HashMap>, + transactions: HashMap>, + by_hash: HashMap>, best_transactions: BTreeSet>, worst_transactions: BTreeSet>, + + insertion_id: u64, } impl + Default> Default for Pool { @@ -89,6 +117,7 @@ impl Pool where by_hash, best_transactions: Default::default(), worst_transactions: Default::default(), + insertion_id: 0, } } @@ -104,10 +133,16 @@ impl Pool where /// If any limit is reached the transaction with the lowest `Score` is evicted to make room. /// /// The `Listener` will be informed on any drops or rejections. - pub fn import(&mut self, mut transaction: T) -> error::Result> { + pub fn import(&mut self, transaction: T) -> error::Result> { let mem_usage = transaction.mem_usage(); - ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(*transaction.hash())); + ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(format!("{:?}", transaction.hash()))); + + self.insertion_id += 1; + let mut transaction = Transaction { + insertion_id: self.insertion_id, + transaction: Arc::new(transaction), + }; // TODO [ToDr] Most likely move this after the transaction is inserted. // Avoid using should_replace, but rather use scoring for that. @@ -115,7 +150,7 @@ impl Pool where let remove_worst = |s: &mut Self, transaction| { match s.remove_worst(&transaction) { Err(err) => { - s.listener.rejected(&Arc::new(transaction), err.kind()); + s.listener.rejected(&transaction, err.kind()); Err(err) }, Ok(removed) => { @@ -138,7 +173,7 @@ impl Pool where } let (result, prev_state, current_state) = { - let transactions = self.transactions.entry(*transaction.sender()).or_insert_with(Transactions::default); + let transactions = self.transactions.entry(transaction.sender().clone()).or_insert_with(Transactions::default); // get worst and best transactions for comparison let prev = transactions.worst_and_best(); let result = transactions.add(transaction, &self.scoring, self.options.max_per_sender); @@ -153,31 +188,31 @@ impl Pool where AddResult::Ok(tx) => { self.listener.added(&tx, None); self.finalize_insert(&tx, None); - Ok(tx) + Ok(tx.transaction) }, AddResult::PushedOut { new, old } | AddResult::Replaced { new, old } => { self.listener.added(&new, Some(&old)); self.finalize_insert(&new, Some(&old)); - Ok(new) + Ok(new.transaction) }, AddResult::TooCheap { new, old } => { - let error = error::ErrorKind::TooCheapToReplace(*old.hash(), *new.hash()); - self.listener.rejected(&Arc::new(new), &error); + let error = error::ErrorKind::TooCheapToReplace(format!("{:x}", old.hash()), format!("{:x}", new.hash())); + self.listener.rejected(&new, &error); bail!(error) }, AddResult::TooCheapToEnter(new, score) => { - let error = error::ErrorKind::TooCheapToEnter(*new.hash(), format!("{:?}", score)); - self.listener.rejected(&Arc::new(new), &error); + let error = error::ErrorKind::TooCheapToEnter(format!("{:x}", new.hash()), format!("{:?}", score)); + self.listener.rejected(&new, &error); bail!(error) } } } /// Updates state of the pool statistics if the transaction was added to a set. - fn finalize_insert(&mut self, new: &Arc, old: Option<&Arc>) { + fn finalize_insert(&mut self, new: &Transaction, old: Option<&Transaction>) { self.mem_usage += new.mem_usage(); - self.by_hash.insert(*new.hash(), new.clone()); + self.by_hash.insert(new.hash().clone(), new.clone()); if let Some(old) = old { self.finalize_remove(old.hash()); @@ -185,23 +220,23 @@ impl Pool where } /// Updates the pool statistics if transaction was removed. - fn finalize_remove(&mut self, hash: &H256) -> Option> { + fn finalize_remove(&mut self, hash: &T::Hash) -> Option> { self.by_hash.remove(hash).map(|old| { - self.mem_usage -= old.mem_usage(); - old + self.mem_usage -= old.transaction.mem_usage(); + old.transaction }) } /// Updates best and worst transactions from a sender. fn update_senders_worst_and_best( &mut self, - previous: Option<((S::Score, Arc), (S::Score, Arc))>, - current: Option<((S::Score, Arc), (S::Score, Arc))>, + previous: Option<((S::Score, Transaction), (S::Score, Transaction))>, + current: Option<((S::Score, Transaction), (S::Score, Transaction))>, ) { let worst_collection = &mut self.worst_transactions; let best_collection = &mut self.best_transactions; - let is_same = |a: &(S::Score, Arc), b: &(S::Score, Arc)| { + let is_same = |a: &(S::Score, Transaction), b: &(S::Score, Transaction)| { a.0 == b.0 && a.1.hash() == b.1.hash() }; @@ -238,19 +273,19 @@ impl Pool where } /// Attempts to remove the worst transaction from the pool if it's worse than the given one. - fn remove_worst(&mut self, transaction: &T) -> error::Result> { + fn remove_worst(&mut self, transaction: &Transaction) -> error::Result> { let to_remove = match self.worst_transactions.iter().next_back() { // No elements to remove? and the pool is still full? None => { warn!("The pool is full but there are no transactions to remove."); - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), "unknown".into()).into()); + return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), "unknown".into()).into()); }, Some(old) => if self.scoring.should_replace(&old.transaction, transaction) { // New transaction is better than the worst one so we can replace it. old.clone() } else { // otherwise fail - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), format!("{:?}", old.score)).into()) + return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), format!("{:?}", old.score)).into()) }, }; @@ -263,7 +298,7 @@ impl Pool where } /// Removes transaction from sender's transaction `HashMap`. - fn remove_from_set, &S) -> R>(&mut self, sender: &Sender, f: F) -> Option { + fn remove_from_set, &S) -> R>(&mut self, sender: &T::Sender, f: F) -> Option { let (prev, next, result) = if let Some(set) = self.transactions.get_mut(sender) { let prev = set.worst_and_best(); let result = f(set, &self.scoring); @@ -286,14 +321,14 @@ impl Pool where self.worst_transactions.clear(); for (_hash, tx) in self.by_hash.drain() { - self.listener.dropped(&tx, None) + self.listener.dropped(&tx.transaction, None) } } /// Removes single transaction from the pool. /// Depending on the `is_invalid` flag the listener /// will either get a `cancelled` or `invalid` notification. - pub fn remove(&mut self, hash: &H256, is_invalid: bool) -> Option> { + pub fn remove(&mut self, hash: &T::Hash, is_invalid: bool) -> Option> { if let Some(tx) = self.finalize_remove(hash) { self.remove_from_set(tx.sender(), |set, scoring| { set.remove(&tx, scoring) @@ -310,7 +345,7 @@ impl Pool where } /// Removes all stalled transactions from given sender. - fn remove_stalled>(&mut self, sender: &Sender, ready: &mut R) -> usize { + fn remove_stalled>(&mut self, sender: &T::Sender, ready: &mut R) -> usize { let removed_from_set = self.remove_from_set(sender, |transactions, scoring| { transactions.cull(ready, scoring) }); @@ -329,7 +364,7 @@ impl Pool where } /// Removes all stalled transactions from given sender list (or from all senders). - pub fn cull>(&mut self, senders: Option<&[Sender]>, mut ready: R) -> usize { + pub fn cull>(&mut self, senders: Option<&[T::Sender]>, mut ready: R) -> usize { let mut removed = 0; match senders { Some(senders) => { @@ -349,13 +384,13 @@ impl Pool where } /// Returns a transaction if it's part of the pool or `None` otherwise. - pub fn find(&self, hash: &H256) -> Option> { - self.by_hash.get(hash).cloned() + pub fn find(&self, hash: &T::Hash) -> Option> { + self.by_hash.get(hash).map(|t| t.transaction.clone()) } /// Returns worst transaction in the queue (if any). pub fn worst_transaction(&self) -> Option> { - self.worst_transactions.iter().next().map(|x| x.transaction.clone()) + self.worst_transactions.iter().next().map(|x| x.transaction.transaction.clone()) } /// Returns an iterator of pending (ready) transactions. @@ -368,7 +403,7 @@ impl Pool where } /// Returns pending (ready) transactions from given sender. - pub fn pending_from_sender>(&self, ready: R, sender: &Sender) -> PendingIterator { + pub fn pending_from_sender>(&self, ready: R, sender: &T::Sender) -> PendingIterator { let best_transactions = self.transactions.get(sender) .and_then(|transactions| transactions.worst_and_best()) .map(|(_, best)| ScoreWithRef::new(best.0, best.1)) @@ -387,7 +422,7 @@ impl Pool where } /// Update score of transactions of a particular sender. - pub fn update_scores(&mut self, sender: &Sender, event: S::Event) { + pub fn update_scores(&mut self, sender: &T::Sender, event: S::Event) { let res = if let Some(set) = self.transactions.get_mut(sender) { let prev = set.worst_and_best(); set.update_scores(&self.scoring, event); @@ -410,7 +445,7 @@ impl Pool where let len = transactions.len(); for (idx, tx) in transactions.iter().enumerate() { match ready.is_ready(tx) { - Readiness::Stalled => status.stalled += 1, + Readiness::Stale => status.stalled += 1, Readiness::Ready => status.pending += 1, Readiness::Future => { status.future += len - idx; @@ -485,7 +520,7 @@ impl<'a, T, R, S, L> Iterator for PendingIterator<'a, T, R, S, L> where self.best_transactions.insert(ScoreWithRef::new(score, tx)); } - return Some(best.transaction) + return Some(best.transaction.transaction) }, state => trace!("[{:?}] Ignoring {:?} transaction.", best.transaction.hash(), state), } diff --git a/transaction-pool/src/ready.rs b/transaction-pool/src/ready.rs index 73524443227..aa913a9eb58 100644 --- a/transaction-pool/src/ready.rs +++ b/transaction-pool/src/ready.rs @@ -17,8 +17,8 @@ /// Transaction readiness. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Readiness { - /// The transaction is stalled (and should/will be removed from the pool). - Stalled, + /// The transaction is stale (and should/will be removed from the pool). + Stale, /// The transaction is ready to be included in pending set. Ready, /// The transaction is not yet ready. diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index 4e7a9833a16..2acfb337485 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -17,9 +17,7 @@ //! A transactions ordering abstraction. use std::{cmp, fmt}; -use std::sync::Arc; - -use {VerifiedTransaction}; +use pool::Transaction; /// Represents a decision what to do with /// a new transaction that tries to enter the pool. @@ -98,7 +96,7 @@ pub trait Scoring: fmt::Debug { /// Updates the transaction scores given a list of transactions and a change to previous scoring. /// NOTE: you can safely assume that both slices have the same length. /// (i.e. score at index `i` represents transaction at the same index) - fn update_scores(&self, txs: &[Arc], scores: &mut [Self::Score], change: Change); + fn update_scores(&self, txs: &[Transaction], scores: &mut [Self::Score], change: Change); /// Decides if `new` should push out `old` transaction from the pool. fn should_replace(&self, old: &T, new: &T) -> bool; @@ -110,7 +108,14 @@ pub struct ScoreWithRef { /// Score pub score: S, /// Shared transaction - pub transaction: Arc, + pub transaction: Transaction, +} + +impl ScoreWithRef { + /// Creates a new `ScoreWithRef` + pub fn new(score: S, transaction: Transaction) -> Self { + ScoreWithRef { score, transaction } + } } impl Clone for ScoreWithRef { @@ -122,30 +127,23 @@ impl Clone for ScoreWithRef { } } -impl ScoreWithRef { - /// Creates a new `ScoreWithRef` - pub fn new(score: S, transaction: Arc) -> Self { - ScoreWithRef { score, transaction } - } -} - -impl Ord for ScoreWithRef { +impl Ord for ScoreWithRef { fn cmp(&self, other: &Self) -> cmp::Ordering { other.score.cmp(&self.score) - .then(other.transaction.insertion_id().cmp(&self.transaction.insertion_id())) + .then(other.transaction.insertion_id.cmp(&self.transaction.insertion_id)) } } -impl PartialOrd for ScoreWithRef { +impl PartialOrd for ScoreWithRef { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl PartialEq for ScoreWithRef { +impl PartialEq for ScoreWithRef { fn eq(&self, other: &Self) -> bool { - self.score == other.score && self.transaction.insertion_id() == other.transaction.insertion_id() + self.score == other.score && self.transaction.insertion_id == other.transaction.insertion_id } } -impl Eq for ScoreWithRef {} +impl Eq for ScoreWithRef {} diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index ab5b2a334b0..cfc6641b5eb 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -17,9 +17,9 @@ use std::cmp; use std::collections::HashMap; -use ethereum_types::U256; -use {scoring, Scoring, Ready, Readiness, Address as Sender}; -use super::{Transaction, SharedTransaction}; +use ethereum_types::{H160 as Sender, U256}; +use {pool, scoring, Scoring, Ready, Readiness}; +use super::Transaction; #[derive(Debug, Default)] pub struct DummyScoring; @@ -44,7 +44,7 @@ impl Scoring for DummyScoring { } } - fn update_scores(&self, txs: &[SharedTransaction], scores: &mut [Self::Score], change: scoring::Change) { + fn update_scores(&self, txs: &[pool::Transaction], scores: &mut [Self::Score], change: scoring::Change) { if let scoring::Change::Event(_) = change { // In case of event reset all scores to 0 for i in 0..txs.len() { @@ -84,7 +84,7 @@ impl Ready for NonceReady { *nonce = *nonce + 1.into(); Readiness::Ready }, - cmp::Ordering::Less => Readiness::Stalled, + cmp::Ordering::Less => Readiness::Stale, } } } diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index 5113a4663c3..b21ea31807c 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -32,15 +32,16 @@ pub struct Transaction { pub gas_price: U256, pub gas: U256, pub sender: Address, - pub insertion_id: u64, pub mem_usage: usize, } impl VerifiedTransaction for Transaction { + type Hash = H256; + type Sender = Address; + fn hash(&self) -> &H256 { &self.hash } fn mem_usage(&self) -> usize { self.mem_usage } fn sender(&self) -> &Address { &self.sender } - fn insertion_id(&self) -> u64 { self.insertion_id } } pub type SharedTransaction = Arc; @@ -123,7 +124,7 @@ fn should_reject_if_above_count() { // Reject second let tx1 = b.tx().nonce(0).new(); let tx2 = b.tx().nonce(1).new(); - let hash = *tx2.hash(); + let hash = format!("{:?}", tx2.hash()); txq.import(tx1).unwrap(); assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); @@ -149,7 +150,7 @@ fn should_reject_if_above_mem_usage() { // Reject second let tx1 = b.tx().nonce(1).mem_usage(1).new(); let tx2 = b.tx().nonce(2).mem_usage(2).new(); - let hash = *tx2.hash(); + let hash = format!("{:?}", tx2.hash()); txq.import(tx1).unwrap(); assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); @@ -175,7 +176,7 @@ fn should_reject_if_above_sender_count() { // Reject second let tx1 = b.tx().nonce(1).new(); let tx2 = b.tx().nonce(2).new(); - let hash = *tx2.hash(); + let hash = format!("{:x}", tx2.hash()); txq.import(tx1).unwrap(); assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); @@ -185,7 +186,7 @@ fn should_reject_if_above_sender_count() { // Replace first let tx1 = b.tx().nonce(1).new(); let tx2 = b.tx().nonce(2).gas_price(2).new(); - let hash = *tx2.hash(); + let hash = format!("{:x}", tx2.hash()); txq.import(tx1).unwrap(); // This results in error because we also compare nonces assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); diff --git a/transaction-pool/src/tests/tx_builder.rs b/transaction-pool/src/tests/tx_builder.rs index e9c1c1d5fcd..88a881aca8a 100644 --- a/transaction-pool/src/tests/tx_builder.rs +++ b/transaction-pool/src/tests/tx_builder.rs @@ -14,9 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::rc::Rc; -use std::cell::Cell; - use super::{Transaction, U256, Address}; #[derive(Debug, Default, Clone)] @@ -26,7 +23,6 @@ pub struct TransactionBuilder { gas: U256, sender: Address, mem_usage: usize, - insertion_id: Rc>, } impl TransactionBuilder { @@ -55,11 +51,6 @@ impl TransactionBuilder { } pub fn new(self) -> Transaction { - let insertion_id = { - let id = self.insertion_id.get() + 1; - self.insertion_id.set(id); - id - }; let hash = self.nonce ^ (U256::from(100) * self.gas_price) ^ (U256::from(100_000) * U256::from(self.sender.low_u64())); Transaction { hash: hash.into(), @@ -67,7 +58,6 @@ impl TransactionBuilder { gas_price: self.gas_price, gas: 21_000.into(), sender: self.sender, - insertion_id, mem_usage: self.mem_usage, } } diff --git a/transaction-pool/src/transactions.rs b/transaction-pool/src/transactions.rs index c839d9e6853..f1a91ff4f83 100644 --- a/transaction-pool/src/transactions.rs +++ b/transaction-pool/src/transactions.rs @@ -15,28 +15,28 @@ // along with Parity. If not, see . use std::{fmt, mem}; -use std::sync::Arc; use smallvec::SmallVec; use ready::{Ready, Readiness}; use scoring::{self, Scoring}; +use pool::Transaction; #[derive(Debug)] pub enum AddResult { - Ok(Arc), + Ok(T), TooCheapToEnter(T, S), TooCheap { - old: Arc, + old: T, new: T, }, Replaced { - old: Arc, - new: Arc, + old: T, + new: T, }, PushedOut { - old: Arc, - new: Arc, + old: T, + new: T, }, } @@ -45,7 +45,7 @@ const PER_SENDER: usize = 8; #[derive(Debug)] pub struct Transactions> { // TODO [ToDr] Consider using something that doesn't require shifting all records. - transactions: SmallVec<[Arc; PER_SENDER]>, + transactions: SmallVec<[Transaction; PER_SENDER]>, scores: SmallVec<[S::Score; PER_SENDER]>, } @@ -67,11 +67,11 @@ impl> Transactions { self.transactions.len() } - pub fn iter(&self) -> ::std::slice::Iter> { + pub fn iter(&self) -> ::std::slice::Iter> { self.transactions.iter() } - pub fn worst_and_best(&self) -> Option<((S::Score, Arc), (S::Score, Arc))> { + pub fn worst_and_best(&self) -> Option<((S::Score, Transaction), (S::Score, Transaction))> { let len = self.scores.len(); self.scores.get(0).cloned().map(|best| { let worst = self.scores[len - 1].clone(); @@ -82,7 +82,7 @@ impl> Transactions { }) } - pub fn find_next(&self, tx: &T, scoring: &S) -> Option<(S::Score, Arc)> { + pub fn find_next(&self, tx: &T, scoring: &S) -> Option<(S::Score, Transaction)> { self.transactions.binary_search_by(|old| scoring.compare(old, &tx)).ok().and_then(|index| { let index = index + 1; if index < self.scores.len() { @@ -93,18 +93,17 @@ impl> Transactions { }) } - fn push_cheapest_transaction(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { + fn push_cheapest_transaction(&mut self, tx: Transaction, scoring: &S, max_count: usize) -> AddResult, S::Score> { let index = self.transactions.len(); if index == max_count { let min_score = self.scores[index - 1].clone(); AddResult::TooCheapToEnter(tx, min_score) } else { - let shared = Arc::new(tx); - self.transactions.push(shared.clone()); + self.transactions.push(tx.clone()); self.scores.push(Default::default()); scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::InsertedAt(index)); - AddResult::Ok(shared) + AddResult::Ok(tx) } } @@ -112,28 +111,26 @@ impl> Transactions { scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::Event(event)); } - pub fn add(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { - let index = match self.transactions.binary_search_by(|old| scoring.compare(old, &tx)) { + pub fn add(&mut self, new: Transaction, scoring: &S, max_count: usize) -> AddResult, S::Score> { + let index = match self.transactions.binary_search_by(|old| scoring.compare(old, &new)) { Ok(index) => index, Err(index) => index, }; // Insert at the end. if index == self.transactions.len() { - return self.push_cheapest_transaction(tx, scoring, max_count) + return self.push_cheapest_transaction(new, scoring, max_count) } // Decide if the transaction should replace some other. - match scoring.choose(&self.transactions[index], &tx) { + match scoring.choose(&self.transactions[index], &new) { // New transaction should be rejected scoring::Choice::RejectNew => AddResult::TooCheap { old: self.transactions[index].clone(), - new: tx, + new, }, // New transaction should be kept along with old ones. scoring::Choice::InsertNew => { - let new = Arc::new(tx); - self.transactions.insert(index, new.clone()); self.scores.insert(index, Default::default()); scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::InsertedAt(index)); @@ -153,7 +150,6 @@ impl> Transactions { }, // New transaction is replacing some other transaction already in the queue. scoring::Choice::ReplaceOld => { - let new = Arc::new(tx); let old = mem::replace(&mut self.transactions[index], new.clone()); scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::ReplacedAt(index)); @@ -181,7 +177,7 @@ impl> Transactions { return true; } - pub fn cull>(&mut self, ready: &mut R, scoring: &S) -> SmallVec<[Arc; PER_SENDER]> { + pub fn cull>(&mut self, ready: &mut R, scoring: &S) -> SmallVec<[Transaction; PER_SENDER]> { let mut result = SmallVec::new(); if self.is_empty() { return result; @@ -190,7 +186,7 @@ impl> Transactions { let mut first_non_stalled = 0; for tx in &self.transactions { match ready.is_ready(tx) { - Readiness::Stalled => { + Readiness::Stale => { first_non_stalled += 1; }, Readiness::Ready | Readiness::Future => break, From 401bfe23681df7ea308072fc7fd5f48acbec4ecc Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 2 May 2018 15:40:27 +0800 Subject: [PATCH 058/147] Fetching logs by hash in blockchain database (#8463) * Fetch logs by hash in blockchain database * Fix tests * Add unit test for branch block logs fetching * Add docs that blocks must already be sorted * Handle branch block cases properly * typo: empty -> is_empty * Remove return_empty_if_none by using a closure * Use BTreeSet to avoid sorting again * Move is_canon to BlockChain * typo: pass value by reference * Use loop and wrap inside blocks to simplify the code Borrowed from https://github.com/paritytech/parity/pull/8463#discussion_r183453326 * typo: missed a comment --- ethcore/src/blockchain/blockchain.rs | 60 ++++++++++++++-- ethcore/src/client/client.rs | 91 +++++++++++++++++++----- ethcore/src/verification/verification.rs | 2 +- 3 files changed, 129 insertions(+), 24 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 6ad8bf8111a..57bcdf2bc28 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -57,6 +57,12 @@ pub trait BlockProvider { /// (though not necessarily a part of the canon chain). fn is_known(&self, hash: &H256) -> bool; + /// Returns true if the given block is known and in the canon chain. + fn is_canon(&self, hash: &H256) -> bool { + let is_canon = || Some(hash == &self.block_hash(self.block_number(hash)?)?); + is_canon().unwrap_or(false) + } + /// Get the first block of the best part of the chain. /// Return `None` if there is no gap and the first block is the genesis. /// Any queries of blocks which precede this one are not guaranteed to @@ -148,7 +154,7 @@ pub trait BlockProvider { fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec; /// Returns logs matching given filter. - fn logs(&self, blocks: Vec, matches: F, limit: Option) -> Vec + fn logs(&self, blocks: Vec, matches: F, limit: Option) -> Vec where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized; } @@ -332,16 +338,18 @@ impl BlockProvider for BlockChain { .collect() } - fn logs(&self, mut blocks: Vec, matches: F, limit: Option) -> Vec + /// Returns logs matching given filter. The order of logs returned will be the same as the order of the blocks + /// provided. And it's the callers responsibility to sort blocks provided in advance. + fn logs(&self, mut blocks: Vec, matches: F, limit: Option) -> Vec where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized { // sort in reverse order - blocks.sort_by(|a, b| b.cmp(a)); + blocks.reverse(); let mut logs = blocks .chunks(128) .flat_map(move |blocks_chunk| { blocks_chunk.into_par_iter() - .filter_map(|number| self.block_hash(*number).map(|hash| (*number, hash))) + .filter_map(|hash| self.block_number(&hash).map(|r| (r, hash))) .filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts))) .filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes()))) .flat_map(|(number, hash, mut receipts, mut hashes)| { @@ -368,7 +376,7 @@ impl BlockProvider for BlockChain { .enumerate() .map(move |(i, log)| LocalizedLogEntry { entry: log, - block_hash: hash, + block_hash: *hash, block_number: number, transaction_hash: tx_hash, // iterating in reverse order @@ -1933,17 +1941,33 @@ mod tests { value: 103.into(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), }.sign(&secret(), None); + let t4 = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Create, + value: 104.into(), + data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), + }.sign(&secret(), None); let tx_hash1 = t1.hash(); let tx_hash2 = t2.hash(); let tx_hash3 = t3.hash(); + let tx_hash4 = t4.hash(); let genesis = BlockBuilder::genesis(); let b1 = genesis.add_block_with_transactions(vec![t1, t2]); let b2 = b1.add_block_with_transactions(iter::once(t3)); + let b3 = genesis.add_block_with(|| BlockOptions { + transactions: vec![t4.clone()], + difficulty: U256::from(9), + ..Default::default() + }); // Branch block let b1_hash = b1.last().hash(); let b1_number = b1.last().number(); let b2_hash = b2.last().hash(); let b2_number = b2.last().number(); + let b3_hash = b3.last().hash(); + let b3_number = b3.last().number(); let db = new_db(); let bc = new_chain(&genesis.last().encoded(), db.clone()); @@ -1974,10 +1998,21 @@ mod tests { ], } ]); + insert_block(&db, &bc, &b3.last().encoded(), vec![ + Receipt { + outcome: TransactionOutcome::StateRoot(H256::default()), + gas_used: 10_000.into(), + log_bloom: Default::default(), + logs: vec![ + LogEntry { address: Default::default(), topics: vec![], data: vec![5], }, + ], + } + ]); // when - let logs1 = bc.logs(vec![1, 2], |_| true, None); - let logs2 = bc.logs(vec![1, 2], |_| true, Some(1)); + let logs1 = bc.logs(vec![b1_hash, b2_hash], |_| true, None); + let logs2 = bc.logs(vec![b1_hash, b2_hash], |_| true, Some(1)); + let logs3 = bc.logs(vec![b3_hash], |_| true, None); // then assert_eq!(logs1, vec![ @@ -2029,6 +2064,17 @@ mod tests { log_index: 0, } ]); + assert_eq!(logs3, vec![ + LocalizedLogEntry { + entry: LogEntry { address: Default::default(), topics: vec![], data: vec![5] }, + block_hash: b3_hash, + block_number: b3_number, + transaction_hash: tx_hash4, + transaction_index: 0, + transaction_log_index: 0, + log_index: 0, + } + ]); } #[test] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index bc20de3dd86..5efdef3a4d6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; +use std::collections::{HashSet, HashMap, BTreeMap, BTreeSet, VecDeque}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; @@ -1848,23 +1848,82 @@ impl BlockChainClient for Client { } fn logs(&self, filter: Filter) -> Vec { - let (from, to) = match (self.block_number_ref(&filter.from_block), self.block_number_ref(&filter.to_block)) { - (Some(from), Some(to)) => (from, to), - _ => return Vec::new(), - }; + // Wrap the logic inside a closure so that we can take advantage of question mark syntax. + let fetch_logs = || { + let chain = self.chain.read(); - let chain = self.chain.read(); - let blocks = filter.bloom_possibilities().iter() - .map(move |bloom| { - chain.blocks_with_bloom(bloom, from, to) - }) - .flat_map(|m| m) - // remove duplicate elements - .collect::>() - .into_iter() - .collect::>(); + // First, check whether `filter.from_block` and `filter.to_block` is on the canon chain. If so, we can use the + // optimized version. + let is_canon = |id| { + match id { + // If it is referred by number, then it is always on the canon chain. + &BlockId::Earliest | &BlockId::Latest | &BlockId::Number(_) => true, + // If it is referred by hash, we see whether a hash -> number -> hash conversion gives us the same + // result. + &BlockId::Hash(ref hash) => chain.is_canon(hash), + } + }; + + let blocks = if is_canon(&filter.from_block) && is_canon(&filter.to_block) { + // If we are on the canon chain, use bloom filter to fetch required hashes. + let from = self.block_number_ref(&filter.from_block)?; + let to = self.block_number_ref(&filter.to_block)?; + + filter.bloom_possibilities().iter() + .map(|bloom| { + chain.blocks_with_bloom(bloom, from, to) + }) + .flat_map(|m| m) + // remove duplicate elements + .collect::>() + .into_iter() + .filter_map(|n| chain.block_hash(n)) + .collect::>() + + } else { + // Otherwise, we use a slower version that finds a link between from_block and to_block. + let from_hash = Self::block_hash(&chain, filter.from_block)?; + let from_number = chain.block_number(&from_hash)?; + let to_hash = Self::block_hash(&chain, filter.from_block)?; + + let blooms = filter.bloom_possibilities(); + let bloom_match = |header: &encoded::Header| { + blooms.iter().any(|bloom| header.log_bloom().contains_bloom(bloom)) + }; + + let (blocks, last_hash) = { + let mut blocks = Vec::new(); + let mut current_hash = to_hash; + + loop { + let header = chain.block_header_data(¤t_hash)?; + if bloom_match(&header) { + blocks.push(current_hash); + } + + // Stop if `from` block is reached. + if header.number() <= from_number { + break; + } + current_hash = header.parent_hash(); + } + + blocks.reverse(); + (blocks, current_hash) + }; + + // Check if we've actually reached the expected `from` block. + if last_hash != from_hash || blocks.is_empty() { + return None; + } + + blocks + }; + + Some(self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit)) + }; - self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit) + fetch_logs().unwrap_or_default() } fn filter_traces(&self, filter: TraceFilter) -> Option> { diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 814a12aadfe..92f3e77f902 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -476,7 +476,7 @@ mod tests { unimplemented!() } - fn logs(&self, _blocks: Vec, _matches: F, _limit: Option) -> Vec + fn logs(&self, _blocks: Vec, _matches: F, _limit: Option) -> Vec where F: Fn(&LogEntry) -> bool, Self: Sized { unimplemented!() } From 6046ca6af8d11aa660ab90b16be851da9c5201df Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 2 May 2018 22:47:53 +0800 Subject: [PATCH 059/147] Pass on storage keys tracing to handle the case when it is not modified (#8491) * Pass on storage keys even if it is not modified * typo: account and storage query `to_pod_diff` builds both `touched_addresses` merge and storage keys merge. * Fix tests * Use state query directly because of suicided accounts * Fix a RefCell borrow issue * Add tests for unmodified storage trace * Address grumbles * typo: remove unwanted empty line * ensure_cached compiles with the original signature --- ethcore/src/state/mod.rs | 114 +++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 27 deletions(-) diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 9fd3fd8525e..255dce5b5de 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -21,7 +21,7 @@ use std::cell::{RefCell, RefMut}; use std::collections::hash_map::Entry; -use std::collections::{HashMap, BTreeMap, HashSet}; +use std::collections::{HashMap, BTreeMap, BTreeSet, HashSet}; use std::fmt; use std::sync::Arc; use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY}; @@ -862,40 +862,65 @@ impl State { })) } - // Return a list of all touched addresses in cache. - fn touched_addresses(&self) -> Vec
{ + /// Populate a PodAccount map from this state, with another state as the account and storage query. + pub fn to_pod_diff(&mut self, query: &State) -> trie::Result { assert!(self.checkpoints.borrow().is_empty()); - self.cache.borrow().iter().map(|(add, _)| *add).collect() - } - fn query_pod(&mut self, query: &PodState, touched_addresses: &[Address]) -> trie::Result<()> { - let pod = query.get(); + // Merge PodAccount::to_pod for cache of self and `query`. + let all_addresses = self.cache.borrow().keys().cloned() + .chain(query.cache.borrow().keys().cloned()) + .collect::>(); + + Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: trie::Result<_>, address| { + let mut m = m?; + + let account = self.ensure_cached(&address, RequireCache::Code, true, |acc| { + acc.map(|acc| { + // Merge all modified storage keys. + let all_keys = { + let self_keys = acc.storage_changes().keys().cloned() + .collect::>(); + + if let Some(ref query_storage) = query.cache.borrow().get(&address) + .and_then(|opt| { + Some(opt.account.as_ref()?.storage_changes().keys().cloned() + .collect::>()) + }) + { + self_keys.union(&query_storage).cloned().collect::>() + } else { + self_keys.into_iter().collect::>() + } + }; - for address in touched_addresses { - if !self.ensure_cached(address, RequireCache::Code, true, |a| a.is_some())? { - continue - } + // Storage must be fetched after ensure_cached to avoid borrow problem. + (*acc.balance(), *acc.nonce(), all_keys, acc.code().map(|x| x.to_vec())) + }) + })?; - if let Some(pod_account) = pod.get(address) { - // needs to be split into two parts for the refcell code here - // to work. - for key in pod_account.storage.keys() { - self.storage_at(address, key)?; - } + if let Some((balance, nonce, storage_keys, code)) = account { + let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: trie::Result<_>, key| { + let mut s = s?; + + s.insert(key, self.storage_at(&address, &key)?); + Ok(s) + })?; + + m.insert(address, PodAccount { + balance, nonce, storage, code + }); } - } - Ok(()) + Ok(m) + })?)) } /// Returns a `StateDiff` describing the difference from `orig` to `self`. /// Consumes self. - pub fn diff_from(&self, orig: State) -> trie::Result { - let addresses_post = self.touched_addresses(); + pub fn diff_from(&self, mut orig: State) -> trie::Result { let pod_state_post = self.to_pod(); - let mut state_pre = orig; - state_pre.query_pod(&pod_state_post, &addresses_post)?; - Ok(pod_state::diff_pod(&state_pre.to_pod(), &pod_state_post)) + let pod_state_pre = orig.to_pod_diff(self)?; + Ok(pod_state::diff_pod(&pod_state_pre, &pod_state_post)) } // load required account data from the databases. @@ -2243,9 +2268,6 @@ mod tests { let original = state.clone(); state.kill_account(&a); - assert_eq!(original.touched_addresses(), vec![]); - assert_eq!(state.touched_addresses(), vec![a]); - let diff = state.diff_from(original).unwrap(); let diff_map = diff.get(); assert_eq!(diff_map.len(), 1); @@ -2258,4 +2280,42 @@ mod tests { storage: Default::default() }), None).as_ref()); } + + #[test] + fn should_trace_diff_unmodified_storage() { + use pod_account; + + let a = 10.into(); + let db = get_temp_state_db(); + + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64))).unwrap(); + state.commit().unwrap(); + state.drop() + }; + + let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + let original = state.clone(); + state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64))).unwrap(); + + let diff = state.diff_from(original).unwrap(); + let diff_map = diff.get(); + assert_eq!(diff_map.len(), 1); + assert!(diff_map.get(&a).is_some()); + assert_eq!(diff_map.get(&a), + pod_account::diff_pod(Some(&PodAccount { + balance: U256::zero(), + nonce: U256::zero(), + code: Some(Default::default()), + storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64)))] + .into_iter().collect(), + }), Some(&PodAccount { + balance: U256::zero(), + nonce: U256::zero(), + code: Some(Default::default()), + storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64)))] + .into_iter().collect(), + })).as_ref()); + } } From 7d3f27993418ec155815e747183f87c86f1cf914 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 3 May 2018 08:01:13 +0100 Subject: [PATCH 060/147] Don't panic in import_block if invalid rlp (#8522) * Don't panic in import_block if invalid rlp * Remove redundant type annotation * Replace RLP header view usage with safe decoding Using the view will panic with invalid RLP. Here we use Rlp decoding directly which will return a `Result<_, DecoderError>`. While this path currently should not have any invalid RLP - it makes it safer if ever called with invalid RLP from other code paths. --- ethcore/src/client/client.rs | 14 ++++++-------- ethcore/src/error.rs | 2 ++ ethcore/src/tests/client.rs | 20 ++++++++++++++++++++ ethcore/src/verification/queue/kind.rs | 9 ++++----- ethcore/src/verification/queue/mod.rs | 23 ++++++++++++++--------- 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 5efdef3a4d6..a37d62a5911 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -447,9 +447,7 @@ impl Importer { /// /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. - fn import_old_block(&self, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { - let block = view!(BlockView, &block_bytes); - let header = block.header(); + fn import_old_block(&self, header: &Header, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { let receipts = ::rlp::decode_list(&receipts_bytes); let hash = header.hash(); let _import_lock = self.import_lock.lock(); @@ -1408,7 +1406,7 @@ impl ImportBlock for Client { use verification::queue::kind::blocks::Unverified; // create unverified block here so the `keccak` calculation can be cached. - let unverified = Unverified::new(bytes); + let unverified = Unverified::from_rlp(bytes)?; { if self.chain.read().is_known(&unverified.hash()) { @@ -1423,19 +1421,19 @@ impl ImportBlock for Client { } fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { + let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; { // check block order - let header = view!(BlockView, &block_bytes).header_view(); if self.chain.read().is_known(&header.hash()) { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } - let status = self.block_status(BlockId::Hash(header.parent_hash())); + let status = self.block_status(BlockId::Hash(*header.parent_hash())); if status == BlockStatus::Unknown || status == BlockStatus::Pending { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(header.parent_hash()))); + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); } } - self.importer.import_old_block(block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into) + self.importer.import_old_block(&header, block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into) } } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index b68bf355347..561701e7620 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -190,6 +190,7 @@ error_chain! { foreign_links { Block(BlockError) #[doc = "Block error"]; + Decoder(::rlp::DecoderError) #[doc = "Rlp decoding error"]; } errors { @@ -206,6 +207,7 @@ impl From for BlockImportError { match e { Error(ErrorKind::Block(block_error), _) => BlockImportErrorKind::Block(block_error).into(), Error(ErrorKind::Import(import_error), _) => BlockImportErrorKind::Import(import_error.into()).into(), + Error(ErrorKind::Util(util_error::ErrorKind::Decoder(decoder_err)), _) => BlockImportErrorKind::Decoder(decoder_err).into(), _ => BlockImportErrorKind::Other(format!("other block import error: {:?}", e)).into(), } } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 0b8200e938a..6dcad9ba62f 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -36,6 +36,7 @@ use views::BlockView; use ethkey::KeyPair; use transaction::{PendingTransaction, Transaction, Action, Condition}; use miner::MinerService; +use rlp::{RlpStream, EMPTY_LIST_RLP}; use tempdir::TempDir; #[test] @@ -111,6 +112,25 @@ fn imports_good_block() { assert!(!block.into_inner().is_empty()); } +#[test] +fn fails_to_import_block_with_invalid_rlp() { + use error::{BlockImportError, BlockImportErrorKind}; + + let client = generate_dummy_client(6); + let mut rlp = RlpStream::new_list(3); + rlp.append_raw(&EMPTY_LIST_RLP, 1); // empty header + rlp.append_raw(&EMPTY_LIST_RLP, 1); + rlp.append_raw(&EMPTY_LIST_RLP, 1); + let invalid_header_block = rlp.out(); + + match client.import_block(invalid_header_block) { + Err(BlockImportError(BlockImportErrorKind::Decoder(_), _)) => (), // all good + Err(_) => panic!("Should fail with a decoder error"), + Ok(_) => panic!("Should not import block with invalid header"), + } +} + + #[test] fn query_none_block() { let tempdir = TempDir::new("").unwrap(); diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index 7007da5be1f..ce9bddf4efe 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -119,14 +119,13 @@ pub mod blocks { impl Unverified { /// Create an `Unverified` from raw bytes. - pub fn new(bytes: Bytes) -> Self { - use views::BlockView; + pub fn from_rlp(bytes: Bytes) -> Result { - let header = view!(BlockView, &bytes).header(); - Unverified { + let header = ::rlp::Rlp::new(&bytes).val_at(0)?; + Ok(Unverified { header: header, bytes: bytes, - } + }) } } diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index ca633b0f3de..f7a558f33d1 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -734,6 +734,7 @@ mod tests { use test_helpers::{get_good_dummy_block_seq, get_good_dummy_block}; use error::*; use views::BlockView; + use bytes::Bytes; // create a test block queue. // auto_scaling enables verifier adjustment. @@ -746,6 +747,10 @@ mod tests { BlockQueue::new(config, engine, IoChannel::disconnected(), true) } + fn new_unverified(bytes: Bytes) -> Unverified { + Unverified::from_rlp(bytes).expect("Should be valid rlp") + } + #[test] fn can_be_created() { // TODO better test @@ -757,7 +762,7 @@ mod tests { #[test] fn can_import_blocks() { let queue = get_test_queue(false); - if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { + if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) { panic!("error importing block that is valid by definition({:?})", e); } } @@ -765,11 +770,11 @@ mod tests { #[test] fn returns_error_for_duplicates() { let queue = get_test_queue(false); - if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { + if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) { panic!("error importing block that is valid by definition({:?})", e); } - let duplicate_import = queue.import(Unverified::new(get_good_dummy_block())); + let duplicate_import = queue.import(new_unverified(get_good_dummy_block())); match duplicate_import { Err(e) => { match e { @@ -786,7 +791,7 @@ mod tests { let queue = get_test_queue(false); let block = get_good_dummy_block(); let hash = view!(BlockView, &block).header().hash().clone(); - if let Err(e) = queue.import(Unverified::new(block)) { + if let Err(e) = queue.import(new_unverified(block)) { panic!("error importing block that is valid by definition({:?})", e); } queue.flush(); @@ -802,14 +807,14 @@ mod tests { let queue = get_test_queue(false); let block = get_good_dummy_block(); let hash = view!(BlockView, &block).header().hash().clone(); - if let Err(e) = queue.import(Unverified::new(block)) { + if let Err(e) = queue.import(new_unverified(block)) { panic!("error importing block that is valid by definition({:?})", e); } queue.flush(); queue.drain(10); queue.mark_as_good(&[ hash ]); - if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { + if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) { panic!("error importing block that has already been drained ({:?})", e); } } @@ -817,7 +822,7 @@ mod tests { #[test] fn returns_empty_once_finished() { let queue = get_test_queue(false); - queue.import(Unverified::new(get_good_dummy_block())) + queue.import(new_unverified(get_good_dummy_block())) .expect("error importing block that is valid by definition"); queue.flush(); queue.drain(1); @@ -835,7 +840,7 @@ mod tests { assert!(!queue.queue_info().is_full()); let mut blocks = get_good_dummy_block_seq(50); for b in blocks.drain(..) { - queue.import(Unverified::new(b)).unwrap(); + queue.import(new_unverified(b)).unwrap(); } assert!(queue.queue_info().is_full()); } @@ -863,7 +868,7 @@ mod tests { *queue.state.0.lock() = State::Work(0); for block in get_good_dummy_block_seq(5000) { - queue.import(Unverified::new(block)).expect("Block good by definition; qed"); + queue.import(new_unverified(block)).expect("Block good by definition; qed"); } // almost all unverified == bump verifier count. From 2f84096f5af769d3339a50272b518173b622a775 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 4 May 2018 10:06:54 +0200 Subject: [PATCH 061/147] Remove expect (#8536) * Remove expect and propagate rlp::DecoderErrors as TrieErrors --- util/patricia_trie/src/lib.rs | 8 ++++++++ util/patricia_trie/src/lookup.rs | 2 +- util/patricia_trie/src/triedb.rs | 27 +++++++++++++++++++++++++++ util/rlp/src/error.rs | 2 +- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/util/patricia_trie/src/lib.rs b/util/patricia_trie/src/lib.rs index 3a1d683c26c..d1563becff0 100644 --- a/util/patricia_trie/src/lib.rs +++ b/util/patricia_trie/src/lib.rs @@ -67,6 +67,8 @@ pub enum TrieError { InvalidStateRoot(H256), /// Trie item not found in the database, IncompleteDatabase(H256), + /// Corrupt Trie item + DecoderError(rlp::DecoderError), } impl fmt::Display for TrieError { @@ -75,6 +77,7 @@ impl fmt::Display for TrieError { TrieError::InvalidStateRoot(ref root) => write!(f, "Invalid state root: {}", root), TrieError::IncompleteDatabase(ref missing) => write!(f, "Database missing expected key: {}", missing), + TrieError::DecoderError(ref err) => write!(f, "Decoding failed with {}", err), } } } @@ -84,10 +87,15 @@ impl error::Error for TrieError { match *self { TrieError::InvalidStateRoot(_) => "Invalid state root", TrieError::IncompleteDatabase(_) => "Incomplete database", + TrieError::DecoderError(ref e) => e.description(), } } } +impl From for Box { + fn from(e: rlp::DecoderError) -> Self { Box::new(TrieError::DecoderError(e)) } +} + /// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries. pub type Result = ::std::result::Result>; diff --git a/util/patricia_trie/src/lookup.rs b/util/patricia_trie/src/lookup.rs index 88d2bc66e02..2d63f7d00e1 100644 --- a/util/patricia_trie/src/lookup.rs +++ b/util/patricia_trie/src/lookup.rs @@ -55,7 +55,7 @@ impl<'a, Q: Query> Lookup<'a, Q> { // without incrementing the depth. let mut node_data = &node_data[..]; loop { - match Node::decoded(node_data).expect("rlp read from db; qed") { + match Node::decoded(node_data)? { Node::Leaf(slice, value) => { return Ok(match slice == key { true => Some(self.query.decode(value)), diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index 682f12467d3..aed683117d3 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -493,3 +493,30 @@ fn get_len() { assert_eq!(t.get_with(b"B", |x: &[u8]| x.len()), Ok(Some(5))); assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None)); } + +// Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking +//#[test] +//fn test_lookup_with_corrupt_data_returns_decoder_error() { +// use memorydb::*; +// use super::TrieMut; +// use super::triedbmut::*; +// use rlp; +// use ethereum_types::H512; +// +// let mut memdb = MemoryDB::new(); +// let mut root = H256::new(); +// { +// let mut t = TrieDBMut::new(&mut memdb, &mut root); +// t.insert(b"A", b"ABC").unwrap(); +// t.insert(b"B", b"ABCBA").unwrap(); +// } +// +// let t = TrieDB::new(&memdb, &root).unwrap(); +// +// // query for an invalid data type to trigger an error +// let q = rlp::decode::; +// let lookup = Lookup{ db: t.db, query: q, hash: root }; +// let query_result = lookup.look_up(NibbleSlice::new(b"A")); +// let expected = Box::new(TrieError::DecoderError(::rlp::DecoderError::RlpIsTooShort)); +// assert_eq!(query_result.unwrap_err(), expected); +//} diff --git a/util/rlp/src/error.rs b/util/rlp/src/error.rs index 5113fdc17df..7aef6cfbf72 100644 --- a/util/rlp/src/error.rs +++ b/util/rlp/src/error.rs @@ -9,7 +9,7 @@ use std::fmt; use std::error::Error as StdError; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone)] /// Error concerning the RLP decoder. pub enum DecoderError { /// Data has additional bytes at the end of the valid RLP fragment. From 387e03764437c7d2f9f1da0b70cf8283488444d4 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 5 May 2018 16:23:50 +0800 Subject: [PATCH 062/147] EIP 145: Bitwise shifting instructions in EVM (#8451) * Add SHL, SHR, SAR opcodes * Add have_bitwise_shifting schedule flag * Add all EIP tests for SHL * Add SHR implementation and tests * Implement SAR and add tests * Add eip145transition config param * Change map_or to map_or_else when possible --- ethcore/evm/src/instructions.rs | 10 +- ethcore/evm/src/interpreter/mod.rs | 55 +++++- ethcore/evm/src/tests.rs | 268 ++++++++++++++++++++++++++++- ethcore/src/spec/spec.rs | 39 +++-- ethcore/vm/src/schedule.rs | 12 +- ethcore/vm/src/tests.rs | 7 + json/src/spec/params.rs | 3 + 7 files changed, 374 insertions(+), 20 deletions(-) diff --git a/ethcore/evm/src/instructions.rs b/ethcore/evm/src/instructions.rs index 3fb9fb93396..6ecfc7f6730 100644 --- a/ethcore/evm/src/instructions.rs +++ b/ethcore/evm/src/instructions.rs @@ -187,6 +187,9 @@ lazy_static! { arr[OR as usize] = InstructionInfo::new("OR", 2, 1, GasPriceTier::VeryLow); arr[XOR as usize] = InstructionInfo::new("XOR", 2, 1, GasPriceTier::VeryLow); arr[BYTE as usize] = InstructionInfo::new("BYTE", 2, 1, GasPriceTier::VeryLow); + arr[SHL as usize] = InstructionInfo::new("SHL", 2, 1, GasPriceTier::VeryLow); + arr[SHR as usize] = InstructionInfo::new("SHR", 2, 1, GasPriceTier::VeryLow); + arr[SAR as usize] = InstructionInfo::new("SAR", 2, 1, GasPriceTier::VeryLow); arr[ADDMOD as usize] = InstructionInfo::new("ADDMOD", 3, 1, GasPriceTier::Mid); arr[MULMOD as usize] = InstructionInfo::new("MULMOD", 3, 1, GasPriceTier::Mid); arr[SIGNEXTEND as usize] = InstructionInfo::new("SIGNEXTEND", 2, 1, GasPriceTier::Low); @@ -354,6 +357,12 @@ pub const XOR: Instruction = 0x18; pub const NOT: Instruction = 0x19; /// retrieve single byte from word pub const BYTE: Instruction = 0x1a; +/// shift left operation +pub const SHL: Instruction = 0x1b; +/// logical shift right operation +pub const SHR: Instruction = 0x1c; +/// arithmetic shift right operation +pub const SAR: Instruction = 0x1d; /// compute SHA3-256 hash pub const SHA3: Instruction = 0x20; @@ -589,4 +598,3 @@ pub const REVERT: Instruction = 0xfd; pub const STATICCALL: Instruction = 0xfa; /// halt execution and register account for later deletion pub const SUICIDE: Instruction = 0xff; - diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 05d1fb78853..160a2e5b1d3 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -224,7 +224,8 @@ impl Interpreter { (instruction == instructions::CREATE2 && !schedule.have_create2) || (instruction == instructions::STATICCALL && !schedule.have_static_call) || ((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) || - (instruction == instructions::REVERT && !schedule.have_revert) { + (instruction == instructions::REVERT && !schedule.have_revert) || + ((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) { return Err(vm::Error::BadInstruction { instruction: instruction @@ -871,6 +872,58 @@ impl Interpreter { }); } }, + instructions::SHL => { + const CONST_256: U256 = U256([256, 0, 0, 0]); + + let shift = stack.pop_back(); + let value = stack.pop_back(); + + let result = if shift >= CONST_256 { + U256::zero() + } else { + value << (shift.as_u32() as usize) + }; + stack.push(result); + }, + instructions::SHR => { + const CONST_256: U256 = U256([256, 0, 0, 0]); + + let shift = stack.pop_back(); + let value = stack.pop_back(); + + let result = if shift >= CONST_256 { + U256::zero() + } else { + value >> (shift.as_u32() as usize) + }; + stack.push(result); + }, + instructions::SAR => { + // We cannot use get_and_reset_sign/set_sign here, because the rounding looks different. + + const CONST_256: U256 = U256([256, 0, 0, 0]); + const CONST_HIBIT: U256 = U256([0, 0, 0, 0x8000000000000000]); + + let shift = stack.pop_back(); + let value = stack.pop_back(); + let sign = value & CONST_HIBIT != U256::zero(); + + let result = if shift >= CONST_256 { + if sign { + U256::max_value() + } else { + U256::zero() + } + } else { + let shift = shift.as_u32() as usize; + let mut shifted = value >> shift; + if sign { + shifted = shifted | (U256::max_value() << (256 - shift)); + } + shifted + }; + stack.push(result); + }, _ => { return Err(vm::Error::BadInstruction { instruction: instruction diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index 3758156e21a..9058d073e80 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -787,6 +787,273 @@ fn test_create_in_staticcall(factory: super::Factory) { assert_eq!(ext.calls.len(), 0); } +evm_test!{test_shl: test_shl_int} +fn test_shl(factory: super::Factory) { + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "00", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "01", + "0000000000000000000000000000000000000000000000000000000000000002"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "ff", + "8000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "0101", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "8000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000000", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); +} + +evm_test!{test_shr: test_shr_int} +fn test_shr(factory: super::Factory) { + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "0000000000000000000000000000000000000000000000000000000000000001", + "00", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "0000000000000000000000000000000000000000000000000000000000000001", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "01", + "4000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "ff", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "0101", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "0000000000000000000000000000000000000000000000000000000000000000", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); +} + +evm_test!{test_sar: test_sar_int} +fn test_sar(factory: super::Factory) { + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "0000000000000000000000000000000000000000000000000000000000000001", + "00", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "0000000000000000000000000000000000000000000000000000000000000001", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "01", + "c000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "ff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "0100", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "0101", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "0000000000000000000000000000000000000000000000000000000000000000", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "4000000000000000000000000000000000000000000000000000000000000000", + "fe", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "f8", + "000000000000000000000000000000000000000000000000000000000000007f"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "fe", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); +} + +fn push_two_pop_one_constantinople_test(factory: &super::Factory, opcode: u8, push1: &str, push2: &str, result: &str) { + let mut push1 = push1.from_hex().unwrap(); + let mut push2 = push2.from_hex().unwrap(); + assert!(push1.len() <= 32 && push1.len() != 0); + assert!(push2.len() <= 32 && push2.len() != 0); + + let mut code = Vec::new(); + code.push(0x60 + ((push1.len() - 1) as u8)); + code.append(&mut push1); + code.push(0x60 + ((push2.len() - 1) as u8)); + code.append(&mut push2); + code.push(opcode); + code.append(&mut vec![0x60, 0x00, 0x55]); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + let mut ext = FakeExt::new_constantinople(); + + let _ = { + let mut vm = factory.create(¶ms.gas); + test_finalize(vm.exec(params, &mut ext)).unwrap() + }; + + assert_store(&ext, 0, result); +} + fn assert_set_contains(set: &HashSet, val: &T) { let contains = set.contains(val); if !contains { @@ -799,4 +1066,3 @@ fn assert_set_contains(set: &HashSet, val: fn assert_store(ext: &FakeExt, pos: u64, val: &str) { assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap()); } - diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 156ab8f15a8..ef69f4847bc 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -105,6 +105,8 @@ pub struct CommonParams { pub eip211_transition: BlockNumber, /// Number of first block where EIP-214 rules begin. pub eip214_transition: BlockNumber, + /// Number of first block where EIP-145 rules begin. + pub eip145_transition: BlockNumber, /// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin. pub dust_protection_transition: BlockNumber, /// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled. @@ -152,6 +154,7 @@ impl CommonParams { schedule.have_revert = block_number >= self.eip140_transition; schedule.have_static_call = block_number >= self.eip214_transition; schedule.have_return_data = block_number >= self.eip211_transition; + schedule.have_bitwise_shifting = block_number >= self.eip145_transition; if block_number >= self.eip210_transition { schedule.blockhash_gas = 800; } @@ -198,16 +201,16 @@ impl From for CommonParams { eip155_transition: p.eip155_transition.map_or(0, Into::into), validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into), validate_chain_id_transition: p.validate_chain_id_transition.map_or(0, Into::into), - eip86_transition: p.eip86_transition.map_or( - BlockNumber::max_value(), + eip86_transition: p.eip86_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip140_transition: p.eip140_transition.map_or( - BlockNumber::max_value(), + eip140_transition: p.eip140_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip210_transition: p.eip210_transition.map_or( - BlockNumber::max_value(), + eip210_transition: p.eip210_transition.map_or_else( + BlockNumber::max_value, Into::into, ), eip210_contract_address: p.eip210_contract_address.map_or(0xf0.into(), Into::into), @@ -220,20 +223,24 @@ impl From for CommonParams { Into::into, ), eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into), - eip211_transition: p.eip211_transition.map_or( - BlockNumber::max_value(), + eip211_transition: p.eip211_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip214_transition: p.eip214_transition.map_or( - BlockNumber::max_value(), + eip145_transition: p.eip145_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip658_transition: p.eip658_transition.map_or( - BlockNumber::max_value(), + eip214_transition: p.eip214_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - dust_protection_transition: p.dust_protection_transition.map_or( - BlockNumber::max_value(), + eip658_transition: p.eip658_transition.map_or_else( + BlockNumber::max_value, + Into::into, + ), + dust_protection_transition: p.dust_protection_transition.map_or_else( + BlockNumber::max_value, Into::into, ), nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into), @@ -245,8 +252,8 @@ impl From for CommonParams { max_transaction_size: p.max_transaction_size.map_or(MAX_TRANSACTION_SIZE, Into::into), max_code_size_transition: p.max_code_size_transition.map_or(0, Into::into), transaction_permission_contract: p.transaction_permission_contract.map(Into::into), - wasm_activation_transition: p.wasm_activation_transition.map_or( - BlockNumber::max_value(), + wasm_activation_transition: p.wasm_activation_transition.map_or_else( + BlockNumber::max_value, Into::into ), } diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index 6cfabed0df3..a0085ef1ece 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -109,6 +109,8 @@ pub struct Schedule { pub have_static_call: bool, /// RETURNDATA and RETURNDATASIZE opcodes enabled. pub have_return_data: bool, + /// SHL, SHR, SAR opcodes enabled. + pub have_bitwise_shifting: bool, /// Kill basic accounts below this balance if touched. pub kill_dust: CleanDustMode, /// Enable EIP-86 rules @@ -194,6 +196,7 @@ impl Schedule { have_create2: false, have_revert: false, have_return_data: false, + have_bitwise_shifting: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -250,6 +253,13 @@ impl Schedule { schedule } + /// Schedule for the Constantinople fork of the Ethereum main net. + pub fn new_constantinople() -> Schedule { + let mut schedule = Self::new_byzantium(); + schedule.have_bitwise_shifting = true; + schedule + } + fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { Schedule { exceptional_failed_code_deposit: efcd, @@ -257,6 +267,7 @@ impl Schedule { have_create2: false, have_revert: false, have_return_data: false, + have_bitwise_shifting: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -328,4 +339,3 @@ fn schedule_evm_assumptions() { assert_eq!(s1.quad_coeff_div, 512); assert_eq!(s2.quad_coeff_div, 512); } - diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index ce47121458f..daf46be0f07 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -88,6 +88,13 @@ impl FakeExt { ext } + /// New fake externalities with constantinople schedule rules + pub fn new_constantinople() -> Self { + let mut ext = FakeExt::default(); + ext.schedule = Schedule::new_constantinople(); + ext + } + /// Alter fake externalities to allow wasm pub fn with_wasm(mut self) -> Self { self.schedule.wasm = Some(Default::default()); diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index ce47086df17..0addf52e4af 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -85,6 +85,9 @@ pub struct Params { #[serde(rename="eip211Transition")] pub eip211_transition: Option, /// See `CommonParams` docs. + #[serde(rename="eip145Transition")] + pub eip145_transition: Option, + /// See `CommonParams` docs. #[serde(rename="eip214Transition")] pub eip214_transition: Option, /// See `CommonParams` docs. From 44d3c90c94d49d606d0ca28b933bbb2cce82c8d8 Mon Sep 17 00:00:00 2001 From: Toralf Wittner Date: Sat, 5 May 2018 11:02:33 +0200 Subject: [PATCH 063/147] Consolidate crypto functionality in `ethcore-crypto`. (#8432) * Consolidate crypto functionality in `ethcore-crypto`. - Move `ecdh`/`ecies` modules to `ethkey`. - Refactor `ethcore-crypto` to use file per module. - Replace `subtle` with `ethcore_crypto::is_equal`. - Add `aes_gcm` module to `ethcore-crypto`. * Rename `aes::{encrypt,decrypt,decrypt_cbc}` ... ... to `aes::{encrypt_128_ctr,decrypt_128_ctr,decrypt_128_cbc}`. --- Cargo.lock | 26 +- ethcore/Cargo.toml | 2 +- ethcore/benches/evm.rs | 9 +- ethcore/crypto/Cargo.toml | 10 +- ethcore/crypto/src/aes.rs | 54 ++++ ethcore/crypto/src/aes_gcm.rs | 199 ++++++++++++ ethcore/crypto/src/digest.rs | 109 +++++++ ethcore/crypto/src/error.rs | 83 +++++ ethcore/crypto/src/hmac.rs | 89 ++++++ ethcore/crypto/src/lib.rs | 299 +----------------- ethcore/crypto/src/pbkdf2.rs | 29 ++ ethcore/crypto/src/scrypt.rs | 39 +++ ethcore/private-tx/src/encryptor.rs | 7 +- ethcore/src/builtin.rs | 25 +- ethcore/src/lib.rs | 2 +- ethkey/Cargo.toml | 3 +- ethkey/src/crypto.rs | 189 +++++++++++ ethkey/src/extended.rs | 22 +- ethkey/src/lib.rs | 5 +- ethstore/Cargo.toml | 2 - ethstore/src/account/crypto.rs | 29 +- ethstore/src/account/safe_account.rs | 25 +- ethstore/src/accounts_dir/disk.rs | 6 +- ethstore/src/accounts_dir/vault.rs | 2 +- ethstore/src/error.rs | 25 +- ethstore/src/ethstore.rs | 2 +- ethstore/src/lib.rs | 2 - ethstore/src/presale.rs | 15 +- rpc/Cargo.toml | 1 - rpc/src/lib.rs | 1 - rpc/src/v1/helpers/ipfs.rs | 12 +- rpc/src/v1/helpers/secretstore.rs | 8 +- rpc/src/v1/impls/light/parity.rs | 4 +- rpc/src/v1/impls/parity.rs | 4 +- secret_store/src/key_server.rs | 35 +- .../client_sessions/decryption_session.rs | 4 +- .../src/key_server_cluster/io/handshake.rs | 2 +- .../src/key_server_cluster/io/message.rs | 4 +- .../key_server_cluster/jobs/decryption_job.rs | 2 +- secret_store/src/node_key_pair.rs | 5 +- secret_store/src/types/error.rs | 8 +- util/network-devp2p/src/connection.rs | 2 +- util/network-devp2p/src/handshake.rs | 2 +- util/network/src/error.rs | 16 +- whisper/Cargo.toml | 1 - whisper/src/lib.rs | 1 - whisper/src/rpc/crypto.rs | 109 ++----- whisper/src/rpc/filter.rs | 2 +- whisper/src/rpc/key_store.rs | 9 +- whisper/src/rpc/mod.rs | 4 +- 50 files changed, 1003 insertions(+), 542 deletions(-) create mode 100644 ethcore/crypto/src/aes.rs create mode 100644 ethcore/crypto/src/aes_gcm.rs create mode 100644 ethcore/crypto/src/digest.rs create mode 100644 ethcore/crypto/src/error.rs create mode 100644 ethcore/crypto/src/hmac.rs create mode 100644 ethcore/crypto/src/pbkdf2.rs create mode 100644 ethcore/crypto/src/scrypt.rs create mode 100644 ethkey/src/crypto.rs diff --git a/Cargo.lock b/Cargo.lock index 741cc3832ce..ceb14ff277c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -509,6 +509,7 @@ dependencies = [ "ethash 1.12.0", "ethcore-bloom-journal 0.1.0", "ethcore-bytes 0.1.0", + "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", "ethcore-logger 1.12.0", "ethcore-miner 1.12.0", @@ -545,7 +546,6 @@ dependencies = [ "rlp 0.2.1", "rlp_compress 0.1.0", "rlp_derive 0.1.0", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", "stats 0.1.0", @@ -576,11 +576,10 @@ version = "0.1.0" name = "ethcore-crypto" version = "0.1.0" dependencies = [ - "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethkey 0.3.0", + "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -925,13 +924,14 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", + "ethcore-crypto 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -966,13 +966,11 @@ dependencies = [ "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2197,7 +2195,6 @@ dependencies = [ "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2362,7 +2359,6 @@ dependencies = [ "ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rlp 0.2.1", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2621,6 +2617,11 @@ dependencies = [ "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quick-error" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quote" version = "0.5.1" @@ -3035,11 +3036,6 @@ name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "subtle" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "syn" version = "0.13.1" @@ -3927,6 +3923,7 @@ dependencies = [ "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" +"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" @@ -3973,7 +3970,6 @@ dependencies = [ "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" "checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e" "checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 147d9484c70..71c84a293f9 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -20,6 +20,7 @@ fetch = { path = "../util/fetch" } hashdb = { path = "../util/hashdb" } memorydb = { path = "../util/memorydb" } patricia-trie = { path = "../util/patricia_trie" } +ethcore-crypto = { path = "crypto" } error-chain = { version = "0.11", default-features = false } ethcore-io = { path = "../util/io" } ethcore-logger = { path = "../logger" } @@ -56,7 +57,6 @@ util-error = { path = "../util/error" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } macros = { path = "../util/macros" } -rust-crypto = "0.2.34" rustc-hex = "1.0" stats = { path = "../util/stats" } trace-time = { path = "../util/trace-time" } diff --git a/ethcore/benches/evm.rs b/ethcore/benches/evm.rs index 324e3382e57..9fe2657d614 100644 --- a/ethcore/benches/evm.rs +++ b/ethcore/benches/evm.rs @@ -20,7 +20,7 @@ extern crate test; extern crate ethcore_util as util; extern crate rand; extern crate bn; -extern crate crypto; +extern crate ethcore_crypto; extern crate ethkey; extern crate rustc_hex; extern crate ethcore_bigint; @@ -61,16 +61,13 @@ fn bn_128_mul(b: &mut Bencher) { #[bench] fn sha256(b: &mut Bencher) { - use crypto::sha2::Sha256; - use crypto::digest::Digest; + use ethcore_crypto::digest::sha256; let mut input: [u8; 256] = [0; 256]; let mut out = [0; 32]; b.iter(|| { - let mut sha = Sha256::new(); - sha.input(&input); - sha.result(&mut input[0..32]); + sha256(&input); }); } diff --git a/ethcore/crypto/Cargo.toml b/ethcore/crypto/Cargo.toml index c3a2191b55a..4fe023f25c4 100644 --- a/ethcore/crypto/Cargo.toml +++ b/ethcore/crypto/Cargo.toml @@ -4,13 +4,9 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] +ethereum-types = "0.3" +quick-error = "1.2" +ring = "0.12" rust-crypto = "0.2.36" tiny-keccak = "1.3" -eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true } -ethkey = { path = "../../ethkey", optional = true } -ethereum-types = "0.3" -subtle = "0.5" -[features] -default = ["secp256k1"] -secp256k1 = ["eth-secp256k1", "ethkey"] diff --git a/ethcore/crypto/src/aes.rs b/ethcore/crypto/src/aes.rs new file mode 100644 index 00000000000..79a8dcc86d6 --- /dev/null +++ b/ethcore/crypto/src/aes.rs @@ -0,0 +1,54 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use error::SymmError; +use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; +use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; +use rcrypto::symmetriccipher::{Encryptor, Decryptor}; +use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer}; + +/// Encrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); + encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true)?; + Ok(()) +} + +/// Decrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); + encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)?; + Ok(()) +} + +/// Decrypt a message (CBC mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result { + let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); + let len = dest.len(); + let mut buffer = RefWriteBuffer::new(dest); + encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; + Ok(len - buffer.remaining()) +} + diff --git a/ethcore/crypto/src/aes_gcm.rs b/ethcore/crypto/src/aes_gcm.rs new file mode 100644 index 00000000000..178b5d1e12c --- /dev/null +++ b/ethcore/crypto/src/aes_gcm.rs @@ -0,0 +1,199 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use error::SymmError; +use ring; + +enum Mode { Aes128Gcm, Aes256Gcm } + +/// AES GCM encryptor. +pub struct Encryptor<'a> { + mode: Mode, + key: ring::aead::SealingKey, + ad: &'a [u8], + offset: usize, +} + +impl<'a> Encryptor<'a> { + pub fn aes_128_gcm(key: &[u8; 16]) -> Result, SymmError> { + let sk = ring::aead::SealingKey::new(&ring::aead::AES_128_GCM, key)?; + Ok(Encryptor { + mode: Mode::Aes128Gcm, + key: sk, + ad: &[], + offset: 0, + }) + } + + pub fn aes_256_gcm(key: &[u8; 32]) -> Result, SymmError> { + let sk = ring::aead::SealingKey::new(&ring::aead::AES_256_GCM, key)?; + Ok(Encryptor { + mode: Mode::Aes256Gcm, + key: sk, + ad: &[], + offset: 0, + }) + } + + /// Optional associated data which is not encrypted but authenticated. + pub fn associate(&mut self, data: &'a [u8]) -> &mut Self { + self.ad = data; + self + } + + /// Optional offset value. Only the slice `[offset..]` will be encrypted. + pub fn offset(&mut self, off: usize) -> &mut Self { + self.offset = off; + self + } + + /// Please note that the pair (key, nonce) must never be reused. Using random nonces + /// limits the number of messages encrypted with the same key to 2^32 (cf. [[1]]) + /// + /// [1]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf + pub fn encrypt(&self, nonce: &[u8; 12], mut data: Vec) -> Result, SymmError> { + if self.offset > data.len() { + return Err(SymmError::offset_error(self.offset)) + } + let tag_len = match self.mode { + Mode::Aes128Gcm => ring::aead::AES_128_GCM.tag_len(), + Mode::Aes256Gcm => ring::aead::AES_256_GCM.tag_len(), + }; + data.extend(::std::iter::repeat(0).take(tag_len)); + let len = ring::aead::seal_in_place(&self.key, nonce, self.ad, &mut data[self.offset ..], tag_len)?; + data.truncate(self.offset + len); + Ok(data) + } +} + +/// AES GCM decryptor. +pub struct Decryptor<'a> { + key: ring::aead::OpeningKey, + ad: &'a [u8], + offset: usize, +} + +impl<'a> Decryptor<'a> { + pub fn aes_128_gcm(key: &[u8; 16]) -> Result, SymmError> { + let ok = ring::aead::OpeningKey::new(&ring::aead::AES_128_GCM, key)?; + Ok(Decryptor { + key: ok, + ad: &[], + offset: 0, + }) + } + + pub fn aes_256_gcm(key: &[u8; 32]) -> Result, SymmError> { + let ok = ring::aead::OpeningKey::new(&ring::aead::AES_256_GCM, key)?; + Ok(Decryptor { + key: ok, + ad: &[], + offset: 0, + }) + } + + /// Optional associated data which is not encrypted but authenticated. + pub fn associate(&mut self, data: &'a [u8]) -> &mut Self { + self.ad = data; + self + } + + /// Optional offset value. Only the slice `[offset..]` will be decrypted. + pub fn offset(&mut self, off: usize) -> &mut Self { + self.offset = off; + self + } + + pub fn decrypt(&self, nonce: &[u8; 12], mut data: Vec) -> Result, SymmError> { + if self.offset > data.len() { + return Err(SymmError::offset_error(self.offset)) + } + let len = ring::aead::open_in_place(&self.key, nonce, self.ad, 0, &mut data[self.offset ..])?.len(); + data.truncate(self.offset + len); + Ok(data) + } +} + +#[cfg(test)] +mod tests { + use super::{Encryptor, Decryptor}; + + #[test] + fn aes_gcm_128() { + let secret = b"1234567890123456"; + let nonce = b"123456789012"; + let message = b"So many books, so little time"; + + let ciphertext = Encryptor::aes_128_gcm(secret) + .unwrap() + .encrypt(nonce, message.to_vec()) + .unwrap(); + + assert!(ciphertext != message); + + let plaintext = Decryptor::aes_128_gcm(secret) + .unwrap() + .decrypt(nonce, ciphertext) + .unwrap(); + + assert_eq!(plaintext, message) + } + + #[test] + fn aes_gcm_256() { + let secret = b"12345678901234567890123456789012"; + let nonce = b"123456789012"; + let message = b"So many books, so little time"; + + let ciphertext = Encryptor::aes_256_gcm(secret) + .unwrap() + .encrypt(nonce, message.to_vec()) + .unwrap(); + + assert!(ciphertext != message); + + let plaintext = Decryptor::aes_256_gcm(secret) + .unwrap() + .decrypt(nonce, ciphertext) + .unwrap(); + + assert_eq!(plaintext, message) + } + + #[test] + fn aes_gcm_256_offset() { + let secret = b"12345678901234567890123456789012"; + let nonce = b"123456789012"; + let message = b"prefix data; So many books, so little time"; + + let ciphertext = Encryptor::aes_256_gcm(secret) + .unwrap() + .offset(13) // length of "prefix data; " + .encrypt(nonce, message.to_vec()) + .unwrap(); + + assert!(ciphertext != &message[..]); + + let plaintext = Decryptor::aes_256_gcm(secret) + .unwrap() + .offset(13) // length of "prefix data; " + .decrypt(nonce, ciphertext) + .unwrap(); + + assert_eq!(plaintext, &message[..]) + } +} + diff --git a/ethcore/crypto/src/digest.rs b/ethcore/crypto/src/digest.rs new file mode 100644 index 00000000000..095a8ca2620 --- /dev/null +++ b/ethcore/crypto/src/digest.rs @@ -0,0 +1,109 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use rcrypto::ripemd160; +use ring::digest::{self, Context, SHA256, SHA512}; +use std::marker::PhantomData; +use std::ops::Deref; + +/// The message digest. +pub struct Digest(InnerDigest, PhantomData); + +enum InnerDigest { + Ring(digest::Digest), + Ripemd160([u8; 20]), +} + +impl Deref for Digest { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + match self.0 { + InnerDigest::Ring(ref d) => d.as_ref(), + InnerDigest::Ripemd160(ref d) => &d[..] + } + } +} + +/// Single-step sha256 digest computation. +pub fn sha256(data: &[u8]) -> Digest { + Digest(InnerDigest::Ring(digest::digest(&SHA256, data)), PhantomData) +} + +/// Single-step sha512 digest computation. +pub fn sha512(data: &[u8]) -> Digest { + Digest(InnerDigest::Ring(digest::digest(&SHA512, data)), PhantomData) +} + +/// Single-step ripemd160 digest computation. +pub fn ripemd160(data: &[u8]) -> Digest { + let mut hasher = Hasher::ripemd160(); + hasher.update(data); + hasher.finish() +} + +pub enum Sha256 {} +pub enum Sha512 {} +pub enum Ripemd160 {} + +/// Stateful digest computation. +pub struct Hasher(Inner, PhantomData); + +enum Inner { + Ring(Context), + Ripemd160(ripemd160::Ripemd160) +} + +impl Hasher { + pub fn sha256() -> Hasher { + Hasher(Inner::Ring(Context::new(&SHA256)), PhantomData) + } +} + +impl Hasher { + pub fn sha512() -> Hasher { + Hasher(Inner::Ring(Context::new(&SHA512)), PhantomData) + } +} + +impl Hasher { + pub fn ripemd160() -> Hasher { + Hasher(Inner::Ripemd160(ripemd160::Ripemd160::new()), PhantomData) + } +} + +impl Hasher { + pub fn update(&mut self, data: &[u8]) { + match self.0 { + Inner::Ring(ref mut ctx) => ctx.update(data), + Inner::Ripemd160(ref mut ctx) => { + use rcrypto::digest::Digest; + ctx.input(data) + } + } + } + + pub fn finish(self) -> Digest { + match self.0 { + Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData), + Inner::Ripemd160(mut ctx) => { + use rcrypto::digest::Digest; + let mut d = [0; 20]; + ctx.result(&mut d); + Digest(InnerDigest::Ripemd160(d), PhantomData) + } + } + } +} diff --git a/ethcore/crypto/src/error.rs b/ethcore/crypto/src/error.rs new file mode 100644 index 00000000000..4de3b80036d --- /dev/null +++ b/ethcore/crypto/src/error.rs @@ -0,0 +1,83 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use rcrypto; +use ring; + +quick_error! { + #[derive(Debug)] + pub enum Error { + Scrypt(e: ScryptError) { + cause(e) + from() + } + Symm(e: SymmError) { + cause(e) + from() + } + } +} + +quick_error! { + #[derive(Debug)] + pub enum ScryptError { + // log(N) < r / 16 + InvalidN { + display("Invalid N argument of the scrypt encryption") + } + // p <= (2^31-1 * 32)/(128 * r) + InvalidP { + display("Invalid p argument of the scrypt encryption") + } + } +} + +quick_error! { + #[derive(Debug)] + pub enum SymmError wraps PrivSymmErr { + RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) { + display("symmetric crypto error") + from() + } + Ring(e: ring::error::Unspecified) { + display("symmetric crypto error") + cause(e) + from() + } + Offset(x: usize) { + display("offset {} greater than slice length", x) + } + } +} + +impl SymmError { + pub(crate) fn offset_error(x: usize) -> SymmError { + SymmError(PrivSymmErr::Offset(x)) + } +} + +impl From for SymmError { + fn from(e: ring::error::Unspecified) -> SymmError { + SymmError(PrivSymmErr::Ring(e)) + } +} + +impl From for SymmError { + fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError { + SymmError(PrivSymmErr::RustCrypto(e)) + } +} + diff --git a/ethcore/crypto/src/hmac.rs b/ethcore/crypto/src/hmac.rs new file mode 100644 index 00000000000..7327250442d --- /dev/null +++ b/ethcore/crypto/src/hmac.rs @@ -0,0 +1,89 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use digest; +use ring::digest::{SHA256, SHA512}; +use ring::hmac::{self, SigningContext}; +use std::marker::PhantomData; +use std::ops::Deref; + +/// HMAC signature. +pub struct Signature(hmac::Signature, PhantomData); + +impl Deref for Signature { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + self.0.as_ref() + } +} + +/// HMAC signing key. +pub struct SigKey(hmac::SigningKey, PhantomData); + +impl SigKey { + pub fn sha256(key: &[u8]) -> SigKey { + SigKey(hmac::SigningKey::new(&SHA256, key), PhantomData) + } +} + +impl SigKey { + pub fn sha512(key: &[u8]) -> SigKey { + SigKey(hmac::SigningKey::new(&SHA512, key), PhantomData) + } +} + +/// Compute HMAC signature of `data`. +pub fn sign(k: &SigKey, data: &[u8]) -> Signature { + Signature(hmac::sign(&k.0, data), PhantomData) +} + +/// Stateful HMAC computation. +pub struct Signer(SigningContext, PhantomData); + +impl Signer { + pub fn with(key: &SigKey) -> Signer { + Signer(hmac::SigningContext::with_key(&key.0), PhantomData) + } + + pub fn update(&mut self, data: &[u8]) { + self.0.update(data) + } + + pub fn sign(self) -> Signature { + Signature(self.0.sign(), PhantomData) + } +} + +/// HMAC signature verification key. +pub struct VerifyKey(hmac::VerificationKey, PhantomData); + +impl VerifyKey { + pub fn sha256(key: &[u8]) -> VerifyKey { + VerifyKey(hmac::VerificationKey::new(&SHA256, key), PhantomData) + } +} + +impl VerifyKey { + pub fn sha512(key: &[u8]) -> VerifyKey { + VerifyKey(hmac::VerificationKey::new(&SHA512, key), PhantomData) + } +} + +/// Verify HMAC signature of `data`. +pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { + hmac::verify(&k.0, data, sig).is_ok() +} + diff --git a/ethcore/crypto/src/lib.rs b/ethcore/crypto/src/lib.rs index caa4cf77c4d..0ee42e35991 100644 --- a/ethcore/crypto/src/lib.rs +++ b/ethcore/crypto/src/lib.rs @@ -18,23 +18,22 @@ extern crate crypto as rcrypto; extern crate ethereum_types; -extern crate subtle; +#[macro_use] +extern crate quick_error; +extern crate ring; extern crate tiny_keccak; -#[cfg(feature = "secp256k1")] -extern crate secp256k1; -#[cfg(feature = "secp256k1")] -extern crate ethkey; +pub mod aes; +pub mod aes_gcm; +pub mod error; +pub mod scrypt; +pub mod digest; +pub mod hmac; +pub mod pbkdf2; -use std::fmt; -use tiny_keccak::Keccak; -use rcrypto::pbkdf2::pbkdf2; -use rcrypto::scrypt::{scrypt, ScryptParams}; -use rcrypto::sha2::Sha256; -use rcrypto::hmac::Hmac; +pub use error::Error; -#[cfg(feature = "secp256k1")] -use secp256k1::Error as SecpError; +use tiny_keccak::Keccak; pub const KEY_LENGTH: usize = 32; pub const KEY_ITERATIONS: usize = 10240; @@ -43,65 +42,6 @@ pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2; /// Default authenticated data to use (in RPC). pub const DEFAULT_MAC: [u8; 2] = [0, 0]; -#[derive(PartialEq, Debug)] -pub enum ScryptError { - // log(N) < r / 16 - InvalidN, - // p <= (2^31-1 * 32)/(128 * r) - InvalidP, -} - -impl fmt::Display for ScryptError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let s = match *self { - ScryptError::InvalidN => "Invalid N argument of the scrypt encryption" , - ScryptError::InvalidP => "Invalid p argument of the scrypt encryption", - }; - - write!(f, "{}", s) - } -} - -#[derive(PartialEq, Debug)] -pub enum Error { - #[cfg(feature = "secp256k1")] - Secp(SecpError), - Scrypt(ScryptError), - InvalidMessage, -} - -impl From for Error { - fn from(err: ScryptError) -> Self { - Error::Scrypt(err) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let s = match *self { - #[cfg(feature = "secp256k1")] - Error::Secp(ref err) => err.to_string(), - Error::Scrypt(ref err) => err.to_string(), - Error::InvalidMessage => "Invalid message".into(), - }; - - write!(f, "{}", s) - } -} - -impl Into for Error { - fn into(self) -> String { - format!("{}", self) - } -} - -#[cfg(feature = "secp256k1")] -impl From for Error { - fn from(e: SecpError) -> Self { - Error::Secp(e) - } -} - pub trait Keccak256 { fn keccak256(&self) -> T where T: Sized; } @@ -117,33 +57,13 @@ impl Keccak256<[u8; 32]> for T where T: AsRef<[u8]> { } pub fn derive_key_iterations(password: &str, salt: &[u8; 32], c: u32) -> (Vec, Vec) { - let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes()); - let mut derived_key = vec![0u8; KEY_LENGTH]; - pbkdf2(&mut h_mac, salt, c, &mut derived_key); + let mut derived_key = [0u8; KEY_LENGTH]; + pbkdf2::sha256(c, pbkdf2::Salt(salt), pbkdf2::Secret(password.as_bytes()), &mut derived_key); let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; (derived_right_bits.to_vec(), derived_left_bits.to_vec()) } -pub fn derive_key_scrypt(password: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), Error> { - // sanity checks - let log_n = (32 - n.leading_zeros() - 1) as u8; - if log_n as u32 >= r * 16 { - return Err(Error::Scrypt(ScryptError::InvalidN)); - } - - if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) { - return Err(Error::Scrypt(ScryptError::InvalidP)); - } - - let mut derived_key = vec![0u8; KEY_LENGTH]; - let scrypt_params = ScryptParams::new(log_n, r, p); - scrypt(password.as_bytes(), salt, &scrypt_params, &mut derived_key); - let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; - let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; - Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) -} - pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { let mut mac = vec![0u8; KEY_LENGTH_AES + cipher_text.len()]; mac[0..KEY_LENGTH_AES].copy_from_slice(derived_left_bits); @@ -151,194 +71,7 @@ pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { mac } -/// AES encryption -pub mod aes { - use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; - use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; - use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError}; - use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer}; - - /// Encrypt a message (CTR mode) - pub fn encrypt(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); - } - - /// Decrypt a message (CTR mode) - pub fn decrypt(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); - } - - - /// Decrypt a message using cbc mode - pub fn decrypt_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result { - let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); - let len = dest.len(); - let mut buffer = RefWriteBuffer::new(dest); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; - Ok(len - buffer.remaining()) - } -} - -/// ECDH functions -#[cfg(feature = "secp256k1")] -pub mod ecdh { - use secp256k1::{ecdh, key, Error as SecpError}; - use ethkey::{Secret, Public, SECP256K1}; - use Error; - - /// Agree on a shared secret - pub fn agree(secret: &Secret, public: &Public) -> Result { - let context = &SECP256K1; - let pdata = { - let mut temp = [4u8; 65]; - (&mut temp[1..65]).copy_from_slice(&public[0..64]); - temp - }; - - let publ = key::PublicKey::from_slice(context, &pdata)?; - let sec = key::SecretKey::from_slice(context, &secret)?; - let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); - - Secret::from_unsafe_slice(&shared[0..32]) - .map_err(|_| Error::Secp(SecpError::InvalidSecretKey)) - } -} - -/// ECIES function -#[cfg(feature = "secp256k1")] -pub mod ecies { - use rcrypto::digest::Digest; - use rcrypto::sha2::Sha256; - use rcrypto::hmac::Hmac; - use rcrypto::mac::Mac; - use ethereum_types::H128; - use ethkey::{Random, Generator, Public, Secret}; - use {Error, ecdh, aes}; - - /// Encrypt a message with a public key, writing an HMAC covering both - /// the plaintext and authenticated data. - /// - /// Authenticated data may be empty. - pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result, Error> { - let r = Random.generate() - .expect("context known to have key-generation capabilities; qed"); - - let z = ecdh::agree(r.secret(), public)?; - let mut key = [0u8; 32]; - let mut mkey = [0u8; 32]; - kdf(&z, &[0u8; 0], &mut key); - let mut hasher = Sha256::new(); - let mkey_material = &key[16..32]; - hasher.input(mkey_material); - hasher.result(&mut mkey); - let ekey = &key[0..16]; - - let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32]; - msg[0] = 0x04u8; - { - let msgd = &mut msg[1..]; - msgd[0..64].copy_from_slice(r.public()); - let iv = H128::random(); - msgd[64..80].copy_from_slice(&iv); - { - let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())]; - aes::encrypt(ekey, &iv, plain, cipher); - } - let mut hmac = Hmac::new(Sha256::new(), &mkey); - { - let cipher_iv = &msgd[64..(64 + 16 + plain.len())]; - hmac.input(cipher_iv); - } - hmac.input(auth_data); - hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]); - } - Ok(msg) - } - - /// Decrypt a message with a secret key, checking HMAC for ciphertext - /// and authenticated data validity. - pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result, Error> { - let meta_len = 1 + 64 + 16 + 32; - if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 { - return Err(Error::InvalidMessage); //invalid message: publickey - } - - let e = &encrypted[1..]; - let p = Public::from_slice(&e[0..64]); - let z = ecdh::agree(secret, &p)?; - let mut key = [0u8; 32]; - kdf(&z, &[0u8; 0], &mut key); - let ekey = &key[0..16]; - let mkey_material = &key[16..32]; - let mut hasher = Sha256::new(); - let mut mkey = [0u8; 32]; - hasher.input(mkey_material); - hasher.result(&mut mkey); - - let clen = encrypted.len() - meta_len; - let cipher_with_iv = &e[64..(64+16+clen)]; - let cipher_iv = &cipher_with_iv[0..16]; - let cipher_no_iv = &cipher_with_iv[16..]; - let msg_mac = &e[(64+16+clen)..]; - - // Verify tag - let mut hmac = Hmac::new(Sha256::new(), &mkey); - hmac.input(cipher_with_iv); - hmac.input(auth_data); - let mut mac = [0u8; 32]; - hmac.raw_result(&mut mac); - - // constant time compare to avoid timing attack. - if ::subtle::slices_equal(&mac[..], msg_mac) != 1 { - return Err(Error::InvalidMessage); - } - - let mut msg = vec![0u8; clen]; - aes::decrypt(ekey, cipher_iv, cipher_no_iv, &mut msg[..]); - Ok(msg) - } - - fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) { - let mut hasher = Sha256::new(); - // SEC/ISO/Shoup specify counter size SHOULD be equivalent - // to size of hash output, however, it also notes that - // the 4 bytes is okay. NIST specifies 4 bytes. - let mut ctr = 1u32; - let mut written = 0usize; - while written < dest.len() { - let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8]; - hasher.input(&ctrs); - hasher.input(secret); - hasher.input(s1); - hasher.result(&mut dest[written..(written + 32)]); - hasher.reset(); - written += 32; - ctr += 1; - } - } -} - -#[cfg(test)] -mod tests { - use ethkey::{Random, Generator}; - use ecies; - - #[test] - fn ecies_shared() { - let kp = Random.generate().unwrap(); - let message = b"So many books, so little time"; - - let shared = b"shared"; - let wrong_shared = b"incorrect"; - let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap(); - assert!(encrypted[..] != message[..]); - assert_eq!(encrypted[0], 0x04); - - assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err()); - let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap(); - assert_eq!(decrypted[..message.len()], message[..]); - } +pub fn is_equal(a: &[u8], b: &[u8]) -> bool { + ring::constant_time::verify_slices_are_equal(a, b).is_ok() } diff --git a/ethcore/crypto/src/pbkdf2.rs b/ethcore/crypto/src/pbkdf2.rs new file mode 100644 index 00000000000..b4c993c5133 --- /dev/null +++ b/ethcore/crypto/src/pbkdf2.rs @@ -0,0 +1,29 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use ring; + +pub struct Salt<'a>(pub &'a [u8]); +pub struct Secret<'a>(pub &'a [u8]); + +pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { + ring::pbkdf2::derive(&ring::digest::SHA256, iter, salt.0, sec.0, &mut out[..]) +} + +pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { + ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..]) +} + diff --git a/ethcore/crypto/src/scrypt.rs b/ethcore/crypto/src/scrypt.rs new file mode 100644 index 00000000000..684ab2c572c --- /dev/null +++ b/ethcore/crypto/src/scrypt.rs @@ -0,0 +1,39 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use error::ScryptError; +use rcrypto::scrypt::{scrypt, ScryptParams}; +use super::{KEY_LENGTH_AES, KEY_LENGTH}; + +pub fn derive_key(pass: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), ScryptError> { + // sanity checks + let log_n = (32 - n.leading_zeros() - 1) as u8; + if log_n as u32 >= r * 16 { + return Err(ScryptError::InvalidN); + } + + if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) { + return Err(ScryptError::InvalidP); + } + + let mut derived_key = vec![0u8; KEY_LENGTH]; + let scrypt_params = ScryptParams::new(log_n, r, p); + scrypt(pass.as_bytes(), salt, &scrypt_params, &mut derived_key); + let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; + let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; + Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) +} + diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs index 5d592de6032..b15acbee71b 100644 --- a/ethcore/private-tx/src/encryptor.rs +++ b/ethcore/private-tx/src/encryptor.rs @@ -217,7 +217,8 @@ impl Encryptor for SecretStoreEncryptor { // encrypt data let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len()); cypher.extend(repeat(0).take(plain_data.len())); - crypto::aes::encrypt(&key, initialisation_vector, plain_data, &mut cypher); + crypto::aes::encrypt_128_ctr(&key, initialisation_vector, plain_data, &mut cypher) + .map_err(|e| ErrorKind::Encrypt(e.to_string()))?; cypher.extend_from_slice(&initialisation_vector); Ok(cypher) @@ -243,8 +244,8 @@ impl Encryptor for SecretStoreEncryptor { let (cypher, iv) = cypher.split_at(cypher_len - INIT_VEC_LEN); let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN); plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN)); - crypto::aes::decrypt(&key, &iv, cypher, &mut plain_data); - + crypto::aes::decrypt_128_ctr(&key, &iv, cypher, &mut plain_data) + .map_err(|e| ErrorKind::Decrypt(e.to_string()))?; Ok(plain_data) } } diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index c18e1f3cd30..a0833cfb5e6 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -18,9 +18,7 @@ use std::cmp::{max, min}; use std::io::{self, Read}; use byteorder::{ByteOrder, BigEndian}; -use crypto::sha2::Sha256 as Sha256Digest; -use crypto::ripemd160::Ripemd160 as Ripemd160Digest; -use crypto::digest::Digest; +use ethcore_crypto::digest; use num::{BigUint, Zero, One}; use hash::keccak; @@ -295,28 +293,17 @@ impl Impl for EcRecover { impl Impl for Sha256 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - let mut sha = Sha256Digest::new(); - sha.input(input); - - let mut out = [0; 32]; - sha.result(&mut out); - - output.write(0, &out); - + let d = digest::sha256(input); + output.write(0, &*d); Ok(()) } } impl Impl for Ripemd160 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - let mut sha = Ripemd160Digest::new(); - sha.input(input); - - let mut out = [0; 32]; - sha.result(&mut out[12..32]); - - output.write(0, &out); - + let hash = digest::ripemd160(input); + output.write(0, &[0; 12][..]); + output.write(12, &hash); Ok(()) } } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 9bb2e94c1cc..b1782cb1d6c 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -63,9 +63,9 @@ extern crate bn; extern crate byteorder; extern crate crossbeam; extern crate common_types as types; -extern crate crypto; extern crate ethash; extern crate ethcore_bloom_journal as bloom_journal; +extern crate ethcore_crypto; extern crate ethcore_io as io; extern crate ethcore_bytes as bytes; extern crate ethcore_logger; diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index 335f92fe15a..d6698f86d9f 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -6,13 +6,14 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.0" edit-distance = "2.0" +ethcore-crypto = { path = "../ethcore/crypto" } eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } ethereum-types = "0.3" lazy_static = "1.0" log = "0.3" mem = { path = "../util/mem" } parity-wordlist = "1.2" +quick-error = "1.2" rand = "0.4" -rust-crypto = "0.2" rustc-hex = "1.0" tiny-keccak = "1.3" diff --git a/ethkey/src/crypto.rs b/ethkey/src/crypto.rs new file mode 100644 index 00000000000..739a463c072 --- /dev/null +++ b/ethkey/src/crypto.rs @@ -0,0 +1,189 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use secp256k1; +use std::io; +use ethcore_crypto::error::SymmError; + +quick_error! { + #[derive(Debug)] + pub enum Error { + Secp(e: secp256k1::Error) { + display("secp256k1 error: {}", e) + cause(e) + from() + } + Io(e: io::Error) { + display("i/o error: {}", e) + cause(e) + from() + } + InvalidMessage { + display("invalid message") + } + Symm(e: SymmError) { + cause(e) + from() + } + } +} + +/// ECDH functions +pub mod ecdh { + use secp256k1::{self, ecdh, key}; + use super::Error; + use {Secret, Public, SECP256K1}; + + /// Agree on a shared secret + pub fn agree(secret: &Secret, public: &Public) -> Result { + let context = &SECP256K1; + let pdata = { + let mut temp = [4u8; 65]; + (&mut temp[1..65]).copy_from_slice(&public[0..64]); + temp + }; + + let publ = key::PublicKey::from_slice(context, &pdata)?; + let sec = key::SecretKey::from_slice(context, &secret)?; + let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); + + Secret::from_unsafe_slice(&shared[0..32]) + .map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey)) + } +} + +/// ECIES function +pub mod ecies { + use ethcore_crypto::{aes, digest, hmac, is_equal}; + use ethereum_types::H128; + use super::{ecdh, Error}; + use {Random, Generator, Public, Secret}; + + /// Encrypt a message with a public key, writing an HMAC covering both + /// the plaintext and authenticated data. + /// + /// Authenticated data may be empty. + pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result, Error> { + let r = Random.generate()?; + let z = ecdh::agree(r.secret(), public)?; + let mut key = [0u8; 32]; + kdf(&z, &[0u8; 0], &mut key); + + let ekey = &key[0..16]; + let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32])); + + let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32]; + msg[0] = 0x04u8; + { + let msgd = &mut msg[1..]; + msgd[0..64].copy_from_slice(r.public()); + let iv = H128::random(); + msgd[64..80].copy_from_slice(&iv); + { + let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())]; + aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?; + } + let mut hmac = hmac::Signer::with(&mkey); + { + let cipher_iv = &msgd[64..(64 + 16 + plain.len())]; + hmac.update(cipher_iv); + } + hmac.update(auth_data); + let sig = hmac.sign(); + msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig); + } + Ok(msg) + } + + /// Decrypt a message with a secret key, checking HMAC for ciphertext + /// and authenticated data validity. + pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result, Error> { + let meta_len = 1 + 64 + 16 + 32; + if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 { + return Err(Error::InvalidMessage); //invalid message: publickey + } + + let e = &encrypted[1..]; + let p = Public::from_slice(&e[0..64]); + let z = ecdh::agree(secret, &p)?; + let mut key = [0u8; 32]; + kdf(&z, &[0u8; 0], &mut key); + + let ekey = &key[0..16]; + let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32])); + + let clen = encrypted.len() - meta_len; + let cipher_with_iv = &e[64..(64+16+clen)]; + let cipher_iv = &cipher_with_iv[0..16]; + let cipher_no_iv = &cipher_with_iv[16..]; + let msg_mac = &e[(64+16+clen)..]; + + // Verify tag + let mut hmac = hmac::Signer::with(&mkey); + hmac.update(cipher_with_iv); + hmac.update(auth_data); + let mac = hmac.sign(); + + if !is_equal(&mac.as_ref()[..], msg_mac) { + return Err(Error::InvalidMessage); + } + + let mut msg = vec![0u8; clen]; + aes::decrypt_128_ctr(ekey, cipher_iv, cipher_no_iv, &mut msg[..])?; + Ok(msg) + } + + fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) { + // SEC/ISO/Shoup specify counter size SHOULD be equivalent + // to size of hash output, however, it also notes that + // the 4 bytes is okay. NIST specifies 4 bytes. + let mut ctr = 1u32; + let mut written = 0usize; + while written < dest.len() { + let mut hasher = digest::Hasher::sha256(); + let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8]; + hasher.update(&ctrs); + hasher.update(secret); + hasher.update(s1); + let d = hasher.finish(); + &mut dest[written..(written + 32)].copy_from_slice(&d); + written += 32; + ctr += 1; + } + } +} + +#[cfg(test)] +mod tests { + use super::ecies; + use {Random, Generator}; + + #[test] + fn ecies_shared() { + let kp = Random.generate().unwrap(); + let message = b"So many books, so little time"; + + let shared = b"shared"; + let wrong_shared = b"incorrect"; + let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap(); + assert!(encrypted[..] != message[..]); + assert_eq!(encrypted[0], 0x04); + + assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err()); + let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap(); + assert_eq!(decrypted[..message.len()], message[..]); + } +} diff --git a/ethkey/src/extended.rs b/ethkey/src/extended.rs index 55bae627542..d41ae54c532 100644 --- a/ethkey/src/extended.rs +++ b/ethkey/src/extended.rs @@ -207,9 +207,7 @@ impl ExtendedKeyPair { // Work is based on BIP0032 // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki mod derivation { - use rcrypto::hmac::Hmac; - use rcrypto::mac::Mac; - use rcrypto::sha2::Sha512; + use ethcore_crypto::hmac; use ethereum_types::{U256, U512, H512, H256}; use secp256k1::key::{SecretKey, PublicKey}; use SECP256K1; @@ -242,10 +240,8 @@ mod derivation { let private: U256 = private_key.into(); // produces 512-bit derived hmac (I) - let mut hmac = Hmac::new(Sha512::new(), &*chain_code); - let mut i_512 = [0u8; 64]; - hmac.input(&data[..]); - hmac.raw_result(&mut i_512); + let skey = hmac::SigKey::sha512(&*chain_code); + let i_512 = hmac::sign(&skey, &data[..]); // left most 256 bits are later added to original private key let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into(); @@ -321,10 +317,8 @@ mod derivation { index.store(&mut data[33..(33 + T::len())]); // HMAC512SHA produces [derived private(256); new chain code(256)] - let mut hmac = Hmac::new(Sha512::new(), &*chain_code); - let mut i_512 = [0u8; 64]; - hmac.input(&data[..]); - hmac.raw_result(&mut i_512); + let skey = hmac::SigKey::sha512(&*chain_code); + let i_512 = hmac::sign(&skey, &data[..]); let new_private = H256::from(&i_512[0..32]); let new_chain_code = H256::from(&i_512[32..64]); @@ -369,10 +363,8 @@ mod derivation { } pub fn seed_pair(seed: &[u8]) -> (H256, H256) { - let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed"); - let mut i_512 = [0u8; 64]; - hmac.input(seed); - hmac.raw_result(&mut i_512); + let skey = hmac::SigKey::sha512(b"Bitcoin seed"); + let i_512 = hmac::sign(&skey, seed); let master_key = H256::from_slice(&i_512[0..32]); let chain_code = H256::from_slice(&i_512[32..64]); diff --git a/ethkey/src/lib.rs b/ethkey/src/lib.rs index 951179771b2..b5cf9845306 100644 --- a/ethkey/src/lib.rs +++ b/ethkey/src/lib.rs @@ -17,11 +17,13 @@ // #![warn(missing_docs)] extern crate byteorder; -extern crate crypto as rcrypto; extern crate edit_distance; +extern crate ethcore_crypto; extern crate ethereum_types; extern crate mem; extern crate parity_wordlist; +#[macro_use] +extern crate quick_error; extern crate rand; extern crate rustc_hex; extern crate secp256k1; @@ -44,6 +46,7 @@ mod secret; mod extended; pub mod brain_recover; +pub mod crypto; pub mod math; pub use self::parity_wordlist::Error as WordlistError; diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index d0524baeafd..6330ce97ce7 100644 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -12,7 +12,6 @@ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" rustc-hex = "1.0" -rust-crypto = "0.2.36" tiny-keccak = "1.3" time = "0.1.34" itertools = "0.5" @@ -22,7 +21,6 @@ ethereum-types = "0.3" dir = { path = "../util/dir" } smallvec = "0.4" parity-wordlist = "1.0" -subtle = "0.5" tempdir = "0.3" [dev-dependencies] diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs index 967c92306ae..bd65bc927b0 100644 --- a/ethstore/src/account/crypto.rs +++ b/ethstore/src/account/crypto.rs @@ -21,7 +21,6 @@ use crypto::Keccak256; use random::Random; use smallvec::SmallVec; use account::{Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf}; -use subtle; /// Encrypted data #[derive(Debug, PartialEq, Clone)] @@ -74,12 +73,12 @@ impl From for String { impl Crypto { /// Encrypt account secret - pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self { + pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Result { Crypto::with_plain(&*secret, password, iterations) } /// Encrypt custom plain data - pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Self { + pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Result { let salt: [u8; 32] = Random::random(); let iv: [u8; 16] = Random::random(); @@ -93,12 +92,12 @@ impl Crypto { let mut ciphertext: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; plain_len]); // aes-128-ctr with initial vector of iv - crypto::aes::encrypt(&derived_left_bits, &iv, plain, &mut *ciphertext); + crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext)?; // KECCAK(DK[16..31] ++ ), where DK[16..31] - derived_right_bits let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256(); - Crypto { + Ok(Crypto { cipher: Cipher::Aes128Ctr(Aes128Ctr { iv: iv, }), @@ -110,7 +109,7 @@ impl Crypto { prf: Prf::HmacSha256, }), mac: mac, - } + }) } /// Try to decrypt and convert result to account secret @@ -132,13 +131,13 @@ impl Crypto { fn do_decrypt(&self, password: &str, expected_len: usize) -> Result, Error> { let (derived_left_bits, derived_right_bits) = match self.kdf { Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c), - Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r)?, + Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(password, ¶ms.salt, params.n, params.p, params.r)?, }; let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256(); - if subtle::slices_equal(&mac, &self.mac) == 0 { - return Err(Error::InvalidPassword); + if !crypto::is_equal(&mac, &self.mac) { + return Err(Error::InvalidPassword) } let mut plain: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; expected_len]); @@ -149,7 +148,7 @@ impl Crypto { debug_assert!(expected_len >= self.ciphertext.len()); let from = expected_len - self.ciphertext.len(); - crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..]); + crypto::aes::decrypt_128_ctr(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..])?; Ok(plain.into_iter().collect()) }, } @@ -164,7 +163,7 @@ mod tests { #[test] fn crypto_with_secret_create() { let keypair = Random.generate().unwrap(); - let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240); + let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap(); let secret = crypto.secret("this is sparta").unwrap(); assert_eq!(keypair.secret(), &secret); } @@ -172,14 +171,14 @@ mod tests { #[test] fn crypto_with_secret_invalid_password() { let keypair = Random.generate().unwrap(); - let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240); + let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap(); assert_matches!(crypto.secret("this is sparta!"), Err(Error::InvalidPassword)) } #[test] fn crypto_with_null_plain_data() { let original_data = b""; - let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240); + let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap(); let decrypted_data = crypto.decrypt("this is sparta").unwrap(); assert_eq!(original_data[..], *decrypted_data); } @@ -187,7 +186,7 @@ mod tests { #[test] fn crypto_with_tiny_plain_data() { let original_data = b"{}"; - let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240); + let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap(); let decrypted_data = crypto.decrypt("this is sparta").unwrap(); assert_eq!(original_data[..], *decrypted_data); } @@ -195,7 +194,7 @@ mod tests { #[test] fn crypto_with_huge_plain_data() { let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect(); - let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240); + let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240).unwrap(); let decrypted_data = crypto.decrypt("this is sparta").unwrap(); assert_eq!(&original_data, &decrypted_data); } diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 478b796e646..069c997e101 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -14,10 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::{KeyPair, sign, Address, Signature, Message, Public, Secret}; -use crypto::ecdh::agree; -use {json, Error, crypto}; +use ethkey::{self, KeyPair, sign, Address, Signature, Message, Public, Secret}; +use ethkey::crypto::ecdh::agree; +use {json, Error}; use account::Version; +use crypto; use super::crypto::Crypto; /// Account representation. @@ -61,16 +62,16 @@ impl SafeAccount { iterations: u32, name: String, meta: String - ) -> Self { - SafeAccount { + ) -> Result { + Ok(SafeAccount { id: id, version: Version::V3, - crypto: Crypto::with_secret(keypair.secret(), password, iterations), + crypto: Crypto::with_secret(keypair.secret(), password, iterations)?, address: keypair.address(), filename: None, name: name, meta: meta, - } + }) } /// Create a new `SafeAccount` from the given `json`; if it was read from a @@ -114,7 +115,7 @@ impl SafeAccount { meta: Some(self.meta), }; let meta_plain = meta_plain.write().map_err(|e| Error::Custom(format!("{:?}", e)))?; - let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations); + let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations)?; Ok(json::VaultKeyFile { id: self.id.into(), @@ -133,7 +134,7 @@ impl SafeAccount { /// Decrypt a message. pub fn decrypt(&self, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { let secret = self.crypto.secret(password)?; - crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) + ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) } /// Agree on shared key. @@ -154,7 +155,7 @@ impl SafeAccount { let result = SafeAccount { id: self.id.clone(), version: self.version.clone(), - crypto: Crypto::with_secret(&secret, new_password, iterations), + crypto: Crypto::with_secret(&secret, new_password, iterations)?, address: self.address.clone(), filename: self.filename.clone(), name: self.name.clone(), @@ -180,7 +181,7 @@ mod tests { let password = "hello world"; let message = Message::default(); let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240, "Test".to_owned(), "{}".to_owned()); - let signature = account.sign(password, &message).unwrap(); + let signature = account.unwrap().sign(password, &message).unwrap(); assert!(verify_public(keypair.public(), &signature, &message).unwrap()); } @@ -191,7 +192,7 @@ mod tests { let sec_password = "this is sparta"; let i = 10240; let message = Message::default(); - let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned()); + let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned()).unwrap(); let new_account = account.change_password(first_password, sec_password, i).unwrap(); assert!(account.sign(first_password, &message).is_ok()); assert!(account.sign(sec_password, &message).is_err()); diff --git a/ethstore/src/accounts_dir/disk.rs b/ethstore/src/accounts_dir/disk.rs index 14461184406..29b7e524660 100644 --- a/ethstore/src/accounts_dir/disk.rs +++ b/ethstore/src/accounts_dir/disk.rs @@ -319,7 +319,7 @@ mod test { // when let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); - let res = directory.insert(account); + let res = directory.insert(account.unwrap()); // then assert!(res.is_ok(), "Should save account succesfuly."); @@ -339,7 +339,7 @@ mod test { let directory = RootDiskDirectory::create(dir.clone()).unwrap(); // when - let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); + let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()).unwrap(); let filename = "test".to_string(); let dedup = true; @@ -424,7 +424,7 @@ mod test { let keypair = Random.generate().unwrap(); let password = "test pass"; let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); - directory.insert(account).expect("Account should be inserted ok"); + directory.insert(account.unwrap()).expect("Account should be inserted ok"); let new_hash = directory.files_hash().expect("New files hash should be calculated ok"); diff --git a/ethstore/src/accounts_dir/vault.rs b/ethstore/src/accounts_dir/vault.rs index 1ef85402a7a..27052626661 100644 --- a/ethstore/src/accounts_dir/vault.rs +++ b/ethstore/src/accounts_dir/vault.rs @@ -235,7 +235,7 @@ fn check_vault_name(name: &str) -> bool { /// Vault can be empty, but still must be pluggable => we store vault password in separate file fn create_vault_file

(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef { let password_hash = key.password.keccak256(); - let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations); + let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?; let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into(); vault_file_path.push(VAULT_FILE_NAME); diff --git a/ethstore/src/error.rs b/ethstore/src/error.rs index f7e0b0bfadc..7c89473280b 100644 --- a/ethstore/src/error.rs +++ b/ethstore/src/error.rs @@ -16,8 +16,8 @@ use std::fmt; use std::io::Error as IoError; -use ethkey::Error as EthKeyError; -use crypto::Error as EthCryptoError; +use ethkey::{self, Error as EthKeyError}; +use crypto::{self, Error as EthCryptoError}; use ethkey::DerivationError; /// Account-related errors. @@ -49,6 +49,8 @@ pub enum Error { CreationFailed, /// `EthKey` error EthKey(EthKeyError), + /// `ethkey::crypto::Error` + EthKeyCrypto(ethkey::crypto::Error), /// `EthCrypto` error EthCrypto(EthCryptoError), /// Derivation error @@ -73,6 +75,7 @@ impl fmt::Display for Error { Error::VaultNotFound => "Vault not found".into(), Error::CreationFailed => "Account creation failed".into(), Error::EthKey(ref err) => err.to_string(), + Error::EthKeyCrypto(ref err) => err.to_string(), Error::EthCrypto(ref err) => err.to_string(), Error::Derivation(ref err) => format!("Derivation error: {:?}", err), Error::Custom(ref s) => s.clone(), @@ -94,12 +97,30 @@ impl From for Error { } } +impl From for Error { + fn from(err: ethkey::crypto::Error) -> Self { + Error::EthKeyCrypto(err) + } +} + impl From for Error { fn from(err: EthCryptoError) -> Self { Error::EthCrypto(err) } } +impl From for Error { + fn from(err: crypto::error::ScryptError) -> Self { + Error::EthCrypto(err.into()) + } +} + +impl From for Error { + fn from(err: crypto::error::SymmError) -> Self { + Error::EthCrypto(err.into()) + } +} + impl From for Error { fn from(err: DerivationError) -> Self { Error::Derivation(err) diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 40a687fc988..46c81153c78 100644 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -458,7 +458,7 @@ impl SimpleSecretStore for EthMultiStore { fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result { let keypair = KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?; let id: [u8; 16] = Random::random(); - let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned()); + let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned())?; self.import(vault, account) } diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index 75df0953ce4..b558126ada6 100644 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -18,7 +18,6 @@ #![warn(missing_docs)] -extern crate crypto as rcrypto; extern crate dir; extern crate itertools; extern crate libc; @@ -28,7 +27,6 @@ extern crate rustc_hex; extern crate serde; extern crate serde_json; extern crate smallvec; -extern crate subtle; extern crate time; extern crate tiny_keccak; extern crate tempdir; diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index 0c3e72e31b8..555d00c1e98 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -1,11 +1,8 @@ use std::fs; use std::path::Path; -use rcrypto::pbkdf2::pbkdf2; -use rcrypto::sha2::Sha256; -use rcrypto::hmac::Hmac; use json; use ethkey::{Address, Secret, KeyPair}; -use crypto::Keccak256; +use crypto::{Keccak256, pbkdf2}; use {crypto, Error}; /// Pre-sale wallet. @@ -42,12 +39,14 @@ impl PresaleWallet { /// Decrypt the wallet. pub fn decrypt(&self, password: &str) -> Result { - let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes()); - let mut derived_key = vec![0u8; 16]; - pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key); + let mut derived_key = [0u8; 32]; + let salt = pbkdf2::Salt(password.as_bytes()); + let sec = pbkdf2::Secret(password.as_bytes()); + pbkdf2::sha256(2000, salt, sec, &mut derived_key); let mut key = vec![0; self.ciphertext.len()]; - let len = crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)?; + let len = crypto::aes::decrypt_128_cbc(&derived_key[0..16], &self.iv, &self.ciphertext, &mut key) + .map_err(|_| Error::InvalidPassword)?; let unpadded = &key[..len]; let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b8eb5254629..731544a55f2 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -17,7 +17,6 @@ multihash ="0.7" order-stat = "0.1" parking_lot = "0.5" rand = "0.4" -rust-crypto = "0.2" rustc-hex = "1.0" semver = "0.9" serde = "1.0" diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 7b5cc36447c..1fc3d0e2428 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -23,7 +23,6 @@ extern crate futures; extern crate ansi_term; extern crate cid; -extern crate crypto as rust_crypto; extern crate futures_cpupool; extern crate itertools; extern crate multihash; diff --git a/rpc/src/v1/helpers/ipfs.rs b/rpc/src/v1/helpers/ipfs.rs index 80ad1c207b0..da51f1fd549 100644 --- a/rpc/src/v1/helpers/ipfs.rs +++ b/rpc/src/v1/helpers/ipfs.rs @@ -18,21 +18,15 @@ use multihash; use cid::{Cid, Codec, Version}; -use rust_crypto::sha2::Sha256; -use rust_crypto::digest::Digest; +use crypto::digest; use jsonrpc_core::Error; use v1::types::Bytes; use super::errors; /// Compute CIDv0 from protobuf encoded bytes. pub fn cid(content: Bytes) -> Result { - let mut hasher = Sha256::new(); - hasher.input(&content.0); - let len = hasher.output_bytes(); - let mut buf = Vec::with_capacity(len); - buf.resize(len, 0); - hasher.result(&mut buf); - let mh = multihash::encode(multihash::Hash::SHA2256, &buf).map_err(errors::encoding)?; + let hash = digest::sha256(&content.0); + let mh = multihash::encode(multihash::Hash::SHA2256, &*hash).map_err(errors::encoding)?; let cid = Cid::new(Codec::DagProtobuf, Version::V0, &mh); Ok(cid.to_string().into()) } diff --git a/rpc/src/v1/helpers/secretstore.rs b/rpc/src/v1/helpers/secretstore.rs index fbcc167e239..019d2b1051f 100644 --- a/rpc/src/v1/helpers/secretstore.rs +++ b/rpc/src/v1/helpers/secretstore.rs @@ -16,7 +16,7 @@ use std::collections::BTreeSet; use rand::{Rng, OsRng}; -use ethkey::{Public, Secret, Random, Generator, math}; +use ethkey::{self, Public, Secret, Random, Generator, math}; use crypto; use bytes::Bytes; use jsonrpc_core::Error; @@ -36,7 +36,7 @@ pub fn generate_document_key(account_public: Public, server_key_public: Public) let (common_point, encrypted_point) = encrypt_secret(document_key.public(), &server_key_public)?; // ..and now encrypt document key with account public - let encrypted_key = crypto::ecies::encrypt(&account_public, &crypto::DEFAULT_MAC, document_key.public()) + let encrypted_key = ethkey::crypto::ecies::encrypt(&account_public, &crypto::DEFAULT_MAC, document_key.public()) .map_err(errors::encryption)?; Ok(EncryptedDocumentKey { @@ -57,7 +57,7 @@ pub fn encrypt_document(key: Bytes, document: Bytes) -> Result { { let (mut encryption_buffer, iv_buffer) = encrypted_document.split_at_mut(document.len()); - crypto::aes::encrypt(&key, &iv, &document, &mut encryption_buffer); + crypto::aes::encrypt_128_ctr(&key, &iv, &document, &mut encryption_buffer).map_err(errors::encryption)?; iv_buffer.copy_from_slice(&iv); } @@ -78,7 +78,7 @@ pub fn decrypt_document(key: Bytes, mut encrypted_document: Bytes) -> Result = decrypted_secret.decrypt_shadows.unwrap().into_iter() .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap()) .collect(); @@ -1423,7 +1423,7 @@ mod tests { // 4 nodes must be able to recover original secret use crypto::DEFAULT_MAC; - use crypto::ecies::decrypt; + use ethkey::crypto::ecies::decrypt; let result = sessions[0].decrypted_secret().unwrap().unwrap(); assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == Some(Ok(result.clone()))).count()); let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter() diff --git a/secret_store/src/key_server_cluster/io/handshake.rs b/secret_store/src/key_server_cluster/io/handshake.rs index 838e48e1f74..af642956322 100644 --- a/secret_store/src/key_server_cluster/io/handshake.rs +++ b/secret_store/src/key_server_cluster/io/handshake.rs @@ -37,7 +37,7 @@ use std::sync::Arc; use std::collections::BTreeSet; use futures::{Future, Poll, Async}; use tokio_io::{AsyncRead, AsyncWrite}; -use crypto::ecdh::agree; +use ethkey::crypto::ecdh::agree; use ethkey::{Random, Generator, KeyPair, Public, Signature, verify_public, sign, recover}; use ethereum_types::H256; use key_server_cluster::{NodeId, Error, NodeKeyPair}; diff --git a/secret_store/src/key_server_cluster/io/message.rs b/secret_store/src/key_server_cluster/io/message.rs index 784b0b2b6a4..9925b789d24 100644 --- a/secret_store/src/key_server_cluster/io/message.rs +++ b/secret_store/src/key_server_cluster/io/message.rs @@ -19,7 +19,7 @@ use std::u16; use std::ops::Deref; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use serde_json; -use crypto::ecies; +use ethkey::crypto::ecies; use ethkey::{Secret, KeyPair}; use ethkey::math::curve_order; use ethereum_types::{H256, U256}; @@ -306,7 +306,7 @@ pub mod tests { use futures::Poll; use tokio_io::{AsyncRead, AsyncWrite}; use ethkey::{Random, Generator, KeyPair}; - use crypto::ecdh::agree; + use ethkey::crypto::ecdh::agree; use key_server_cluster::Error; use key_server_cluster::message::Message; use super::{MESSAGE_HEADER_SIZE, CURRENT_HEADER_VERSION, MessageHeader, fix_shared_key, encrypt_message, diff --git a/secret_store/src/key_server_cluster/jobs/decryption_job.rs b/secret_store/src/key_server_cluster/jobs/decryption_job.rs index 1f14a484daf..2c11fe0ab36 100644 --- a/secret_store/src/key_server_cluster/jobs/decryption_job.rs +++ b/secret_store/src/key_server_cluster/jobs/decryption_job.rs @@ -17,8 +17,8 @@ use std::collections::{BTreeSet, BTreeMap}; use ethereum_types::H256; use ethkey::{Public, Secret}; -use crypto::ecies::encrypt; use crypto::DEFAULT_MAC; +use ethkey::crypto::ecies::encrypt; use key_server_cluster::{Error, NodeId, DocumentKeyShare, EncryptedDocumentKeyShadow}; use key_server_cluster::math; use key_server_cluster::jobs::job_session::{JobPartialRequestAction, JobPartialResponseAction, JobExecutor}; diff --git a/secret_store/src/node_key_pair.rs b/secret_store/src/node_key_pair.rs index 55c2a8a28a1..428dba6c1a7 100644 --- a/secret_store/src/node_key_pair.rs +++ b/secret_store/src/node_key_pair.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::sync::Arc; -use crypto::ecdh::agree; +use ethkey::crypto::ecdh::agree; use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_address}; use ethcore::account_provider::AccountProvider; use ethereum_types::{H256, Address}; @@ -54,7 +54,8 @@ impl NodeKeyPair for PlainNodeKeyPair { } fn compute_shared_key(&self, peer_public: &Public) -> Result { - agree(self.key_pair.secret(), peer_public).map_err(|e| EthKeyError::Custom(e.into())) + agree(self.key_pair.secret(), peer_public) + .map_err(|e| EthKeyError::Custom(e.to_string())) .and_then(KeyPair::from_secret) } } diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs index 6469585facb..1fceb120e82 100644 --- a/secret_store/src/types/error.rs +++ b/secret_store/src/types/error.rs @@ -168,6 +168,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: ethkey::crypto::Error) -> Self { + Error::EthKey(err.to_string()) + } +} + impl From for Error { fn from(err: kvdb::Error) -> Self { Error::Database(err.to_string()) @@ -176,7 +182,7 @@ impl From for Error { impl From for Error { fn from(err: crypto::Error) -> Self { - Error::EthKey(err.into()) + Error::EthKey(err.to_string()) } } diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 2b390baf75e..5dbf71fa01c 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -34,7 +34,7 @@ use rcrypto::symmetriccipher::*; use rcrypto::buffer::*; use tiny_keccak::Keccak; use bytes::{Buf, BufMut}; -use crypto; +use ethkey::crypto; use network::{Error, ErrorKind}; const ENCRYPTED_HEADER_LEN: usize = 32; diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 37c39eb618e..a203af5b4b4 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -25,7 +25,7 @@ use connection::{Connection}; use node_table::NodeId; use io::{IoContext, StreamToken}; use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; -use crypto::{ecdh, ecies}; +use ethkey::crypto::{ecdh, ecies}; use network::{Error, ErrorKind, HostInfo}; #[derive(PartialEq, Eq, Debug)] diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 48bcf759656..6342bfe4ad6 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -151,8 +151,14 @@ impl From for Error { } } -impl From for Error { - fn from(_err: crypto::Error) -> Self { +impl From for Error { + fn from(_err: ethkey::crypto::Error) -> Self { + ErrorKind::Auth.into() + } +} + +impl From for Error { + fn from(_err: crypto::error::SymmError) -> Self { ErrorKind::Auth.into() } } @@ -168,11 +174,11 @@ fn test_errors() { match *>::from(rlp::DecoderError::RlpIsTooBig).kind() { ErrorKind::Auth => {}, - _ => panic!("Unexpeceted error"), + _ => panic!("Unexpected error"), } - match *>::from(crypto::Error::InvalidMessage).kind() { + match *>::from(ethkey::crypto::Error::InvalidMessage).kind() { ErrorKind::Auth => {}, - _ => panic!("Unexpeceted error"), + _ => panic!("Unexpected error"), } } diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index bd1fc2dbb05..ed370e38a2d 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -17,7 +17,6 @@ mem = { path = "../util/mem" } ordered-float = "0.5" parking_lot = "0.5" rand = "0.4" -ring = "0.12" rlp = { path = "../util/rlp" } serde = "1.0" serde_derive = "1.0" diff --git a/whisper/src/lib.rs b/whisper/src/lib.rs index 4aa1a99b9e6..85ab55e0f46 100644 --- a/whisper/src/lib.rs +++ b/whisper/src/lib.rs @@ -28,7 +28,6 @@ extern crate ordered_float; extern crate parking_lot; extern crate rand; extern crate rlp; -extern crate ring; extern crate serde; extern crate slab; extern crate smallvec; diff --git a/whisper/src/rpc/crypto.rs b/whisper/src/rpc/crypto.rs index 8780045b472..667656d6bf3 100644 --- a/whisper/src/rpc/crypto.rs +++ b/whisper/src/rpc/crypto.rs @@ -16,11 +16,11 @@ //! Encryption schemes supported by RPC layer. -use crypto; +use crypto::aes_gcm::{Encryptor, Decryptor}; +use ethkey::crypto::ecies; use ethereum_types::H256; use ethkey::{self, Public, Secret}; use mem::Memzero; -use ring::aead::{self, AES_256_GCM, SealingKey, OpeningKey}; /// Length of AES key pub const AES_KEY_LEN: usize = 32; @@ -72,38 +72,15 @@ impl EncryptionInstance { } /// Encrypt the supplied plaintext - pub fn encrypt(self, plain: &[u8]) -> Vec { + pub fn encrypt(self, plain: &[u8]) -> Option> { match self.0 { EncryptionInner::AES(key, nonce, encode) => { - let sealing_key = SealingKey::new(&AES_256_GCM, &*key) - .expect("key is of correct len; qed"); - - let encrypt_plain = move |buf: &mut Vec| { - let out_suffix_capacity = AES_256_GCM.tag_len(); - - let prepend_len = buf.len(); - buf.extend(plain); - - buf.resize(prepend_len + plain.len() + out_suffix_capacity, 0); - - let out_size = aead::seal_in_place( - &sealing_key, - &nonce, - &[], // no authenticated data. - &mut buf[prepend_len..], - out_suffix_capacity, - ).expect("key, nonce, buf are valid and out suffix large enough; qed"); - - // truncate to the output size and return. - buf.truncate(prepend_len + out_size); - }; - match encode { AesEncode::AppendedNonce => { - let mut buf = Vec::new(); - encrypt_plain(&mut buf); + let mut enc = Encryptor::aes_256_gcm(&*key).ok()?; + let mut buf = enc.encrypt(&nonce, plain.to_vec()).ok()?; buf.extend(&nonce[..]); - buf + Some(buf) } AesEncode::OnTopics(topics) => { let mut buf = Vec::new(); @@ -111,14 +88,16 @@ impl EncryptionInstance { xor(&mut t.0, &key); buf.extend(&t.0); } - encrypt_plain(&mut buf); - buf + let mut enc = Encryptor::aes_256_gcm(&*key).ok()?; + enc.offset(buf.len()); + buf.extend(plain); + let ciphertext = enc.encrypt(&nonce, buf).ok()?; + Some(ciphertext) } } } EncryptionInner::ECIES(valid_public) => { - crypto::ecies::encrypt(&valid_public, &[], plain) - .expect("validity of public key an invariant of the type; qed") + ecies::encrypt(&valid_public, &[], plain).ok() } } } @@ -169,58 +148,36 @@ impl DecryptionInstance { pub fn decrypt(self, ciphertext: &[u8]) -> Option> { match self.0 { DecryptionInner::AES(extract) => { - let decrypt = | - key: Memzero<[u8; AES_KEY_LEN]>, - nonce: [u8; AES_NONCE_LEN], - ciphertext: &[u8] - | { - if ciphertext.len() < AES_256_GCM.tag_len() { return None } - - let opening_key = OpeningKey::new(&AES_256_GCM, &*key) - .expect("key length is valid for mode; qed"); - - let mut buf = ciphertext.to_vec(); - - // decrypted plaintext always ends up at the - // front of the buffer. - let maybe_decrypted = aead::open_in_place( - &opening_key, - &nonce, - &[], // no authenticated data - 0, // no header. - &mut buf, - ).ok().map(|plain_slice| plain_slice.len()); - - maybe_decrypted.map(move |len| { buf.truncate(len); buf }) - }; - match extract { AesExtract::AppendedNonce(key) => { - if ciphertext.len() < AES_NONCE_LEN { return None } - + if ciphertext.len() < AES_NONCE_LEN { + return None + } // nonce is the suffix of ciphertext. let mut nonce = [0; AES_NONCE_LEN]; let nonce_offset = ciphertext.len() - AES_NONCE_LEN; - nonce.copy_from_slice(&ciphertext[nonce_offset..]); - decrypt(key, nonce, &ciphertext[..nonce_offset]) + Decryptor::aes_256_gcm(&*key).ok()? + .decrypt(&nonce, Vec::from(&ciphertext[..nonce_offset])) + .ok() } AesExtract::OnTopics(num_topics, known_index, known_topic) => { - if ciphertext.len() < num_topics * 32 { return None } - + if ciphertext.len() < num_topics * 32 { + return None + } let mut salted_topic = H256::new(); salted_topic.copy_from_slice(&ciphertext[(known_index * 32)..][..32]); - let key = Memzero::from((salted_topic ^ known_topic).0); - let offset = num_topics * 32; - decrypt(key, BROADCAST_IV, &ciphertext[offset..]) + Decryptor::aes_256_gcm(&*key).ok()? + .decrypt(&BROADCAST_IV, Vec::from(&ciphertext[offset..])) + .ok() } } } DecryptionInner::ECIES(secret) => { // secret is checked for validity, so only fails on invalid message. - crypto::ecies::decrypt(&secret, &[], ciphertext).ok() + ecies::decrypt(&secret, &[], ciphertext).ok() } } } @@ -230,16 +187,6 @@ impl DecryptionInstance { mod tests { use super::*; - #[test] - fn aes_key_len_should_be_equal_to_constant() { - assert_eq!(::ring::aead::AES_256_GCM.key_len(), AES_KEY_LEN); - } - - #[test] - fn aes_nonce_len_should_be_equal_to_constant() { - assert_eq!(::ring::aead::AES_256_GCM.nonce_len(), AES_NONCE_LEN); - } - #[test] fn encrypt_asymmetric() { use ethkey::{Generator, Random}; @@ -247,7 +194,7 @@ mod tests { let key_pair = Random.generate().unwrap(); let test_message = move |message: &[u8]| { let instance = EncryptionInstance::ecies(key_pair.public().clone()).unwrap(); - let ciphertext = instance.encrypt(&message); + let ciphertext = instance.encrypt(&message).unwrap(); if !message.is_empty() { assert!(&ciphertext[..message.len()] != message) @@ -273,7 +220,7 @@ mod tests { let key = Memzero::from(rng.gen::<[u8; 32]>()); let instance = EncryptionInstance::aes(key.clone(), rng.gen()); - let ciphertext = instance.encrypt(message); + let ciphertext = instance.encrypt(message).unwrap(); if !message.is_empty() { assert!(&ciphertext[..message.len()] != message) @@ -303,7 +250,7 @@ mod tests { let key = Memzero::from(rng.gen::<[u8; 32]>()); let instance = EncryptionInstance::broadcast(key, all_topics); - let ciphertext = instance.encrypt(message); + let ciphertext = instance.encrypt(message).unwrap(); if !message.is_empty() { assert!(&ciphertext[..message.len()] != message) diff --git a/whisper/src/rpc/filter.rs b/whisper/src/rpc/filter.rs index 5a192ac04cd..8d125174ed7 100644 --- a/whisper/src/rpc/filter.rs +++ b/whisper/src/rpc/filter.rs @@ -402,7 +402,7 @@ mod tests { sign_with: Some(signing_pair.secret().unwrap()) }).unwrap(); - let encrypted = encryption_instance.encrypt(&payload); + let encrypted = encryption_instance.encrypt(&payload).unwrap(); let message = Message::create(CreateParams { ttl: 100, diff --git a/whisper/src/rpc/key_store.rs b/whisper/src/rpc/key_store.rs index 02781e20adc..1fb4e264ace 100644 --- a/whisper/src/rpc/key_store.rs +++ b/whisper/src/rpc/key_store.rs @@ -25,7 +25,6 @@ use ethereum_types::H256; use ethkey::{KeyPair, Public, Secret}; use mem::Memzero; use rand::{Rng, OsRng}; -use ring::error::Unspecified; use rpc::crypto::{AES_KEY_LEN, EncryptionInstance, DecryptionInstance}; @@ -54,10 +53,8 @@ impl Key { } /// From secret asymmetric key. Fails if secret is invalid. - pub fn from_secret(secret: Secret) -> Result { - KeyPair::from_secret(secret) - .map(Key::Asymmetric) - .map_err(|_| Unspecified) + pub fn from_secret(secret: Secret) -> Option { + KeyPair::from_secret(secret).map(Key::Asymmetric).ok() } /// From raw symmetric key. @@ -179,7 +176,7 @@ mod tests { #[test] fn rejects_invalid_secret() { let bad_secret = ::ethkey::Secret::from([0xff; 32]); - assert!(Key::from_secret(bad_secret).is_err()); + assert!(Key::from_secret(bad_secret).is_none()); } #[test] diff --git a/whisper/src/rpc/mod.rs b/whisper/src/rpc/mod.rs index e9e65770853..7daa3f45590 100644 --- a/whisper/src/rpc/mod.rs +++ b/whisper/src/rpc/mod.rs @@ -226,7 +226,7 @@ impl Whisper for WhisperClien fn add_private_key(&self, private: types::Private) -> Result { let key_pair = Key::from_secret(private.into_inner().into()) - .map_err(|_| whisper_error("Invalid private key"))?; + .ok_or_else(|| whisper_error("Invalid private key"))?; Ok(HexEncode(self.store.write().insert(key_pair))) } @@ -317,7 +317,7 @@ impl Whisper for WhisperClien sign_with: sign_with.as_ref(), }).map_err(whisper_error)?; - encryption.encrypt(&payload) + encryption.encrypt(&payload).ok_or(whisper_error("encryption error"))? }; // mining the packet is the heaviest item of work by far. From f196dc4c355cad59c06251e055bddace94639d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 7 May 2018 11:57:03 +0100 Subject: [PATCH 064/147] ethcore, rpc, machine: refactor block reward application and tracing (#8490) --- ethcore/src/engines/authority_round/mod.rs | 9 ++++-- ethcore/src/engines/block_reward.rs | 34 +++++++++++++++++----- ethcore/src/engines/mod.rs | 2 +- ethcore/src/engines/null_engine.rs | 20 +++++-------- ethcore/src/engines/tendermint/mod.rs | 10 +++++-- ethcore/src/ethereum/ethash.rs | 25 ++++++++-------- ethcore/src/machine.rs | 24 ++++++++++----- ethcore/src/trace/types/trace.rs | 8 +++++ machine/src/lib.rs | 8 ----- rpc/src/v1/types/trace.rs | 8 +++++ 10 files changed, 93 insertions(+), 55 deletions(-) diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 4807d6c3fbb..c2aee7c6efc 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1015,8 +1015,10 @@ impl Engine for AuthorityRound { let author = *block.header().author(); benefactors.push((author, RewardKind::Author)); - let rewards = match self.block_reward_contract { + let rewards: Vec<_> = match self.block_reward_contract { Some(ref c) if block.header().number() >= self.block_reward_contract_transition => { + // NOTE: this logic should be moved to a function when another + // engine needs support for block reward contract. let mut call = |to, data| { let result = self.machine.execute_as_system( block, @@ -1027,10 +1029,11 @@ impl Engine for AuthorityRound { result.map_err(|e| format!("{}", e)) }; - c.reward(&benefactors, &mut call)? + let rewards = c.reward(&benefactors, &mut call)?; + rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect() }, _ => { - benefactors.into_iter().map(|(author, _)| (author, self.block_reward)).collect() + benefactors.into_iter().map(|(author, reward_kind)| (author, reward_kind, self.block_reward)).collect() }, }; diff --git a/ethcore/src/engines/block_reward.rs b/ethcore/src/engines/block_reward.rs index 510a5255f5f..9a9d54e4af1 100644 --- a/ethcore/src/engines/block_reward.rs +++ b/ethcore/src/engines/block_reward.rs @@ -14,13 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! A module with types for declaring block rewards and a client interface for interacting with a +//! block reward contract. + use ethabi; use ethabi::ParamType; use ethereum_types::{H160, Address, U256}; -use block::ExecutedBlock; use error::Error; -use machine::EthereumMachine; +use machine::WithRewards; +use parity_machine::{Machine, WithBalances}; +use trace; use super::SystemCall; use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json"); @@ -37,6 +41,8 @@ pub enum RewardKind { Uncle = 1, /// Reward attributed to the author(s) of empty step(s) included in the block (AuthorityRound engine). EmptyStep = 2, + /// Reward attributed by an external protocol (e.g. block reward contract). + External = 3, } impl From for u16 { @@ -45,6 +51,17 @@ impl From for u16 { } } +impl Into for RewardKind { + fn into(self) -> trace::RewardType { + match self { + RewardKind::Author => trace::RewardType::Block, + RewardKind::Uncle => trace::RewardType::Uncle, + RewardKind::EmptyStep => trace::RewardType::EmptyStep, + RewardKind::External => trace::RewardType::External, + } + } +} + /// A client for the block reward contract. pub struct BlockRewardContract { /// Address of the contract. @@ -112,14 +129,17 @@ impl BlockRewardContract { /// Applies the given block rewards, i.e. adds the given balance to each benefactors' address. /// If tracing is enabled the operations are recorded. -pub fn apply_block_rewards(rewards: &[(Address, U256)], block: &mut ExecutedBlock, machine: &EthereumMachine) -> Result<(), Error> { - use parity_machine::WithBalances; - - for &(ref author, ref block_reward) in rewards { +pub fn apply_block_rewards( + rewards: &[(Address, RewardKind, U256)], + block: &mut M::LiveBlock, + machine: &M, +) -> Result<(), M::Error> { + for &(ref author, _, ref block_reward) in rewards { machine.add_balance(block, author, block_reward)?; } - machine.note_rewards(block, &rewards, &[]) + let rewards: Vec<_> = rewards.into_iter().map(|&(a, k, r)| (a, k.into(), r)).collect(); + machine.note_rewards(block, &rewards) } #[cfg(test)] diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index a17ae356e6f..e019636f53a 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -18,7 +18,6 @@ mod authority_round; mod basic_authority; -mod block_reward; mod instant_seal; mod null_engine; mod signer; @@ -27,6 +26,7 @@ mod transition; mod validator_set; mod vote_collector; +pub mod block_reward; pub mod epoch; pub use self::authority_round::AuthorityRound; diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index f20a9cdfd9d..278eb037c06 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -16,7 +16,9 @@ use ethereum_types::U256; use engines::Engine; +use engines::block_reward::{self, RewardKind}; use header::BlockNumber; +use machine::WithRewards; use parity_machine::{Header, LiveBlock, WithBalances}; /// Params for a null engine. @@ -56,7 +58,7 @@ impl Default for NullEngine { } } -impl Engine for NullEngine { +impl Engine for NullEngine { fn name(&self) -> &str { "NullEngine" } @@ -74,26 +76,20 @@ impl Engine for NullEngine { let n_uncles = LiveBlock::uncles(&*block).len(); + let mut rewards = Vec::new(); + // Bestow block reward let result_block_reward = reward + reward.shr(5) * U256::from(n_uncles); - let mut uncle_rewards = Vec::with_capacity(n_uncles); - - self.machine.add_balance(block, &author, &result_block_reward)?; + rewards.push((author, RewardKind::Author, result_block_reward)); // bestow uncle rewards. for u in LiveBlock::uncles(&*block) { let uncle_author = u.author(); let result_uncle_reward = (reward * U256::from(8 + u.number() - number)).shr(3); - - uncle_rewards.push((*uncle_author, result_uncle_reward)); - } - - for &(ref a, ref reward) in &uncle_rewards { - self.machine.add_balance(block, a, reward)?; + rewards.push((*uncle_author, RewardKind::Uncle, result_uncle_reward)); } - // note and trace. - self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards) + block_reward::apply_block_rewards(&rewards, block, &self.machine) } fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 289beaad0cc..d80a5e182f1 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -41,6 +41,7 @@ use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; +use engines::block_reward::{self, RewardKind}; use io::IoService; use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, SimpleList}; @@ -550,10 +551,13 @@ impl Engine for Tendermint { /// Apply the block reward on finalisation of the block. fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error>{ - use parity_machine::WithBalances; let author = *block.header().author(); - self.machine.add_balance(block, &author, &self.block_reward)?; - self.machine.note_rewards(block, &[(author, self.block_reward)], &[]) + + block_reward::apply_block_rewards( + &[(author, RewardKind::Author, self.block_reward)], + block, + &self.machine, + ) } fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> { diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 09e9caf727b..09151415c87 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -19,6 +19,7 @@ use std::cmp; use std::collections::BTreeMap; use std::sync::Arc; use hash::{KECCAK_EMPTY_LIST_RLP}; +use engines::block_reward::{self, RewardKind}; use ethash::{quick_get_difficulty, slow_hash_block_number, EthashManager, OptimizeFor}; use ethereum_types::{H256, H64, U256, Address}; use unexpected::{OutOfBounds, Mismatch}; @@ -233,11 +234,13 @@ impl Engine for Arc { /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { use std::ops::Shr; - use parity_machine::{LiveBlock, WithBalances}; + use parity_machine::LiveBlock; let author = *LiveBlock::header(&*block).author(); let number = LiveBlock::header(&*block).number(); + let mut rewards = Vec::new(); + // Applies EIP-649 reward. let reward = if number >= self.ethash_params.eip649_transition { self.ethash_params.eip649_reward.unwrap_or(self.ethash_params.block_reward) @@ -253,20 +256,21 @@ impl Engine for Arc { // Bestow block rewards. let mut result_block_reward = reward + reward.shr(5) * U256::from(n_uncles); - let mut uncle_rewards = Vec::with_capacity(n_uncles); if number >= self.ethash_params.mcip3_transition { result_block_reward = self.ethash_params.mcip3_miner_reward; + let ubi_contract = self.ethash_params.mcip3_ubi_contract; let ubi_reward = self.ethash_params.mcip3_ubi_reward; let dev_contract = self.ethash_params.mcip3_dev_contract; let dev_reward = self.ethash_params.mcip3_dev_reward; - self.machine.add_balance(block, &author, &result_block_reward)?; - self.machine.add_balance(block, &ubi_contract, &ubi_reward)?; - self.machine.add_balance(block, &dev_contract, &dev_reward)?; + rewards.push((author, RewardKind::Author, result_block_reward)); + rewards.push((ubi_contract, RewardKind::External, ubi_reward)); + rewards.push((dev_contract, RewardKind::External, dev_reward)); + } else { - self.machine.add_balance(block, &author, &result_block_reward)?; + rewards.push((author, RewardKind::Author, result_block_reward)); } // Bestow uncle rewards. @@ -278,15 +282,10 @@ impl Engine for Arc { reward.shr(5) }; - uncle_rewards.push((*uncle_author, result_uncle_reward)); - } - - for &(ref a, ref reward) in &uncle_rewards { - self.machine.add_balance(block, a, reward)?; + rewards.push((*uncle_author, RewardKind::Uncle, result_uncle_reward)); } - // Note and trace. - self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards) + block_reward::apply_block_rewards(&rewards, block, &self.machine) } fn verify_local_seal(&self, header: &Header) -> Result<(), Error> { diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index e3bf7d340ca..4aa72b50d92 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -437,22 +437,30 @@ impl ::parity_machine::WithBalances for EthereumMachine { fn add_balance(&self, live: &mut ExecutedBlock, address: &Address, amount: &U256) -> Result<(), Error> { live.state_mut().add_balance(address, amount, CleanupMode::NoEmpty).map_err(Into::into) } +} + +/// A state machine that uses block rewards. +pub trait WithRewards: ::parity_machine::Machine { + /// Note block rewards, traces each reward storing information about benefactor, amount and type + /// of reward. + fn note_rewards( + &self, + live: &mut Self::LiveBlock, + rewards: &[(Address, RewardType, U256)], + ) -> Result<(), Self::Error>; +} +impl WithRewards for EthereumMachine { fn note_rewards( &self, live: &mut Self::LiveBlock, - direct: &[(Address, U256)], - indirect: &[(Address, U256)], + rewards: &[(Address, RewardType, U256)], ) -> Result<(), Self::Error> { if let Tracing::Enabled(ref mut traces) = *live.traces_mut() { let mut tracer = ExecutiveTracer::default(); - for &(address, amount) in direct { - tracer.trace_reward(address, amount, RewardType::Block); - } - - for &(address, amount) in indirect { - tracer.trace_reward(address, amount, RewardType::Uncle); + for &(address, ref reward_type, amount) in rewards { + tracer.trace_reward(address, amount, reward_type.clone()); } traces.push(tracer.drain().into()); diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index 06f24efac38..cdb00a52294 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -141,6 +141,10 @@ pub enum RewardType { Block, /// Uncle Uncle, + /// Empty step (AuthorityRound) + EmptyStep, + /// A reward directly attributed by an external protocol (e.g. block reward contract) + External, } impl Encodable for RewardType { @@ -148,6 +152,8 @@ impl Encodable for RewardType { let v = match *self { RewardType::Block => 0u32, RewardType::Uncle => 1, + RewardType::EmptyStep => 2, + RewardType::External => 3, }; Encodable::rlp_append(&v, s); } @@ -158,6 +164,8 @@ impl Decodable for RewardType { rlp.as_val().and_then(|v| Ok(match v { 0u32 => RewardType::Block, 1 => RewardType::Uncle, + 2 => RewardType::EmptyStep, + 3 => RewardType::External, _ => return Err(DecoderError::Custom("Invalid value of RewardType item")), })) } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 3a45c38d2ef..54ee403d954 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -106,12 +106,4 @@ pub trait WithBalances: Machine { /// Increment the balance of an account in the state of the live block. fn add_balance(&self, live: &mut Self::LiveBlock, address: &Address, amount: &U256) -> Result<(), Self::Error>; - - /// Note block rewards. "direct" rewards are for authors, "indirect" are for e.g. uncles. - fn note_rewards( - &self, - _live: &mut Self::LiveBlock, - _direct: &[(Address, U256)], - _indirect: &[(Address, U256)], - ) -> Result<(), Self::Error> { Ok(()) } } diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index a984c64ba80..6eb222f5e63 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -308,6 +308,12 @@ pub enum RewardType { /// Uncle #[serde(rename="uncle")] Uncle, + /// EmptyStep (AuthorityRound) + #[serde(rename="emptyStep")] + EmptyStep, + /// External (attributed as part of an external protocol) + #[serde(rename="external")] + External, } impl From for RewardType { @@ -315,6 +321,8 @@ impl From for RewardType { match c { trace::RewardType::Block => RewardType::Block, trace::RewardType::Uncle => RewardType::Uncle, + trace::RewardType::EmptyStep => RewardType::EmptyStep, + trace::RewardType::External => RewardType::External, } } } From e952e0f01875340c3ed1470181f83d9da68aeef0 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 7 May 2018 18:58:25 +0800 Subject: [PATCH 065/147] Keep all enacted blocks notify in order (#8524) * Keep all enacted blocks notify in order * Collect is unnecessary * Update ChainNotify to use ChainRouteType * Fix all ethcore fn defs * Wrap the type within ChainRoute * Fix private-tx and sync api * Fix secret_store API * Fix updater API * Fix rpc api * Fix informant api * Eagerly cache enacted/retracted and remove contain_enacted/retracted * Fix indent * tests: should use full expr form for struct constructor * Use into_enacted_retracted to further avoid copy * typo: not a function * rpc/tests: ChainRoute -> ChainRoute::new --- ethcore/private-tx/src/lib.rs | 4 +- ethcore/src/blockchain/import_route.rs | 2 +- ethcore/src/client/chain_notify.rs | 88 ++++++++++++++++++- ethcore/src/client/client.rs | 49 +++-------- ethcore/src/client/mod.rs | 2 +- ethcore/src/snapshot/watcher.rs | 10 +-- ethcore/sync/src/api.rs | 9 +- ethcore/sync/src/tests/helpers.rs | 7 +- parity/informant.rs | 4 +- rpc/src/v1/impls/eth_pubsub.rs | 49 ++++++----- rpc/src/v1/tests/mocked/eth_pubsub.rs | 10 +-- secret_store/src/acl_storage.rs | 6 +- secret_store/src/key_server_set.rs | 6 +- .../src/listener/service_contract_listener.rs | 6 +- updater/src/updater.rs | 4 +- 15 files changed, 158 insertions(+), 98 deletions(-) diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 26a31fc7ae3..723d4918298 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -79,7 +79,7 @@ use ethcore::executed::{Executed}; use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction}; use ethcore::{contract_address as ethcore_contract_address}; use ethcore::client::{ - Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, CallContract + Client, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage, BlockId, CallContract }; use ethcore::account_provider::AccountProvider; use ethcore::miner::{self, Miner, MinerService}; @@ -668,7 +668,7 @@ fn find_account_password(passwords: &Vec, account_provider: &AccountProv } impl ChainNotify for Provider { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !imported.is_empty() { trace!("New blocks imported, try to prune the queue"); if let Err(err) = self.process_queue() { diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs index cf5d3ca1e78..080d3b06824 100644 --- a/ethcore/src/blockchain/import_route.rs +++ b/ethcore/src/blockchain/import_route.rs @@ -20,7 +20,7 @@ use ethereum_types::H256; use blockchain::block_info::{BlockInfo, BlockLocation}; /// Import route for newly inserted block. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub struct ImportRoute { /// Blocks that were invalidated by new block. pub retracted: Vec, diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index a1f84d2a139..8330fb40d9e 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -17,7 +17,9 @@ use bytes::Bytes; use ethereum_types::H256; use transaction::UnverifiedTransaction; +use blockchain::ImportRoute; use std::time::Duration; +use std::collections::HashMap; /// Messages to broadcast via chain pub enum ChainMessageType { @@ -29,6 +31,89 @@ pub enum ChainMessageType { SignedPrivateTransaction(Vec), } +/// Route type to indicate whether it is enacted or retracted. +#[derive(Clone)] +pub enum ChainRouteType { + /// Enacted block + Enacted, + /// Retracted block + Retracted +} + +/// A complete chain enacted retracted route. +#[derive(Default, Clone)] +pub struct ChainRoute { + route: Vec<(H256, ChainRouteType)>, + enacted: Vec, + retracted: Vec, +} + +impl<'a> From<&'a [ImportRoute]> for ChainRoute { + fn from(import_results: &'a [ImportRoute]) -> ChainRoute { + ChainRoute::new(import_results.iter().flat_map(|route| { + route.retracted.iter().map(|h| (*h, ChainRouteType::Retracted)) + .chain(route.enacted.iter().map(|h| (*h, ChainRouteType::Enacted))) + }).collect()) + } +} + +impl ChainRoute { + /// Create a new ChainRoute based on block hash and route type pairs. + pub fn new(route: Vec<(H256, ChainRouteType)>) -> Self { + let (enacted, retracted) = Self::to_enacted_retracted(&route); + + Self { route, enacted, retracted } + } + + /// Gather all non-duplicate enacted and retracted blocks. + fn to_enacted_retracted(route: &[(H256, ChainRouteType)]) -> (Vec, Vec) { + fn map_to_vec(map: Vec<(H256, bool)>) -> Vec { + map.into_iter().map(|(k, _v)| k).collect() + } + + // Because we are doing multiple inserts some of the blocks that were enacted in import `k` + // could be retracted in import `k+1`. This is why to understand if after all inserts + // the block is enacted or retracted we iterate over all routes and at the end final state + // will be in the hashmap + let map = route.iter().fold(HashMap::new(), |mut map, route| { + match &route.1 { + &ChainRouteType::Enacted => { + map.insert(route.0, true); + }, + &ChainRouteType::Retracted => { + map.insert(route.0, false); + }, + } + map + }); + + // Split to enacted retracted (using hashmap value) + let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v); + // And convert tuples to keys + (map_to_vec(enacted), map_to_vec(retracted)) + } + + /// Consume route and return the enacted retracted form. + pub fn into_enacted_retracted(self) -> (Vec, Vec) { + (self.enacted, self.retracted) + } + + /// All non-duplicate enacted blocks. + pub fn enacted(&self) -> &[H256] { + &self.enacted + } + + /// All non-duplicate retracted blocks. + pub fn retracted(&self) -> &[H256] { + &self.retracted + } + + /// All blocks in the route. + pub fn route(&self) -> &[(H256, ChainRouteType)] { + &self.route + } +} + /// Represents what has to be handled by actor listening to chain events pub trait ChainNotify : Send + Sync { /// fires when chain has new blocks. @@ -36,8 +121,7 @@ pub trait ChainNotify : Send + Sync { &self, _imported: Vec, _invalid: Vec, - _enacted: Vec, - _retracted: Vec, + _route: ChainRoute, _sealed: Vec, // Block bytes. _proposed: Vec, diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a37d62a5911..8119ebd35f6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::{HashSet, HashMap, BTreeMap, BTreeSet, VecDeque}; +use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; @@ -45,7 +45,7 @@ use client::{ use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, - ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType + ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType }; use encoded; use engines::{EthEngine, EpochTransition}; @@ -245,32 +245,6 @@ impl Importer { }) } - fn calculate_enacted_retracted(&self, import_results: &[ImportRoute]) -> (Vec, Vec) { - fn map_to_vec(map: Vec<(H256, bool)>) -> Vec { - map.into_iter().map(|(k, _v)| k).collect() - } - - // In ImportRoute we get all the blocks that have been enacted and retracted by single insert. - // Because we are doing multiple inserts some of the blocks that were enacted in import `k` - // could be retracted in import `k+1`. This is why to understand if after all inserts - // the block is enacted or retracted we iterate over all routes and at the end final state - // will be in the hashmap - let map = import_results.iter().fold(HashMap::new(), |mut map, route| { - for hash in &route.enacted { - map.insert(hash.clone(), true); - } - for hash in &route.retracted { - map.insert(hash.clone(), false); - } - map - }); - - // Split to enacted retracted (using hashmap value) - let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v); - // And convert tuples to keys - (map_to_vec(enacted), map_to_vec(retracted)) - } - /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self, client: &Client) -> usize { @@ -336,18 +310,17 @@ impl Importer { { if !imported_blocks.is_empty() && is_empty { - let (enacted, retracted) = self.calculate_enacted_retracted(&import_results); + let route = ChainRoute::from(import_results.as_ref()); if is_empty { - self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, &enacted, &retracted, false); + self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, route.enacted(), route.retracted(), false); } client.notify(|notify| { notify.new_blocks( imported_blocks.clone(), invalid_blocks.clone(), - enacted.clone(), - retracted.clone(), + route.clone(), Vec::new(), proposed_blocks.clone(), duration, @@ -1421,7 +1394,7 @@ impl ImportBlock for Client { } fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { - let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; + let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; { // check block order if self.chain.read().is_known(&header.hash()) { @@ -2155,14 +2128,13 @@ impl ImportSealedBlock for Client { self.state_db.write().sync_cache(&route.enacted, &route.retracted, false); route }; - let (enacted, retracted) = self.importer.calculate_enacted_retracted(&[route]); - self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted, true); + let route = ChainRoute::from([route].as_ref()); + self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), true); self.notify(|notify| { notify.new_blocks( vec![h.clone()], vec![], - enacted.clone(), - retracted.clone(), + route.clone(), vec![h.clone()], vec![], start.elapsed(), @@ -2180,8 +2152,7 @@ impl BroadcastProposalBlock for Client { notify.new_blocks( vec![], vec![], - vec![], - vec![], + ChainRoute::default(), vec![], vec![block.rlp_bytes()], DURATION_ZERO, diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 1e4ccba585f..05e2018258f 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -31,7 +31,7 @@ pub use self::error::Error; pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; pub use self::io_message::ClientIoMessage; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; -pub use self::chain_notify::{ChainNotify, ChainMessageType}; +pub use self::chain_notify::{ChainNotify, ChainRoute, ChainRouteType, ChainMessageType}; pub use self::traits::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter diff --git a/ethcore/src/snapshot/watcher.rs b/ethcore/src/snapshot/watcher.rs index 936feaefba8..6e04fe6d16d 100644 --- a/ethcore/src/snapshot/watcher.rs +++ b/ethcore/src/snapshot/watcher.rs @@ -17,7 +17,7 @@ //! Watcher for snapshot-related chain events. use parking_lot::Mutex; -use client::{BlockInfo, Client, ChainNotify, ClientIoMessage}; +use client::{BlockInfo, Client, ChainNotify, ChainRoute, ClientIoMessage}; use ids::BlockId; use io::IoChannel; @@ -103,8 +103,7 @@ impl ChainNotify for Watcher { &self, imported: Vec, _: Vec, - _: Vec, - _: Vec, + _: ChainRoute, _: Vec, _: Vec, _duration: Duration) @@ -131,7 +130,7 @@ impl ChainNotify for Watcher { mod tests { use super::{Broadcast, Oracle, Watcher}; - use client::ChainNotify; + use client::{ChainNotify, ChainRoute}; use ethereum_types::{H256, U256}; @@ -174,8 +173,7 @@ mod tests { watcher.new_blocks( hashes, vec![], - vec![], - vec![], + ChainRoute::default(), vec![], vec![], DURATION_ZERO, diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 5e96f11cf37..7690eeb864b 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -25,7 +25,7 @@ use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, Protocol use ethereum_types::{H256, H512, U256}; use io::{TimerToken}; use ethcore::ethstore::ethkey::Secret; -use ethcore::client::{BlockChainClient, ChainNotify, ChainMessageType}; +use ethcore::client::{BlockChainClient, ChainNotify, ChainRoute, ChainMessageType}; use ethcore::snapshot::SnapshotService; use ethcore::header::BlockNumber; use sync_io::NetSyncIo; @@ -409,8 +409,7 @@ impl ChainNotify for EthSync { fn new_blocks(&self, imported: Vec, invalid: Vec, - enacted: Vec, - retracted: Vec, + route: ChainRoute, sealed: Vec, proposed: Vec, _duration: Duration) @@ -424,8 +423,8 @@ impl ChainNotify for EthSync { &mut sync_io, &imported, &invalid, - &enacted, - &retracted, + route.enacted(), + route.retracted(), &sealed, &proposed); }); diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 54467adb775..dc52fdd8b85 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -23,7 +23,7 @@ use bytes::Bytes; use network::{self, PeerId, ProtocolId, PacketId, SessionInfo}; use tests::snapshot::*; use ethcore::client::{TestBlockChainClient, BlockChainClient, Client as EthcoreClient, - ClientConfig, ChainNotify, ChainMessageType, ClientIoMessage}; + ClientConfig, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage}; use ethcore::header::BlockNumber; use ethcore::snapshot::SnapshotService; use ethcore::spec::Spec; @@ -535,12 +535,13 @@ impl ChainNotify for EthPeer { fn new_blocks(&self, imported: Vec, invalid: Vec, - enacted: Vec, - retracted: Vec, + route: ChainRoute, sealed: Vec, proposed: Vec, _duration: Duration) { + let (enacted, retracted) = route.into_enacted_retracted(); + self.new_blocks_queue.write().push_back(NewBlockMessage { imported, invalid, diff --git a/parity/informant.rs b/parity/informant.rs index 5c2e0ab89d3..beeb258b522 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -25,7 +25,7 @@ use std::time::{Instant, Duration}; use atty; use ethcore::client::{ BlockId, BlockChainClient, ChainInfo, BlockInfo, BlockChainInfo, - BlockQueueInfo, ChainNotify, ClientReport, Client, ClientIoMessage + BlockQueueInfo, ChainNotify, ChainRoute, ClientReport, Client, ClientIoMessage }; use ethcore::header::BlockNumber; use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; @@ -351,7 +351,7 @@ impl Informant { } impl ChainNotify for Informant { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, duration: Duration) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _route: ChainRoute, _sealed: Vec, _proposed: Vec, duration: Duration) { let mut last_import = self.last_import.lock(); let client = &self.target.client; diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index 1a872f5600a..30459594466 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -34,7 +34,7 @@ use v1::types::{pubsub, RichHeader, Log}; use ethcore::encoded; use ethcore::filter::Filter as EthFilter; -use ethcore::client::{BlockChainClient, ChainNotify, BlockId}; +use ethcore::client::{BlockChainClient, ChainNotify, ChainRoute, ChainRouteType, BlockId}; use sync::LightSync; use light::cache::Cache; use light::on_demand::OnDemand; @@ -141,19 +141,20 @@ impl ChainNotificationHandler { } } - fn notify_logs(&self, enacted: &[H256], logs: F) where - F: Fn(EthFilter) -> T, + fn notify_logs(&self, enacted: &[(H256, Ex)], logs: F) where + F: Fn(EthFilter, &Ex) -> T, + Ex: Send, T: IntoFuture, Error = Error>, T::Future: Send + 'static, { for &(ref subscriber, ref filter) in self.logs_subscribers.read().values() { let logs = futures::future::join_all(enacted .iter() - .map(|hash| { + .map(|&(hash, ref ex)| { let mut filter = filter.clone(); - filter.from_block = BlockId::Hash(*hash); + filter.from_block = BlockId::Hash(hash); filter.to_block = filter.from_block.clone(); - logs(filter).into_future() + logs(filter, ex).into_future() }) .collect::>() ); @@ -214,7 +215,7 @@ impl LightChainNotify for ChainNotificationHandler { .collect::>(); self.notify_heads(&headers); - self.notify_logs(&enacted, |filter| self.client.logs(filter)) + self.notify_logs(&enacted.iter().map(|h| (*h, ())).collect::>(), |filter, _| self.client.logs(filter)) } } @@ -223,17 +224,21 @@ impl ChainNotify for ChainNotificationHandler { &self, _imported: Vec, _invalid: Vec, - enacted: Vec, - retracted: Vec, + route: ChainRoute, _sealed: Vec, // Block bytes. _proposed: Vec, _duration: Duration, ) { const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; - let headers = enacted + let headers = route.route() .iter() - .filter_map(|hash| self.client.block_header(BlockId::Hash(*hash))) + .filter_map(|&(hash, ref typ)| { + match typ { + &ChainRouteType::Retracted => None, + &ChainRouteType::Enacted => self.client.block_header(BlockId::Hash(hash)) + } + }) .map(|header| { let hash = header.hash(); (header, self.client.block_extra_info(BlockId::Hash(hash)).expect(EXTRA_INFO_PROOF)) @@ -243,17 +248,17 @@ impl ChainNotify for ChainNotificationHandler { // Headers self.notify_heads(&headers); - // Enacted logs - self.notify_logs(&enacted, |filter| { - Ok(self.client.logs(filter).into_iter().map(Into::into).collect()) - }); - - // Retracted logs - self.notify_logs(&retracted, |filter| { - Ok(self.client.logs(filter).into_iter().map(Into::into).map(|mut log: Log| { - log.log_type = "removed".into(); - log - }).collect()) + // We notify logs enacting and retracting as the order in route. + self.notify_logs(route.route(), |filter, ex| { + match ex { + &ChainRouteType::Enacted => + Ok(self.client.logs(filter).into_iter().map(Into::into).collect()), + &ChainRouteType::Retracted => + Ok(self.client.logs(filter).into_iter().map(Into::into).map(|mut log: Log| { + log.log_type = "removed".into(); + log + }).collect()), + } }); } } diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index fb28ba31274..936695a9a13 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -24,7 +24,7 @@ use std::time::Duration; use v1::{EthPubSub, EthPubSubClient, Metadata}; -use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify}; +use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify, ChainRoute, ChainRouteType}; use parity_reactor::EventLoop; const DURATION_ZERO: Duration = Duration::from_millis(0); @@ -57,13 +57,13 @@ fn should_subscribe_to_new_heads() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x1","extraData":"0x","gasLimit":"0xf4240","gasUsed":"0x0","hash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","number":"0x1","parentHash":"0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x1c9","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","timestamp":"0x0","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); // Notify about two blocks - handler.new_blocks(vec![], vec![], vec![h2, h3], vec![], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h2, ChainRouteType::Enacted), (h3, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO); // Receive both let (res, receiver) = receiver.into_future().wait().unwrap(); @@ -129,7 +129,7 @@ fn should_subscribe_to_logs() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications (enacted) - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) @@ -137,7 +137,7 @@ fn should_subscribe_to_logs() { assert_eq!(res, Some(response.into())); // Check notifications (retracted) - handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Retracted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 50414eff26c..b3427fa1b20 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use std::collections::{HashMap, HashSet}; use std::time::Duration; use parking_lot::{Mutex, RwLock}; -use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; +use ethcore::client::{BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo}; use ethereum_types::{H256, Address}; use bytes::Bytes; use trusted_client::TrustedClient; @@ -76,8 +76,8 @@ impl AclStorage for OnChainAclStorage { } impl ChainNotify for OnChainAclStorage { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { - if !enacted.is_empty() || !retracted.is_empty() { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { + if !route.enacted().is_empty() || !route.retracted().is_empty() { self.contract.lock().update() } } diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index 25651bb4cad..d13017261c4 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -19,7 +19,7 @@ use std::net::SocketAddr; use std::collections::{BTreeMap, HashSet}; use std::time::Duration; use parking_lot::Mutex; -use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, CallContract, RegistryInfo}; +use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo}; use ethcore::filter::Filter; use ethkey::public_to_address; use hash::keccak; @@ -163,7 +163,9 @@ impl KeyServerSet for OnChainKeyServerSet { } impl ChainNotify for OnChainKeyServerSet { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { + let (enacted, retracted) = route.into_enacted_retracted(); + if !enacted.is_empty() || !retracted.is_empty() { self.contract.lock().update(enacted, retracted) } diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 0e273b3eeee..214235210fa 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -20,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; use std::thread; use parking_lot::Mutex; -use ethcore::client::ChainNotify; +use ethcore::client::{ChainNotify, ChainRoute}; use ethkey::{Public, public_to_address}; use bytes::Bytes; use ethereum_types::{H256, U256, Address}; @@ -428,8 +428,8 @@ impl Drop for ServiceContractListener { } impl ChainNotify for ServiceContractListener { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { - let enacted_len = enacted.len(); + fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { + let enacted_len = route.enacted().len(); if enacted_len == 0 { return; } diff --git a/updater/src/updater.rs b/updater/src/updater.rs index c5f45c7658a..f8a98f3b0f4 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -28,7 +28,7 @@ use target_info::Target; use bytes::Bytes; use ethcore::BlockNumber; use ethcore::filter::Filter; -use ethcore::client::{BlockId, BlockChainClient, ChainNotify}; +use ethcore::client::{BlockId, BlockChainClient, ChainNotify, ChainRoute}; use ethereum_types::H256; use sync::{SyncProvider}; use hash_fetch::{self as fetch, HashFetch}; @@ -660,7 +660,7 @@ impl Updater, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, _route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { match (self.client.upgrade(), self.sync.as_ref().and_then(Weak::upgrade)) { (Some(ref c), Some(ref s)) if !s.status().is_syncing(c.queue_info()) => self.poll(), _ => {}, From 63f2b4c9fe3e4823a27a1d74c77671b0e3ab9a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 7 May 2018 12:11:12 +0100 Subject: [PATCH 066/147] Node table sorting according to last contact data (#8541) * network-devp2p: sort nodes in node table using last contact data * network-devp2p: rename node contact types in node table json output * network-devp2p: fix node table tests * network-devp2p: note node failure when failed to establish connection * network-devp2p: handle UselessPeer error * network-devp2p: note failure when marking node as useless --- util/network-devp2p/src/host.rs | 28 +++- util/network-devp2p/src/node_table.rs | 230 +++++++++++++++++++------- 2 files changed, 188 insertions(+), 70 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 73ca2aca4bd..2de9a1884c8 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -105,10 +105,13 @@ pub struct NetworkContext<'s> { impl<'s> NetworkContext<'s> { /// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler. - fn new(io: &'s IoContext, + fn new( + io: &'s IoContext, protocol: ProtocolId, - session: Option, sessions: Arc>>, - reserved_peers: &'s HashSet) -> NetworkContext<'s> { + session: Option, + sessions: Arc>>, + reserved_peers: &'s HashSet, + ) -> NetworkContext<'s> { let id = session.as_ref().map(|s| s.lock().token()); NetworkContext { io: io, @@ -585,10 +588,8 @@ impl Host { let address = { let mut nodes = self.nodes.write(); if let Some(node) = nodes.get_mut(id) { - node.attempts += 1; node.endpoint.address - } - else { + } else { debug!(target: "network", "Connection to expired node aborted"); return; } @@ -600,6 +601,7 @@ impl Host { }, Err(e) => { debug!(target: "network", "{}: Can't connect to address {:?}: {:?}", id, address, e); + self.nodes.write().note_failure(&id); return; } } @@ -685,10 +687,12 @@ impl Host { Err(e) => { let s = session.lock(); trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); - if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() { + if let ErrorKind::Disconnect(DisconnectReason::UselessPeer) = *e.kind() { if let Some(id) = s.id() { if !self.reserved_nodes.read().contains(id) { - self.nodes.write().mark_as_useless(id); + let mut nodes = self.nodes.write(); + nodes.note_failure(&id); + nodes.mark_as_useless(id); } } } @@ -754,6 +758,10 @@ impl Host { } } } + + // Note connection success + self.nodes.write().note_success(&id); + for (p, _) in self.handlers.read().iter() { if s.have_capability(*p) { ready_data.push(*p); @@ -1024,7 +1032,9 @@ impl IoHandler for Host { if let Some(session) = session { session.lock().disconnect(io, DisconnectReason::DisconnectRequested); if let Some(id) = session.lock().id() { - self.nodes.write().mark_as_useless(id) + let mut nodes = self.nodes.write(); + nodes.note_failure(&id); + nodes.mark_as_useless(id); } } trace!(target: "network", "Disabling peer {}", peer); diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index fd18c10a12c..5079455866c 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -21,6 +21,8 @@ use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, use std::path::PathBuf; use std::str::FromStr; use std::{fs, mem, slice}; +use std::time::{self, Duration, SystemTime}; +use rand::{self, Rng}; use ethereum_types::H512; use rlp::{Rlp, RlpStream, DecoderError}; use network::{Error, ErrorKind, AllowIP, IpFilter}; @@ -128,40 +130,64 @@ impl FromStr for NodeEndpoint { } } -#[derive(PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum PeerType { _Required, Optional } +/// A type for representing an interaction (contact) with a node at a given time +/// that was either a success or a failure. +#[derive(Clone, Copy, Debug)] +pub enum NodeContact { + Success(SystemTime), + Failure(SystemTime), +} + +impl NodeContact { + fn success() -> NodeContact { + NodeContact::Success(SystemTime::now()) + } + + fn failure() -> NodeContact { + NodeContact::Failure(SystemTime::now()) + } + + fn time(&self) -> SystemTime { + match *self { + NodeContact::Success(t) | NodeContact::Failure(t) => t + } + } + + /// Filters and old contact, returning `None` if it happened longer than a + /// week ago. + fn recent(&self) -> Option<&NodeContact> { + let t = self.time(); + if let Ok(d) = t.elapsed() { + if d < Duration::from_secs(60 * 60 * 24 * 7) { + return Some(self); + } + } + + None + } +} + +#[derive(Debug)] pub struct Node { pub id: NodeId, pub endpoint: NodeEndpoint, pub peer_type: PeerType, - pub attempts: u32, - pub failures: u32, + pub last_contact: Option, } -const DEFAULT_FAILURE_PERCENTAGE: usize = 50; - impl Node { pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { Node { id: id, endpoint: endpoint, peer_type: PeerType::Optional, - attempts: 0, - failures: 0, - } - } - - /// Returns the node's failure percentage (0..100) in buckets of 5%. If there are 0 connection attempts for this - /// node the default failure percentage is returned (50%). - pub fn failure_percentage(&self) -> usize { - if self.attempts == 0 { - DEFAULT_FAILURE_PERCENTAGE - } else { - (self.failures * 100 / self.attempts / 5 * 5) as usize + last_contact: None, } } } @@ -191,8 +217,7 @@ impl FromStr for Node { id: id, endpoint: endpoint, peer_type: PeerType::Optional, - attempts: 0, - failures: 0, + last_contact: None, }) } } @@ -231,28 +256,61 @@ impl NodeTable { /// Add a node to table pub fn add_node(&mut self, mut node: Node) { - // preserve attempts and failure counter - let (attempts, failures) = - self.nodes.get(&node.id).map_or((0, 0), |n| (n.attempts, n.failures)); - - node.attempts = attempts; - node.failures = failures; - + // preserve node last_contact + node.last_contact = self.nodes.get(&node.id).and_then(|n| n.last_contact); self.nodes.insert(node.id.clone(), node); } + /// Returns a list of ordered nodes according to their most recent contact + /// and filtering useless nodes. The algorithm for creating the sorted nodes + /// is: + /// - Contacts that aren't recent (older than 1 week) are discarded + /// - (1) Nodes with a successful contact are ordered (most recent success first) + /// - (2) Nodes with unknown contact (older than 1 week or new nodes) are randomly shuffled + /// - (3) Nodes with a failed contact are ordered (oldest failure first) + /// - The final result is the concatenation of (1), (2) and (3) fn ordered_entries(&self) -> Vec<&Node> { - let mut refs: Vec<&Node> = self.nodes.values() - .filter(|n| !self.useless_nodes.contains(&n.id)) - .collect(); + let mut success = Vec::new(); + let mut failures = Vec::new(); + let mut unknown = Vec::new(); + + let nodes = self.nodes.values() + .filter(|n| !self.useless_nodes.contains(&n.id)); + + for node in nodes { + // discard contact points older that aren't recent + match node.last_contact.as_ref().and_then(|c| c.recent()) { + Some(&NodeContact::Success(_)) => { + success.push(node); + }, + Some(&NodeContact::Failure(_)) => { + failures.push(node); + }, + None => { + unknown.push(node); + }, + } + } - refs.sort_by(|a, b| { - a.failure_percentage().cmp(&b.failure_percentage()) - .then_with(|| a.failures.cmp(&b.failures)) - .then_with(|| b.attempts.cmp(&a.attempts)) // we use reverse ordering for number of attempts + success.sort_by(|a, b| { + let a = a.last_contact.expect("vector only contains values with defined last_contact; qed"); + let b = b.last_contact.expect("vector only contains values with defined last_contact; qed"); + // inverse ordering, most recent successes come first + b.time().cmp(&a.time()) }); - refs + failures.sort_by(|a, b| { + let a = a.last_contact.expect("vector only contains values with defined last_contact; qed"); + let b = b.last_contact.expect("vector only contains values with defined last_contact; qed"); + // normal ordering, most distant failures come first + a.time().cmp(&b.time()) + }); + + rand::thread_rng().shuffle(&mut unknown); + + success.append(&mut unknown); + success.append(&mut failures); + success } /// Returns node ids sorted by failure percentage, for nodes with the same failure percentage the absolute number of @@ -296,10 +354,17 @@ impl NodeTable { } } - /// Increase failure counte for a node + /// Set last contact as failure for a node pub fn note_failure(&mut self, id: &NodeId) { if let Some(node) = self.nodes.get_mut(id) { - node.failures += 1; + node.last_contact = Some(NodeContact::failure()); + } + } + + /// Set last contact as success for a node + pub fn note_success(&mut self, id: &NodeId) { + if let Some(node) = self.nodes.get_mut(id) { + node.last_contact = Some(NodeContact::success()); } } @@ -396,19 +461,38 @@ mod json { pub nodes: Vec, } + #[derive(Serialize, Deserialize)] + pub enum NodeContact { + #[serde(rename = "success")] + Success(u64), + #[serde(rename = "failure")] + Failure(u64), + } + + impl NodeContact { + pub fn into_node_contact(self) -> super::NodeContact { + match self { + NodeContact::Success(s) => super::NodeContact::Success( + time::UNIX_EPOCH + Duration::from_secs(s) + ), + NodeContact::Failure(s) => super::NodeContact::Failure( + time::UNIX_EPOCH + Duration::from_secs(s) + ), + } + } + } + #[derive(Serialize, Deserialize)] pub struct Node { pub url: String, - pub attempts: u32, - pub failures: u32, + pub last_contact: Option, } impl Node { pub fn into_node(self) -> Option { match super::Node::from_str(&self.url) { Ok(mut node) => { - node.attempts = self.attempts; - node.failures = self.failures; + node.last_contact = self.last_contact.map(|c| c.into_node_contact()); Some(node) }, _ => None, @@ -418,10 +502,18 @@ mod json { impl<'a> From<&'a super::Node> for Node { fn from(node: &'a super::Node) -> Self { + let last_contact = node.last_contact.and_then(|c| { + match c { + super::NodeContact::Success(t) => + t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Success(d.as_secs())), + super::NodeContact::Failure(t) => + t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Failure(d.as_secs())), + } + }); + Node { url: format!("{}", node), - attempts: node.attempts, - failures: node.failures, + last_contact } } } @@ -464,42 +556,54 @@ mod tests { } #[test] - fn table_failure_percentage_order() { + fn table_last_contact_order() { let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node4 = Node::from_str("enode://d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node5 = Node::from_str("enode://e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node6 = Node::from_str("enode://f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id4 = H512::from_str("d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id5 = H512::from_str("e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id6 = H512::from_str("f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let mut table = NodeTable::new(None); table.add_node(node1); table.add_node(node2); table.add_node(node3); table.add_node(node4); + table.add_node(node5); + table.add_node(node6); - // node 1 - failure percentage 100% - table.get_mut(&id1).unwrap().attempts = 2; - table.note_failure(&id1); + // failures - nodes 1 & 2 table.note_failure(&id1); - - // node2 - failure percentage 33% - table.get_mut(&id2).unwrap().attempts = 3; table.note_failure(&id2); - // node3 - failure percentage 0% - table.get_mut(&id3).unwrap().attempts = 1; + // success - nodes 3 & 4 + table.note_success(&id3); + table.note_success(&id4); - // node4 - failure percentage 50% (default when no attempts) + // success - node 5 (old contact) + table.get_mut(&id5).unwrap().last_contact = Some(NodeContact::Success(time::UNIX_EPOCH)); + + // unknown - node 6 let r = table.nodes(IpFilter::default()); - assert_eq!(r[0][..], id3[..]); - assert_eq!(r[1][..], id2[..]); - assert_eq!(r[2][..], id4[..]); - assert_eq!(r[3][..], id1[..]); + assert_eq!(r[0][..], id4[..]); // most recent success + assert_eq!(r[1][..], id3[..]); + + // unknown (old contacts and new nodes), randomly shuffled + assert!( + r[2][..] == id5[..] && r[3][..] == id6[..] || + r[2][..] == id6[..] && r[3][..] == id5[..] + ); + + assert_eq!(r[4][..], id1[..]); // oldest failure + assert_eq!(r[5][..], id2[..]); } #[test] @@ -507,23 +611,27 @@ mod tests { let tempdir = TempDir::new("").unwrap(); let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + { let mut table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned())); table.add_node(node1); table.add_node(node2); + table.add_node(node3); - table.get_mut(&id1).unwrap().attempts = 1; - table.get_mut(&id2).unwrap().attempts = 1; - table.note_failure(&id2); + table.note_success(&id2); + table.note_failure(&id3); } { let table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned())); let r = table.nodes(IpFilter::default()); - assert_eq!(r[0][..], id1[..]); - assert_eq!(r[1][..], id2[..]); + assert_eq!(r[0][..], id2[..]); // latest success + assert_eq!(r[1][..], id1[..]); // unknown + assert_eq!(r[2][..], id3[..]); // oldest failure } } From 29acdb70442697358c456a5798c11bf73accfd17 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 8 May 2018 11:22:12 +0200 Subject: [PATCH 067/147] Rlp decode returns Result (#8527) rlp::decode returns Result Make a best effort to handle decoding errors gracefully throughout the code, using `expect` where the value is guaranteed to be valid (and in other places where it makes sense). --- ethcore/light/src/client/header_chain.rs | 27 +++++++++++++----------- ethcore/light/src/net/request_credits.rs | 2 +- ethcore/light/src/types/request/mod.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 4 ++-- ethcore/src/db.rs | 13 +++++------- ethcore/src/encoded.rs | 11 +++++----- ethcore/src/engines/tendermint/mod.rs | 6 ++++-- ethcore/src/header.rs | 4 ++-- ethcore/src/snapshot/account.rs | 6 +++--- ethcore/src/snapshot/mod.rs | 6 +++--- ethcore/src/snapshot/tests/helpers.rs | 2 +- ethcore/src/snapshot/tests/state.rs | 2 +- ethcore/src/state/account.rs | 23 +++++++++++--------- ethcore/src/state/mod.rs | 17 ++++++++++----- ethcore/src/trace/types/flat.rs | 2 +- ethcore/transaction/src/transaction.rs | 5 +++-- ethcore/types/src/receipt.rs | 4 ++-- ethcore/vm/src/call_type.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 3 ++- util/journaldb/src/archivedb.rs | 13 ++++++------ util/journaldb/src/earlymergedb.rs | 2 +- util/journaldb/src/overlaydb.rs | 2 +- util/journaldb/src/overlayrecentdb.rs | 4 ++-- util/journaldb/src/refcounteddb.rs | 15 +++++++------ util/rlp/src/lib.rs | 6 +++--- util/rlp/tests/tests.rs | 6 ++++-- util/rlp_derive/tests/rlp.rs | 4 ++-- whisper/src/message.rs | 4 ++-- 28 files changed, 107 insertions(+), 90 deletions(-) diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index abcb04c3662..02a18a60dfe 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -228,7 +228,7 @@ impl HeaderChain { let decoded_header = spec.genesis_header(); let chain = if let Some(current) = db.get(col, CURRENT_KEY)? { - let curr : BestAndLatest = ::rlp::decode(¤t); + let curr : BestAndLatest = ::rlp::decode(¤t).expect("decoding db value failed"); let mut cur_number = curr.latest_num; let mut candidates = BTreeMap::new(); @@ -236,7 +236,7 @@ impl HeaderChain { // load all era entries, referenced headers within them, // and live epoch proofs. while let Some(entry) = db.get(col, era_key(cur_number).as_bytes())? { - let entry: Entry = ::rlp::decode(&entry); + let entry: Entry = ::rlp::decode(&entry).expect("decoding db value failed"); trace!(target: "chain", "loaded header chain entry for era {} with {} candidates", cur_number, entry.candidates.len()); @@ -524,7 +524,10 @@ impl HeaderChain { None } Ok(None) => panic!("stored candidates always have corresponding headers; qed"), - Ok(Some(header)) => Some((epoch_transition, ::rlp::decode(&header))), + Ok(Some(header)) => Some(( + epoch_transition, + ::rlp::decode(&header).expect("decoding value from db failed") + )), }; } } @@ -591,7 +594,7 @@ impl HeaderChain { in an inconsistent state", h_num); ErrorKind::Database(msg.into()) })?; - ::rlp::decode(&bytes) + ::rlp::decode(&bytes).expect("decoding db value failed") }; let total_difficulty = entry.candidates.iter() @@ -604,9 +607,9 @@ impl HeaderChain { .total_difficulty; break Ok(Some(SpecHardcodedSync { - header: header, - total_difficulty: total_difficulty, - chts: chts, + header, + total_difficulty, + chts, })); }, None => { @@ -742,7 +745,7 @@ impl HeaderChain { /// so including it within a CHT would be redundant. pub fn cht_root(&self, n: usize) -> Option { match self.db.get(self.col, cht_key(n as u64).as_bytes()) { - Ok(val) => val.map(|x| ::rlp::decode(&x)), + Ok(db_fetch) => db_fetch.map(|bytes| ::rlp::decode(&bytes).expect("decoding value from db failed")), Err(e) => { warn!(target: "chain", "Error reading from database: {}", e); None @@ -793,7 +796,7 @@ impl HeaderChain { pub fn pending_transition(&self, hash: H256) -> Option { let key = pending_transition_key(hash); match self.db.get(self.col, &*key) { - Ok(val) => val.map(|x| ::rlp::decode(&x)), + Ok(db_fetch) => db_fetch.map(|bytes| ::rlp::decode(&bytes).expect("decoding value from db failed")), Err(e) => { warn!(target: "chain", "Error reading from database: {}", e); None @@ -1192,7 +1195,7 @@ mod tests { let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600)))); - let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).unwrap(); + let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).expect("failed to instantiate a new HeaderChain"); let mut parent_hash = genesis_header.hash(); let mut rolling_timestamp = genesis_header.timestamp(); @@ -1211,14 +1214,14 @@ mod tests { parent_hash = header.hash(); let mut tx = db.transaction(); - let pending = chain.insert(&mut tx, header, None).unwrap(); + let pending = chain.insert(&mut tx, header, None).expect("failed inserting a transaction"); db.write(tx).unwrap(); chain.apply_pending(pending); rolling_timestamp += 10; } - let hardcoded_sync = chain.read_hardcoded_sync().unwrap().unwrap(); + let hardcoded_sync = chain.read_hardcoded_sync().expect("failed reading hardcoded sync").expect("failed unwrapping hardcoded sync"); assert_eq!(hardcoded_sync.chts.len(), 3); assert_eq!(hardcoded_sync.total_difficulty, total_difficulty); let decoded: Header = hardcoded_sync.header.decode(); diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index abe609dabbd..29570b613cf 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -407,7 +407,7 @@ mod tests { let costs = CostTable::default(); let serialized = ::rlp::encode(&costs); - let new_costs: CostTable = ::rlp::decode(&*serialized); + let new_costs: CostTable = ::rlp::decode(&*serialized).unwrap(); assert_eq!(costs, new_costs); } diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index 8d911d3f555..bda992df975 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -1642,7 +1642,7 @@ mod tests { { // check as single value. let bytes = ::rlp::encode(&val); - let new_val: T = ::rlp::decode(&bytes); + let new_val: T = ::rlp::decode(&bytes).unwrap(); assert_eq!(val, new_val); // check as list containing single value. diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 57bcdf2bc28..0e18c5f889c 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -438,7 +438,7 @@ impl<'a> Iterator for EpochTransitionIter<'a> { return None } - let transitions: EpochTransitions = ::rlp::decode(&val[..]); + let transitions: EpochTransitions = ::rlp::decode(&val[..]).expect("decode error: the db is corrupted or the data structure has changed"); // if there are multiple candidates, at most one will be on the // canon chain. @@ -462,7 +462,7 @@ impl<'a> Iterator for EpochTransitionIter<'a> { impl BlockChain { /// Create new instance of blockchain from given Genesis. pub fn new(config: Config, genesis: &[u8], db: Arc) -> BlockChain { - // 400 is the avarage size of the key + // 400 is the average size of the key let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400); let mut bc = BlockChain { diff --git a/ethcore/src/db.rs b/ethcore/src/db.rs index d11adc7710d..a1c7d6b0f5e 100644 --- a/ethcore/src/db.rs +++ b/ethcore/src/db.rs @@ -218,15 +218,12 @@ impl Writable for DBTransaction { } impl Readable for KVDB { - fn read(&self, col: Option, key: &Key) -> Option where T: rlp::Decodable, R: Deref { - let result = self.get(col, &key.key()); + fn read(&self, col: Option, key: &Key) -> Option + where T: rlp::Decodable, R: Deref { + self.get(col, &key.key()) + .expect(&format!("db get failed, key: {:?}", &key.key() as &[u8])) + .map(|v| rlp::decode(&v).expect("decode db value failed") ) - match result { - Ok(option) => option.map(|v| rlp::decode(&v)), - Err(err) => { - panic!("db get failed, key: {:?}, err: {:?}", &key.key() as &[u8], err); - } - } } fn exists(&self, col: Option, key: &Key) -> bool where R: Deref { diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 1f627666a90..01df386cc2e 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -24,13 +24,12 @@ //! decoded object where parts like the hash can be saved. use block::Block as FullBlock; -use header::{BlockNumber, Header as FullHeader}; -use transaction::UnverifiedTransaction; - +use ethereum_types::{H256, Bloom, U256, Address}; use hash::keccak; +use header::{BlockNumber, Header as FullHeader}; use heapsize::HeapSizeOf; -use ethereum_types::{H256, Bloom, U256, Address}; use rlp::{Rlp, RlpStream}; +use transaction::UnverifiedTransaction; use views::{self, BlockView, HeaderView, BodyView}; /// Owning header view. @@ -48,7 +47,7 @@ impl Header { pub fn new(encoded: Vec) -> Self { Header(encoded) } /// Upgrade this encoded view to a fully owned `Header` object. - pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0) } + pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0).expect("decoding failure") } /// Get a borrowed header view onto the data. #[inline] @@ -205,7 +204,7 @@ impl Block { pub fn header_view(&self) -> HeaderView { self.view().header_view() } /// Decode to a full block. - pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0) } + pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0).expect("decoding failure") } /// Decode the header. pub fn decode_header(&self) -> FullHeader { self.view().rlp().val_at(0) } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index d80a5e182f1..93fc347e942 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -143,8 +143,10 @@ impl super::EpochVerifier for EpochVerifier } fn check_finality_proof(&self, proof: &[u8]) -> Option> { - let header: Header = ::rlp::decode(proof); - self.verify_light(&header).ok().map(|_| vec![header.hash()]) + match ::rlp::decode(proof) { + Ok(header) => self.verify_light(&header).ok().map(|_| vec![header.hash()]), + Err(_) => None // REVIEW: log perhaps? Not sure what the policy is. + } } } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index a31aa029b31..ba71eb30497 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -398,7 +398,7 @@ mod tests { let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap(); let nonce_decoded = "ab4e252a7e8c2a23".from_hex().unwrap(); - let header: Header = rlp::decode(&header_rlp); + let header: Header = rlp::decode(&header_rlp).expect("error decoding header"); let seal_fields = header.seal.clone(); assert_eq!(seal_fields.len(), 2); assert_eq!(seal_fields[0], mix_hash); @@ -415,7 +415,7 @@ mod tests { // that's rlp of block header created with ethash engine. let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap(); - let header: Header = rlp::decode(&header_rlp); + let header: Header = rlp::decode(&header_rlp).expect("error decoding header"); let encoded_header = rlp::encode(&header).into_vec(); assert_eq!(header_rlp, encoded_header); diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 6c9e0f3d6e8..49f45136e9b 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -236,7 +236,7 @@ mod tests { }; let thin_rlp = ::rlp::encode(&account); - assert_eq!(::rlp::decode::(&thin_rlp), account); + assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); let fat_rlp = Rlp::new(&fat_rlps[0]).at(1).unwrap(); @@ -261,7 +261,7 @@ mod tests { }; let thin_rlp = ::rlp::encode(&account); - assert_eq!(::rlp::decode::(&thin_rlp), account); + assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); let fat_rlp = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); let fat_rlp = Rlp::new(&fat_rlp[0]).at(1).unwrap(); @@ -286,7 +286,7 @@ mod tests { }; let thin_rlp = ::rlp::encode(&account); - assert_eq!(::rlp::decode::(&thin_rlp), account); + assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); let fat_rlps = to_fat_rlps(&keccak(addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), 500, 1000).unwrap(); let mut root = KECCAK_NULL_RLP; diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index fbf0c5ca5ec..94236e9e95d 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -281,7 +281,7 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex(rlp).storage_root); + known_storage_roots.insert(*hash, ::rlp::decode::(rlp)?.storage_root); } if let Some(&(ref hash, ref rlp)) = out_chunk.iter().next() { - known_storage_roots.insert(*hash, ::rlp::decode::(rlp).storage_root); + known_storage_roots.insert(*hash, ::rlp::decode::(rlp)?.storage_root); } Ok(status) } diff --git a/ethcore/src/snapshot/tests/helpers.rs b/ethcore/src/snapshot/tests/helpers.rs index 51f417149bf..067a3abab07 100644 --- a/ethcore/src/snapshot/tests/helpers.rs +++ b/ethcore/src/snapshot/tests/helpers.rs @@ -75,7 +75,7 @@ impl StateProducer { // sweep once to alter storage tries. for &mut (ref mut address_hash, ref mut account_data) in &mut accounts_to_modify { - let mut account: BasicAccount = ::rlp::decode(&*account_data); + let mut account: BasicAccount = ::rlp::decode(&*account_data).expect("error decoding basic account"); let acct_db = AccountDBMut::from_hash(db, *address_hash); fill_storage(acct_db, &mut account.storage_root, &mut self.storage_seed); *account_data = DBValue::from_vec(::rlp::encode(&account).into_vec()); diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index f17fa7dde5a..05926a7e662 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -114,7 +114,7 @@ fn get_code_from_prev_chunk() { // first one will have code inlined, // second will just have its hash. let thin_rlp = acc_stream.out(); - let acc: BasicAccount = ::rlp::decode(&thin_rlp); + let acc: BasicAccount = ::rlp::decode(&thin_rlp).expect("error decoding basic account"); let mut make_chunk = |acc, hash| { let mut db = MemoryDB::new(); diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index f9c8f258e60..ff7d70bd3aa 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -21,6 +21,7 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeMap}; use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP, keccak}; use ethereum_types::{H256, U256, Address}; +use error::Error; use hashdb::HashDB; use kvdb::DBValue; use bytes::{Bytes, ToPretty}; @@ -144,9 +145,10 @@ impl Account { } /// Create a new account from RLP. - pub fn from_rlp(rlp: &[u8]) -> Account { - let basic: BasicAccount = ::rlp::decode(rlp); - basic.into() + pub fn from_rlp(rlp: &[u8]) -> Result { + ::rlp::decode::(rlp) + .map(|ba| ba.into()) + .map_err(|e| e.into()) } /// Create a new contract account. @@ -202,8 +204,8 @@ impl Account { return Ok(value); } let db = SecTrieDB::new(db, &self.storage_root)?; - - let item: U256 = db.get_with(key, ::rlp::decode)?.unwrap_or_else(U256::zero); + let panicky_decoder = |bytes:&[u8]| ::rlp::decode(&bytes).expect("decoding db value failed"); + let item: U256 = db.get_with(key, panicky_decoder)?.unwrap_or_else(U256::zero); let value: H256 = item.into(); self.storage_cache.borrow_mut().insert(key.clone(), value.clone()); Ok(value) @@ -478,7 +480,8 @@ impl Account { let trie = TrieDB::new(db, &self.storage_root)?; let item: U256 = { - let query = (&mut recorder, ::rlp::decode); + let panicky_decoder = |bytes:&[u8]| ::rlp::decode(bytes).expect("decoding db value failed"); + let query = (&mut recorder, panicky_decoder); trie.get_with(&storage_key, query)?.unwrap_or_else(U256::zero) }; @@ -528,7 +531,7 @@ mod tests { a.rlp() }; - let a = Account::from_rlp(&rlp); + let a = Account::from_rlp(&rlp).expect("decoding db value failed"); assert_eq!(*a.storage_root().unwrap(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2".into()); assert_eq!(a.storage_at(&db.immutable(), &0x00u64.into()).unwrap(), 0x1234u64.into()); assert_eq!(a.storage_at(&db.immutable(), &0x01u64.into()).unwrap(), H256::default()); @@ -546,10 +549,10 @@ mod tests { a.rlp() }; - let mut a = Account::from_rlp(&rlp); + let mut a = Account::from_rlp(&rlp).expect("decoding db value failed"); assert!(a.cache_code(&db.immutable()).is_some()); - let mut a = Account::from_rlp(&rlp); + let mut a = Account::from_rlp(&rlp).expect("decoding db value failed"); assert_eq!(a.note_code(vec![0x55, 0x44, 0xffu8]), Ok(())); } @@ -609,7 +612,7 @@ mod tests { #[test] fn rlpio() { let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new()); - let b = Account::from_rlp(&a.rlp()); + let b = Account::from_rlp(&a.rlp()).unwrap(); assert_eq!(a.balance(), b.balance()); assert_eq!(a.nonce(), b.nonce()); assert_eq!(a.code_hash(), b.code_hash()); diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 255dce5b5de..20d564588c5 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -605,7 +605,8 @@ impl State { // account is not found in the global cache, get from the DB and insert into local let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); - let maybe_acc = db.get_with(address, Account::from_rlp)?; + let from_rlp = |b: &[u8]| Account::from_rlp(b).expect("decoding db value failed"); + let maybe_acc = db.get_with(address, from_rlp)?; let r = maybe_acc.as_ref().map_or(Ok(H256::new()), |a| { let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), a.address_hash(address)); a.storage_at(account_db.as_hashdb(), key) @@ -983,7 +984,8 @@ impl State { // not found in the global cache, get from the DB and insert into local let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root)?; - let mut maybe_acc = db.get_with(a, Account::from_rlp)?; + let from_rlp = |b: &[u8]| Account::from_rlp(b).expect("decoding db value failed"); + let mut maybe_acc = db.get_with(a, from_rlp)?; if let Some(ref mut account) = maybe_acc.as_mut() { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); @@ -1012,7 +1014,8 @@ impl State { None => { let maybe_acc = if !self.db.is_known_null(a) { let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root)?; - AccountEntry::new_clean(db.get_with(a, Account::from_rlp)?) + let from_rlp = |b:&[u8]| { Account::from_rlp(b).expect("decoding db value failed") }; + AccountEntry::new_clean(db.get_with(a, from_rlp)?) } else { AccountEntry::new_clean(None) }; @@ -1064,7 +1067,10 @@ impl State { let mut recorder = Recorder::new(); let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?; let maybe_account: Option = { - let query = (&mut recorder, ::rlp::decode); + let panicky_decoder = |bytes: &[u8]| { + ::rlp::decode(bytes).expect(&format!("prove_account, could not query trie for account key={}", &account_key)) + }; + let query = (&mut recorder, panicky_decoder); trie.get_with(&account_key, query)? }; let account = maybe_account.unwrap_or_else(|| BasicAccount { @@ -1086,7 +1092,8 @@ impl State { // TODO: probably could look into cache somehow but it's keyed by // address, not keccak(address). let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?; - let acc = match trie.get_with(&account_key, Account::from_rlp)? { + let from_rlp = |b: &[u8]| Account::from_rlp(b).expect("decoding db value failed"); + let acc = match trie.get_with(&account_key, from_rlp)? { Some(acc) => acc, None => return Ok((Vec::new(), H256::new())), }; diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index e2746ca7f7d..00cf517df80 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -244,7 +244,7 @@ mod tests { ]); let encoded = ::rlp::encode(&block_traces); - let decoded = ::rlp::decode(&encoded); + let decoded = ::rlp::decode(&encoded).expect("error decoding block traces"); assert_eq!(block_traces, decoded); } } diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 571dec3faeb..6152e61acb6 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -576,7 +576,8 @@ mod tests { #[test] fn sender_test() { - let t: UnverifiedTransaction = rlp::decode(&::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); + let bytes = ::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap(); + let t: UnverifiedTransaction = rlp::decode(&bytes).expect("decoding UnverifiedTransaction failed"); assert_eq!(t.data, b""); assert_eq!(t.gas, U256::from(0x5208u64)); assert_eq!(t.gas_price, U256::from(0x01u64)); @@ -645,7 +646,7 @@ mod tests { use rustc_hex::FromHex; let test_vector = |tx_data: &str, address: &'static str| { - let signed = rlp::decode(&FromHex::from_hex(tx_data).unwrap()); + let signed = rlp::decode(&FromHex::from_hex(tx_data).unwrap()).expect("decoding tx data failed"); let signed = SignedTransaction::new(signed).unwrap(); assert_eq!(signed.sender(), address.into()); println!("chainid: {:?}", signed.chain_id()); diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index c1defbc151f..8846d27c027 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -193,7 +193,7 @@ mod tests { ); let encoded = ::rlp::encode(&r); assert_eq!(&encoded[..], &expected[..]); - let decoded: Receipt = ::rlp::decode(&encoded); + let decoded: Receipt = ::rlp::decode(&encoded).expect("decoding receipt failed"); assert_eq!(decoded, r); } @@ -211,7 +211,7 @@ mod tests { ); let encoded = ::rlp::encode(&r); assert_eq!(&encoded[..], &expected[..]); - let decoded: Receipt = ::rlp::decode(&encoded); + let decoded: Receipt = ::rlp::decode(&encoded).expect("decoding receipt failed"); assert_eq!(decoded, r); } } diff --git a/ethcore/vm/src/call_type.rs b/ethcore/vm/src/call_type.rs index 83260825f3c..dc00b2b8392 100644 --- a/ethcore/vm/src/call_type.rs +++ b/ethcore/vm/src/call_type.rs @@ -64,7 +64,7 @@ mod tests { fn should_encode_and_decode_call_type() { let original = CallType::Call; let encoded = encode(&original); - let decoded = decode(&encoded); + let decoded = decode(&encoded).expect("failure decoding CallType"); assert_eq!(original, decoded); } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index badf5bff728..39a2e842db1 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -566,7 +566,8 @@ fn rpc_eth_pending_transaction_by_hash() { let tester = EthTester::default(); { - let tx = rlp::decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); + let bytes = FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap(); + let tx = rlp::decode(&bytes).expect("decoding failure"); let tx = SignedTransaction::new(tx).unwrap(); tester.miner.pending_transactions.lock().insert(H256::zero(), tx); } diff --git a/util/journaldb/src/archivedb.rs b/util/journaldb/src/archivedb.rs index e00b37d3c4a..b58558a332a 100644 --- a/util/journaldb/src/archivedb.rs +++ b/util/journaldb/src/archivedb.rs @@ -45,14 +45,15 @@ pub struct ArchiveDB { impl ArchiveDB { /// Create a new instance from a key-value db. - pub fn new(backing: Arc, col: Option) -> ArchiveDB { - let latest_era = backing.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") - .map(|val| decode::(&val)); + pub fn new(backing: Arc, column: Option) -> ArchiveDB { + let latest_era = backing.get(column, &LATEST_ERA_KEY) + .expect("Low-level database error.") + .map(|val| decode::(&val).expect("decoding db value failed")); ArchiveDB { overlay: MemoryDB::new(), - backing: backing, - latest_era: latest_era, - column: col, + backing, + latest_era, + column, } } diff --git a/util/journaldb/src/earlymergedb.rs b/util/journaldb/src/earlymergedb.rs index bb8e49d41ed..e76cdcd313a 100644 --- a/util/journaldb/src/earlymergedb.rs +++ b/util/journaldb/src/earlymergedb.rs @@ -263,7 +263,7 @@ impl EarlyMergeDB { let mut refs = HashMap::new(); let mut latest_era = None; if let Some(val) = db.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); + let mut era = decode::(&val).expect("decoding db value failed"); latest_era = Some(era); loop { let mut db_key = DatabaseKey { diff --git a/util/journaldb/src/overlaydb.rs b/util/journaldb/src/overlaydb.rs index fa7ff04596e..54d0bb12d76 100644 --- a/util/journaldb/src/overlaydb.rs +++ b/util/journaldb/src/overlaydb.rs @@ -137,7 +137,7 @@ impl OverlayDB { fn payload(&self, key: &H256) -> Option { self.backing.get(self.column, key) .expect("Low-level database error. Some issue with your hard disk?") - .map(|d| decode(&d)) + .map(|d| decode(&d).expect("decoding db value failed")) } /// Put the refs and value of the given key, possibly deleting it from the db. diff --git a/util/journaldb/src/overlayrecentdb.rs b/util/journaldb/src/overlayrecentdb.rs index fdc178350e6..2c9ce5cb1dd 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -186,7 +186,7 @@ impl OverlayRecentDB { let mut earliest_era = None; let mut cumulative_size = 0; if let Some(val) = db.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); + let mut era = decode::(&val).expect("decoding db value failed"); latest_era = Some(era); loop { let mut db_key = DatabaseKey { @@ -195,7 +195,7 @@ impl OverlayRecentDB { }; while let Some(rlp_data) = db.get(col, &encode(&db_key)).expect("Low-level database error.") { trace!("read_overlay: era={}, index={}", era, db_key.index); - let value = decode::(&rlp_data); + let value = decode::(&rlp_data).expect(&format!("read_overlay: Error decoding DatabaseValue era={}, index{}", era, db_key.index)); count += value.inserts.len(); let mut inserted_keys = Vec::new(); for (k, v) in value.inserts { diff --git a/util/journaldb/src/refcounteddb.rs b/util/journaldb/src/refcounteddb.rs index bf366faf753..944d81d3733 100644 --- a/util/journaldb/src/refcounteddb.rs +++ b/util/journaldb/src/refcounteddb.rs @@ -62,17 +62,18 @@ pub struct RefCountedDB { impl RefCountedDB { /// Create a new instance given a `backing` database. - pub fn new(backing: Arc, col: Option) -> RefCountedDB { - let latest_era = backing.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") - .map(|val| decode::(&val)); + pub fn new(backing: Arc, column: Option) -> RefCountedDB { + let latest_era = backing.get(column, &LATEST_ERA_KEY) + .expect("Low-level database error.") + .map(|v| decode::(&v).expect("decoding db value failed")); RefCountedDB { - forward: OverlayDB::new(backing.clone(), col), - backing: backing, + forward: OverlayDB::new(backing.clone(), column), + backing, inserts: vec![], removes: vec![], - latest_era: latest_era, - column: col, + latest_era, + column, } } } diff --git a/util/rlp/src/lib.rs b/util/rlp/src/lib.rs index a6754e22de9..b416b1c25b0 100644 --- a/util/rlp/src/lib.rs +++ b/util/rlp/src/lib.rs @@ -63,13 +63,13 @@ pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; /// /// fn main () { /// let data = vec![0x83, b'c', b'a', b't']; -/// let animal: String = rlp::decode(&data); +/// let animal: String = rlp::decode(&data).expect("could not decode"); /// assert_eq!(animal, "cat".to_owned()); /// } /// ``` -pub fn decode(bytes: &[u8]) -> T where T: Decodable { +pub fn decode(bytes: &[u8]) -> Result where T: Decodable { let rlp = Rlp::new(bytes); - rlp.as_val().expect("trusted rlp should be valid") + rlp.as_val() } pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable { diff --git a/util/rlp/tests/tests.rs b/util/rlp/tests/tests.rs index 6ff426a7739..041c267667d 100644 --- a/util/rlp/tests/tests.rs +++ b/util/rlp/tests/tests.rs @@ -209,8 +209,10 @@ struct VDTestPair(Vec, Vec) where T: Decodable + fmt::Debug + cmp::Eq; fn run_decode_tests(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq { for t in &tests { - let res: T = rlp::decode(&t.1); - assert_eq!(res, t.0); + let res : Result = rlp::decode(&t.1); + assert!(res.is_ok()); + let res = res.unwrap(); + assert_eq!(&res, &t.0); } } diff --git a/util/rlp_derive/tests/rlp.rs b/util/rlp_derive/tests/rlp.rs index c873805247d..ba51309146e 100644 --- a/util/rlp_derive/tests/rlp.rs +++ b/util/rlp_derive/tests/rlp.rs @@ -24,7 +24,7 @@ fn test_encode_foo() { let out = encode(&foo).into_vec(); assert_eq!(out, expected); - let decoded = decode(&expected); + let decoded = decode(&expected).expect("decode failure"); assert_eq!(foo, decoded); } @@ -38,7 +38,7 @@ fn test_encode_foo_wrapper() { let out = encode(&foo).into_vec(); assert_eq!(out, expected); - let decoded = decode(&expected); + let decoded = decode(&expected).expect("decode failure"); assert_eq!(foo, decoded); } diff --git a/whisper/src/message.rs b/whisper/src/message.rs index fbf2faf3fdf..d0de9af4b5a 100644 --- a/whisper/src/message.rs +++ b/whisper/src/message.rs @@ -446,7 +446,7 @@ mod tests { }; let encoded = ::rlp::encode(&envelope); - let decoded = ::rlp::decode(&encoded); + let decoded = ::rlp::decode(&encoded).expect("failure decoding Envelope"); assert_eq!(envelope, decoded) } @@ -462,7 +462,7 @@ mod tests { }; let encoded = ::rlp::encode(&envelope); - let decoded = ::rlp::decode(&encoded); + let decoded = ::rlp::decode(&encoded).expect("failure decoding Envelope"); assert_eq!(envelope, decoded) } From fe42ec95b571a8a20b4ff03c0bebb7f3eea4f429 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 9 May 2018 08:47:21 +0200 Subject: [PATCH 068/147] Parity as a library (#8412) * Parity as a library * Fix concerns * Allow using a null on_client_restart_cb * Fix more concerns * Test the C library in test.sh * Reduce CMake version to 3.5 * Move the clib test before cargo test * Add println in test --- Cargo.lock | 8 +- Cargo.toml | 5 +- parity-clib-example/CMakeLists.txt | 19 ++ parity-clib-example/main.cpp | 28 +++ parity-clib/Cargo.toml | 17 ++ parity-clib/parity.h | 93 ++++++++++ parity-clib/src/lib.rs | 133 ++++++++++++++ parity/blockchain.rs | 7 - parity/cli/usage.rs | 1 + parity/configuration.rs | 41 +++-- parity/lib.rs | 249 ++++++++++++++++++++++++++ parity/main.rs | 275 +++++++---------------------- parity/run.rs | 138 +++++---------- parity/snapshot.rs | 3 - parity/url.rs | 3 +- test.sh | 16 +- 16 files changed, 702 insertions(+), 334 deletions(-) create mode 100644 parity-clib-example/CMakeLists.txt create mode 100644 parity-clib-example/main.cpp create mode 100644 parity-clib/Cargo.toml create mode 100644 parity-clib/parity.h create mode 100644 parity-clib/src/lib.rs create mode 100644 parity/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ceb14ff277c..64e468e6703 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1954,7 +1954,6 @@ dependencies = [ "ethcore-private-tx 1.0.0", "ethcore-secretstore 1.0.0", "ethcore-service 0.1.0", - "ethcore-stratum 1.12.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2008,6 +2007,13 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parity-clib" +version = "1.12.0" +dependencies = [ + "parity 1.12.0", +] + [[package]] name = "parity-dapps" version = "1.12.0" diff --git a/Cargo.toml b/Cargo.toml index a611458e653..de1a78bf4fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ ethcore-miner = { path = "miner" } ethcore-network = { path = "util/network" } ethcore-private-tx = { path = "ethcore/private-tx" } ethcore-service = { path = "ethcore/service" } -ethcore-stratum = { path = "ethcore/stratum" } ethcore-sync = { path = "ethcore/sync" } ethcore-transaction = { path = "ethcore/transaction" } ethereum-types = "0.3" @@ -108,6 +107,9 @@ slow-blocks = ["ethcore/slow-blocks"] secretstore = ["ethcore-secretstore"] final = ["parity-version/final"] +[lib] +path = "parity/lib.rs" + [[bin]] path = "parity/main.rs" name = "parity" @@ -130,6 +132,7 @@ members = [ "ethstore/cli", "evmbin", "miner", + "parity-clib", "transaction-pool", "whisper", "whisper/cli", diff --git a/parity-clib-example/CMakeLists.txt b/parity-clib-example/CMakeLists.txt new file mode 100644 index 00000000000..143d014e322 --- /dev/null +++ b/parity-clib-example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.5) +include(ExternalProject) + +include_directories("${CMAKE_SOURCE_DIR}/../parity-clib") + +add_executable(parity-example main.cpp) + +ExternalProject_Add( + libparity + DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + COMMAND cargo build -p parity-clib # Note: use --release in a real project + BINARY_DIR "${CMAKE_SOURCE_DIR}/../target" + INSTALL_COMMAND "" + LOG_BUILD ON) + +add_dependencies(parity-example libparity) +target_link_libraries(parity-example "${CMAKE_SOURCE_DIR}/../target/debug/libparity.so") diff --git a/parity-clib-example/main.cpp b/parity-clib-example/main.cpp new file mode 100644 index 00000000000..1fadf1b5b56 --- /dev/null +++ b/parity-clib-example/main.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +void on_restart(void*, const char*, size_t) {} + +int main() { + ParityParams cfg = { 0 }; + cfg.on_client_restart_cb = on_restart; + + const char* args[] = {"--light"}; + size_t str_lens[] = {7}; + if (parity_config_from_cli(args, str_lens, 1, &cfg.configuration) != 0) { + return 1; + } + + void* parity; + if (parity_start(&cfg, &parity) != 0) { + return 1; + } + + sleep(5); + if (parity != NULL) { + parity_destroy(parity); + } + + return 0; +} diff --git a/parity-clib/Cargo.toml b/parity-clib/Cargo.toml new file mode 100644 index 00000000000..001f954c211 --- /dev/null +++ b/parity-clib/Cargo.toml @@ -0,0 +1,17 @@ +[package] +description = "C bindings for the Parity Ethereum client" +name = "parity-clib" +version = "1.12.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[lib] +name = "parity" +crate-type = ["cdylib", "staticlib"] + +[dependencies] +parity = { path = "../", default-features = false } + +[features] +default = [] +final = ["parity/final"] diff --git a/parity-clib/parity.h b/parity-clib/parity.h new file mode 100644 index 00000000000..b61da8e458b --- /dev/null +++ b/parity-clib/parity.h @@ -0,0 +1,93 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#ifndef _PARITY_H_INCLUDED_ +#define _PARITY_H_INCLUDED_ + +#include + +/// Parameters to pass to `parity_start`. +struct ParityParams { + /// Configuration object, as handled by the `parity_config_*` functions. + /// Note that calling `parity_start` will destroy the configuration object (even on failure). + void *configuration; + + /// Callback function to call when the client receives an RPC request to change its chain spec. + /// + /// Will only be called if you enable the `--can-restart` flag. + /// + /// The first parameter of the callback is the value of `on_client_restart_cb_custom`. + /// The second and third parameters of the callback are the string pointer and length. + void (*on_client_restart_cb)(void* custom, const char* new_chain, size_t new_chain_len); + + /// Custom parameter passed to the `on_client_restart_cb` callback as first parameter. + void *on_client_restart_cb_custom; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/// Builds a new configuration object by parsing a list of CLI arguments. +/// +/// The first two parameters are string pointers and string lengths. They must have a length equal +/// to `len`. The strings don't need to be zero-terminated. +/// +/// On success, the produced object will be written to the `void*` pointed by `out`. +/// +/// Returns 0 on success, and non-zero on error. +/// +/// # Example +/// +/// ```no_run +/// void* cfg; +/// const char *args[] = {"--light", "--can-restart"}; +/// size_t str_lens[] = {7, 13}; +/// if (parity_config_from_cli(args, str_lens, 2, &cfg) != 0) { +/// return 1; +/// } +/// ``` +/// +int parity_config_from_cli(char const* const* args, size_t const* arg_lens, size_t len, void** out); + +/// Destroys a configuration object created earlier. +/// +/// **Important**: You probably don't need to call this function. Calling `parity_start` destroys +/// the configuration object as well (even on failure). +void parity_config_destroy(void* cfg); + +/// Starts the parity client in background threads. Returns a pointer to a struct that represents +/// the running client. Can also return NULL if the execution completes instantly. +/// +/// **Important**: The configuration object passed inside `cfg` is destroyed when you +/// call `parity_start` (even on failure). +/// +/// On success, the produced object will be written to the `void*` pointed by `out`. +/// +/// Returns 0 on success, and non-zero on error. +int parity_start(const ParityParams* params, void** out); + +/// Destroys the parity client created with `parity_start`. +/// +/// **Warning**: `parity_start` can return NULL if execution finished instantly, in which case you +/// must not call this function. +void parity_destroy(void* parity); + +#ifdef __cplusplus +} +#endif + +#endif // include guard diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs new file mode 100644 index 00000000000..b08d6487d1a --- /dev/null +++ b/parity-clib/src/lib.rs @@ -0,0 +1,133 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Note that all the structs and functions here are documented in `parity.h`, to avoid +//! duplicating documentation. + +extern crate parity; + +use std::os::raw::{c_char, c_void, c_int}; +use std::panic; +use std::ptr; +use std::slice; + +#[repr(C)] +pub struct ParityParams { + pub configuration: *mut c_void, + pub on_client_restart_cb: Option, + pub on_client_restart_cb_custom: *mut c_void, +} + +#[no_mangle] +pub extern fn parity_config_from_cli(args: *const *const c_char, args_lens: *const usize, len: usize, output: *mut *mut c_void) -> c_int { + unsafe { + panic::catch_unwind(|| { + *output = ptr::null_mut(); + + let args = { + let arg_ptrs = slice::from_raw_parts(args, len); + let arg_lens = slice::from_raw_parts(args_lens, len); + + let mut args = Vec::with_capacity(len + 1); + args.push("parity".to_owned()); + + for (&arg, &len) in arg_ptrs.iter().zip(arg_lens.iter()) { + let string = slice::from_raw_parts(arg as *const u8, len); + match String::from_utf8(string.to_owned()) { + Ok(a) => args.push(a), + Err(_) => return 1, + }; + } + + args + }; + + match parity::Configuration::parse_cli(&args) { + Ok(mut cfg) => { + // Always disable the auto-updater when used as a library. + cfg.args.arg_auto_update = "none".to_owned(); + + let cfg = Box::into_raw(Box::new(cfg)); + *output = cfg as *mut _; + 0 + }, + Err(_) => { + 1 + }, + } + }).unwrap_or(1) + } +} + +#[no_mangle] +pub extern fn parity_config_destroy(cfg: *mut c_void) { + unsafe { + let _ = panic::catch_unwind(|| { + let _cfg = Box::from_raw(cfg as *mut parity::Configuration); + }); + } +} + +#[no_mangle] +pub extern fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) -> c_int { + unsafe { + panic::catch_unwind(|| { + *output = ptr::null_mut(); + let cfg: &ParityParams = &*cfg; + + let config = Box::from_raw(cfg.configuration as *mut parity::Configuration); + + let on_client_restart_cb = { + struct Cb(Option, *mut c_void); + unsafe impl Send for Cb {} + unsafe impl Sync for Cb {} + impl Cb { + fn call(&self, new_chain: String) { + if let Some(ref cb) = self.0 { + cb(self.1, new_chain.as_bytes().as_ptr() as *const _, new_chain.len()) + } + } + } + let cb = Cb(cfg.on_client_restart_cb, cfg.on_client_restart_cb_custom); + move |new_chain: String| { cb.call(new_chain); } + }; + + let action = match parity::start(*config, on_client_restart_cb, || {}) { + Ok(action) => action, + Err(_) => return 1, + }; + + match action { + parity::ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 }, + parity::ExecutionAction::Instant(None) => 0, + parity::ExecutionAction::Running(client) => { + *output = Box::into_raw(Box::::new(client)) as *mut c_void; + 0 + } + } + }).unwrap_or(1) + } +} + +#[no_mangle] +pub extern fn parity_destroy(client: *mut c_void) { + unsafe { + let _ = panic::catch_unwind(|| { + let client = Box::from_raw(client as *mut parity::RunningClient); + client.shutdown(); + }); + } +} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index f9c2f8ba378..027814f2451 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -37,7 +37,6 @@ use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_ use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; -use fdlimit; use ethcore_private_tx; use db; @@ -178,8 +177,6 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { // load user defaults let user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = cmd.pruning.to_algorithm(&user_defaults); @@ -327,8 +324,6 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { // load user defaults let mut user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = cmd.pruning.to_algorithm(&user_defaults); @@ -518,8 +513,6 @@ fn start_client( // load user defaults let user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = pruning.to_algorithm(&user_defaults); diff --git a/parity/cli/usage.rs b/parity/cli/usage.rs index 2bdeaaed1a5..ce138fdff3d 100644 --- a/parity/cli/usage.rs +++ b/parity/cli/usage.rs @@ -198,6 +198,7 @@ macro_rules! usage { } } + /// Parsed command line arguments. #[derive(Debug, PartialEq)] pub struct Args { $( diff --git a/parity/configuration.rs b/parity/configuration.rs index 93cc9a4dd6a..3151621801c 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -92,23 +92,30 @@ pub struct Execute { pub cmd: Cmd, } +/// Configuration for the Parity client. #[derive(Debug, PartialEq)] pub struct Configuration { + /// Arguments to be interpreted. pub args: Args, } impl Configuration { - pub fn parse>(command: &[S]) -> Result { - let args = Args::parse(command)?; - + /// Parses a configuration from a list of command line arguments. + /// + /// # Example + /// + /// ``` + /// let _cfg = parity::Configuration::parse_cli(&["--light", "--chain", "koven"]).unwrap(); + /// ``` + pub fn parse_cli>(command: &[S]) -> Result { let config = Configuration { - args: args, + args: Args::parse(command)?, }; Ok(config) } - pub fn into_command(self) -> Result { + pub(crate) fn into_command(self) -> Result { let dirs = self.directories(); let pruning = self.args.arg_pruning.parse()?; let pruning_history = self.args.arg_pruning_history; @@ -1843,7 +1850,7 @@ mod tests { let filename = tempdir.path().join("peers"); File::create(&filename).unwrap().write_all(b" \n\t\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); assert!(conf.init_reserved_nodes().is_ok()); } @@ -1853,7 +1860,7 @@ mod tests { let filename = tempdir.path().join("peers_comments"); File::create(&filename).unwrap().write_all(b"# Sample comment\nenode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@172.0.0.1:30303\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); let reserved_nodes = conf.init_reserved_nodes(); assert!(reserved_nodes.is_ok()); assert_eq!(reserved_nodes.unwrap().len(), 1); @@ -1862,7 +1869,7 @@ mod tests { #[test] fn test_dev_preset() { let args = vec!["parity", "--config", "dev"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1876,7 +1883,7 @@ mod tests { #[test] fn test_mining_preset() { let args = vec!["parity", "--config", "mining"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 50); @@ -1898,7 +1905,7 @@ mod tests { #[test] fn test_non_standard_ports_preset() { let args = vec!["parity", "--config", "non-standard-ports"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.network_port, 30305); @@ -1911,7 +1918,7 @@ mod tests { #[test] fn test_insecure_preset() { let args = vec!["parity", "--config", "insecure"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.update_policy.require_consensus, false); @@ -1931,7 +1938,7 @@ mod tests { #[test] fn test_dev_insecure_preset() { let args = vec!["parity", "--config", "dev-insecure"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1954,7 +1961,7 @@ mod tests { #[test] fn test_override_preset() { let args = vec!["parity", "--config", "mining", "--min-peers=99"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 99); @@ -2077,7 +2084,7 @@ mod tests { #[test] fn should_respect_only_max_peers_and_default() { let args = vec!["parity", "--max-peers=50"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 25); @@ -2090,7 +2097,7 @@ mod tests { #[test] fn should_respect_only_max_peers_less_than_default() { let args = vec!["parity", "--max-peers=5"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2103,7 +2110,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_default() { let args = vec!["parity", "--min-peers=5"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2116,7 +2123,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_greater_than_default() { let args = vec!["parity", "--min-peers=500"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 500); diff --git a/parity/lib.rs b/parity/lib.rs new file mode 100644 index 00000000000..4d9d1a2c95f --- /dev/null +++ b/parity/lib.rs @@ -0,0 +1,249 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Ethcore client application. + +#![warn(missing_docs)] + +extern crate ansi_term; +extern crate docopt; +#[macro_use] +extern crate clap; +extern crate dir; +extern crate env_logger; +extern crate futures; +extern crate futures_cpupool; +extern crate atty; +extern crate jsonrpc_core; +extern crate num_cpus; +extern crate number_prefix; +extern crate parking_lot; +extern crate regex; +extern crate rlp; +extern crate rpassword; +extern crate rustc_hex; +extern crate semver; +extern crate serde; +extern crate serde_json; +#[macro_use] +extern crate serde_derive; +extern crate toml; + +extern crate ethcore; +extern crate ethcore_bytes as bytes; +extern crate ethcore_io as io; +extern crate ethcore_light as light; +extern crate ethcore_logger; +extern crate ethcore_miner as miner; +extern crate ethcore_network as network; +extern crate ethcore_private_tx; +extern crate ethcore_service; +extern crate ethcore_sync as sync; +extern crate ethcore_transaction as transaction; +extern crate ethereum_types; +extern crate ethkey; +extern crate kvdb; +extern crate node_health; +extern crate panic_hook; +extern crate parity_hash_fetch as hash_fetch; +extern crate parity_ipfs_api; +extern crate parity_local_store as local_store; +extern crate parity_reactor; +extern crate parity_rpc; +extern crate parity_updater as updater; +extern crate parity_version; +extern crate parity_whisper; +extern crate path; +extern crate rpc_cli; +extern crate node_filter; +extern crate keccak_hash as hash; +extern crate journaldb; +extern crate registrar; + +#[macro_use] +extern crate log as rlog; + +#[cfg(feature="secretstore")] +extern crate ethcore_secretstore; + +#[cfg(feature = "dapps")] +extern crate parity_dapps; + +#[cfg(test)] +#[macro_use] +extern crate pretty_assertions; + +#[cfg(windows)] extern crate winapi; + +#[cfg(test)] +extern crate tempdir; + +mod account; +mod blockchain; +mod cache; +mod cli; +mod configuration; +mod dapps; +mod export_hardcoded_sync; +mod ipfs; +mod deprecated; +mod helpers; +mod informant; +mod light_helpers; +mod modules; +mod params; +mod presale; +mod rpc; +mod rpc_apis; +mod run; +mod secretstore; +mod signer; +mod snapshot; +mod upgrade; +mod url; +mod user_defaults; +mod whisper; +mod db; + +use std::net::{TcpListener}; +use std::io::BufReader; +use std::fs::File; +use ansi_term::Style; +use hash::keccak_buffer; +use cli::Args; +use configuration::{Cmd, Execute}; +use deprecated::find_deprecated; +use ethcore_logger::{Config as LogConfig, setup_log}; + +pub use self::configuration::Configuration; +pub use self::run::RunningClient; + +fn print_hash_of(maybe_file: Option) -> Result { + if let Some(file) = maybe_file { + let mut f = BufReader::new(File::open(&file).map_err(|_| "Unable to open file".to_owned())?); + let hash = keccak_buffer(&mut f).map_err(|_| "Unable to read from file".to_owned())?; + Ok(format!("{:x}", hash)) + } else { + Err("Streaming from standard input not yet supported. Specify a file.".to_owned()) + } +} + +/// Action that Parity performed when running `start`. +pub enum ExecutionAction { + /// The execution didn't require starting a node, and thus has finished. + /// Contains the string to print on stdout, if any. + Instant(Option), + + /// The client has started running and must be shut down manually by calling `shutdown`. + /// + /// If you don't call `shutdown()`, execution will continue in the background. + Running(RunningClient), +} + +fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Result + where Cr: Fn(String) + 'static + Send, + Rr: Fn() + 'static + Send +{ + // TODO: move this to `main()` and expose in the C API so that users can setup logging the way + // they want + let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed"); + + match command.cmd { + Cmd::Run(run_cmd) => { + if run_cmd.ui_conf.enabled && !run_cmd.ui_conf.info_page_only { + warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead.")); + warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases")); + } + + if run_cmd.ui && run_cmd.dapps_conf.enabled { + // Check if Parity is already running + let addr = format!("{}:{}", run_cmd.ui_conf.interface, run_cmd.ui_conf.port); + if !TcpListener::bind(&addr as &str).is_ok() { + return open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config).map(|_| ExecutionAction::Instant(None)); + } + } + + // start ui + if run_cmd.ui { + open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config)?; + } + + if let Some(ref dapp) = run_cmd.dapp { + open_dapp(&run_cmd.dapps_conf, &run_cmd.http_conf, dapp)?; + } + + let outcome = run::execute(run_cmd, logger, on_client_rq, on_updater_rq)?; + Ok(ExecutionAction::Running(outcome)) + }, + Cmd::Version => Ok(ExecutionAction::Instant(Some(Args::print_version()))), + Cmd::Hash(maybe_file) => print_hash_of(maybe_file).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| ExecutionAction::Instant(None)), + Cmd::SignerToken(ws_conf, ui_conf, logger_config) => signer::execute(ws_conf, ui_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::ExportHardcodedSync(export_hs_cmd) => export_hardcoded_sync::execute(export_hs_cmd).map(|s| ExecutionAction::Instant(Some(s))), + } +} + +/// Starts the parity client. +/// +/// `on_client_rq` is the action to perform when the client receives an RPC request to be restarted +/// with a different chain. +/// +/// `on_updater_rq` is the action to perform when the updater has a new binary to execute. +/// +/// The first parameter is the command line arguments that you would pass when running the parity +/// binary. +/// +/// On error, returns what to print on stderr. +pub fn start(conf: Configuration, on_client_rq: Cr, on_updater_rq: Rr) -> Result + where Cr: Fn(String) + 'static + Send, + Rr: Fn() + 'static + Send +{ + let deprecated = find_deprecated(&conf.args); + for d in deprecated { + println!("{}", d); + } + + execute(conf.into_command()?, on_client_rq, on_updater_rq) +} + +fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { + if !ui_conf.enabled { + return Err("Cannot use UI command with UI turned off.".into()) + } + + let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; + // Open a browser + url::open(&token.url).map_err(|e| format!("{}", e))?; + // Print a message + println!("{}", token.message); + Ok(()) +} + +fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { + if !dapps_conf.enabled { + return Err("Cannot use DAPP command with Dapps turned off.".into()) + } + + let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); + url::open(&url).map_err(|e| format!("{}", e))?; + Ok(()) +} diff --git a/parity/main.rs b/parity/main.rs index 6774a83864c..e489ad865e4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,187 +18,28 @@ #![warn(missing_docs)] -extern crate ansi_term; +extern crate parity; + extern crate ctrlc; -extern crate docopt; -#[macro_use] -extern crate clap; extern crate dir; -extern crate env_logger; extern crate fdlimit; -extern crate futures; -extern crate futures_cpupool; -extern crate atty; -extern crate jsonrpc_core; -extern crate num_cpus; -extern crate number_prefix; -extern crate parking_lot; -extern crate regex; -extern crate rlp; -extern crate rpassword; -extern crate rustc_hex; -extern crate semver; -extern crate serde; -extern crate serde_json; #[macro_use] -extern crate serde_derive; -extern crate toml; - -extern crate ethcore; -extern crate ethcore_bytes as bytes; -extern crate ethcore_io as io; -extern crate ethcore_light as light; -extern crate ethcore_logger; -extern crate ethcore_miner as miner; -extern crate ethcore_network as network; -extern crate ethcore_private_tx; -extern crate ethcore_service; -extern crate ethcore_sync as sync; -extern crate ethcore_transaction as transaction; -extern crate ethereum_types; -extern crate ethkey; -extern crate kvdb; -extern crate node_health; +extern crate log; extern crate panic_hook; -extern crate parity_hash_fetch as hash_fetch; -extern crate parity_ipfs_api; -extern crate parity_local_store as local_store; -extern crate parity_reactor; -extern crate parity_rpc; -extern crate parity_updater as updater; -extern crate parity_version; -extern crate parity_whisper; -extern crate path; -extern crate rpc_cli; -extern crate node_filter; -extern crate keccak_hash as hash; -extern crate journaldb; -extern crate registrar; - -#[macro_use] -extern crate log as rlog; - -#[cfg(feature="stratum")] -extern crate ethcore_stratum; - -#[cfg(feature="secretstore")] -extern crate ethcore_secretstore; - -#[cfg(feature = "dapps")] -extern crate parity_dapps; - -#[cfg(test)] -#[macro_use] -extern crate pretty_assertions; +extern crate parking_lot; #[cfg(windows)] extern crate winapi; -#[cfg(test)] -extern crate tempdir; - -mod account; -mod blockchain; -mod cache; -mod cli; -mod configuration; -mod dapps; -mod export_hardcoded_sync; -mod ipfs; -mod deprecated; -mod helpers; -mod informant; -mod light_helpers; -mod modules; -mod params; -mod presale; -mod rpc; -mod rpc_apis; -mod run; -mod secretstore; -mod signer; -mod snapshot; -mod upgrade; -mod url; -mod user_defaults; -mod whisper; -mod db; - -#[cfg(feature="stratum")] -mod stratum; - use std::{process, env}; -use std::collections::HashMap; -use std::io::{self as stdio, BufReader, Read, Write}; +use std::io::{self as stdio, Read, Write}; use std::fs::{remove_file, metadata, File, create_dir_all}; use std::path::PathBuf; -use hash::keccak_buffer; -use cli::Args; -use configuration::{Cmd, Execute, Configuration}; -use deprecated::find_deprecated; -use ethcore_logger::setup_log; +use std::sync::Arc; +use ctrlc::CtrlC; use dir::default_hypervisor_path; - -fn print_hash_of(maybe_file: Option) -> Result { - if let Some(file) = maybe_file { - let mut f = BufReader::new(File::open(&file).map_err(|_| "Unable to open file".to_owned())?); - let hash = keccak_buffer(&mut f).map_err(|_| "Unable to read from file".to_owned())?; - Ok(format!("{:x}", hash)) - } else { - Err("Streaming from standard input not yet supported. Specify a file.".to_owned()) - } -} - -enum PostExecutionAction { - Print(String), - Restart(Option), - Quit, -} - -fn execute(command: Execute, can_restart: bool) -> Result { - let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed"); - - match command.cmd { - Cmd::Run(run_cmd) => { - let (restart, spec_name) = run::execute(run_cmd, can_restart, logger)?; - Ok(if restart { PostExecutionAction::Restart(spec_name) } else { PostExecutionAction::Quit }) - }, - Cmd::Version => Ok(PostExecutionAction::Print(Args::print_version())), - Cmd::Hash(maybe_file) => print_hash_of(maybe_file).map(|s| PostExecutionAction::Print(s)), - Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| PostExecutionAction::Print(s)), - Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| PostExecutionAction::Print(s)), - Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| PostExecutionAction::Quit), - Cmd::SignerToken(ws_conf, ui_conf, logger_config) => signer::execute(ws_conf, ui_conf, logger_config).map(|s| PostExecutionAction::Print(s)), - Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| PostExecutionAction::Print(s)), - Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| PostExecutionAction::Print(s)), - Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| PostExecutionAction::Print(s)), - Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd).map(|s| PostExecutionAction::Print(s)), - Cmd::ExportHardcodedSync(export_hs_cmd) => export_hardcoded_sync::execute(export_hs_cmd).map(|s| PostExecutionAction::Print(s)), - } -} - -fn start(mut args: Vec) -> Result { - args.insert(0, "parity".to_owned()); - let conf = Configuration::parse(&args).unwrap_or_else(|e| e.exit()); - let can_restart = conf.args.flag_can_restart; - - let deprecated = find_deprecated(&conf.args); - for d in deprecated { - println!("{}", d); - } - - let cmd = conf.into_command()?; - execute(cmd, can_restart) -} - -#[cfg(not(feature="stratum"))] -fn stratum_main(_: &mut HashMap) {} - -#[cfg(feature="stratum")] -fn stratum_main(alt_mains: &mut HashMap) { - alt_mains.insert("stratum".to_owned(), stratum::main); -} - -fn sync_main(_: &mut HashMap) {} +use fdlimit::raise_fd_limit; +use parity::{start, ExecutionAction}; +use parking_lot::{Condvar, Mutex}; fn updates_path(name: &str) -> PathBuf { let mut dest = PathBuf::from(default_hypervisor_path()); @@ -275,48 +116,68 @@ const PLEASE_RESTART_EXIT_CODE: i32 = 69; // Returns the exit error code. fn main_direct(force_can_restart: bool) -> i32 { global_init(); - let mut alt_mains = HashMap::new(); - sync_main(&mut alt_mains); - stratum_main(&mut alt_mains); - let res = if let Some(f) = std::env::args().nth(1).and_then(|arg| alt_mains.get(&arg.to_string())) { - f(); - 0 + + let mut conf = { + let args = std::env::args().collect::>(); + parity::Configuration::parse_cli(&args).unwrap_or_else(|e| e.exit()) + }; + + if let Some(spec_override) = take_spec_name_override() { + conf.args.flag_testnet = false; + conf.args.arg_chain = spec_override; + } + + let can_restart = force_can_restart || conf.args.flag_can_restart; + + // increase max number of open files + raise_fd_limit(); + + let exit = Arc::new((Mutex::new((false, None)), Condvar::new())); + + let exec = if can_restart { + let e1 = exit.clone(); + let e2 = exit.clone(); + start(conf, + move |new_chain: String| { *e1.0.lock() = (true, Some(new_chain)); e1.1.notify_all(); }, + move || { *e2.0.lock() = (true, None); e2.1.notify_all(); }) } else { - let mut args = std::env::args().skip(1).collect::>(); - if force_can_restart && !args.iter().any(|arg| arg == "--can-restart") { - args.push("--can-restart".to_owned()); - } + trace!(target: "mode", "Not hypervised: not setting exit handlers."); + start(conf, move |_| {}, move || {}) + }; - if let Some(spec_override) = take_spec_name_override() { - args.retain(|f| f != "--testnet"); - args.retain(|f| !f.starts_with("--chain=")); - while let Some(pos) = args.iter().position(|a| a == "--chain") { - if args.len() > pos + 1 { - args.remove(pos + 1); + let res = match exec { + Ok(result) => match result { + ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 }, + ExecutionAction::Instant(None) => 0, + ExecutionAction::Running(client) => { + CtrlC::set_handler({ + let e = exit.clone(); + move || { e.1.notify_all(); } + }); + + // Wait for signal + let mut lock = exit.0.lock(); + let _ = exit.1.wait(&mut lock); + + client.shutdown(); + + match &*lock { + &(true, ref spec_name_override) => { + if let &Some(ref spec_name) = spec_name_override { + set_spec_name_override(spec_name.clone()); + } + PLEASE_RESTART_EXIT_CODE + }, + _ => 0, } - args.remove(pos); - } - args.push("--chain".to_owned()); - args.push(spec_override); - } - - match start(args) { - Ok(result) => match result { - PostExecutionAction::Print(s) => { println!("{}", s); 0 }, - PostExecutionAction::Restart(spec_name_override) => { - if let Some(spec_name) = spec_name_override { - set_spec_name_override(spec_name); - } - PLEASE_RESTART_EXIT_CODE - }, - PostExecutionAction::Quit => 0, - }, - Err(err) => { - writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed"); - 1 }, - } + }, + Err(err) => { + writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed"); + 1 + }, }; + global_cleanup(); res } diff --git a/parity/run.rs b/parity/run.rs index fdb32293b9c..73113055bbf 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -19,10 +19,8 @@ use std::fmt; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; use std::thread; -use std::net::{TcpListener}; -use ansi_term::{Colour, Style}; -use ctrlc::CtrlC; +use ansi_term::Colour; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; use ethcore::ethstore::ethkey; @@ -34,7 +32,6 @@ use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_service::ClientService; use sync::{self, SyncConfig}; use miner::work_notify::WorkPoster; -use fdlimit::raise_fd_limit; use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; @@ -45,7 +42,6 @@ use node_filter::NodeFilter; use node_health; use parity_reactor::EventLoop; use parity_rpc::{NetworkSettings, informant, is_major_importing}; -use parking_lot::{Condvar, Mutex}; use updater::{UpdatePolicy, Updater}; use parity_version::version; use ethcore_private_tx::{ProviderConfig, EncryptorConfig, SecretStoreEncryptor}; @@ -65,7 +61,6 @@ use rpc; use rpc_apis; use secretstore; use signer; -use url; use db; // how often to take periodic snapshots. @@ -138,28 +133,6 @@ pub struct RunCmd { pub no_hardcoded_sync: bool, } -pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { - if !ui_conf.enabled { - return Err("Cannot use UI command with UI turned off.".into()) - } - - let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; - // Open a browser - url::open(&token.url).map_err(|e| format!("{}", e))?; - // Print a message - println!("{}", token.message); - Ok(()) -} - -pub fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { - if !dapps_conf.enabled { - return Err("Cannot use DAPP command with Dapps turned off.".into()) - } - - let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); - url::open(&url).map_err(|e| format!("{}", e))?; - Ok(()) -} // node info fetcher for the local store. struct FullNodeInfo { miner: Option>, // TODO: only TXQ needed, just use that after decoupling. @@ -415,10 +388,12 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: }, }; - // start ui - if cmd.ui { - open_ui(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config)?; - } - - if let Some(dapp) = cmd.dapp { - open_dapp(&cmd.dapps_conf, &cmd.http_conf, &dapp)?; - } - client.set_exit_handler(on_client_rq); updater.set_exit_handler(on_updater_rq); - Ok(RunningClient::Full { - informant, - client, - keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + Ok(RunningClient { + inner: RunningClientInner::Full { + informant, + client, + keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + } }) } -enum RunningClient { +/// Parity client currently executing in background threads. +/// +/// Should be destroyed by calling `shutdown()`, otherwise execution will continue in the +/// background. +pub struct RunningClient { + inner: RunningClientInner +} + +enum RunningClientInner { Light { informant: Arc>, client: Arc, @@ -931,9 +907,10 @@ enum RunningClient { } impl RunningClient { - fn shutdown(self) { - match self { - RunningClient::Light { informant, client, keep_alive } => { + /// Shuts down the client. + pub fn shutdown(self) { + match self.inner { + RunningClientInner::Light { informant, client, keep_alive } => { // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); @@ -943,7 +920,7 @@ impl RunningClient { drop(client); wait_for_drop(weak_client); }, - RunningClient::Full { informant, client, keep_alive } => { + RunningClientInner::Full { informant, client, keep_alive } => { info!("Finishing work, please wait..."); // Create a weak reference to the client so that we can wait on shutdown // until it is dropped @@ -961,51 +938,24 @@ impl RunningClient { } } -pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<(bool, Option), String> { - if cmd.ui_conf.enabled && !cmd.ui_conf.info_page_only { - warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead.")); - warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases")); - } - - if cmd.ui && cmd.dapps_conf.enabled { - // Check if Parity is already running - let addr = format!("{}:{}", cmd.ui_conf.interface, cmd.ui_conf.port); - if !TcpListener::bind(&addr as &str).is_ok() { - return open_ui(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config).map(|_| (false, None)); - } - } - - // increase max number of open files - raise_fd_limit(); - - let exit = Arc::new((Mutex::new((false, None)), Condvar::new())); - - let running_client = if cmd.light { - execute_light_impl(cmd, logger)? - } else if can_restart { - let e1 = exit.clone(); - let e2 = exit.clone(); - execute_impl(cmd, logger, - move |new_chain: String| { *e1.0.lock() = (true, Some(new_chain)); e1.1.notify_all(); }, - move || { *e2.0.lock() = (true, None); e2.1.notify_all(); })? +/// Executes the given run command. +/// +/// `on_client_rq` is the action to perform when the client receives an RPC request to be restarted +/// with a different chain. +/// +/// `on_updater_rq` is the action to perform when the updater has a new binary to execute. +/// +/// On error, returns what to print on stderr. +pub fn execute(cmd: RunCmd, logger: Arc, + on_client_rq: Cr, on_updater_rq: Rr) -> Result + where Cr: Fn(String) + 'static + Send, + Rr: Fn() + 'static + Send +{ + if cmd.light { + execute_light_impl(cmd, logger) } else { - trace!(target: "mode", "Not hypervised: not setting exit handlers."); - execute_impl(cmd, logger, move |_| {}, move || {})? - }; - - // Handle possible exits - CtrlC::set_handler({ - let e = exit.clone(); - move || { e.1.notify_all(); } - }); - - // Wait for signal - let mut l = exit.0.lock(); - let _ = exit.1.wait(&mut l); - - running_client.shutdown(); - - Ok(l.clone()) + execute_impl(cmd, logger, on_client_rq, on_updater_rq) + } } #[cfg(not(windows))] diff --git a/parity/snapshot.rs b/parity/snapshot.rs index ad93801c0b5..423864679a2 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -35,7 +35,6 @@ use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_ use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; -use fdlimit; use ethcore_private_tx; use db; @@ -149,8 +148,6 @@ impl SnapshotCommand { // load user defaults let user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = self.pruning.to_algorithm(&user_defaults); diff --git a/parity/url.rs b/parity/url.rs index 41c4e545831..4f547c28f07 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -80,8 +80,9 @@ pub fn open(url: &str) -> Result<(), Error> { } #[cfg(target_os="android")] -pub fn open(_url: &str) { +pub fn open(_url: &str) -> Result<(), Error> { // TODO: While it is generally always bad to leave a function implemented, there is not much // more we can do here. This function will eventually be removed when we compile Parity // as a library and not as a full binary. + Ok(()) } diff --git a/test.sh b/test.sh index 84940a6aca4..6dcd258ea36 100755 --- a/test.sh +++ b/test.sh @@ -40,8 +40,18 @@ echo "________Validate chainspecs________" fi -# Running test's +# Running the C example +echo "________Running the C example________" +cd parity-clib-example && \ + mkdir -p build && \ + cd build && \ + cmake .. && \ + make && \ + ./parity-example && \ + cd .. && \ + rm -rf build && \ + cd .. + +# Running tests echo "________Running Parity Full Test Suite________" - cargo test -j 8 $OPTIONS --features "$FEATURES" --all $1 - From a22ff24ce3548a908e95d17362d9129150989755 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 9 May 2018 14:48:55 +0800 Subject: [PATCH 069/147] Trace precompiled contracts when the transfer value is not zero (#8486) * Trace precompiled contracts when the transfer value is not zero * Add tests for precompiled CALL tracing * Use byzantium test machine for the new test * Add notes in comments on why we don't trace all precompileds * Use is_transferred instead of transferred --- ethcore/src/executive.rs | 86 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index cded6358e8f..e29da093c7d 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -428,8 +428,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { self.state.discard_checkpoint(); output.write(0, &builtin_out_buffer); - // trace only top level calls to builtins to avoid DDoS attacks - if self.depth == 0 { + // Trace only top level calls and calls with balance transfer to builtins. The reason why we don't + // trace all internal calls to builtin contracts is that memcpy (IDENTITY) is a heavily used + // function. + let is_transferred = match params.value { + ActionValue::Transfer(value) => value != U256::zero(), + ActionValue::Apparent(_) => false, + }; + if self.depth == 0 || is_transferred { let mut trace_output = tracer.prepare_trace_output(); if let Some(out) = trace_output.as_mut() { *out = output.to_owned(); @@ -722,6 +728,12 @@ mod tests { machine } + fn make_byzantium_machine(max_depth: usize) -> EthereumMachine { + let mut machine = ::ethereum::new_byzantium_test_machine(); + machine.set_schedule_creation_rules(Box::new(move |s, _| s.max_depth = max_depth)); + machine + } + #[test] fn test_contract_address() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); @@ -813,6 +825,76 @@ mod tests { assert_eq!(substate.contracts_created.len(), 0); } + #[test] + fn test_call_to_precompiled_tracing() { + // code: + // + // 60 00 - push 00 out size + // 60 00 - push 00 out offset + // 60 00 - push 00 in size + // 60 00 - push 00 in offset + // 60 01 - push 01 value + // 60 03 - push 03 to + // 61 ffff - push fff gas + // f1 - CALL + + let code = "60006000600060006001600361fffff1".from_hex().unwrap(); + let sender = Address::from_str("4444444444444444444444444444444444444444").unwrap(); + let address = Address::from_str("5555555555555555555555555555555555555555").unwrap(); + + let mut params = ActionParams::default(); + params.address = address.clone(); + params.code_address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + params.value = ActionValue::Transfer(U256::from(100)); + params.call_type = CallType::Call; + let mut state = get_temp_state(); + state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); + let info = EnvInfo::default(); + let machine = make_byzantium_machine(5); + let mut substate = Substate::new(); + let mut tracer = ExecutiveTracer::default(); + let mut vm_tracer = ExecutiveVMTracer::toplevel(); + + let mut ex = Executive::new(&mut state, &info, &machine); + let output = BytesRef::Fixed(&mut[0u8;0]); + ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap(); + + assert_eq!(tracer.drain(), vec![FlatTrace { + action: trace::Action::Call(trace::Call { + from: "4444444444444444444444444444444444444444".into(), + to: "5555555555555555555555555555555555555555".into(), + value: 100.into(), + gas: 100_000.into(), + input: vec![], + call_type: CallType::Call + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 33021.into(), + output: vec![] + }), + subtraces: 1, + trace_address: Default::default() + }, FlatTrace { + action: trace::Action::Call(trace::Call { + from: "5555555555555555555555555555555555555555".into(), + to: "0000000000000000000000000000000000000003".into(), + value: 1.into(), + gas: 66560.into(), + input: vec![], + call_type: CallType::Call + }), result: trace::Res::Call(trace::CallResult { + gas_used: 600.into(), + output: vec![] + }), + subtraces: 0, + trace_address: vec![0].into_iter().collect(), + }]); + } + #[test] // Tracing is not suported in JIT fn test_call_to_create() { From eadd68b8e29eef30eccfea64dd845bd434551104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 May 2018 08:49:34 +0200 Subject: [PATCH 070/147] Don't block sync when importing old blocks (#8530) * Alter IO queueing. * Don't require IoMessages to be Clone * Ancient blocks imported via IoChannel. * Get rid of private transactions io message. * Get rid of deadlock and fix disconnected handler. * Revert to old disconnect condition. * Fix tests. * Fix deadlock. --- Cargo.lock | 2 + ethcore/private-tx/src/lib.rs | 250 +++++++++--------- ethcore/private-tx/tests/private_contract.rs | 2 +- ethcore/service/Cargo.toml | 1 + ethcore/service/src/lib.rs | 3 + ethcore/service/src/service.rs | 32 +-- ethcore/src/client/ancient_import.rs | 50 +++- ethcore/src/client/client.rs | 254 +++++++++++-------- ethcore/src/client/io_message.rs | 30 ++- ethcore/src/client/mod.rs | 3 +- ethcore/src/client/test_client.rs | 32 +-- ethcore/src/client/traits.rs | 24 +- ethcore/src/views/block.rs | 5 +- ethcore/sync/Cargo.toml | 1 + ethcore/sync/src/api.rs | 4 + ethcore/sync/src/block_sync.rs | 2 +- ethcore/sync/src/chain.rs | 5 +- ethcore/sync/src/lib.rs | 2 + ethcore/sync/src/tests/helpers.rs | 6 +- ethcore/sync/src/tests/private.rs | 9 +- util/io/src/lib.rs | 4 +- util/io/src/service.rs | 50 ++-- util/io/src/worker.rs | 10 +- 23 files changed, 452 insertions(+), 329 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64e468e6703..b02fcbd24e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -818,6 +818,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "stop-guard 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", ] [[package]] @@ -866,6 +867,7 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", "triehash 0.1.0", ] diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 723d4918298..7aca4c85dc4 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -149,8 +149,8 @@ impl Provider where { encryptor: Box, config: ProviderConfig, channel: IoChannel, - ) -> Result { - Ok(Provider { + ) -> Self { + Provider { encryptor, validator_accounts: config.validator_accounts.into_iter().collect(), signer_account: config.signer_account, @@ -162,7 +162,7 @@ impl Provider where { miner, accounts, channel, - }) + } } // TODO [ToDr] Don't use `ChainNotify` here! @@ -243,50 +243,6 @@ impl Provider where { Ok(original_transaction) } - /// Process received private transaction - pub fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { - trace!("Private transaction received"); - let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?; - let contract = private_tx.contract; - let contract_validators = self.get_validators(BlockId::Latest, &contract)?; - - let validation_account = contract_validators - .iter() - .find(|address| self.validator_accounts.contains(address)); - - match validation_account { - None => { - // TODO [ToDr] This still seems a bit invalid, imho we should still import the transaction to the pool. - // Importing to pool verifies correctness and nonce; here we are just blindly forwarding. - // - // Not for verification, broadcast further to peers - self.broadcast_private_transaction(rlp.into()); - return Ok(()); - }, - Some(&validation_account) => { - let hash = private_tx.hash(); - trace!("Private transaction taken for verification"); - let original_tx = self.extract_original_transaction(private_tx, &contract)?; - trace!("Validating transaction: {:?}", original_tx); - // Verify with the first account available - trace!("The following account will be used for verification: {:?}", validation_account); - let nonce_cache = Default::default(); - self.transactions_for_verification.lock().add_transaction( - original_tx, - contract, - validation_account, - hash, - self.pool_client(&nonce_cache), - )?; - // NOTE This will just fire `on_private_transaction_queued` but from a client thread. - // It seems that a lot of heavy work (verification) is done in this thread anyway - // it might actually make sense to decouple it from clientService and just use dedicated thread - // for both verification and execution. - self.channel.send(ClientIoMessage::NewPrivateTransaction).map_err(|_| ErrorKind::ClientIsMalformed.into()) - } - } - } - fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { let engine = self.client.engine(); let refuse_service_transactions = true; @@ -299,11 +255,6 @@ impl Provider where { ) } - /// Private transaction for validation added into queue - pub fn on_private_transaction_queued(&self) -> Result<(), Error> { - self.process_queue() - } - /// Retrieve and verify the first available private transaction for every sender /// /// TODO [ToDr] It seems that: @@ -347,73 +298,6 @@ impl Provider where { Ok(()) } - /// Add signed private transaction into the store - /// Creates corresponding public transaction if last required singature collected and sends it to the chain - pub fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { - let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?; - trace!("Signature for private transaction received: {:?}", tx); - let private_hash = tx.private_transaction_hash(); - let desc = match self.transactions_for_signing.lock().get(&private_hash) { - None => { - // TODO [ToDr] Verification (we can't just blindly forward every transaction) - - // Not our transaction, broadcast further to peers - self.broadcast_signed_private_transaction(rlp.into()); - return Ok(()); - }, - Some(desc) => desc, - }; - - let last = self.last_required_signature(&desc, tx.signature())?; - - if last { - let mut signatures = desc.received_signatures.clone(); - signatures.push(tx.signature()); - let rsv: Vec = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect(); - //Create public transaction - let public_tx = self.public_transaction( - desc.state.clone(), - &desc.original_transaction, - &rsv, - desc.original_transaction.nonce, - desc.original_transaction.gas_price - )?; - trace!("Last required signature received, public transaction created: {:?}", public_tx); - //Sign and add it to the queue - let chain_id = desc.original_transaction.chain_id(); - let hash = public_tx.hash(chain_id); - let signer_account = self.signer_account.ok_or_else(|| ErrorKind::SignerAccountNotSet)?; - let password = find_account_password(&self.passwords, &*self.accounts, &signer_account); - let signature = self.accounts.sign(signer_account, password, hash)?; - let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?; - match self.miner.import_own_transaction(&*self.client, signed.into()) { - Ok(_) => trace!("Public transaction added to queue"), - Err(err) => { - trace!("Failed to add transaction to queue, error: {:?}", err); - bail!(err); - } - } - //Remove from store for signing - match self.transactions_for_signing.lock().remove(&private_hash) { - Ok(_) => {} - Err(err) => { - trace!("Failed to remove transaction from signing store, error: {:?}", err); - bail!(err); - } - } - } else { - //Add signature to the store - match self.transactions_for_signing.lock().add_signature(&private_hash, tx.signature()) { - Ok(_) => trace!("Signature stored for private transaction"), - Err(err) => { - trace!("Failed to add signature to signing store, error: {:?}", err); - bail!(err); - } - } - } - Ok(()) - } - fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result { if desc.received_signatures.contains(&sign) { return Ok(false); @@ -657,6 +541,134 @@ impl Provider where { } } +pub trait Importer { + /// Process received private transaction + fn import_private_transaction(&self, _rlp: &[u8]) -> Result<(), Error>; + + /// Add signed private transaction into the store + /// + /// Creates corresponding public transaction if last required signature collected and sends it to the chain + fn import_signed_private_transaction(&self, _rlp: &[u8]) -> Result<(), Error>; +} + +// TODO [ToDr] Offload more heavy stuff to the IoService thread. +// It seems that a lot of heavy work (verification) is done in this thread anyway +// it might actually make sense to decouple it from clientService and just use dedicated thread +// for both verification and execution. + +impl Importer for Arc { + fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { + trace!("Private transaction received"); + let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?; + let contract = private_tx.contract; + let contract_validators = self.get_validators(BlockId::Latest, &contract)?; + + let validation_account = contract_validators + .iter() + .find(|address| self.validator_accounts.contains(address)); + + match validation_account { + None => { + // TODO [ToDr] This still seems a bit invalid, imho we should still import the transaction to the pool. + // Importing to pool verifies correctness and nonce; here we are just blindly forwarding. + // + // Not for verification, broadcast further to peers + self.broadcast_private_transaction(rlp.into()); + return Ok(()); + }, + Some(&validation_account) => { + let hash = private_tx.hash(); + trace!("Private transaction taken for verification"); + let original_tx = self.extract_original_transaction(private_tx, &contract)?; + trace!("Validating transaction: {:?}", original_tx); + // Verify with the first account available + trace!("The following account will be used for verification: {:?}", validation_account); + let nonce_cache = Default::default(); + self.transactions_for_verification.lock().add_transaction( + original_tx, + contract, + validation_account, + hash, + self.pool_client(&nonce_cache), + )?; + let provider = Arc::downgrade(self); + self.channel.send(ClientIoMessage::execute(move |_| { + if let Some(provider) = provider.upgrade() { + if let Err(e) = provider.process_queue() { + debug!("Unable to process the queue: {}", e); + } + } + })).map_err(|_| ErrorKind::ClientIsMalformed.into()) + } + } + } + + fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { + let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?; + trace!("Signature for private transaction received: {:?}", tx); + let private_hash = tx.private_transaction_hash(); + let desc = match self.transactions_for_signing.lock().get(&private_hash) { + None => { + // TODO [ToDr] Verification (we can't just blindly forward every transaction) + + // Not our transaction, broadcast further to peers + self.broadcast_signed_private_transaction(rlp.into()); + return Ok(()); + }, + Some(desc) => desc, + }; + + let last = self.last_required_signature(&desc, tx.signature())?; + + if last { + let mut signatures = desc.received_signatures.clone(); + signatures.push(tx.signature()); + let rsv: Vec = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect(); + //Create public transaction + let public_tx = self.public_transaction( + desc.state.clone(), + &desc.original_transaction, + &rsv, + desc.original_transaction.nonce, + desc.original_transaction.gas_price + )?; + trace!("Last required signature received, public transaction created: {:?}", public_tx); + //Sign and add it to the queue + let chain_id = desc.original_transaction.chain_id(); + let hash = public_tx.hash(chain_id); + let signer_account = self.signer_account.ok_or_else(|| ErrorKind::SignerAccountNotSet)?; + let password = find_account_password(&self.passwords, &*self.accounts, &signer_account); + let signature = self.accounts.sign(signer_account, password, hash)?; + let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?; + match self.miner.import_own_transaction(&*self.client, signed.into()) { + Ok(_) => trace!("Public transaction added to queue"), + Err(err) => { + trace!("Failed to add transaction to queue, error: {:?}", err); + bail!(err); + } + } + //Remove from store for signing + match self.transactions_for_signing.lock().remove(&private_hash) { + Ok(_) => {} + Err(err) => { + trace!("Failed to remove transaction from signing store, error: {:?}", err); + bail!(err); + } + } + } else { + //Add signature to the store + match self.transactions_for_signing.lock().add_signature(&private_hash, tx.signature()) { + Ok(_) => trace!("Signature stored for private transaction"), + Err(err) => { + trace!("Failed to add signature to signing store, error: {:?}", err); + bail!(err); + } + } + } + Ok(()) + } +} + /// Try to unlock account using stored password, return found password if any fn find_account_password(passwords: &Vec, account_provider: &AccountProvider, account: &Address) -> Option { for password in passwords { diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs index e53ad5e5f68..e7e608c2b61 100644 --- a/ethcore/private-tx/tests/private_contract.rs +++ b/ethcore/private-tx/tests/private_contract.rs @@ -74,7 +74,7 @@ fn private_contract() { Box::new(NoopEncryptor::default()), config, io, - ).unwrap()); + )); let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]); diff --git a/ethcore/service/Cargo.toml b/ethcore/service/Cargo.toml index b612baf5660..3a10849b61f 100644 --- a/ethcore/service/Cargo.toml +++ b/ethcore/service/Cargo.toml @@ -13,6 +13,7 @@ ethcore-sync = { path = "../sync" } kvdb = { path = "../../util/kvdb" } log = "0.3" stop-guard = { path = "../../util/stop-guard" } +trace-time = { path = "../../util/trace-time" } [dev-dependencies] tempdir = "0.3" diff --git a/ethcore/service/src/lib.rs b/ethcore/service/src/lib.rs index 1604e84b10a..d85a377cde2 100644 --- a/ethcore/service/src/lib.rs +++ b/ethcore/service/src/lib.rs @@ -28,6 +28,9 @@ extern crate error_chain; #[macro_use] extern crate log; +#[macro_use] +extern crate trace_time; + #[cfg(test)] extern crate tempdir; diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index b60d4194c90..5f46799796a 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -33,7 +33,7 @@ use ethcore::snapshot::{RestorationStatus}; use ethcore::spec::Spec; use ethcore::account_provider::AccountProvider; -use ethcore_private_tx; +use ethcore_private_tx::{self, Importer}; use Error; pub struct PrivateTxService { @@ -112,14 +112,13 @@ impl ClientService { account_provider, encryptor, private_tx_conf, - io_service.channel())?, - ); + io_service.channel(), + )); let private_tx = Arc::new(PrivateTxService::new(provider)); let client_io = Arc::new(ClientIoHandler { client: client.clone(), snapshot: snapshot.clone(), - private_tx: private_tx.clone(), }); io_service.register_handler(client_io)?; @@ -175,7 +174,6 @@ impl ClientService { struct ClientIoHandler { client: Arc, snapshot: Arc, - private_tx: Arc, } const CLIENT_TICK_TIMER: TimerToken = 0; @@ -191,6 +189,7 @@ impl IoHandler for ClientIoHandler { } fn timeout(&self, _io: &IoContext, timer: TimerToken) { + trace_time!("service::read"); match timer { CLIENT_TICK_TIMER => { use ethcore::snapshot::SnapshotService; @@ -203,20 +202,24 @@ impl IoHandler for ClientIoHandler { } fn message(&self, _io: &IoContext, net_message: &ClientIoMessage) { + trace_time!("service::message"); use std::thread; match *net_message { - ClientIoMessage::BlockVerified => { self.client.import_verified_blocks(); } - ClientIoMessage::NewTransactions(ref transactions, peer_id) => { - self.client.import_queued_transactions(transactions, peer_id); + ClientIoMessage::BlockVerified => { + self.client.import_verified_blocks(); } ClientIoMessage::BeginRestoration(ref manifest) => { if let Err(e) = self.snapshot.init_restore(manifest.clone(), true) { warn!("Failed to initialize snapshot restoration: {}", e); } } - ClientIoMessage::FeedStateChunk(ref hash, ref chunk) => self.snapshot.feed_state_chunk(*hash, chunk), - ClientIoMessage::FeedBlockChunk(ref hash, ref chunk) => self.snapshot.feed_block_chunk(*hash, chunk), + ClientIoMessage::FeedStateChunk(ref hash, ref chunk) => { + self.snapshot.feed_state_chunk(*hash, chunk) + } + ClientIoMessage::FeedBlockChunk(ref hash, ref chunk) => { + self.snapshot.feed_block_chunk(*hash, chunk) + } ClientIoMessage::TakeSnapshot(num) => { let client = self.client.clone(); let snapshot = self.snapshot.clone(); @@ -231,12 +234,9 @@ impl IoHandler for ClientIoHandler { debug!(target: "snapshot", "Failed to initialize periodic snapshot thread: {:?}", e); } }, - ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) { - trace!(target: "poa", "Invalid message received: {}", e); - }, - ClientIoMessage::NewPrivateTransaction => if let Err(e) = self.private_tx.provider.on_private_transaction_queued() { - warn!("Failed to handle private transaction {:?}", e); - }, + ClientIoMessage::Execute(ref exec) => { + (*exec.0)(&self.client); + } _ => {} // ignore other messages } } diff --git a/ethcore/src/client/ancient_import.rs b/ethcore/src/client/ancient_import.rs index 13699ea5a0e..c2523a13a56 100644 --- a/ethcore/src/client/ancient_import.rs +++ b/ethcore/src/client/ancient_import.rs @@ -32,16 +32,16 @@ const HEAVY_VERIFY_RATE: f32 = 0.02; /// Ancient block verifier: import an ancient sequence of blocks in order from a starting /// epoch. pub struct AncientVerifier { - cur_verifier: RwLock>>, + cur_verifier: RwLock>>>, engine: Arc, } impl AncientVerifier { - /// Create a new ancient block verifier with the given engine and initial verifier. - pub fn new(engine: Arc, start_verifier: Box>) -> Self { + /// Create a new ancient block verifier with the given engine. + pub fn new(engine: Arc) -> Self { AncientVerifier { - cur_verifier: RwLock::new(start_verifier), - engine: engine, + cur_verifier: RwLock::new(None), + engine, } } @@ -53,17 +53,49 @@ impl AncientVerifier { header: &Header, chain: &BlockChain, ) -> Result<(), ::error::Error> { - match rng.gen::() <= HEAVY_VERIFY_RATE { - true => self.cur_verifier.read().verify_heavy(header)?, - false => self.cur_verifier.read().verify_light(header)?, + // perform verification + let verified = if let Some(ref cur_verifier) = *self.cur_verifier.read() { + match rng.gen::() <= HEAVY_VERIFY_RATE { + true => cur_verifier.verify_heavy(header)?, + false => cur_verifier.verify_light(header)?, + } + true + } else { + false + }; + + // when there is no verifier initialize it. + // We use a bool flag to avoid double locking in the happy case + if !verified { + { + let mut cur_verifier = self.cur_verifier.write(); + if cur_verifier.is_none() { + *cur_verifier = Some(self.initial_verifier(header, chain)?); + } + } + // Call again to verify. + return self.verify(rng, header, chain); } // ancient import will only use transitions obtained from the snapshot. if let Some(transition) = chain.epoch_transition(header.number(), header.hash()) { let v = self.engine.epoch_verifier(&header, &transition.proof).known_confirmed()?; - *self.cur_verifier.write() = v; + *self.cur_verifier.write() = Some(v); } Ok(()) } + + fn initial_verifier(&self, header: &Header, chain: &BlockChain) + -> Result>, ::error::Error> + { + trace!(target: "client", "Initializing ancient block restoration."); + let current_epoch_data = chain.epoch_transitions() + .take_while(|&(_, ref t)| t.block_number < header.number()) + .last() + .map(|(_, t)| t.proof) + .expect("At least one epoch entry (genesis) always stored; qed"); + + self.engine.epoch_verifier(&header, ¤t_epoch_data).known_confirmed() + } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8119ebd35f6..bffa4e38ba8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -15,15 +15,16 @@ // along with Parity. If not, see . use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; +use std::fmt; use std::str::FromStr; -use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; +use std::sync::{Arc, Weak}; use std::time::{Instant, Duration}; -use itertools::Itertools; // util use hash::keccak; use bytes::Bytes; +use itertools::Itertools; use journaldb; use trie::{TrieSpec, TrieFactory, Trie}; use kvdb::{DBValue, KeyValueDB, DBTransaction}; @@ -45,7 +46,8 @@ use client::{ use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, - ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType + ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType, + IoClient, }; use encoded; use engines::{EthEngine, EpochTransition}; @@ -55,7 +57,7 @@ use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; use factory::{Factories, VmFactory}; use header::{BlockNumber, Header}; -use io::IoChannel; +use io::{IoChannel, IoError}; use log_entry::LocalizedLogEntry; use miner::{Miner, MinerService}; use ethcore_miner::pool::VerifiedTransaction; @@ -85,6 +87,7 @@ pub use verification::queue::QueueInfo as BlockQueueInfo; use_contract!(registry, "Registry", "res/contracts/registrar.json"); const MAX_TX_QUEUE_SIZE: usize = 4096; +const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096; const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2; const MIN_HISTORY_SIZE: u64 = 8; @@ -154,10 +157,7 @@ struct Importer { pub miner: Arc, /// Ancient block verifier: import an ancient sequence of blocks in order from a starting epoch - pub ancient_verifier: Mutex>, - - /// Random number generator used by `AncientVerifier` - pub rng: Mutex, + pub ancient_verifier: AncientVerifier, /// Ethereum engine to be used during import pub engine: Arc, @@ -204,8 +204,13 @@ pub struct Client { /// List of actors to be notified on certain chain events notify: RwLock>>, - /// Count of pending transactions in the queue - queue_transactions: AtomicUsize, + /// Queued transactions from IO + queue_transactions: IoChannelQueue, + /// Ancient blocks import queue + queue_ancient_blocks: IoChannelQueue, + /// Consensus messages import queue + queue_consensus_message: IoChannelQueue, + last_hashes: RwLock>, factories: Factories, @@ -239,8 +244,7 @@ impl Importer { verifier: verification::new(config.verifier_type.clone()), block_queue, miner, - ancient_verifier: Mutex::new(None), - rng: Mutex::new(OsRng::new()?), + ancient_verifier: AncientVerifier::new(engine.clone()), engine, }) } @@ -416,55 +420,25 @@ impl Importer { Ok(locked_block) } + /// Import a block with transaction receipts. /// /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. - fn import_old_block(&self, header: &Header, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { - let receipts = ::rlp::decode_list(&receipts_bytes); + fn import_old_block(&self, header: &Header, block_bytes: &[u8], receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result { + let receipts = ::rlp::decode_list(receipts_bytes); let hash = header.hash(); let _import_lock = self.import_lock.lock(); { trace_time!("import_old_block"); - let mut ancient_verifier = self.ancient_verifier.lock(); - - { - // closure for verifying a block. - let verify_with = |verifier: &AncientVerifier| -> Result<(), ::error::Error> { - // verify the block, passing the chain for updating the epoch - // verifier. - let mut rng = OsRng::new().map_err(UtilError::from)?; - verifier.verify(&mut rng, &header, &chain) - }; - - // initialize the ancient block verifier if we don't have one already. - match &mut *ancient_verifier { - &mut Some(ref verifier) => { - verify_with(verifier)? - } - x @ &mut None => { - // load most recent epoch. - trace!(target: "client", "Initializing ancient block restoration."); - let current_epoch_data = chain.epoch_transitions() - .take_while(|&(_, ref t)| t.block_number < header.number()) - .last() - .map(|(_, t)| t.proof) - .expect("At least one epoch entry (genesis) always stored; qed"); - - let current_verifier = self.engine.epoch_verifier(&header, ¤t_epoch_data) - .known_confirmed()?; - let current_verifier = AncientVerifier::new(self.engine.clone(), current_verifier); - - verify_with(¤t_verifier)?; - *x = Some(current_verifier); - } - } - } + // verify the block, passing the chain for updating the epoch verifier. + let mut rng = OsRng::new().map_err(UtilError::from)?; + self.ancient_verifier.verify(&mut rng, &header, &chain)?; // Commit results let mut batch = DBTransaction::new(); - chain.insert_unordered_block(&mut batch, &block_bytes, receipts, None, false, true); + chain.insert_unordered_block(&mut batch, block_bytes, receipts, None, false, true); // Final commit to the DB db.write_buffered(batch); chain.commit(); @@ -734,7 +708,9 @@ impl Client { report: RwLock::new(Default::default()), io_channel: Mutex::new(message_channel), notify: RwLock::new(Vec::new()), - queue_transactions: AtomicUsize::new(0), + queue_transactions: IoChannelQueue::new(MAX_TX_QUEUE_SIZE), + queue_ancient_blocks: IoChannelQueue::new(MAX_ANCIENT_BLOCKS_QUEUE_SIZE), + queue_consensus_message: IoChannelQueue::new(usize::max_value()), last_hashes: RwLock::new(VecDeque::new()), factories: factories, history: history, @@ -820,7 +796,7 @@ impl Client { } fn notify(&self, f: F) where F: Fn(&ChainNotify) { - for np in self.notify.read().iter() { + for np in &*self.notify.read() { if let Some(n) = np.upgrade() { f(&*n); } @@ -954,24 +930,6 @@ impl Client { } } - /// Import transactions from the IO queue - pub fn import_queued_transactions(&self, transactions: &[Bytes], peer_id: usize) -> usize { - trace_time!("import_queued_transactions"); - self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst); - - let txs: Vec = transactions - .iter() - .filter_map(|bytes| self.engine().decode_transaction(bytes).ok()) - .collect(); - - self.notify(|notify| { - notify.transactions_received(&txs, peer_id); - }); - - let results = self.importer.miner.import_external_transactions(self, txs); - results.len() - } - /// Get shared miner reference. #[cfg(test)] pub fn miner(&self) -> Arc { @@ -1392,22 +1350,6 @@ impl ImportBlock for Client { } Ok(self.importer.block_queue.import(unverified)?) } - - fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { - let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; - { - // check block order - if self.chain.read().is_known(&header.hash()) { - bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); - } - let status = self.block_status(BlockId::Hash(*header.parent_hash())); - if status == BlockStatus::Unknown || status == BlockStatus::Pending { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); - } - } - - self.importer.import_old_block(&header, block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into) - } } impl StateClient for Client { @@ -1958,35 +1900,10 @@ impl BlockChainClient for Client { (*self.build_last_hashes(&self.chain.read().best_block_hash())).clone() } - fn queue_transactions(&self, transactions: Vec, peer_id: usize) { - let queue_size = self.queue_transactions.load(AtomicOrdering::Relaxed); - trace!(target: "external_tx", "Queue size: {}", queue_size); - if queue_size > MAX_TX_QUEUE_SIZE { - debug!("Ignoring {} transactions: queue is full", transactions.len()); - } else { - let len = transactions.len(); - match self.io_channel.lock().send(ClientIoMessage::NewTransactions(transactions, peer_id)) { - Ok(_) => { - self.queue_transactions.fetch_add(len, AtomicOrdering::SeqCst); - } - Err(e) => { - debug!("Ignoring {} transactions: error queueing: {}", len, e); - } - } - } - } - fn ready_transactions(&self) -> Vec> { self.importer.miner.ready_transactions(self) } - fn queue_consensus_message(&self, message: Bytes) { - let channel = self.io_channel.lock().clone(); - if let Err(e) = channel.send(ClientIoMessage::NewMessage(message)) { - debug!("Ignoring the message, error queueing: {}", e); - } - } - fn signing_chain_id(&self) -> Option { self.engine.signing_chain_id(&self.latest_env_info()) } @@ -2034,6 +1951,72 @@ impl BlockChainClient for Client { } } +impl IoClient for Client { + fn queue_transactions(&self, transactions: Vec, peer_id: usize) { + let len = transactions.len(); + self.queue_transactions.queue(&mut self.io_channel.lock(), len, move |client| { + trace_time!("import_queued_transactions"); + + let txs: Vec = transactions + .iter() + .filter_map(|bytes| client.engine.decode_transaction(bytes).ok()) + .collect(); + + client.notify(|notify| { + notify.transactions_received(&txs, peer_id); + }); + + client.importer.miner.import_external_transactions(client, txs); + }).unwrap_or_else(|e| { + debug!(target: "client", "Ignoring {} transactions: {}", len, e); + }); + } + + fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { + let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; + let hash = header.hash(); + + { + // check block order + if self.chain.read().is_known(&header.hash()) { + bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); + } + let status = self.block_status(BlockId::Hash(*header.parent_hash())); + if status == BlockStatus::Unknown || status == BlockStatus::Pending { + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); + } + } + + match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), 1, move |client| { + client.importer.import_old_block( + &header, + &block_bytes, + &receipts_bytes, + &**client.db.read(), + &*client.chain.read() + ).map(|_| ()).unwrap_or_else(|e| { + error!(target: "client", "Error importing ancient block: {}", e); + }); + }) { + Ok(_) => Ok(hash), + Err(e) => bail!(BlockImportErrorKind::Other(format!("{}", e))), + } + } + + fn queue_consensus_message(&self, message: Bytes) { + match self.queue_consensus_message.queue(&mut self.io_channel.lock(), 1, move |client| { + if let Err(e) = client.engine().handle_message(&message) { + debug!(target: "poa", "Invalid message received: {}", e); + } + }) { + Ok(_) => (), + Err(e) => { + debug!(target: "poa", "Ignoring the message, error queueing: {}", e); + } + } + } +} + impl ReopenBlock for Client { fn reopen_block(&self, block: ClosedBlock) -> OpenBlock { let engine = &*self.engine; @@ -2409,3 +2392,54 @@ mod tests { }); } } + +#[derive(Debug)] +enum QueueError { + Channel(IoError), + Full(usize), +} + +impl fmt::Display for QueueError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + QueueError::Channel(ref c) => fmt::Display::fmt(c, fmt), + QueueError::Full(limit) => write!(fmt, "The queue is full ({})", limit), + } + } +} + +/// Queue some items to be processed by IO client. +struct IoChannelQueue { + currently_queued: Arc, + limit: usize, +} + +impl IoChannelQueue { + pub fn new(limit: usize) -> Self { + IoChannelQueue { + currently_queued: Default::default(), + limit, + } + } + + pub fn queue(&self, channel: &mut IoChannel, count: usize, fun: F) -> Result<(), QueueError> where + F: Fn(&Client) + Send + Sync + 'static, + { + let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed); + ensure!(queue_size < self.limit, QueueError::Full(self.limit)); + + let currently_queued = self.currently_queued.clone(); + let result = channel.send(ClientIoMessage::execute(move |client| { + currently_queued.fetch_sub(count, AtomicOrdering::SeqCst); + fun(client); + })); + + match result { + Ok(_) => { + self.currently_queued.fetch_add(count, AtomicOrdering::SeqCst); + Ok(()) + }, + Err(e) => Err(QueueError::Channel(e)), + } + } +} diff --git a/ethcore/src/client/io_message.rs b/ethcore/src/client/io_message.rs index e19d3054fe0..817c7260205 100644 --- a/ethcore/src/client/io_message.rs +++ b/ethcore/src/client/io_message.rs @@ -14,19 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; +use std::fmt; use bytes::Bytes; +use client::Client; +use ethereum_types::H256; use snapshot::ManifestData; /// Message type for external and internal events -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Debug)] pub enum ClientIoMessage { /// Best Block Hash in chain has been changed NewChainHead, /// A block is ready BlockVerified, - /// New transaction RLPs are ready to be imported - NewTransactions(Vec, usize), /// Begin snapshot restoration BeginRestoration(ManifestData), /// Feed a state chunk to the snapshot service @@ -35,9 +35,23 @@ pub enum ClientIoMessage { FeedBlockChunk(H256, Bytes), /// Take a snapshot for the block with given number. TakeSnapshot(u64), - /// New consensus message received. - NewMessage(Bytes), - /// New private transaction arrived - NewPrivateTransaction, + /// Execute wrapped closure + Execute(Callback), +} + +impl ClientIoMessage { + /// Create new `ClientIoMessage` that executes given procedure. + pub fn execute(fun: F) -> Self { + ClientIoMessage::Execute(Callback(Box::new(fun))) + } +} + +/// A function to invoke in the client thread. +pub struct Callback(pub Box); + +impl fmt::Debug for Callback { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "") + } } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 05e2018258f..4c410d30117 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -36,9 +36,8 @@ pub use self::traits::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter }; -//pub use self::private_notify::PrivateNotify; pub use state::StateInfo; -pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient}; +pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient, IoClient}; pub use types::ids::*; pub use types::trace_filter::Filter as TraceFilter; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index c2e06009b64..b229159667d 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -39,7 +39,7 @@ use client::{ PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, - Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter + Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, IoClient }; use db::{NUM_COLUMNS, COL_STATE}; use header::{Header as BlockHeader, BlockNumber}; @@ -556,10 +556,6 @@ impl ImportBlock for TestBlockChainClient { } Ok(h) } - - fn import_block_with_receipts(&self, b: Bytes, _r: Bytes) -> Result { - self.import_block(b) - } } impl Call for TestBlockChainClient { @@ -809,16 +805,6 @@ impl BlockChainClient for TestBlockChainClient { self.traces.read().clone() } - fn queue_transactions(&self, transactions: Vec, _peer_id: usize) { - // import right here - let txs = transactions.into_iter().filter_map(|bytes| Rlp::new(&bytes).as_val().ok()).collect(); - self.miner.import_external_transactions(self, txs); - } - - fn queue_consensus_message(&self, message: Bytes) { - self.spec.engine.handle_message(&message).unwrap(); - } - fn ready_transactions(&self) -> Vec> { self.miner.ready_transactions(self) } @@ -863,6 +849,22 @@ impl BlockChainClient for TestBlockChainClient { fn eip86_transition(&self) -> u64 { u64::max_value() } } +impl IoClient for TestBlockChainClient { + fn queue_transactions(&self, transactions: Vec, _peer_id: usize) { + // import right here + let txs = transactions.into_iter().filter_map(|bytes| Rlp::new(&bytes).as_val().ok()).collect(); + self.miner.import_external_transactions(self, txs); + } + + fn queue_ancient_block(&self, b: Bytes, _r: Bytes) -> Result { + self.import_block(b) + } + + fn queue_consensus_message(&self, message: Bytes) { + self.spec.engine.handle_message(&message).unwrap(); + } +} + impl ProvingBlockChainClient for TestBlockChainClient { fn prove_storage(&self, _: H256, _: H256, _: BlockId) -> Option<(Vec, H256)> { None diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 7d4d5846c69..358e24fa905 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -168,9 +168,6 @@ pub trait RegistryInfo { pub trait ImportBlock { /// Import a block into the blockchain. fn import_block(&self, bytes: Bytes) -> Result; - - /// Import a block with transaction receipts. Does no sealing and transaction validation. - fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result; } /// Provides `call_contract` method @@ -201,8 +198,21 @@ pub trait EngineInfo { fn engine(&self) -> &EthEngine; } +/// IO operations that should off-load heavy work to another thread. +pub trait IoClient: Sync + Send { + /// Queue transactions for importing. + fn queue_transactions(&self, transactions: Vec, peer_id: usize); + + /// Queue block import with transaction receipts. Does no sealing and transaction validation. + fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result; + + /// Queue conensus engine message. + fn queue_consensus_message(&self, message: Bytes); +} + /// Blockchain database client. Owns and manages a blockchain and a block queue. -pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock { +pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock ++ IoClient { /// Look up the block number for the given block ID. fn block_number(&self, id: BlockId) -> Option; @@ -310,12 +320,6 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Get last hashes starting from best block. fn last_hashes(&self) -> LastHashes; - /// Queue transactions for importing. - fn queue_transactions(&self, transactions: Vec, peer_id: usize); - - /// Queue conensus engine message. - fn queue_consensus_message(&self, message: Bytes); - /// List all transactions that are allowed into the next block. fn ready_transactions(&self) -> Vec>; diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index f610504d85f..3bed1818f24 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -29,7 +29,6 @@ pub struct BlockView<'a> { rlp: ViewRlp<'a> } - impl<'a> BlockView<'a> { /// Creates new view onto block from rlp. /// Use the `view!` macro to create this view in order to capture debugging info. @@ -39,9 +38,9 @@ impl<'a> BlockView<'a> { /// ``` /// #[macro_use] /// extern crate ethcore; - /// + /// /// use ethcore::views::{BlockView}; - /// + /// /// fn main() { /// let bytes : &[u8] = &[]; /// let block_view = view!(BlockView, bytes); diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index d2d060e686f..ba03075d0e3 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -30,6 +30,7 @@ heapsize = "0.4" semver = "0.9" smallvec = { version = "0.4", features = ["heapsizeof"] } parking_lot = "0.5" +trace-time = { path = "../../util/trace-time" } ipnetwork = "0.12.6" [dev-dependencies] diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 7690eeb864b..4fd0cbb54dd 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -379,10 +379,12 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { + trace_time!("sync::read"); ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay), *peer, packet_id, data); } fn connected(&self, io: &NetworkContext, peer: &PeerId) { + trace_time!("sync::connected"); // If warp protocol is supported only allow warp handshake let warp_protocol = io.protocol_version(WARP_SYNC_PROTOCOL_ID, *peer).unwrap_or(0) != 0; let warp_context = io.subprotocol_name() == WARP_SYNC_PROTOCOL_ID; @@ -392,12 +394,14 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } fn disconnected(&self, io: &NetworkContext, peer: &PeerId) { + trace_time!("sync::disconnected"); if io.subprotocol_name() != WARP_SYNC_PROTOCOL_ID { self.sync.write().on_peer_aborting(&mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay), *peer); } } fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { + trace_time!("sync::timeout"); let mut io = NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay); self.sync.write().maintain_peers(&mut io); self.sync.write().maintain_sync(&mut io); diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index 4a5acae526b..7411fa30ccf 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -496,7 +496,7 @@ impl BlockDownloader { } let result = if let Some(receipts) = receipts { - io.chain().import_block_with_receipts(block, receipts) + io.chain().queue_ancient_block(block, receipts) } else { io.chain().import_block(block) }; diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index 25d9a09f6bc..1a6af101159 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -1789,10 +1789,13 @@ impl ChainSync { } pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + debug!(target: "sync", "{} -> Dispatching packet: {}", peer, packet_id); + if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) { debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); return; } + let rlp = Rlp::new(data); let result = match packet_id { STATUS_PACKET => self.on_peer_status(io, peer, &rlp), @@ -1831,7 +1834,7 @@ impl ChainSync { PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, }; if timeout { - trace!(target:"sync", "Timeout {}", peer_id); + debug!(target:"sync", "Timeout {}", peer_id); io.disconnect_peer(*peer_id); aborting.push(*peer_id); } diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index a3e24bdb823..3eb2e8332b4 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -54,6 +54,8 @@ extern crate macros; extern crate log; #[macro_use] extern crate heapsize; +#[macro_use] +extern crate trace_time; mod chain; mod blocks; diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index dc52fdd8b85..3a4697cc093 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -520,11 +520,9 @@ impl TestIoHandler { impl IoHandler for TestIoHandler { fn message(&self, _io: &IoContext, net_message: &ClientIoMessage) { match *net_message { - ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) { - panic!("Invalid message received: {}", e); - }, - ClientIoMessage::NewPrivateTransaction => { + ClientIoMessage::Execute(ref exec) => { *self.private_tx_queued.lock() += 1; + (*exec.0)(&self.client); }, _ => {} // ignore other messages } diff --git a/ethcore/sync/src/tests/private.rs b/ethcore/sync/src/tests/private.rs index a9e8718e5e7..b54240bfb87 100644 --- a/ethcore/sync/src/tests/private.rs +++ b/ethcore/sync/src/tests/private.rs @@ -24,7 +24,7 @@ use ethcore::CreateContractAddress; use transaction::{Transaction, Action}; use ethcore::executive::{contract_address}; use ethcore::test_helpers::{push_block_with_transactions}; -use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor}; +use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer}; use ethcore::account_provider::AccountProvider; use ethkey::{KeyPair}; use tests::helpers::{TestNet, TestIoHandler}; @@ -84,7 +84,7 @@ fn send_private_transaction() { Box::new(NoopEncryptor::default()), signer_config, IoChannel::to_handler(Arc::downgrade(&io_handler0)), - ).unwrap()); + )); pm0.add_notify(net.peers[0].clone()); let pm1 = Arc::new(Provider::new( @@ -94,7 +94,7 @@ fn send_private_transaction() { Box::new(NoopEncryptor::default()), validator_config, IoChannel::to_handler(Arc::downgrade(&io_handler1)), - ).unwrap()); + )); pm1.add_notify(net.peers[1].clone()); // Create and deploy contract @@ -133,7 +133,6 @@ fn send_private_transaction() { //process received private transaction message let private_transaction = received_private_transactions[0].clone(); assert!(pm1.import_private_transaction(&private_transaction).is_ok()); - assert!(pm1.on_private_transaction_queued().is_ok()); //send signed response net.sync(); @@ -147,4 +146,4 @@ fn send_private_transaction() { assert!(pm0.import_signed_private_transaction(&signed_private_transaction).is_ok()); let local_transactions = net.peer(0).miner.local_transactions(); assert_eq!(local_transactions.len(), 1); -} \ No newline at end of file +} diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index 20b908ac91d..9232b2a909a 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -106,7 +106,7 @@ impl From<::std::io::Error> for IoError { } } -impl From>> for IoError where Message: Send + Clone { +impl From>> for IoError where Message: Send { fn from(_err: NotifyError>) -> IoError { IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error")) } @@ -115,7 +115,7 @@ impl From>> for IoError where M /// Generic IO handler. /// All the handler function are called from within IO event loop. /// `Message` type is used as notification data -pub trait IoHandler: Send + Sync where Message: Send + Sync + Clone + 'static { +pub trait IoHandler: Send + Sync where Message: Send + Sync + 'static { /// Initialize the handler fn initialize(&self, _io: &IoContext) {} /// Timer function called after a timeout created with `HandlerIo::timeout`. diff --git a/util/io/src/service.rs b/util/io/src/service.rs index 19f2d4b3bb5..0de674ae121 100644 --- a/util/io/src/service.rs +++ b/util/io/src/service.rs @@ -41,7 +41,7 @@ const MAX_HANDLERS: usize = 8; /// Messages used to communicate with the event loop from other threads. #[derive(Clone)] -pub enum IoMessage where Message: Send + Clone + Sized { +pub enum IoMessage where Message: Send + Sized { /// Shutdown the event loop Shutdown, /// Register a new protocol handler. @@ -74,16 +74,16 @@ pub enum IoMessage where Message: Send + Clone + Sized { token: StreamToken, }, /// Broadcast a message across all protocol handlers. - UserMessage(Message) + UserMessage(Arc) } /// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem. -pub struct IoContext where Message: Send + Clone + Sync + 'static { +pub struct IoContext where Message: Send + Sync + 'static { channel: IoChannel, handler: HandlerId, } -impl IoContext where Message: Send + Clone + Sync + 'static { +impl IoContext where Message: Send + Sync + 'static { /// Create a new IO access point. Takes references to all the data that can be updated within the IO handler. pub fn new(channel: IoChannel, handler: HandlerId) -> IoContext { IoContext { @@ -187,7 +187,7 @@ pub struct IoManager where Message: Send + Sync { work_ready: Arc, } -impl IoManager where Message: Send + Sync + Clone + 'static { +impl IoManager where Message: Send + Sync + 'static { /// Creates a new instance and registers it with the event loop. pub fn start( event_loop: &mut EventLoop>, @@ -219,7 +219,7 @@ impl IoManager where Message: Send + Sync + Clone + 'static { } } -impl Handler for IoManager where Message: Send + Clone + Sync + 'static { +impl Handler for IoManager where Message: Send + Sync + 'static { type Timeout = Token; type Message = IoMessage; @@ -317,7 +317,12 @@ impl Handler for IoManager where Message: Send + Clone + Sync for id in 0 .. MAX_HANDLERS { if let Some(h) = self.handlers.read().get(id) { let handler = h.clone(); - self.worker_channel.push(Work { work_type: WorkType::Message(data.clone()), token: 0, handler: handler, handler_id: id }); + self.worker_channel.push(Work { + work_type: WorkType::Message(data.clone()), + token: 0, + handler: handler, + handler_id: id + }); } } self.work_ready.notify_all(); @@ -326,21 +331,30 @@ impl Handler for IoManager where Message: Send + Clone + Sync } } -#[derive(Clone)] -enum Handlers where Message: Send + Clone { +enum Handlers where Message: Send { SharedCollection(Weak>, HandlerId>>>), Single(Weak>), } +impl Clone for Handlers { + fn clone(&self) -> Self { + use self::Handlers::*; + + match *self { + SharedCollection(ref w) => SharedCollection(w.clone()), + Single(ref w) => Single(w.clone()), + } + } +} + /// Allows sending messages into the event loop. All the IO handlers will get the message /// in the `message` callback. -pub struct IoChannel where Message: Send + Clone{ +pub struct IoChannel where Message: Send { channel: Option>>, handlers: Handlers, - } -impl Clone for IoChannel where Message: Send + Clone + Sync + 'static { +impl Clone for IoChannel where Message: Send + Sync + 'static { fn clone(&self) -> IoChannel { IoChannel { channel: self.channel.clone(), @@ -349,11 +363,11 @@ impl Clone for IoChannel where Message: Send + Clone + Sync + } } -impl IoChannel where Message: Send + Clone + Sync + 'static { +impl IoChannel where Message: Send + Sync + 'static { /// Send a message through the channel pub fn send(&self, message: Message) -> Result<(), IoError> { match self.channel { - Some(ref channel) => channel.send(IoMessage::UserMessage(message))?, + Some(ref channel) => channel.send(IoMessage::UserMessage(Arc::new(message)))?, None => self.send_sync(message)? } Ok(()) @@ -413,13 +427,13 @@ impl IoChannel where Message: Send + Clone + Sync + 'static { /// General IO Service. Starts an event loop and dispatches IO requests. /// 'Message' is a notification message type -pub struct IoService where Message: Send + Sync + Clone + 'static { +pub struct IoService where Message: Send + Sync + 'static { thread: Mutex>>, host_channel: Mutex>>, handlers: Arc>, HandlerId>>>, } -impl IoService where Message: Send + Sync + Clone + 'static { +impl IoService where Message: Send + Sync + 'static { /// Starts IO event loop pub fn start() -> Result, IoError> { let mut config = EventLoopBuilder::new(); @@ -462,7 +476,7 @@ impl IoService where Message: Send + Sync + Clone + 'static { /// Send a message over the network. Normaly `HostIo::send` should be used. This can be used from non-io threads. pub fn send_message(&self, message: Message) -> Result<(), IoError> { - self.host_channel.lock().send(IoMessage::UserMessage(message))?; + self.host_channel.lock().send(IoMessage::UserMessage(Arc::new(message)))?; Ok(()) } @@ -472,7 +486,7 @@ impl IoService where Message: Send + Sync + Clone + 'static { } } -impl Drop for IoService where Message: Send + Sync + Clone { +impl Drop for IoService where Message: Send + Sync { fn drop(&mut self) { self.stop() } diff --git a/util/io/src/worker.rs b/util/io/src/worker.rs index 79570d3612a..0f0d448ecb4 100644 --- a/util/io/src/worker.rs +++ b/util/io/src/worker.rs @@ -38,7 +38,7 @@ pub enum WorkType { Writable, Hup, Timeout, - Message(Message) + Message(Arc) } pub struct Work { @@ -65,7 +65,7 @@ impl Worker { wait: Arc, wait_mutex: Arc>, ) -> Worker - where Message: Send + Sync + Clone + 'static { + where Message: Send + Sync + 'static { let deleting = Arc::new(AtomicBool::new(false)); let mut worker = Worker { thread: None, @@ -86,7 +86,7 @@ impl Worker { channel: IoChannel, wait: Arc, wait_mutex: Arc>, deleting: Arc) - where Message: Send + Sync + Clone + 'static { + where Message: Send + Sync + 'static { loop { { let lock = wait_mutex.lock().expect("Poisoned work_loop mutex"); @@ -105,7 +105,7 @@ impl Worker { } } - fn do_work(work: Work, channel: IoChannel) where Message: Send + Sync + Clone + 'static { + fn do_work(work: Work, channel: IoChannel) where Message: Send + Sync + 'static { match work.work_type { WorkType::Readable => { work.handler.stream_readable(&IoContext::new(channel, work.handler_id), work.token); @@ -120,7 +120,7 @@ impl Worker { work.handler.timeout(&IoContext::new(channel, work.handler_id), work.token); } WorkType::Message(message) => { - work.handler.message(&IoContext::new(channel, work.handler_id), &message); + work.handler.message(&IoContext::new(channel, work.handler_id), &*message); } } } From 5a2a75664d655ecd00881f40c65426b743a8a594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 May 2018 08:54:37 +0200 Subject: [PATCH 071/147] Make trace-time publishable. (#8568) --- transaction-pool/Cargo.toml | 2 +- util/trace-time/Cargo.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index 342c376f63c..8965c8cee01 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Parity Technologies "] error-chain = "0.11" log = "0.3" smallvec = "0.4" -trace-time = { path = "../util/trace-time" } +trace-time = { path = "../util/trace-time", version = "0.1" } [dev-dependencies] ethereum-types = "0.3" diff --git a/util/trace-time/Cargo.toml b/util/trace-time/Cargo.toml index 00597ebfc49..288a2c4e47c 100644 --- a/util/trace-time/Cargo.toml +++ b/util/trace-time/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "trace-time" +description = "Easily trace time to execute a scope." version = "0.1.0" authors = ["Parity Technologies "] +license = "GPL-3.0" [dependencies] log = "0.3" From 51cddaaf222e324c07e53a37a19c116f99b24da0 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 9 May 2018 14:55:01 +0800 Subject: [PATCH 072/147] Remove State::replace_backend (#8569) --- ethcore/src/state/mod.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 20d564588c5..5b969bccb93 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -402,19 +402,6 @@ impl State { self.factories.vm.clone() } - /// Swap the current backend for another. - // TODO: [rob] find a less hacky way to avoid duplication of `Client::state_at`. - pub fn replace_backend(self, backend: T) -> State { - State { - db: backend, - root: self.root, - cache: self.cache, - checkpoints: self.checkpoints, - account_start_nonce: self.account_start_nonce, - factories: self.factories, - } - } - /// Create a recoverable checkpoint of this state. pub fn checkpoint(&mut self) { self.checkpoints.get_mut().push(HashMap::new()); From 816e68be7dc2ac823d98a497b47a58c6ed2dfb28 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 9 May 2018 12:05:34 +0200 Subject: [PATCH 073/147] Refactoring `ethcore-sync` - Fixing warp-sync barrier (#8543) * Start dividing sync chain : first supplier method * WIP - updated chain sync supplier * Finish refactoring the Chain Sync Supplier * Create Chain Sync Requester * Add Propagator for Chain Sync * Add the Chain Sync Handler * Move tests from mod -> handler * Move tests to propagator * Refactor SyncRequester arguments * Refactoring peer fork header handler * Fix wrong highest block number in snapshot sync * Small refactor... * Address PR grumbles * Retry failed CI job * Fix tests * PR Grumbles --- ethcore/sync/src/chain.rs | 3112 -------------------------- ethcore/sync/src/chain/handler.rs | 828 +++++++ ethcore/sync/src/chain/mod.rs | 1379 ++++++++++++ ethcore/sync/src/chain/propagator.rs | 636 ++++++ ethcore/sync/src/chain/requester.rs | 154 ++ ethcore/sync/src/chain/supplier.rs | 446 ++++ ethcore/sync/src/tests/snapshot.rs | 12 +- 7 files changed, 3453 insertions(+), 3114 deletions(-) delete mode 100644 ethcore/sync/src/chain.rs create mode 100644 ethcore/sync/src/chain/handler.rs create mode 100644 ethcore/sync/src/chain/mod.rs create mode 100644 ethcore/sync/src/chain/propagator.rs create mode 100644 ethcore/sync/src/chain/requester.rs create mode 100644 ethcore/sync/src/chain/supplier.rs diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs deleted file mode 100644 index 1a6af101159..00000000000 --- a/ethcore/sync/src/chain.rs +++ /dev/null @@ -1,3112 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -/// `BlockChain` synchronization strategy. -/// Syncs to peers and keeps up to date. -/// This implementation uses ethereum protocol v63 -/// -/// Syncing strategy summary. -/// Split the chain into ranges of N blocks each. Download ranges sequentially. Split each range into subchains of M blocks. Download subchains in parallel. -/// State. -/// Sync state consists of the following data: -/// - s: State enum which can be one of the following values: `ChainHead`, `Blocks`, `Idle` -/// - H: A set of downloaded block headers -/// - B: A set of downloaded block bodies -/// - S: Set of block subchain start block hashes to download. -/// - l: Last imported / common block hash -/// - P: A set of connected peers. For each peer we maintain its last known total difficulty and starting block hash being requested if any. -/// General behaviour. -/// We start with all sets empty, l is set to the best block in the block chain, s is set to `ChainHead`. -/// If at any moment a bad block is reported by the block queue, we set s to `ChainHead`, reset l to the best block in the block chain and clear H, B and S. -/// If at any moment P becomes empty, we set s to `ChainHead`, and clear H, B and S. -/// -/// Workflow for `ChainHead` state. -/// In this state we try to get subchain headers with a single `GetBlockHeaders` request. -/// On `NewPeer` / On `Restart`: -/// If peer's total difficulty is higher and there are less than 5 peers downloading, request N/M headers with interval M+1 starting from l -/// On `BlockHeaders(R)`: -/// If R is empty: -/// If l is equal to genesis block hash or l is more than 1000 blocks behind our best hash: -/// Remove current peer from P. set l to the best block in the block chain. Select peer with maximum total difficulty from P and restart. -/// Else -/// Set l to l’s parent and restart. -/// Else if we already have all the headers in the block chain or the block queue: -/// Set s to `Idle`, -/// Else -/// Set S to R, set s to `Blocks`. -/// -/// All other messages are ignored. -/// -/// Workflow for `Blocks` state. -/// In this state we download block headers and bodies from multiple peers. -/// On `NewPeer` / On `Restart`: -/// For all idle peers: -/// Find a set of 256 or less block hashes in H which are not in B and not being downloaded by other peers. If the set is not empty: -/// Request block bodies for the hashes in the set. -/// Else -/// Find an element in S which is not being downloaded by other peers. If found: Request M headers starting from the element. -/// -/// On `BlockHeaders(R)`: -/// If R is empty remove current peer from P and restart. -/// Validate received headers: -/// For each header find a parent in H or R or the blockchain. Restart if there is a block with unknown parent. -/// Find at least one header from the received list in S. Restart if there is none. -/// Go to `CollectBlocks`. -/// -/// On `BlockBodies(R)`: -/// If R is empty remove current peer from P and restart. -/// Add bodies with a matching header in H to B. -/// Go to `CollectBlocks`. -/// -/// `CollectBlocks`: -/// Find a chain of blocks C in H starting from h where h’s parent equals to l. The chain ends with the first block which does not have a body in B. -/// Add all blocks from the chain to the block queue. Remove them from H and B. Set l to the hash of the last block from C. -/// Update and merge subchain heads in S. For each h in S find a chain of blocks in B starting from h. Remove h from S. if the chain does not include an element from S add the end of the chain to S. -/// If H is empty and S contains a single element set s to `ChainHead`. -/// Restart. -/// -/// All other messages are ignored. -/// Workflow for Idle state. -/// On `NewBlock`: -/// Import the block. If the block is unknown set s to `ChainHead` and restart. -/// On `NewHashes`: -/// Set s to `ChainHead` and restart. -/// -/// All other messages are ignored. -/// - -use std::sync::Arc; -use std::collections::{HashSet, HashMap}; -use std::cmp; -use std::time::{Duration, Instant}; -use hash::keccak; -use heapsize::HeapSizeOf; -use ethereum_types::{H256, U256}; -use plain_hasher::H256FastMap; -use parking_lot::RwLock; -use bytes::Bytes; -use rlp::{Rlp, RlpStream, DecoderError, Encodable}; -use network::{self, PeerId, PacketId}; -use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockImportErrorKind, BlockQueueInfo}; -use ethcore::error::*; -use ethcore::snapshot::{ManifestData, RestorationStatus}; -use transaction::SignedTransaction; -use sync_io::SyncIo; -use super::{WarpSync, SyncConfig}; -use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction}; -use rand::Rng; -use snapshot::{Snapshot, ChunkType}; -use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; -use private_tx::PrivateTxHandler; -use transactions_stats::{TransactionsStats, Stats as TransactionStats}; -use transaction::UnverifiedTransaction; - -known_heap_size!(0, PeerInfo); - -type PacketDecodeError = DecoderError; - -/// 63 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_63: u8 = 63; -/// 62 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_62: u8 = 62; -/// 1 version of Parity protocol. -pub const PAR_PROTOCOL_VERSION_1: u8 = 1; -/// 2 version of Parity protocol (consensus messages added). -pub const PAR_PROTOCOL_VERSION_2: u8 = 2; -/// 3 version of Parity protocol (private transactions messages added). -pub const PAR_PROTOCOL_VERSION_3: u8 = 3; - -const MAX_BODIES_TO_SEND: usize = 256; -const MAX_HEADERS_TO_SEND: usize = 512; -const MAX_NODE_DATA_TO_SEND: usize = 1024; -const MAX_RECEIPTS_TO_SEND: usize = 1024; -const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256; -const MIN_PEERS_PROPAGATION: usize = 4; -const MAX_PEERS_PROPAGATION: usize = 128; -const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20; -const MAX_NEW_HASHES: usize = 64; -const MAX_NEW_BLOCK_AGE: BlockNumber = 20; -// maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). -const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; -// Maximal number of transactions in sent in single packet. -const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; -// Min number of blocks to be behind for a snapshot sync -const SNAPSHOT_RESTORE_THRESHOLD: BlockNumber = 30000; -const SNAPSHOT_MIN_PEERS: usize = 3; - -const STATUS_PACKET: u8 = 0x00; -const NEW_BLOCK_HASHES_PACKET: u8 = 0x01; -const TRANSACTIONS_PACKET: u8 = 0x02; -const GET_BLOCK_HEADERS_PACKET: u8 = 0x03; -const BLOCK_HEADERS_PACKET: u8 = 0x04; -const GET_BLOCK_BODIES_PACKET: u8 = 0x05; -const BLOCK_BODIES_PACKET: u8 = 0x06; -const NEW_BLOCK_PACKET: u8 = 0x07; - -const GET_NODE_DATA_PACKET: u8 = 0x0d; -const NODE_DATA_PACKET: u8 = 0x0e; -const GET_RECEIPTS_PACKET: u8 = 0x0f; -const RECEIPTS_PACKET: u8 = 0x10; - -pub const ETH_PACKET_COUNT: u8 = 0x11; - -const GET_SNAPSHOT_MANIFEST_PACKET: u8 = 0x11; -const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12; -const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13; -const SNAPSHOT_DATA_PACKET: u8 = 0x14; -const CONSENSUS_DATA_PACKET: u8 = 0x15; -const PRIVATE_TRANSACTION_PACKET: u8 = 0x16; -const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17; - -pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; - -const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; - -const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); -const STATUS_TIMEOUT: Duration = Duration::from_secs(5); -const HEADERS_TIMEOUT: Duration = Duration::from_secs(15); -const BODIES_TIMEOUT: Duration = Duration::from_secs(20); -const RECEIPTS_TIMEOUT: Duration = Duration::from_secs(10); -const FORK_HEADER_TIMEOUT: Duration = Duration::from_secs(3); -const SNAPSHOT_MANIFEST_TIMEOUT: Duration = Duration::from_secs(5); -const SNAPSHOT_DATA_TIMEOUT: Duration = Duration::from_secs(120); - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -/// Sync state -pub enum SyncState { - /// Collecting enough peers to start syncing. - WaitingPeers, - /// Waiting for snapshot manifest download - SnapshotManifest, - /// Downloading snapshot data - SnapshotData, - /// Waiting for snapshot restoration progress. - SnapshotWaiting, - /// Downloading new blocks - Blocks, - /// Initial chain sync complete. Waiting for new packets - Idle, - /// Block downloading paused. Waiting for block queue to process blocks and free some space - Waiting, - /// Downloading blocks learned from `NewHashes` packet - NewBlocks, -} - -/// Syncing status and statistics -#[derive(Clone, Copy)] -pub struct SyncStatus { - /// State - pub state: SyncState, - /// Syncing protocol version. That's the maximum protocol version we connect to. - pub protocol_version: u8, - /// The underlying p2p network version. - pub network_id: u64, - /// `BlockChain` height for the moment the sync started. - pub start_block_number: BlockNumber, - /// Last fully downloaded and imported block number (if any). - pub last_imported_block_number: Option, - /// Highest block number in the download queue (if any). - pub highest_block_number: Option, - /// Total number of blocks for the sync process. - pub blocks_total: BlockNumber, - /// Number of blocks downloaded so far. - pub blocks_received: BlockNumber, - /// Total number of connected peers - pub num_peers: usize, - /// Total number of active peers. - pub num_active_peers: usize, - /// Heap memory used in bytes. - pub mem_used: usize, - /// Snapshot chunks - pub num_snapshot_chunks: usize, - /// Snapshot chunks downloaded - pub snapshot_chunks_done: usize, - /// Last fully downloaded and imported ancient block number (if any). - pub last_imported_old_block_number: Option, -} - -impl SyncStatus { - /// Indicates if snapshot download is in progress - pub fn is_snapshot_syncing(&self) -> bool { - self.state == SyncState::SnapshotManifest - || self.state == SyncState::SnapshotData - || self.state == SyncState::SnapshotWaiting - } - - /// Returns max no of peers to display in informants - pub fn current_max_peers(&self, min_peers: u32, max_peers: u32) -> u32 { - if self.num_peers as u32 > min_peers { - max_peers - } else { - min_peers - } - } - - /// Is it doing a major sync? - pub fn is_syncing(&self, queue_info: BlockQueueInfo) -> bool { - let is_syncing_state = match self.state { SyncState::Idle | SyncState::NewBlocks => false, _ => true }; - let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3; - is_verifying || is_syncing_state - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -/// Peer data type requested -enum PeerAsking { - Nothing, - ForkHeader, - BlockHeaders, - BlockBodies, - BlockReceipts, - SnapshotManifest, - SnapshotData, -} - -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -/// Block downloader channel. -enum BlockSet { - /// New blocks better than out best blocks - NewBlocks, - /// Missing old blocks - OldBlocks, -} -#[derive(Clone, Eq, PartialEq)] -enum ForkConfirmation { - /// Fork block confirmation pending. - Unconfirmed, - /// Peers chain is too short to confirm the fork. - TooShort, - /// Fork is confirmed. - Confirmed, -} - -#[derive(Clone)] -/// Syncing peer information -struct PeerInfo { - /// eth protocol version - protocol_version: u8, - /// Peer chain genesis hash - genesis: H256, - /// Peer network id - network_id: u64, - /// Peer best block hash - latest_hash: H256, - /// Peer total difficulty if known - difficulty: Option, - /// Type of data currenty being requested from peer. - asking: PeerAsking, - /// A set of block numbers being requested - asking_blocks: Vec, - /// Holds requested header hash if currently requesting block header by hash - asking_hash: Option, - /// Holds requested snapshot chunk hash if any. - asking_snapshot_data: Option, - /// Request timestamp - ask_time: Instant, - /// Holds a set of transactions recently sent to this peer to avoid spamming. - last_sent_transactions: HashSet, - /// Pending request is expired and result should be ignored - expired: bool, - /// Peer fork confirmation status - confirmation: ForkConfirmation, - /// Best snapshot hash - snapshot_hash: Option, - /// Best snapshot block number - snapshot_number: Option, - /// Block set requested - block_set: Option, -} - -impl PeerInfo { - fn can_sync(&self) -> bool { - self.confirmation == ForkConfirmation::Confirmed && !self.expired - } - - fn is_allowed(&self) -> bool { - self.confirmation != ForkConfirmation::Unconfirmed && !self.expired - } - - fn reset_asking(&mut self) { - self.asking_blocks.clear(); - self.asking_hash = None; - // mark any pending requests as expired - if self.asking != PeerAsking::Nothing && self.is_allowed() { - self.expired = true; - } - } -} - -#[cfg(not(test))] -mod random { - use rand; - pub fn new() -> rand::ThreadRng { rand::thread_rng() } -} -#[cfg(test)] -mod random { - use rand::{self, SeedableRng}; - pub fn new() -> rand::XorShiftRng { rand::XorShiftRng::from_seed([0, 1, 2, 3]) } -} - -/// Blockchain sync handler. -/// See module documentation for more details. -pub struct ChainSync { - /// Sync state - state: SyncState, - /// Last block number for the start of sync - starting_block: BlockNumber, - /// Highest block number seen - highest_block: Option, - /// All connected peers - peers: HashMap, - /// Peers active for current sync round - active_peers: HashSet, - /// Block download process for new blocks - new_blocks: BlockDownloader, - /// Block download process for ancient blocks - old_blocks: Option, - /// Last propagated block number - last_sent_block_number: BlockNumber, - /// Network ID - network_id: u64, - /// Optional fork block to check - fork_block: Option<(BlockNumber, H256)>, - /// Snapshot downloader. - snapshot: Snapshot, - /// Connected peers pending Status message. - /// Value is request timestamp. - handshaking_peers: HashMap, - /// Sync start timestamp. Measured when first peer is connected - sync_start_time: Option, - /// Transactions propagation statistics - transactions_stats: TransactionsStats, - /// Enable ancient block downloading - download_old_blocks: bool, - /// Shared private tx service. - private_tx_handler: Arc, - /// Enable warp sync. - warp_sync: WarpSync, -} - -type RlpResponseResult = Result, PacketDecodeError>; - -impl ChainSync { - /// Create a new instance of syncing strategy. - pub fn new(config: SyncConfig, chain: &BlockChainClient, private_tx_handler: Arc) -> ChainSync { - let chain_info = chain.chain_info(); - let best_block = chain.chain_info().best_block_number; - let state = match config.warp_sync { - WarpSync::Enabled => SyncState::WaitingPeers, - WarpSync::OnlyAndAfter(block) if block > best_block => SyncState::WaitingPeers, - _ => SyncState::Idle, - }; - - let mut sync = ChainSync { - state, - starting_block: best_block, - highest_block: None, - peers: HashMap::new(), - handshaking_peers: HashMap::new(), - active_peers: HashSet::new(), - new_blocks: BlockDownloader::new(false, &chain_info.best_block_hash, chain_info.best_block_number), - old_blocks: None, - last_sent_block_number: 0, - network_id: config.network_id, - fork_block: config.fork_block, - download_old_blocks: config.download_old_blocks, - snapshot: Snapshot::new(), - sync_start_time: None, - transactions_stats: TransactionsStats::default(), - private_tx_handler, - warp_sync: config.warp_sync, - }; - sync.update_targets(chain); - sync - } - - /// Returns synchonization status - pub fn status(&self) -> SyncStatus { - let last_imported_number = self.new_blocks.last_imported_block_number(); - SyncStatus { - state: self.state.clone(), - protocol_version: ETH_PROTOCOL_VERSION_63, - network_id: self.network_id, - start_block_number: self.starting_block, - last_imported_block_number: Some(last_imported_number), - last_imported_old_block_number: self.old_blocks.as_ref().map(|d| d.last_imported_block_number()), - highest_block_number: self.highest_block.map(|n| cmp::max(n, last_imported_number)), - blocks_received: if last_imported_number > self.starting_block { last_imported_number - self.starting_block } else { 0 }, - blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, - num_peers: self.peers.values().filter(|p| p.is_allowed()).count(), - num_active_peers: self.peers.values().filter(|p| p.is_allowed() && p.asking != PeerAsking::Nothing).count(), - num_snapshot_chunks: self.snapshot.total_chunks(), - snapshot_chunks_done: self.snapshot.done_chunks(), - mem_used: - self.new_blocks.heap_size() - + self.old_blocks.as_ref().map_or(0, |d| d.heap_size()) - + self.peers.heap_size_of_children(), - } - } - - /// Returns information on peers connections - pub fn peer_info(&self, peer_id: &PeerId) -> Option { - self.peers.get(peer_id).map(|peer_data| { - PeerInfoDigest { - version: peer_data.protocol_version as u32, - difficulty: peer_data.difficulty, - head: peer_data.latest_hash, - } - }) - } - - /// Returns transactions propagation statistics - pub fn transactions_stats(&self) -> &H256FastMap { - self.transactions_stats.stats() - } - - /// Updates transactions were received by a peer - pub fn transactions_received(&mut self, txs: &[UnverifiedTransaction], peer_id: PeerId) { - if let Some(peer_info) = self.peers.get_mut(&peer_id) { - peer_info.last_sent_transactions.extend(txs.iter().map(|tx| tx.hash())); - } - } - - /// Abort all sync activity - pub fn abort(&mut self, io: &mut SyncIo) { - self.reset_and_continue(io); - self.peers.clear(); - } - - /// Reset sync. Clear all downloaded data but keep the queue - fn reset(&mut self, io: &mut SyncIo) { - self.new_blocks.reset(); - let chain_info = io.chain().chain_info(); - for (_, ref mut p) in &mut self.peers { - if p.block_set != Some(BlockSet::OldBlocks) { - p.reset_asking(); - if p.difficulty.is_none() { - // assume peer has up to date difficulty - p.difficulty = Some(chain_info.pending_total_difficulty); - } - } - } - self.state = SyncState::Idle; - // Reactivate peers only if some progress has been made - // since the last sync round of if starting fresh. - self.active_peers = self.peers.keys().cloned().collect(); - } - - /// Restart sync - pub fn reset_and_continue(&mut self, io: &mut SyncIo) { - trace!(target: "sync", "Restarting"); - if self.state == SyncState::SnapshotData { - debug!(target:"sync", "Aborting snapshot restore"); - io.snapshot_service().abort_restore(); - } - self.snapshot.clear(); - self.reset(io); - self.continue_sync(io); - } - - /// Remove peer from active peer set. Peer will be reactivated on the next sync - /// round. - fn deactivate_peer(&mut self, _io: &mut SyncIo, peer_id: PeerId) { - trace!(target: "sync", "Deactivating peer {}", peer_id); - self.active_peers.remove(&peer_id); - } - - fn maybe_start_snapshot_sync(&mut self, io: &mut SyncIo) { - if !self.warp_sync.is_enabled() || io.snapshot_service().supported_versions().is_none() { - trace!(target: "sync", "Skipping warp sync. Disabled or not supported."); - return; - } - if self.state != SyncState::WaitingPeers && self.state != SyncState::Blocks && self.state != SyncState::Waiting { - trace!(target: "sync", "Skipping warp sync. State: {:?}", self.state); - return; - } - // Make sure the snapshot block is not too far away from best block and network best block and - // that it is higher than fork detection block - let our_best_block = io.chain().chain_info().best_block_number; - let fork_block = self.fork_block.as_ref().map(|&(n, _)| n).unwrap_or(0); - - let (best_hash, max_peers, snapshot_peers) = { - let expected_warp_block = match self.warp_sync { - WarpSync::OnlyAndAfter(block) => block, - _ => 0, - }; - //collect snapshot infos from peers - let snapshots = self.peers.iter() - .filter(|&(_, p)| p.is_allowed() && p.snapshot_number.map_or(false, |sn| - our_best_block < sn && (sn - our_best_block) > SNAPSHOT_RESTORE_THRESHOLD && - sn > fork_block && - sn > expected_warp_block && - self.highest_block.map_or(true, |highest| highest >= sn && (highest - sn) <= SNAPSHOT_RESTORE_THRESHOLD) - )) - .filter_map(|(p, peer)| peer.snapshot_hash.map(|hash| (p, hash.clone()))) - .filter(|&(_, ref hash)| !self.snapshot.is_known_bad(hash)); - - let mut snapshot_peers = HashMap::new(); - let mut max_peers: usize = 0; - let mut best_hash = None; - for (p, hash) in snapshots { - let peers = snapshot_peers.entry(hash).or_insert_with(Vec::new); - peers.push(*p); - if peers.len() > max_peers { - max_peers = peers.len(); - best_hash = Some(hash); - } - } - (best_hash, max_peers, snapshot_peers) - }; - - let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed() > WAIT_PEERS_TIMEOUT); - - if let (Some(hash), Some(peers)) = (best_hash, best_hash.map_or(None, |h| snapshot_peers.get(&h))) { - if max_peers >= SNAPSHOT_MIN_PEERS { - trace!(target: "sync", "Starting confirmed snapshot sync {:?} with {:?}", hash, peers); - self.start_snapshot_sync(io, peers); - } else if timeout { - trace!(target: "sync", "Starting unconfirmed snapshot sync {:?} with {:?}", hash, peers); - self.start_snapshot_sync(io, peers); - } - } else if timeout && !self.warp_sync.is_warp_only() { - trace!(target: "sync", "No snapshots found, starting full sync"); - self.state = SyncState::Idle; - self.continue_sync(io); - } - } - - fn start_snapshot_sync(&mut self, io: &mut SyncIo, peers: &[PeerId]) { - if !self.snapshot.have_manifest() { - for p in peers { - if self.peers.get(p).map_or(false, |p| p.asking == PeerAsking::Nothing) { - self.request_snapshot_manifest(io, *p); - } - } - self.state = SyncState::SnapshotManifest; - trace!(target: "sync", "New snapshot sync with {:?}", peers); - } else { - self.state = SyncState::SnapshotData; - trace!(target: "sync", "Resumed snapshot sync with {:?}", peers); - } - } - - /// Restart sync disregarding the block queue status. May end up re-downloading up to QUEUE_SIZE blocks - pub fn restart(&mut self, io: &mut SyncIo) { - self.update_targets(io.chain()); - self.reset_and_continue(io); - } - - /// Update sync after the blockchain has been changed externally. - pub fn update_targets(&mut self, chain: &BlockChainClient) { - // Do not assume that the block queue/chain still has our last_imported_block - let chain = chain.chain_info(); - self.new_blocks = BlockDownloader::new(false, &chain.best_block_hash, chain.best_block_number); - self.old_blocks = None; - if self.download_old_blocks { - if let (Some(ancient_block_hash), Some(ancient_block_number)) = (chain.ancient_block_hash, chain.ancient_block_number) { - - trace!(target: "sync", "Downloading old blocks from {:?} (#{}) till {:?} (#{:?})", ancient_block_hash, ancient_block_number, chain.first_block_hash, chain.first_block_number); - let mut downloader = BlockDownloader::with_unlimited_reorg(true, &ancient_block_hash, ancient_block_number); - if let Some(hash) = chain.first_block_hash { - trace!(target: "sync", "Downloader target set to {:?}", hash); - downloader.set_target(&hash); - } - self.old_blocks = Some(downloader); - } - } - } - - /// Called by peer to report status - fn on_peer_status(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - self.handshaking_peers.remove(&peer_id); - let protocol_version: u8 = r.val_at(0)?; - let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer_id) != 0; - let peer = PeerInfo { - protocol_version: protocol_version, - network_id: r.val_at(1)?, - difficulty: Some(r.val_at(2)?), - latest_hash: r.val_at(3)?, - genesis: r.val_at(4)?, - asking: PeerAsking::Nothing, - asking_blocks: Vec::new(), - asking_hash: None, - ask_time: Instant::now(), - last_sent_transactions: HashSet::new(), - expired: false, - confirmation: if self.fork_block.is_none() { ForkConfirmation::Confirmed } else { ForkConfirmation::Unconfirmed }, - asking_snapshot_data: None, - snapshot_hash: if warp_protocol { Some(r.val_at(5)?) } else { None }, - snapshot_number: if warp_protocol { Some(r.val_at(6)?) } else { None }, - block_set: None, - }; - - trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{}, snapshot:{:?})", - peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis, peer.snapshot_number); - if io.is_expired() { - trace!(target: "sync", "Status packet from expired session {}:{}", peer_id, io.peer_info(peer_id)); - return Ok(()); - } - - if self.peers.contains_key(&peer_id) { - debug!(target: "sync", "Unexpected status packet from {}:{}", peer_id, io.peer_info(peer_id)); - return Ok(()); - } - let chain_info = io.chain().chain_info(); - if peer.genesis != chain_info.genesis_hash { - io.disable_peer(peer_id); - trace!(target: "sync", "Peer {} genesis hash mismatch (ours: {}, theirs: {})", peer_id, chain_info.genesis_hash, peer.genesis); - return Ok(()); - } - if peer.network_id != self.network_id { - io.disable_peer(peer_id); - trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, self.network_id, peer.network_id); - return Ok(()); - } - if (warp_protocol && peer.protocol_version != PAR_PROTOCOL_VERSION_1 && peer.protocol_version != PAR_PROTOCOL_VERSION_2 && peer.protocol_version != PAR_PROTOCOL_VERSION_3) - || (!warp_protocol && peer.protocol_version != ETH_PROTOCOL_VERSION_63 && peer.protocol_version != ETH_PROTOCOL_VERSION_62) { - io.disable_peer(peer_id); - trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); - return Ok(()); - } - - if self.sync_start_time.is_none() { - self.sync_start_time = Some(Instant::now()); - } - - self.peers.insert(peer_id.clone(), peer); - // Don't activate peer immediatelly when searching for common block. - // Let the current sync round complete first. - self.active_peers.insert(peer_id.clone()); - debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); - if let Some((fork_block, _)) = self.fork_block { - self.request_fork_header_by_number(io, peer_id, fork_block); - } else { - self.sync_peer(io, peer_id, false); - } - Ok(()) - } - - /// Called by peer once it has new block headers during sync - fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - let confirmed = match self.peers.get_mut(&peer_id) { - Some(ref mut peer) if peer.asking == PeerAsking::ForkHeader => { - peer.asking = PeerAsking::Nothing; - let item_count = r.item_count()?; - let (fork_number, fork_hash) = self.fork_block.expect("ForkHeader request is sent only fork block is Some; qed").clone(); - if item_count == 0 || item_count != 1 { - trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id); - peer.confirmation = ForkConfirmation::TooShort; - } else { - let header = r.at(0)?.as_raw(); - if keccak(&header) == fork_hash { - trace!(target: "sync", "{}: Confirmed peer", peer_id); - peer.confirmation = ForkConfirmation::Confirmed; - if !io.chain_overlay().read().contains_key(&fork_number) { - io.chain_overlay().write().insert(fork_number, header.to_vec()); - } - } else { - trace!(target: "sync", "{}: Fork mismatch", peer_id); - io.disable_peer(peer_id); - return Ok(()); - } - } - true - }, - _ => false, - }; - if confirmed { - self.sync_peer(io, peer_id, false); - return Ok(()); - } - - self.clear_peer_download(peer_id); - let expected_hash = self.peers.get(&peer_id).and_then(|p| p.asking_hash); - let allowed = self.peers.get(&peer_id).map(|p| p.is_allowed()).unwrap_or(false); - let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders) || expected_hash.is_none() || !allowed { - trace!(target: "sync", "{}: Ignored unexpected headers, expected_hash = {:?}", peer_id, expected_hash); - self.continue_sync(io); - return Ok(()); - } - let item_count = r.item_count()?; - trace!(target: "sync", "{} -> BlockHeaders ({} entries), state = {:?}, set = {:?}", peer_id, item_count, self.state, block_set); - if (self.state == SyncState::Idle || self.state == SyncState::WaitingPeers) && self.old_blocks.is_none() { - trace!(target: "sync", "Ignored unexpected block headers"); - self.continue_sync(io); - return Ok(()); - } - if self.state == SyncState::Waiting { - trace!(target: "sync", "Ignored block headers while waiting"); - self.continue_sync(io); - return Ok(()); - } - - let result = { - let downloader = match block_set { - BlockSet::NewBlocks => &mut self.new_blocks, - BlockSet::OldBlocks => { - match self.old_blocks { - None => { - trace!(target: "sync", "Ignored block headers while block download is inactive"); - self.continue_sync(io); - return Ok(()); - }, - Some(ref mut blocks) => blocks, - } - } - }; - downloader.import_headers(io, r, expected_hash) - }; - - match result { - Err(DownloaderImportError::Useless) => { - self.deactivate_peer(io, peer_id); - }, - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - self.deactivate_peer(io, peer_id); - self.continue_sync(io); - return Ok(()); - }, - Ok(DownloadAction::Reset) => { - // mark all outstanding requests as expired - trace!("Resetting downloads for {:?}", block_set); - for (_, ref mut p) in self.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { - p.reset_asking(); - } - - } - Ok(DownloadAction::None) => {}, - } - - self.collect_blocks(io, block_set); - // give a task to the same peer first if received valuable headers. - self.sync_peer(io, peer_id, false); - // give tasks to other peers - self.continue_sync(io); - Ok(()) - } - - /// Called by peer once it has new block bodies - fn on_peer_block_bodies(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - self.clear_peer_download(peer_id); - let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !self.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { - trace!(target: "sync", "{}: Ignored unexpected bodies", peer_id); - self.continue_sync(io); - return Ok(()); - } - let item_count = r.item_count()?; - trace!(target: "sync", "{} -> BlockBodies ({} entries), set = {:?}", peer_id, item_count, block_set); - if item_count == 0 { - self.deactivate_peer(io, peer_id); - } - else if self.state == SyncState::Waiting { - trace!(target: "sync", "Ignored block bodies while waiting"); - } - else - { - let result = { - let downloader = match block_set { - BlockSet::NewBlocks => &mut self.new_blocks, - BlockSet::OldBlocks => match self.old_blocks { - None => { - trace!(target: "sync", "Ignored block headers while block download is inactive"); - self.continue_sync(io); - return Ok(()); - }, - Some(ref mut blocks) => blocks, - } - }; - downloader.import_bodies(io, r) - }; - - match result { - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - self.deactivate_peer(io, peer_id); - self.continue_sync(io); - return Ok(()); - }, - Err(DownloaderImportError::Useless) => { - self.deactivate_peer(io, peer_id); - }, - Ok(()) => (), - } - - self.collect_blocks(io, block_set); - self.sync_peer(io, peer_id, false); - } - self.continue_sync(io); - Ok(()) - } - - /// Called by peer once it has new block receipts - fn on_peer_block_receipts(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - self.clear_peer_download(peer_id); - let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !self.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { - trace!(target: "sync", "{}: Ignored unexpected receipts", peer_id); - self.continue_sync(io); - return Ok(()); - } - let item_count = r.item_count()?; - trace!(target: "sync", "{} -> BlockReceipts ({} entries)", peer_id, item_count); - if item_count == 0 { - self.deactivate_peer(io, peer_id); - } - else if self.state == SyncState::Waiting { - trace!(target: "sync", "Ignored block receipts while waiting"); - } - else - { - let result = { - let downloader = match block_set { - BlockSet::NewBlocks => &mut self.new_blocks, - BlockSet::OldBlocks => match self.old_blocks { - None => { - trace!(target: "sync", "Ignored block headers while block download is inactive"); - self.continue_sync(io); - return Ok(()); - }, - Some(ref mut blocks) => blocks, - } - }; - downloader.import_receipts(io, r) - }; - - match result { - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - self.deactivate_peer(io, peer_id); - self.continue_sync(io); - return Ok(()); - }, - Err(DownloaderImportError::Useless) => { - self.deactivate_peer(io, peer_id); - }, - Ok(()) => (), - } - - self.collect_blocks(io, block_set); - self.sync_peer(io, peer_id, false); - } - self.continue_sync(io); - Ok(()) - } - - /// Called by peer once it has new block bodies - fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id); - return Ok(()); - } - let difficulty: U256 = r.val_at(1)?; - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - if peer.difficulty.map_or(true, |pd| difficulty > pd) { - peer.difficulty = Some(difficulty); - } - } - let block_rlp = r.at(0)?; - let header_rlp = block_rlp.at(0)?; - let h = keccak(&header_rlp.as_raw()); - trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); - let header: BlockHeader = header_rlp.as_val()?; - if header.number() > self.highest_block.unwrap_or(0) { - self.highest_block = Some(header.number()); - } - let mut unknown = false; - { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.latest_hash = header.hash(); - } - } - let last_imported_number = self.new_blocks.last_imported_block_number(); - if last_imported_number > header.number() && last_imported_number - header.number() > MAX_NEW_BLOCK_AGE { - trace!(target: "sync", "Ignored ancient new block {:?}", h); - io.disable_peer(peer_id); - return Ok(()); - } - match io.chain().import_block(block_rlp.as_raw().to_vec()) { - Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { - trace!(target: "sync", "New block already in chain {:?}", h); - }, - Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { - trace!(target: "sync", "New block already queued {:?}", h); - }, - Ok(_) => { - // abort current download of the same block - self.complete_sync(io); - self.new_blocks.mark_as_known(&header.hash(), header.number()); - trace!(target: "sync", "New block queued {:?} ({})", h, header.number()); - }, - Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => { - unknown = true; - trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); - }, - Err(e) => { - debug!(target: "sync", "Bad new block {:?} : {:?}", h, e); - io.disable_peer(peer_id); - } - }; - if unknown { - if self.state != SyncState::Idle { - trace!(target: "sync", "NewBlock ignored while seeking"); - } else { - trace!(target: "sync", "New unknown block {:?}", h); - //TODO: handle too many unknown blocks - self.sync_peer(io, peer_id, true); - } - } - self.continue_sync(io); - Ok(()) - } - - /// Handles `NewHashes` packet. Initiates headers download for any unknown hashes. - fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id); - return Ok(()); - } - let hashes: Vec<_> = r.iter().take(MAX_NEW_HASHES).map(|item| (item.val_at::(0), item.val_at::(1))).collect(); - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - // Peer has new blocks with unknown difficulty - peer.difficulty = None; - if let Some(&(Ok(ref h), _)) = hashes.last() { - peer.latest_hash = h.clone(); - } - } - if self.state != SyncState::Idle { - trace!(target: "sync", "Ignoring new hashes since we're already downloading."); - let max = r.iter().take(MAX_NEW_HASHES).map(|item| item.val_at::(1).unwrap_or(0)).fold(0u64, cmp::max); - if max > self.highest_block.unwrap_or(0) { - self.highest_block = Some(max); - } - self.continue_sync(io); - return Ok(()); - } - trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count()?); - let mut max_height: BlockNumber = 0; - let mut new_hashes = Vec::new(); - let last_imported_number = self.new_blocks.last_imported_block_number(); - for (rh, rn) in hashes { - let hash = rh?; - let number = rn?; - if number > self.highest_block.unwrap_or(0) { - self.highest_block = Some(number); - } - if self.new_blocks.is_downloading(&hash) { - continue; - } - if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE { - trace!(target: "sync", "Ignored ancient new block hash {:?}", hash); - io.disable_peer(peer_id); - continue; - } - match io.chain().block_status(BlockId::Hash(hash.clone())) { - BlockStatus::InChain => { - trace!(target: "sync", "New block hash already in chain {:?}", hash); - }, - BlockStatus::Queued => { - trace!(target: "sync", "New hash block already queued {:?}", hash); - }, - BlockStatus::Unknown | BlockStatus::Pending => { - new_hashes.push(hash.clone()); - if number > max_height { - trace!(target: "sync", "New unknown block hash {:?}", hash); - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.latest_hash = hash.clone(); - } - max_height = number; - } - }, - BlockStatus::Bad => { - debug!(target: "sync", "Bad new block hash {:?}", hash); - io.disable_peer(peer_id); - return Ok(()); - } - } - }; - if max_height != 0 { - trace!(target: "sync", "Downloading blocks for new hashes"); - self.new_blocks.reset_to(new_hashes); - self.state = SyncState::NewBlocks; - self.sync_peer(io, peer_id, true); - } - self.continue_sync(io); - Ok(()) - } - - /// Called when snapshot manifest is downloaded from a peer. - fn on_snapshot_manifest(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring snapshot manifest from unconfirmed peer {}", peer_id); - return Ok(()); - } - self.clear_peer_download(peer_id); - if !self.reset_peer_asking(peer_id, PeerAsking::SnapshotManifest) || self.state != SyncState::SnapshotManifest { - trace!(target: "sync", "{}: Ignored unexpected/expired manifest", peer_id); - self.continue_sync(io); - return Ok(()); - } - - let manifest_rlp = r.at(0)?; - let manifest = match ManifestData::from_rlp(manifest_rlp.as_raw()) { - Err(e) => { - trace!(target: "sync", "{}: Ignored bad manifest: {:?}", peer_id, e); - io.disable_peer(peer_id); - self.continue_sync(io); - return Ok(()); - } - Ok(manifest) => manifest, - }; - - let is_supported_version = io.snapshot_service().supported_versions() - .map_or(false, |(l, h)| manifest.version >= l && manifest.version <= h); - - if !is_supported_version { - trace!(target: "sync", "{}: Snapshot manifest version not supported: {}", peer_id, manifest.version); - io.disable_peer(peer_id); - self.continue_sync(io); - return Ok(()); - } - self.snapshot.reset_to(&manifest, &keccak(manifest_rlp.as_raw())); - io.snapshot_service().begin_restore(manifest); - self.state = SyncState::SnapshotData; - - // give a task to the same peer first. - self.sync_peer(io, peer_id, false); - // give tasks to other peers - self.continue_sync(io); - Ok(()) - } - - /// Called when snapshot data is downloaded from a peer. - fn on_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring snapshot data from unconfirmed peer {}", peer_id); - return Ok(()); - } - self.clear_peer_download(peer_id); - if !self.reset_peer_asking(peer_id, PeerAsking::SnapshotData) || (self.state != SyncState::SnapshotData && self.state != SyncState::SnapshotWaiting) { - trace!(target: "sync", "{}: Ignored unexpected snapshot data", peer_id); - self.continue_sync(io); - return Ok(()); - } - - // check service status - let status = io.snapshot_service().status(); - match status { - RestorationStatus::Inactive | RestorationStatus::Failed => { - trace!(target: "sync", "{}: Snapshot restoration aborted", peer_id); - self.state = SyncState::WaitingPeers; - - // only note bad if restoration failed. - if let (Some(hash), RestorationStatus::Failed) = (self.snapshot.snapshot_hash(), status) { - trace!(target: "sync", "Noting snapshot hash {} as bad", hash); - self.snapshot.note_bad(hash); - } - - self.snapshot.clear(); - self.continue_sync(io); - return Ok(()); - }, - RestorationStatus::Ongoing { .. } => { - trace!(target: "sync", "{}: Snapshot restoration is ongoing", peer_id); - }, - } - - let snapshot_data: Bytes = r.val_at(0)?; - match self.snapshot.validate_chunk(&snapshot_data) { - Ok(ChunkType::Block(hash)) => { - trace!(target: "sync", "{}: Processing block chunk", peer_id); - io.snapshot_service().restore_block_chunk(hash, snapshot_data); - } - Ok(ChunkType::State(hash)) => { - trace!(target: "sync", "{}: Processing state chunk", peer_id); - io.snapshot_service().restore_state_chunk(hash, snapshot_data); - } - Err(()) => { - trace!(target: "sync", "{}: Got bad snapshot chunk", peer_id); - io.disconnect_peer(peer_id); - self.continue_sync(io); - return Ok(()); - } - } - - if self.snapshot.is_complete() { - // wait for snapshot restoration process to complete - self.state = SyncState::SnapshotWaiting; - } - // give a task to the same peer first. - self.sync_peer(io, peer_id, false); - // give tasks to other peers - self.continue_sync(io); - Ok(()) - } - - /// Called by peer when it is disconnecting - pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) { - trace!(target: "sync", "== Disconnecting {}: {}", peer, io.peer_info(peer)); - self.handshaking_peers.remove(&peer); - if self.peers.contains_key(&peer) { - debug!(target: "sync", "Disconnected {}", peer); - self.clear_peer_download(peer); - self.peers.remove(&peer); - self.active_peers.remove(&peer); - self.continue_sync(io); - } - } - - /// Called when a new peer is connected - pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { - trace!(target: "sync", "== Connected {}: {}", peer, io.peer_info(peer)); - if let Err(e) = self.send_status(io, peer) { - debug!(target:"sync", "Error sending status request: {:?}", e); - io.disconnect_peer(peer); - } else { - self.handshaking_peers.insert(peer, Instant::now()); - } - } - - /// Resume downloading - fn continue_sync(&mut self, io: &mut SyncIo) { - let mut peers: Vec<(PeerId, U256, u8)> = self.peers.iter().filter_map(|(k, p)| - if p.can_sync() { Some((*k, p.difficulty.unwrap_or_else(U256::zero), p.protocol_version)) } else { None }).collect(); - random::new().shuffle(&mut peers); //TODO: sort by rating - // prefer peers with higher protocol version - peers.sort_by(|&(_, _, ref v1), &(_, _, ref v2)| v1.cmp(v2)); - trace!(target: "sync", "Syncing with peers: {} active, {} confirmed, {} total", self.active_peers.len(), peers.len(), self.peers.len()); - for (p, _, _) in peers { - if self.active_peers.contains(&p) { - self.sync_peer(io, p, false); - } - } - - if - self.state != SyncState::WaitingPeers && - self.state != SyncState::SnapshotWaiting && - self.state != SyncState::Waiting && - self.state != SyncState::Idle && - !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.block_set != Some(BlockSet::OldBlocks) && p.can_sync()) - { - self.complete_sync(io); - } - } - - /// Called after all blocks have been downloaded - fn complete_sync(&mut self, io: &mut SyncIo) { - trace!(target: "sync", "Sync complete"); - self.reset(io); - self.state = SyncState::Idle; - } - - /// Enter waiting state - fn pause_sync(&mut self) { - trace!(target: "sync", "Block queue full, pausing sync"); - self.state = SyncState::Waiting; - } - - /// Find something to do for a peer. Called for a new peer or when a peer is done with its task. - fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) { - if !self.active_peers.contains(&peer_id) { - trace!(target: "sync", "Skipping deactivated peer {}", peer_id); - return; - } - let (peer_latest, peer_difficulty, peer_snapshot_number, peer_snapshot_hash) = { - if let Some(peer) = self.peers.get_mut(&peer_id) { - if peer.asking != PeerAsking::Nothing || !peer.can_sync() { - trace!(target: "sync", "Skipping busy peer {}", peer_id); - return; - } - if self.state == SyncState::Waiting { - trace!(target: "sync", "Waiting for the block queue"); - return; - } - if self.state == SyncState::SnapshotWaiting { - trace!(target: "sync", "Waiting for the snapshot restoration"); - return; - } - (peer.latest_hash.clone(), peer.difficulty.clone(), peer.snapshot_number.as_ref().cloned().unwrap_or(0), peer.snapshot_hash.as_ref().cloned()) - } else { - return; - } - }; - let chain_info = io.chain().chain_info(); - let syncing_difficulty = chain_info.pending_total_difficulty; - let num_active_peers = self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(); - - let higher_difficulty = peer_difficulty.map_or(true, |pd| pd > syncing_difficulty); - if force || higher_difficulty || self.old_blocks.is_some() { - match self.state { - SyncState::WaitingPeers => { - trace!( - target: "sync", - "Checking snapshot sync: {} vs {} (peer: {})", - peer_snapshot_number, - chain_info.best_block_number, - peer_id - ); - self.maybe_start_snapshot_sync(io); - }, - SyncState::Idle | SyncState::Blocks | SyncState::NewBlocks => { - if io.chain().queue_info().is_full() { - self.pause_sync(); - return; - } - - let have_latest = io.chain().block_status(BlockId::Hash(peer_latest)) != BlockStatus::Unknown; - trace!(target: "sync", "Considering peer {}, force={}, td={:?}, our td={}, latest={}, have_latest={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, peer_latest, have_latest, self.state); - if !have_latest && (higher_difficulty || force || self.state == SyncState::NewBlocks) { - // check if got new blocks to download - trace!(target: "sync", "Syncing with peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); - if let Some(request) = self.new_blocks.request_blocks(io, num_active_peers) { - self.request_blocks(io, peer_id, request, BlockSet::NewBlocks); - if self.state == SyncState::Idle { - self.state = SyncState::Blocks; - } - return; - } - } - - if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { - self.request_blocks(io, peer_id, request, BlockSet::OldBlocks); - return; - } - }, - SyncState::SnapshotData => { - if let RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } = io.snapshot_service().status() { - if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target: "sync", "Snapshot queue full, pausing sync"); - self.state = SyncState::SnapshotWaiting; - return; - } - } - if peer_snapshot_hash.is_some() && peer_snapshot_hash == self.snapshot.snapshot_hash() { - self.request_snapshot_data(io, peer_id); - } - }, - SyncState::SnapshotManifest | //already downloading from other peer - SyncState::Waiting | SyncState::SnapshotWaiting => () - } - } else { - trace!(target: "sync", "Skipping peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); - } - } - - /// Perofrm block download request` - fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId, request: BlockRequest, block_set: BlockSet) { - match request { - BlockRequest::Headers { start, count, skip } => { - self.request_headers_by_hash(io, peer_id, &start, count, skip, false, block_set); - }, - BlockRequest::Bodies { hashes } => { - self.request_bodies(io, peer_id, hashes, block_set); - }, - BlockRequest::Receipts { hashes } => { - self.request_receipts(io, peer_id, hashes, block_set); - }, - } - } - - /// Find some headers or blocks to download for a peer. - fn request_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId) { - self.clear_peer_download(peer_id); - // find chunk data to download - if let Some(hash) = self.snapshot.needed_chunk() { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.asking_snapshot_data = Some(hash.clone()); - } - self.request_snapshot_chunk(io, peer_id, &hash); - } - } - - /// Clear all blocks/headers marked as being downloaded by a peer. - fn clear_peer_download(&mut self, peer_id: PeerId) { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - match peer.asking { - PeerAsking::BlockHeaders => { - if let Some(ref hash) = peer.asking_hash { - self.new_blocks.clear_header_download(hash); - if let Some(ref mut old) = self.old_blocks { - old.clear_header_download(hash); - } - } - }, - PeerAsking::BlockBodies => { - self.new_blocks.clear_body_download(&peer.asking_blocks); - if let Some(ref mut old) = self.old_blocks { - old.clear_body_download(&peer.asking_blocks); - } - }, - PeerAsking::BlockReceipts => { - self.new_blocks.clear_receipt_download(&peer.asking_blocks); - if let Some(ref mut old) = self.old_blocks { - old.clear_receipt_download(&peer.asking_blocks); - } - }, - PeerAsking::SnapshotData => { - if let Some(hash) = peer.asking_snapshot_data { - self.snapshot.clear_chunk_download(&hash); - } - }, - _ => (), - } - } - } - - /// Checks if there are blocks fully downloaded that can be imported into the blockchain and does the import. - fn collect_blocks(&mut self, io: &mut SyncIo, block_set: BlockSet) { - match block_set { - BlockSet::NewBlocks => { - if self.new_blocks.collect_blocks(io, self.state == SyncState::NewBlocks) == Err(DownloaderImportError::Invalid) { - self.restart(io); - } - }, - BlockSet::OldBlocks => { - if self.old_blocks.as_mut().map_or(false, |downloader| { downloader.collect_blocks(io, false) == Err(DownloaderImportError::Invalid) }) { - self.restart(io); - } else if self.old_blocks.as_ref().map_or(false, |downloader| { downloader.is_complete() }) { - trace!(target: "sync", "Background block download is complete"); - self.old_blocks = None; - } - } - } - } - - /// Request headers from a peer by block hash - fn request_headers_by_hash(&mut self, sync: &mut SyncIo, peer_id: PeerId, h: &H256, count: u64, skip: u64, reverse: bool, set: BlockSet) { - trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}, set = {:?}", peer_id, count, h, set); - let mut rlp = RlpStream::new_list(4); - rlp.append(h); - rlp.append(&count); - rlp.append(&skip); - rlp.append(&if reverse {1u32} else {0u32}); - self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out()); - let peer = self.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); - peer.asking_hash = Some(h.clone()); - peer.block_set = Some(set); - } - - /// Request headers from a peer by block number - fn request_fork_header_by_number(&mut self, sync: &mut SyncIo, peer_id: PeerId, n: BlockNumber) { - trace!(target: "sync", "{} <- GetForkHeader: at {}", peer_id, n); - let mut rlp = RlpStream::new_list(4); - rlp.append(&n); - rlp.append(&1u32); - rlp.append(&0u32); - rlp.append(&0u32); - self.send_request(sync, peer_id, PeerAsking::ForkHeader, GET_BLOCK_HEADERS_PACKET, rlp.out()); - } - - /// Request snapshot manifest from a peer. - fn request_snapshot_manifest(&mut self, sync: &mut SyncIo, peer_id: PeerId) { - trace!(target: "sync", "{} <- GetSnapshotManifest", peer_id); - let rlp = RlpStream::new_list(0); - self.send_request(sync, peer_id, PeerAsking::SnapshotManifest, GET_SNAPSHOT_MANIFEST_PACKET, rlp.out()); - } - - /// Request snapshot chunk from a peer. - fn request_snapshot_chunk(&mut self, sync: &mut SyncIo, peer_id: PeerId, chunk: &H256) { - trace!(target: "sync", "{} <- GetSnapshotData {:?}", peer_id, chunk); - let mut rlp = RlpStream::new_list(1); - rlp.append(chunk); - self.send_request(sync, peer_id, PeerAsking::SnapshotData, GET_SNAPSHOT_DATA_PACKET, rlp.out()); - } - - /// Request block bodies from a peer - fn request_bodies(&mut self, sync: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { - let mut rlp = RlpStream::new_list(hashes.len()); - trace!(target: "sync", "{} <- GetBlockBodies: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); - for h in &hashes { - rlp.append(&h.clone()); - } - self.send_request(sync, peer_id, PeerAsking::BlockBodies, GET_BLOCK_BODIES_PACKET, rlp.out()); - let peer = self.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); - peer.asking_blocks = hashes; - peer.block_set = Some(set); - } - - /// Request block receipts from a peer - fn request_receipts(&mut self, sync: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { - let mut rlp = RlpStream::new_list(hashes.len()); - trace!(target: "sync", "{} <- GetBlockReceipts: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); - for h in &hashes { - rlp.append(&h.clone()); - } - self.send_request(sync, peer_id, PeerAsking::BlockReceipts, GET_RECEIPTS_PACKET, rlp.out()); - let peer = self.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); - peer.asking_blocks = hashes; - peer.block_set = Some(set); - } - - /// Reset peer status after request is complete. - fn reset_peer_asking(&mut self, peer_id: PeerId, asking: PeerAsking) -> bool { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.expired = false; - peer.block_set = None; - if peer.asking != asking { - trace!(target:"sync", "Asking {:?} while expected {:?}", peer.asking, asking); - peer.asking = PeerAsking::Nothing; - return false; - } else { - peer.asking = PeerAsking::Nothing; - return true; - } - } - false - } - - /// Generic request sender - fn send_request(&mut self, sync: &mut SyncIo, peer_id: PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - if peer.asking != PeerAsking::Nothing { - warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking); - } - peer.asking = asking; - peer.ask_time = Instant::now(); - let result = if packet_id >= ETH_PACKET_COUNT { - sync.send_protocol(WARP_SYNC_PROTOCOL_ID, peer_id, packet_id, packet) - } else { - sync.send(peer_id, packet_id, packet) - }; - if let Err(e) = result { - debug!(target:"sync", "Error sending request: {:?}", e); - sync.disconnect_peer(peer_id); - } - } - } - - /// Generic packet sender - fn send_packet(&mut self, sync: &mut SyncIo, peer_id: PeerId, packet_id: PacketId, packet: Bytes) { - if let Err(e) = sync.send(peer_id, packet_id, packet) { - debug!(target:"sync", "Error sending packet: {:?}", e); - sync.disconnect_peer(peer_id); - } - } - - /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - // Accept transactions only when fully synced - if !io.is_chain_queue_empty() || (self.state != SyncState::Idle && self.state != SyncState::NewBlocks) { - trace!(target: "sync", "{} Ignoring transactions while syncing", peer_id); - return Ok(()); - } - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "{} Ignoring transactions from unconfirmed/unknown peer", peer_id); - return Ok(()); - } - - let item_count = r.item_count()?; - trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count); - let mut transactions = Vec::with_capacity(item_count); - for i in 0 .. item_count { - let rlp = r.at(i)?; - let tx = rlp.as_raw().to_vec(); - transactions.push(tx); - } - io.chain().queue_transactions(transactions, peer_id); - Ok(()) - } - - /// Send Status message - fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), network::Error> { - let warp_protocol_version = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer); - let warp_protocol = warp_protocol_version != 0; - let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63 }; - trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol); - let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 }); - let chain = io.chain().chain_info(); - packet.append(&(protocol as u32)); - packet.append(&self.network_id); - packet.append(&chain.total_difficulty); - packet.append(&chain.best_block_hash); - packet.append(&chain.genesis_hash); - if warp_protocol { - let manifest = match self.old_blocks.is_some() { - true => None, - false => io.snapshot_service().manifest(), - }; - let block_number = manifest.as_ref().map_or(0, |m| m.block_number); - let manifest_hash = manifest.map_or(H256::new(), |m| keccak(m.into_rlp())); - packet.append(&manifest_hash); - packet.append(&block_number); - } - io.respond(STATUS_PACKET, packet.out()) - } - - /// Respond to GetBlockHeaders request - fn return_block_headers(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - // Packet layout: - // [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ] - let max_headers: usize = r.val_at(1)?; - let skip: usize = r.val_at(2)?; - let reverse: bool = r.val_at(3)?; - let last = io.chain().chain_info().best_block_number; - let number = if r.at(0)?.size() == 32 { - // id is a hash - let hash: H256 = r.val_at(0)?; - trace!(target: "sync", "{} -> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", peer_id, hash, max_headers, skip, reverse); - match io.chain().block_header(BlockId::Hash(hash)) { - Some(hdr) => { - let number = hdr.number().into(); - debug_assert_eq!(hdr.hash(), hash); - - if max_headers == 1 || io.chain().block_hash(BlockId::Number(number)) != Some(hash) { - // Non canonical header or single header requested - // TODO: handle single-step reverse hashchains of non-canon hashes - trace!(target:"sync", "Returning single header: {:?}", hash); - let mut rlp = RlpStream::new_list(1); - rlp.append_raw(&hdr.into_inner(), 1); - return Ok(Some((BLOCK_HEADERS_PACKET, rlp))); - } - number - } - None => return Ok(Some((BLOCK_HEADERS_PACKET, RlpStream::new_list(0)))) //no such header, return nothing - } - } else { - trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, r.val_at::(0)?, max_headers, skip, reverse); - r.val_at(0)? - }; - - let mut number = if reverse { - cmp::min(last, number) - } else { - cmp::max(0, number) - }; - let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers); - let mut count = 0; - let mut data = Bytes::new(); - let inc = (skip + 1) as BlockNumber; - let overlay = io.chain_overlay().read(); - - while number <= last && count < max_count { - if let Some(hdr) = overlay.get(&number) { - trace!(target: "sync", "{}: Returning cached fork header", peer_id); - data.extend_from_slice(hdr); - count += 1; - } else if let Some(hdr) = io.chain().block_header(BlockId::Number(number)) { - data.append(&mut hdr.into_inner()); - count += 1; - } else { - // No required block. - break; - } - if reverse { - if number <= inc || number == 0 { - break; - } - number -= inc; - } - else { - number += inc; - } - } - let mut rlp = RlpStream::new_list(count as usize); - rlp.append_raw(&data, count as usize); - trace!(target: "sync", "{} -> GetBlockHeaders: returned {} entries", peer_id, count); - Ok(Some((BLOCK_HEADERS_PACKET, rlp))) - } - - /// Respond to GetBlockBodies request - fn return_block_bodies(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = r.item_count().unwrap_or(0); - if count == 0 { - debug!(target: "sync", "Empty GetBlockBodies request, ignoring."); - return Ok(None); - } - count = cmp::min(count, MAX_BODIES_TO_SEND); - let mut added = 0usize; - let mut data = Bytes::new(); - for i in 0..count { - if let Some(body) = io.chain().block_body(BlockId::Hash(r.val_at::(i)?)) { - data.append(&mut body.into_inner()); - added += 1; - } - } - let mut rlp = RlpStream::new_list(added); - rlp.append_raw(&data, added); - trace!(target: "sync", "{} -> GetBlockBodies: returned {} entries", peer_id, added); - Ok(Some((BLOCK_BODIES_PACKET, rlp))) - } - - /// Respond to GetNodeData request - fn return_node_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = r.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetNodeData: {} entries", peer_id, count); - if count == 0 { - debug!(target: "sync", "Empty GetNodeData request, ignoring."); - return Ok(None); - } - count = cmp::min(count, MAX_NODE_DATA_TO_SEND); - let mut added = 0usize; - let mut data = Vec::new(); - for i in 0..count { - if let Some(node) = io.chain().state_data(&r.val_at::(i)?) { - data.push(node); - added += 1; - } - } - trace!(target: "sync", "{} -> GetNodeData: return {} entries", peer_id, added); - let mut rlp = RlpStream::new_list(added); - for d in data { - rlp.append(&d); - } - Ok(Some((NODE_DATA_PACKET, rlp))) - } - - fn return_receipts(io: &SyncIo, rlp: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = rlp.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetReceipts: {} entries", peer_id, count); - if count == 0 { - debug!(target: "sync", "Empty GetReceipts request, ignoring."); - return Ok(None); - } - count = cmp::min(count, MAX_RECEIPTS_HEADERS_TO_SEND); - let mut added_headers = 0usize; - let mut added_receipts = 0usize; - let mut data = Bytes::new(); - for i in 0..count { - if let Some(mut receipts_bytes) = io.chain().block_receipts(&rlp.val_at::(i)?) { - data.append(&mut receipts_bytes); - added_receipts += receipts_bytes.len(); - added_headers += 1; - if added_receipts > MAX_RECEIPTS_TO_SEND { break; } - } - } - let mut rlp_result = RlpStream::new_list(added_headers); - rlp_result.append_raw(&data, added_headers); - Ok(Some((RECEIPTS_PACKET, rlp_result))) - } - - /// Respond to GetSnapshotManifest request - fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let count = r.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); - if count != 0 { - debug!(target: "sync", "Invalid GetSnapshotManifest request, ignoring."); - return Ok(None); - } - let rlp = match io.snapshot_service().manifest() { - Some(manifest) => { - trace!(target: "sync", "{} <- SnapshotManifest", peer_id); - let mut rlp = RlpStream::new_list(1); - rlp.append_raw(&manifest.into_rlp(), 1); - rlp - }, - None => { - trace!(target: "sync", "{}: No manifest to return", peer_id); - RlpStream::new_list(0) - } - }; - Ok(Some((SNAPSHOT_MANIFEST_PACKET, rlp))) - } - - /// Respond to GetSnapshotData request - fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let hash: H256 = r.val_at(0)?; - trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); - let rlp = match io.snapshot_service().chunk(hash) { - Some(data) => { - let mut rlp = RlpStream::new_list(1); - trace!(target: "sync", "{} <- SnapshotData", peer_id); - rlp.append(&data); - rlp - }, - None => { - RlpStream::new_list(0) - } - }; - Ok(Some((SNAPSHOT_DATA_PACKET, rlp))) - } - - fn return_rlp(io: &mut SyncIo, rlp: &Rlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> - where FRlp : Fn(&SyncIo, &Rlp, PeerId) -> RlpResponseResult, - FError : FnOnce(network::Error) -> String - { - let response = rlp_func(io, rlp, peer); - match response { - Err(e) => Err(e), - Ok(Some((packet_id, rlp_stream))) => { - io.respond(packet_id, rlp_stream.out()).unwrap_or_else( - |e| debug!(target: "sync", "{:?}", error_func(e))); - Ok(()) - } - _ => Ok(()) - } - } - - /// Dispatch incoming requests and responses - pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { - let rlp = Rlp::new(data); - let result = match packet_id { - GET_BLOCK_BODIES_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_block_bodies, - |e| format!("Error sending block bodies: {:?}", e)), - - GET_BLOCK_HEADERS_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_block_headers, - |e| format!("Error sending block headers: {:?}", e)), - - GET_RECEIPTS_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_receipts, - |e| format!("Error sending receipts: {:?}", e)), - - GET_NODE_DATA_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_node_data, - |e| format!("Error sending nodes: {:?}", e)), - - GET_SNAPSHOT_MANIFEST_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_snapshot_manifest, - |e| format!("Error sending snapshot manifest: {:?}", e)), - - GET_SNAPSHOT_DATA_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_snapshot_data, - |e| format!("Error sending snapshot data: {:?}", e)), - CONSENSUS_DATA_PACKET => ChainSync::on_consensus_packet(io, peer, &rlp), - _ => { - sync.write().on_packet(io, peer, packet_id, data); - Ok(()) - } - }; - result.unwrap_or_else(|e| { - debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); - }) - } - - pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { - debug!(target: "sync", "{} -> Dispatching packet: {}", peer, packet_id); - - if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) { - debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); - return; - } - - let rlp = Rlp::new(data); - let result = match packet_id { - STATUS_PACKET => self.on_peer_status(io, peer, &rlp), - TRANSACTIONS_PACKET => self.on_peer_transactions(io, peer, &rlp), - BLOCK_HEADERS_PACKET => self.on_peer_block_headers(io, peer, &rlp), - BLOCK_BODIES_PACKET => self.on_peer_block_bodies(io, peer, &rlp), - RECEIPTS_PACKET => self.on_peer_block_receipts(io, peer, &rlp), - NEW_BLOCK_PACKET => self.on_peer_new_block(io, peer, &rlp), - NEW_BLOCK_HASHES_PACKET => self.on_peer_new_hashes(io, peer, &rlp), - SNAPSHOT_MANIFEST_PACKET => self.on_snapshot_manifest(io, peer, &rlp), - SNAPSHOT_DATA_PACKET => self.on_snapshot_data(io, peer, &rlp), - PRIVATE_TRANSACTION_PACKET => self.on_private_transaction(io, peer, &rlp), - SIGNED_PRIVATE_TRANSACTION_PACKET => self.on_signed_private_transaction(io, peer, &rlp), - _ => { - debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id); - Ok(()) - } - }; - result.unwrap_or_else(|e| { - debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); - }) - } - - pub fn maintain_peers(&mut self, io: &mut SyncIo) { - let tick = Instant::now(); - let mut aborting = Vec::new(); - for (peer_id, peer) in &self.peers { - let elapsed = tick - peer.ask_time; - let timeout = match peer.asking { - PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT, - PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT, - PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT, - PeerAsking::Nothing => false, - PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT, - PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT, - PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, - }; - if timeout { - debug!(target:"sync", "Timeout {}", peer_id); - io.disconnect_peer(*peer_id); - aborting.push(*peer_id); - } - } - for p in aborting { - self.on_peer_aborting(io, p); - } - - // Check for handshake timeouts - for (peer, &ask_time) in &self.handshaking_peers { - let elapsed = (tick - ask_time) / 1_000_000_000; - if elapsed > STATUS_TIMEOUT { - trace!(target:"sync", "Status timeout {}", peer); - io.disconnect_peer(*peer); - } - } - } - - fn check_resume(&mut self, io: &mut SyncIo) { - if self.state == SyncState::Waiting && !io.chain().queue_info().is_full() && self.state == SyncState::Waiting { - self.state = SyncState::Blocks; - self.continue_sync(io); - } else if self.state == SyncState::SnapshotWaiting { - match io.snapshot_service().status() { - RestorationStatus::Inactive => { - trace!(target:"sync", "Snapshot restoration is complete"); - self.restart(io); - self.continue_sync(io); - }, - RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { - if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target:"sync", "Resuming snapshot sync"); - self.state = SyncState::SnapshotData; - self.continue_sync(io); - } - }, - RestorationStatus::Failed => { - trace!(target: "sync", "Snapshot restoration aborted"); - self.state = SyncState::WaitingPeers; - self.snapshot.clear(); - self.continue_sync(io); - }, - } - } - } - - /// creates rlp to send for the tree defined by 'from' and 'to' hashes - fn create_new_hashes_rlp(chain: &BlockChainClient, from: &H256, to: &H256) -> Option { - match chain.tree_route(from, to) { - Some(route) => { - let uncles = chain.find_uncles(from).unwrap_or_else(Vec::new); - match route.blocks.len() { - 0 => None, - _ => { - let mut blocks = route.blocks; - blocks.extend(uncles); - let mut rlp_stream = RlpStream::new_list(blocks.len()); - for block_hash in blocks { - let mut hash_rlp = RlpStream::new_list(2); - let number = chain.block_header(BlockId::Hash(block_hash.clone())) - .expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.").number(); - hash_rlp.append(&block_hash); - hash_rlp.append(&number); - rlp_stream.append_raw(hash_rlp.as_raw(), 1); - } - Some(rlp_stream.out()) - } - } - }, - None => None - } - } - - /// creates rlp from block bytes and total difficulty - fn create_block_rlp(bytes: &Bytes, total_difficulty: U256) -> Bytes { - let mut rlp_stream = RlpStream::new_list(2); - rlp_stream.append_raw(bytes, 1); - rlp_stream.append(&total_difficulty); - rlp_stream.out() - } - - /// creates latest block rlp for the given client - fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes { - ChainSync::create_block_rlp( - &chain.block(BlockId::Hash(chain.chain_info().best_block_hash)) - .expect("Best block always exists").into_inner(), - chain.chain_info().total_difficulty - ) - } - - /// creates given hash block rlp for the given client - fn create_new_block_rlp(chain: &BlockChainClient, hash: &H256) -> Bytes { - ChainSync::create_block_rlp( - &chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed").into_inner(), - chain.block_total_difficulty(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed.") - ) - } - - /// returns peer ids that have different blocks than our chain - fn get_lagging_peers(&mut self, chain_info: &BlockChainInfo) -> Vec { - let latest_hash = chain_info.best_block_hash; - self - .peers - .iter_mut() - .filter_map(|(&id, ref mut peer_info)| { - trace!(target: "sync", "Checking peer our best {} their best {}", latest_hash, peer_info.latest_hash); - if peer_info.latest_hash != latest_hash { - Some(id) - } else { - None - } - }) - .collect::>() - } - - fn select_random_peers(peers: &[PeerId]) -> Vec { - // take sqrt(x) peers - let mut peers = peers.to_vec(); - let mut count = (peers.len() as f64).powf(0.5).round() as usize; - count = cmp::min(count, MAX_PEERS_PROPAGATION); - count = cmp::max(count, MIN_PEERS_PROPAGATION); - random::new().shuffle(&mut peers); - peers.truncate(count); - peers - } - - fn get_consensus_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() - } - - fn get_private_transaction_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3 { Some(*id) } else { None }).collect() - } - - /// propagates latest block to a set of peers - fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, blocks: &[H256], peers: &[PeerId]) -> usize { - trace!(target: "sync", "Sending NewBlocks to {:?}", peers); - let mut sent = 0; - for peer_id in peers { - if blocks.is_empty() { - let rlp = ChainSync::create_latest_block_rlp(io.chain()); - self.send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); - } else { - for h in blocks { - let rlp = ChainSync::create_new_block_rlp(io.chain(), h); - self.send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); - } - } - if let Some(ref mut peer) = self.peers.get_mut(peer_id) { - peer.latest_hash = chain_info.best_block_hash.clone(); - } - sent += 1; - } - sent - } - - /// propagates new known hashes to all peers - fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize { - trace!(target: "sync", "Sending NewHashes to {:?}", peers); - let mut sent = 0; - let last_parent = *io.chain().best_block_header().parent_hash(); - for peer_id in peers { - sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) { - Some(rlp) => { - { - if let Some(ref mut peer) = self.peers.get_mut(peer_id) { - peer.latest_hash = chain_info.best_block_hash.clone(); - } - } - self.send_packet(io, *peer_id, NEW_BLOCK_HASHES_PACKET, rlp); - 1 - }, - None => 0 - } - } - sent - } - - /// propagates new transactions to all peers - pub fn propagate_new_transactions(&mut self, io: &mut SyncIo) -> usize { - // Early out if nobody to send to. - if self.peers.is_empty() { - return 0; - } - - let transactions = io.chain().ready_transactions(); - if transactions.is_empty() { - return 0; - } - - let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.iter() - .map(|tx| tx.signed()) - .partition(|tx| !tx.gas_price.is_zero()); - - // usual transactions could be propagated to all peers - let mut affected_peers = HashSet::new(); - if !transactions.is_empty() { - let peers = self.select_peers_for_transactions(|_| true); - affected_peers = self.propagate_transactions_to_peers(io, peers, transactions); - } - - // most of times service_transactions will be empty - // => there's no need to merge packets - if !service_transactions.is_empty() { - let service_transactions_peers = self.select_peers_for_transactions(|peer_id| accepts_service_transaction(&io.peer_info(*peer_id))); - let service_transactions_affected_peers = self.propagate_transactions_to_peers(io, service_transactions_peers, service_transactions); - affected_peers.extend(&service_transactions_affected_peers); - } - - affected_peers.len() - } - - fn select_peers_for_transactions(&self, filter: F) -> Vec - where F: Fn(&PeerId) -> bool { - // sqrt(x)/x scaled to max u32 - let fraction = ((self.peers.len() as f64).powf(-0.5) * (u32::max_value() as f64).round()) as u32; - let small = self.peers.len() < MIN_PEERS_PROPAGATION; - - let mut random = random::new(); - self.peers.keys() - .cloned() - .filter(filter) - .filter(|_| small || random.next_u32() < fraction) - .take(MAX_PEERS_PROPAGATION) - .collect() - } - - fn propagate_transactions_to_peers(&mut self, io: &mut SyncIo, peers: Vec, transactions: Vec<&SignedTransaction>) -> HashSet { - let all_transactions_hashes = transactions.iter() - .map(|tx| tx.hash()) - .collect::>(); - let all_transactions_rlp = { - let mut packet = RlpStream::new_list(transactions.len()); - for tx in &transactions { packet.append(&**tx); } - packet.out() - }; - - // Clear old transactions from stats - self.transactions_stats.retain(&all_transactions_hashes); - - // sqrt(x)/x scaled to max u32 - let block_number = io.chain().chain_info().best_block_number; - - let lucky_peers = { - peers.into_iter() - .filter_map(|peer_id| { - let stats = &mut self.transactions_stats; - let peer_info = self.peers.get_mut(&peer_id) - .expect("peer_id is form peers; peers is result of select_peers_for_transactions; select_peers_for_transactions selects peers from self.peers; qed"); - - // Send all transactions - if peer_info.last_sent_transactions.is_empty() { - // update stats - for hash in &all_transactions_hashes { - let id = io.peer_session_info(peer_id).and_then(|info| info.id); - stats.propagated(hash, id, block_number); - } - peer_info.last_sent_transactions = all_transactions_hashes.clone(); - return Some((peer_id, all_transactions_hashes.len(), all_transactions_rlp.clone())); - } - - // Get hashes of all transactions to send to this peer - let to_send = all_transactions_hashes.difference(&peer_info.last_sent_transactions) - .take(MAX_TRANSACTIONS_TO_PROPAGATE) - .cloned() - .collect::>(); - if to_send.is_empty() { - return None; - } - - // Construct RLP - let (packet, to_send) = { - let mut to_send = to_send; - let mut packet = RlpStream::new(); - packet.begin_unbounded_list(); - let mut pushed = 0; - for tx in &transactions { - let hash = tx.hash(); - if to_send.contains(&hash) { - let mut transaction = RlpStream::new(); - tx.rlp_append(&mut transaction); - let appended = packet.append_raw_checked(&transaction.drain(), 1, MAX_TRANSACTION_PACKET_SIZE); - if !appended { - // Maximal packet size reached just proceed with sending - debug!("Transaction packet size limit reached. Sending incomplete set of {}/{} transactions.", pushed, to_send.len()); - to_send = to_send.into_iter().take(pushed).collect(); - break; - } - pushed += 1; - } - } - packet.complete_unbounded_list(); - (packet, to_send) - }; - - // Update stats - let id = io.peer_session_info(peer_id).and_then(|info| info.id); - for hash in &to_send { - // update stats - stats.propagated(hash, id, block_number); - } - - peer_info.last_sent_transactions = all_transactions_hashes - .intersection(&peer_info.last_sent_transactions) - .chain(&to_send) - .cloned() - .collect(); - Some((peer_id, to_send.len(), packet.out())) - }) - .collect::>() - }; - - // Send RLPs - let mut peers = HashSet::new(); - if lucky_peers.len() > 0 { - let mut max_sent = 0; - let lucky_peers_len = lucky_peers.len(); - for (peer_id, sent, rlp) in lucky_peers { - peers.insert(peer_id); - self.send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp); - trace!(target: "sync", "{:02} <- Transactions ({} entries)", peer_id, sent); - max_sent = cmp::max(max_sent, sent); - } - debug!(target: "sync", "Sent up to {} transactions to {} peers.", max_sent, lucky_peers_len); - } - - peers - } - - fn propagate_latest_blocks(&mut self, io: &mut SyncIo, sealed: &[H256]) { - let chain_info = io.chain().chain_info(); - if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let mut peers = self.get_lagging_peers(&chain_info); - if sealed.is_empty() { - let hashes = self.propagate_new_hashes(&chain_info, io, &peers); - peers = ChainSync::select_random_peers(&peers); - let blocks = self.propagate_blocks(&chain_info, io, sealed, &peers); - if blocks != 0 || hashes != 0 { - trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); - } - } else { - self.propagate_blocks(&chain_info, io, sealed, &peers); - self.propagate_new_hashes(&chain_info, io, &peers); - trace!(target: "sync", "Sent sealed block to all peers"); - }; - } - self.last_sent_block_number = chain_info.best_block_number; - } - - /// Distribute valid proposed blocks to subset of current peers. - fn propagate_proposed_blocks(&mut self, io: &mut SyncIo, proposed: &[Bytes]) { - let peers = self.get_consensus_peers(); - trace!(target: "sync", "Sending proposed blocks to {:?}", peers); - for block in proposed { - let rlp = ChainSync::create_block_rlp( - block, - io.chain().chain_info().total_difficulty - ); - for peer_id in &peers { - self.send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp.clone()); - } - } - } - - /// Maintain other peers. Send out any new blocks and transactions - pub fn maintain_sync(&mut self, io: &mut SyncIo) { - self.maybe_start_snapshot_sync(io); - self.check_resume(io); - } - - /// called when block is imported to chain - propagates the blocks and updates transactions sent to peers - pub fn chain_new_blocks(&mut self, io: &mut SyncIo, _imported: &[H256], invalid: &[H256], enacted: &[H256], _retracted: &[H256], sealed: &[H256], proposed: &[Bytes]) { - let queue_info = io.chain().queue_info(); - let is_syncing = self.status().is_syncing(queue_info); - - if !is_syncing || !sealed.is_empty() || !proposed.is_empty() { - trace!(target: "sync", "Propagating blocks, state={:?}", self.state); - self.propagate_latest_blocks(io, sealed); - self.propagate_proposed_blocks(io, proposed); - } - if !invalid.is_empty() { - trace!(target: "sync", "Bad blocks in the queue, restarting"); - self.restart(io); - } - - if !is_syncing && !enacted.is_empty() && !self.peers.is_empty() { - // Select random peer to re-broadcast transactions to. - let peer = random::new().gen_range(0, self.peers.len()); - trace!(target: "sync", "Re-broadcasting transactions to a random peer."); - self.peers.values_mut().nth(peer).map(|peer_info| - peer_info.last_sent_transactions.clear() - ); - } - } - - /// Called when peer sends us new consensus packet - fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - trace!(target: "sync", "Received consensus packet from {:?}", peer_id); - io.chain().queue_consensus_message(r.as_raw().to_vec()); - Ok(()) - } - - /// Broadcast consensus message to peers. - pub fn propagate_consensus_packet(&mut self, io: &mut SyncIo, packet: Bytes) { - let lucky_peers = ChainSync::select_random_peers(&self.get_consensus_peers()); - trace!(target: "sync", "Sending consensus packet to {:?}", lucky_peers); - for peer_id in lucky_peers { - self.send_packet(io, peer_id, CONSENSUS_DATA_PACKET, packet.clone()); - } - } - - /// Called when peer sends us new private transaction packet - fn on_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); - return Ok(()); - } - - trace!(target: "sync", "Received private transaction packet from {:?}", peer_id); - - if let Err(e) = self.private_tx_handler.import_private_transaction(r.as_raw()) { - trace!(target: "sync", "Ignoring the message, error queueing: {}", e); - } - Ok(()) - } - - /// Broadcast private transaction message to peers. - pub fn propagate_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { - let lucky_peers = ChainSync::select_random_peers(&self.get_private_transaction_peers()); - trace!(target: "sync", "Sending private transaction packet to {:?}", lucky_peers); - for peer_id in lucky_peers { - self.send_packet(io, peer_id, PRIVATE_TRANSACTION_PACKET, packet.clone()); - } - } - - /// Called when peer sends us signed private transaction packet - fn on_signed_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); - return Ok(()); - } - - trace!(target: "sync", "Received signed private transaction packet from {:?}", peer_id); - if let Err(e) = self.private_tx_handler.import_signed_private_transaction(r.as_raw()) { - trace!(target: "sync", "Ignoring the message, error queueing: {}", e); - } - Ok(()) - } - - /// Broadcast signed private transaction message to peers. - pub fn propagate_signed_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { - let lucky_peers = ChainSync::select_random_peers(&self.get_private_transaction_peers()); - trace!(target: "sync", "Sending signed private transaction packet to {:?}", lucky_peers); - for peer_id in lucky_peers { - self.send_packet(io, peer_id, SIGNED_PRIVATE_TRANSACTION_PACKET, packet.clone()); - } - } - -} - -/// Checks if peer is able to process service transactions -fn accepts_service_transaction(client_id: &str) -> bool { - // Parity versions starting from this will accept service-transactions - const SERVICE_TRANSACTIONS_VERSION: (u32, u32) = (1u32, 6u32); - // Parity client string prefix - const PARITY_CLIENT_ID_PREFIX: &'static str = "Parity/v"; - - if !client_id.starts_with(PARITY_CLIENT_ID_PREFIX) { - return false; - } - let ver: Vec = client_id[PARITY_CLIENT_ID_PREFIX.len()..].split('.') - .take(2) - .filter_map(|s| s.parse().ok()) - .collect(); - ver.len() == 2 && (ver[0] > SERVICE_TRANSACTIONS_VERSION.0 || (ver[0] == SERVICE_TRANSACTIONS_VERSION.0 && ver[1] >= SERVICE_TRANSACTIONS_VERSION.1)) -} - -#[cfg(test)] -mod tests { - use std::collections::{HashSet, VecDeque}; - use ethkey; - use network::PeerId; - use tests::helpers::{TestIo}; - use tests::snapshot::TestSnapshotService; - use ethereum_types::{H256, U256, Address}; - use parking_lot::RwLock; - use bytes::Bytes; - use rlp::{Rlp, RlpStream}; - use super::*; - use ::SyncConfig; - use super::{PeerInfo, PeerAsking}; - use ethcore::header::*; - use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; - use ethcore::miner::MinerService; - use private_tx::NoopPrivateTxHandler; - - fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { - let mut header = Header::new(); - header.set_gas_limit(0.into()); - header.set_difficulty((order * 100).into()); - header.set_timestamp((order * 10) as u64); - header.set_number(order as u64); - header.set_parent_hash(parent_hash); - header.set_state_root(H256::zero()); - - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); - rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); - rlp.out() - } - - fn get_dummy_blocks(order: u32, parent_hash: H256) -> Bytes { - let mut rlp = RlpStream::new_list(1); - rlp.append_raw(&get_dummy_block(order, parent_hash), 1); - let difficulty: U256 = (100 * order).into(); - rlp.append(&difficulty); - rlp.out() - } - - fn get_dummy_hashes() -> Bytes { - let mut rlp = RlpStream::new_list(5); - for _ in 0..5 { - let mut hash_d_rlp = RlpStream::new_list(2); - let hash: H256 = H256::from(0u64); - let diff: U256 = U256::from(1u64); - hash_d_rlp.append(&hash); - hash_d_rlp.append(&diff); - - rlp.append_raw(&hash_d_rlp.out(), 1); - } - - rlp.out() - } - - fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo { - BlockQueueInfo { - unverified_queue_size: unverified, - verified_queue_size: verified, - verifying_queue_size: 0, - max_queue_size: 1000, - max_mem_use: 1000, - mem_used: 500 - } - } - - fn sync_status(state: SyncState) -> SyncStatus { - SyncStatus { - state: state, - protocol_version: 0, - network_id: 0, - start_block_number: 0, - last_imported_block_number: None, - highest_block_number: None, - blocks_total: 0, - blocks_received: 0, - num_peers: 0, - num_active_peers: 0, - mem_used: 0, - num_snapshot_chunks: 0, - snapshot_chunks_done: 0, - last_imported_old_block_number: None, - } - } - - #[test] - fn is_still_verifying() { - assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(2, 1))); - assert!(sync_status(SyncState::Idle).is_syncing(queue_info(2, 2))); - } - - #[test] - fn is_synced_state() { - assert!(sync_status(SyncState::Blocks).is_syncing(queue_info(0, 0))); - assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(0, 0))); - } - - #[test] - fn return_receipts_empty() { - let mut client = TestBlockChainClient::new(); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let io = TestIo::new(&mut client, &ss, &queue, None); - - let result = ChainSync::return_receipts(&io, &Rlp::new(&[0xc0]), 0); - - assert!(result.is_ok()); - } - - #[test] - fn return_receipts() { - let mut client = TestBlockChainClient::new(); - let queue = RwLock::new(VecDeque::new()); - let sync = dummy_sync_with_peer(H256::new(), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let mut receipt_list = RlpStream::new_list(4); - receipt_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); - receipt_list.append(&H256::from("ff00000000000000000000000000000000000000000000000000000000000000")); - receipt_list.append(&H256::from("fff0000000000000000000000000000000000000000000000000000000000000")); - receipt_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); - - let receipts_request = receipt_list.out(); - // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_receipts(&io, &Rlp::new(&receipts_request.clone()), 0); - - assert!(result.is_ok()); - let rlp_result = result.unwrap(); - assert!(rlp_result.is_some()); - - // the length of two rlp-encoded receipts - assert_eq!(603, rlp_result.unwrap().1.out().len()); - - io.sender = Some(2usize); - ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, super::GET_RECEIPTS_PACKET, &receipts_request); - assert_eq!(1, io.packets.len()); - } - - #[test] - fn return_block_headers() { - use ethcore::views::HeaderView; - fn make_hash_req(h: &H256, count: usize, skip: usize, reverse: bool) -> Bytes { - let mut rlp = RlpStream::new_list(4); - rlp.append(h); - rlp.append(&count); - rlp.append(&skip); - rlp.append(&if reverse {1u32} else {0u32}); - rlp.out() - } - - fn make_num_req(n: usize, count: usize, skip: usize, reverse: bool) -> Bytes { - let mut rlp = RlpStream::new_list(4); - rlp.append(&n); - rlp.append(&count); - rlp.append(&skip); - rlp.append(&if reverse {1u32} else {0u32}); - rlp.out() - } - fn to_header_vec(rlp: ::chain::RlpResponseResult) -> Vec { - Rlp::new(&rlp.unwrap().unwrap().1.out()).iter().map(|r| r.as_raw().to_vec()).collect() - } - - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Nothing); - let blocks: Vec<_> = (0 .. 100) - .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); - - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let io = TestIo::new(&mut client, &ss, &queue, None); - - let unknown: H256 = H256::new(); - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); - assert!(to_header_vec(result).is_empty()); - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); - assert!(to_header_vec(result).is_empty()); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); - } - - #[test] - fn return_nodes() { - let mut client = TestBlockChainClient::new(); - let queue = RwLock::new(VecDeque::new()); - let sync = dummy_sync_with_peer(H256::new(), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let mut node_list = RlpStream::new_list(3); - node_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); - node_list.append(&H256::from("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa")); - node_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); - - let node_request = node_list.out(); - // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_node_data(&io, &Rlp::new(&node_request.clone()), 0); - - assert!(result.is_ok()); - let rlp_result = result.unwrap(); - assert!(rlp_result.is_some()); - - // the length of one rlp-encoded hashe - let rlp = rlp_result.unwrap().1.out(); - let rlp = Rlp::new(&rlp); - assert_eq!(Ok(1), rlp.item_count()); - - io.sender = Some(2usize); - - ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, super::GET_NODE_DATA_PACKET, &node_request); - assert_eq!(1, io.packets.len()); - } - - fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync { - let mut sync = ChainSync::new(SyncConfig::default(), client, Arc::new(NoopPrivateTxHandler)); - insert_dummy_peer(&mut sync, 0, peer_latest_hash); - sync - } - - fn insert_dummy_peer(sync: &mut ChainSync, peer_id: PeerId, peer_latest_hash: H256) { - sync.peers.insert(peer_id, - PeerInfo { - protocol_version: 0, - genesis: H256::zero(), - network_id: 0, - latest_hash: peer_latest_hash, - difficulty: None, - asking: PeerAsking::Nothing, - asking_blocks: Vec::new(), - asking_hash: None, - ask_time: Instant::now(), - last_sent_transactions: HashSet::new(), - expired: false, - confirmation: super::ForkConfirmation::Confirmed, - snapshot_number: None, - snapshot_hash: None, - asking_snapshot_data: None, - block_set: None, - }); - - } - - #[test] - fn finds_lagging_peers() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10), &client); - let chain_info = client.chain_info(); - - let lagging_peers = sync.get_lagging_peers(&chain_info); - - assert_eq!(1, lagging_peers.len()); - } - - #[test] - fn calculates_tree_for_lagging_peer() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(15, EachBlockWith::Uncle); - - let start = client.block_hash_delta_minus(4); - let end = client.block_hash_delta_minus(2); - - // wrong way end -> start, should be None - let rlp = ChainSync::create_new_hashes_rlp(&client, &end, &start); - assert!(rlp.is_none()); - - let rlp = ChainSync::create_new_hashes_rlp(&client, &start, &end).unwrap(); - // size of three rlp encoded hash-difficulty - assert_eq!(107, rlp.len()); - } - - #[test] - fn sends_new_hashes_to_lagging_peer() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let peers = sync.get_lagging_peers(&chain_info); - let peer_count = sync.propagate_new_hashes(&chain_info, &mut io, &peers); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated - assert_eq!(1, peer_count); - // NEW_BLOCK_HASHES_PACKET - assert_eq!(0x01, io.packets[0].packet_id); - } - - #[test] - fn sends_latest_block_to_lagging_peer() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peers = sync.get_lagging_peers(&chain_info); - let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[], &peers); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated - assert_eq!(1, peer_count); - // NEW_BLOCK_PACKET - assert_eq!(0x07, io.packets[0].packet_id); - } - - #[test] - fn sends_sealed_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let hash = client.block_hash(BlockId::Number(99)).unwrap(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peers = sync.get_lagging_peers(&chain_info); - let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[hash.clone()], &peers); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated - assert_eq!(1, peer_count); - // NEW_BLOCK_PACKET - assert_eq!(0x07, io.packets[0].packet_id); - } - - #[test] - fn sends_proposed_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(2, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let block = client.block(BlockId::Latest).unwrap().into_inner(); - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - sync.peers.insert(0, - PeerInfo { - // Messaging protocol - protocol_version: 2, - genesis: H256::zero(), - network_id: 0, - latest_hash: client.block_hash_delta_minus(1), - difficulty: None, - asking: PeerAsking::Nothing, - asking_blocks: Vec::new(), - asking_hash: None, - ask_time: Instant::now(), - last_sent_transactions: HashSet::new(), - expired: false, - confirmation: super::ForkConfirmation::Confirmed, - snapshot_number: None, - snapshot_hash: None, - asking_snapshot_data: None, - block_set: None, - }); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - sync.propagate_proposed_blocks(&mut io, &[block]); - - // 1 message should be sent - assert_eq!(1, io.packets.len()); - // NEW_BLOCK_PACKET - assert_eq!(0x07, io.packets[0].packet_id); - } - - #[test] - fn propagates_transactions() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - // Try to propagate same transactions for the second time - let peer_count2 = sync.propagate_new_transactions(&mut io); - // Even after new block transactions should not be propagated twice - sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); - // Try to propagate same transactions for the third time - let peer_count3 = sync.propagate_new_transactions(&mut io); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated but only once - assert_eq!(1, peer_count); - assert_eq!(0, peer_count2); - assert_eq!(0, peer_count3); - // TRANSACTIONS_PACKET - assert_eq!(0x02, io.packets[0].packet_id); - } - - #[test] - fn does_not_propagate_new_transactions_after_new_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - io.chain.insert_transaction_to_queue(); - // New block import should not trigger propagation. - // (we only propagate on timeout) - sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); - - // 2 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should receive the message - assert_eq!(1, peer_count); - // TRANSACTIONS_PACKET - assert_eq!(0x02, io.packets[0].packet_id); - } - - #[test] - fn does_not_fail_for_no_peers() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - // Sync with no peers - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); - // Try to propagate same transactions for the second time - let peer_count2 = sync.propagate_new_transactions(&mut io); - - assert_eq!(0, io.packets.len()); - assert_eq!(0, peer_count); - assert_eq!(0, peer_count2); - } - - #[test] - fn propagates_transactions_without_alternating() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - // should sent some - { - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - assert_eq!(1, io.packets.len()); - assert_eq!(1, peer_count); - } - // Insert some more - client.insert_transaction_to_queue(); - let (peer_count2, peer_count3) = { - let mut io = TestIo::new(&mut client, &ss, &queue, None); - // Propagate new transactions - let peer_count2 = sync.propagate_new_transactions(&mut io); - // And now the peer should have all transactions - let peer_count3 = sync.propagate_new_transactions(&mut io); - (peer_count2, peer_count3) - }; - - // 2 message should be send (in total) - assert_eq!(2, queue.read().len()); - // 1 peer should be updated but only once after inserting new transaction - assert_eq!(1, peer_count2); - assert_eq!(0, peer_count3); - // TRANSACTIONS_PACKET - assert_eq!(0x02, queue.read()[0].packet_id); - assert_eq!(0x02, queue.read()[1].packet_id); - } - - #[test] - fn should_maintain_transations_propagation_stats() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - sync.propagate_new_transactions(&mut io); - - let stats = sync.transactions_stats(); - assert_eq!(stats.len(), 1, "Should maintain stats for single transaction.") - } - - #[test] - fn should_propagate_service_transaction_to_selected_peers_only() { - let mut client = TestBlockChainClient::new(); - client.insert_transaction_with_gas_price_to_queue(U256::zero()); - let block_hash = client.block_hash_delta_minus(1); - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - // when peer#1 is Geth - insert_dummy_peer(&mut sync, 1, block_hash); - io.peers_info.insert(1, "Geth".to_owned()); - // and peer#2 is Parity, accepting service transactions - insert_dummy_peer(&mut sync, 2, block_hash); - io.peers_info.insert(2, "Parity/v1.6".to_owned()); - // and peer#3 is Parity, discarding service transactions - insert_dummy_peer(&mut sync, 3, block_hash); - io.peers_info.insert(3, "Parity/v1.5".to_owned()); - // and peer#4 is Parity, accepting service transactions - insert_dummy_peer(&mut sync, 4, block_hash); - io.peers_info.insert(4, "Parity/v1.7.3-ABCDEFGH".to_owned()); - - // and new service transaction is propagated to peers - sync.propagate_new_transactions(&mut io); - - // peer#2 && peer#4 are receiving service transaction - assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 2)); // TRANSACTIONS_PACKET - assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 4)); // TRANSACTIONS_PACKET - assert_eq!(io.packets.len(), 2); - } - - #[test] - fn should_propagate_service_transaction_is_sent_as_separate_message() { - let mut client = TestBlockChainClient::new(); - let tx1_hash = client.insert_transaction_to_queue(); - let tx2_hash = client.insert_transaction_with_gas_price_to_queue(U256::zero()); - let block_hash = client.block_hash_delta_minus(1); - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - // when peer#1 is Parity, accepting service transactions - insert_dummy_peer(&mut sync, 1, block_hash); - io.peers_info.insert(1, "Parity/v1.6".to_owned()); - - // and service + non-service transactions are propagated to peers - sync.propagate_new_transactions(&mut io); - - // two separate packets for peer are queued: - // 1) with non-service-transaction - // 2) with service transaction - let sent_transactions: Vec = io.packets.iter() - .filter_map(|p| { - if p.packet_id != 0x02 || p.recipient != 1 { // TRANSACTIONS_PACKET - return None; - } - - let rlp = Rlp::new(&*p.data); - let item_count = rlp.item_count().unwrap_or(0); - if item_count != 1 { - return None; - } - - rlp.at(0).ok().and_then(|r| r.as_val().ok()) - }) - .collect(); - assert_eq!(sent_transactions.len(), 2); - assert!(sent_transactions.iter().any(|tx| tx.hash() == tx1_hash)); - assert!(sent_transactions.iter().any(|tx| tx.hash() == tx2_hash)); - } - - #[test] - fn handles_peer_new_block_malformed() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - - let block_data = get_dummy_block(11, client.chain_info().best_block_hash); - - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - //sync.have_common_block = true; - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let block = Rlp::new(&block_data); - - let result = sync.on_peer_new_block(&mut io, 0, &block); - - assert!(result.is_err()); - } - - #[test] - fn handles_peer_new_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - - let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); - - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let block = Rlp::new(&block_data); - - let result = sync.on_peer_new_block(&mut io, 0, &block); - - assert!(result.is_ok()); - } - - #[test] - fn handles_peer_new_block_empty() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let empty_data = vec![]; - let block = Rlp::new(&empty_data); - - let result = sync.on_peer_new_block(&mut io, 0, &block); - - assert!(result.is_err()); - } - - #[test] - fn handles_peer_new_hashes() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let hashes_data = get_dummy_hashes(); - let hashes_rlp = Rlp::new(&hashes_data); - - let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); - - assert!(result.is_ok()); - } - - #[test] - fn handles_peer_new_hashes_empty() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let empty_hashes_data = vec![]; - let hashes_rlp = Rlp::new(&empty_hashes_data); - - let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); - - assert!(result.is_ok()); - } - - // idea is that what we produce when propagading latest hashes should be accepted in - // on_peer_new_hashes in our code as well - #[test] - fn hashes_rlp_mutually_acceptable() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let peers = sync.get_lagging_peers(&chain_info); - sync.propagate_new_hashes(&chain_info, &mut io, &peers); - - let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_hashes(&mut io, 0, &Rlp::new(data)); - assert!(result.is_ok()); - } - - // idea is that what we produce when propagading latest block should be accepted in - // on_peer_new_block in our code as well - #[test] - fn block_rlp_mutually_acceptable() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let peers = sync.get_lagging_peers(&chain_info); - sync.propagate_blocks(&chain_info, &mut io, &[], &peers); - - let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_block(&mut io, 0, &Rlp::new(data)); - assert!(result.is_ok()); - } - - #[test] - fn should_add_transactions_to_queue() { - fn sender(tx: &UnverifiedTransaction) -> Address { - ethkey::public_to_address(&tx.recover_public().unwrap()) - } - - // given - let mut client = TestBlockChainClient::new(); - client.add_blocks(98, EachBlockWith::Uncle); - client.add_blocks(1, EachBlockWith::UncleAndTransaction); - client.add_blocks(1, EachBlockWith::Transaction); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - - let good_blocks = vec![client.block_hash_delta_minus(2)]; - let retracted_blocks = vec![client.block_hash_delta_minus(1)]; - - // Add some balance to clients and reset nonces - for h in &[good_blocks[0], retracted_blocks[0]] { - let block = client.block(BlockId::Hash(*h)).unwrap(); - let sender = sender(&block.transactions()[0]);; - client.set_balance(sender, U256::from(10_000_000_000_000_000_000u64)); - client.set_nonce(sender, U256::from(0)); - } - - - // when - { - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); - } - // We need to update nonce status (because we say that the block has been imported) - for h in &[good_blocks[0]] { - let block = client.block(BlockId::Hash(*h)).unwrap(); - client.set_nonce(sender(&block.transactions()[0]), U256::from(1)); - } - { - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks, false); - sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); - } - - // then - assert_eq!(client.miner.ready_transactions(&client).len(), 1); - } - - #[test] - fn should_not_add_transactions_to_queue_if_not_synced() { - // given - let mut client = TestBlockChainClient::new(); - client.add_blocks(98, EachBlockWith::Uncle); - client.add_blocks(1, EachBlockWith::UncleAndTransaction); - client.add_blocks(1, EachBlockWith::Transaction); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - - let good_blocks = vec![client.block_hash_delta_minus(2)]; - let retracted_blocks = vec![client.block_hash_delta_minus(1)]; - - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - // when - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.queue_status().status.transaction_count, 0); - sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); - - // then - let status = io.chain.miner.queue_status(); - assert_eq!(status.status.transaction_count, 0); - } -} diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs new file mode 100644 index 00000000000..966b7ce20ad --- /dev/null +++ b/ethcore/sync/src/chain/handler.rs @@ -0,0 +1,828 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use api::WARP_SYNC_PROTOCOL_ID; +use block_sync::{BlockDownloaderImportError as DownloaderImportError, DownloadAction}; +use bytes::Bytes; +use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind}; +use ethcore::error::*; +use ethcore::header::{BlockNumber, Header as BlockHeader}; +use ethcore::snapshot::{ManifestData, RestorationStatus}; +use ethereum_types::{H256, U256}; +use hash::keccak; +use network::PeerId; +use rlp::Rlp; +use snapshot::ChunkType; +use std::cmp; +use std::collections::HashSet; +use std::time::Instant; +use sync_io::SyncIo; + +use super::{ + BlockSet, + ChainSync, + ForkConfirmation, + PacketDecodeError, + PeerAsking, + PeerInfo, + SyncRequester, + SyncState, + ETH_PROTOCOL_VERSION_62, + ETH_PROTOCOL_VERSION_63, + MAX_NEW_BLOCK_AGE, + MAX_NEW_HASHES, + PAR_PROTOCOL_VERSION_1, + PAR_PROTOCOL_VERSION_2, + PAR_PROTOCOL_VERSION_3, + BLOCK_BODIES_PACKET, + BLOCK_HEADERS_PACKET, + NEW_BLOCK_HASHES_PACKET, + NEW_BLOCK_PACKET, + PRIVATE_TRANSACTION_PACKET, + RECEIPTS_PACKET, + SIGNED_PRIVATE_TRANSACTION_PACKET, + SNAPSHOT_DATA_PACKET, + SNAPSHOT_MANIFEST_PACKET, + STATUS_PACKET, + TRANSACTIONS_PACKET, +}; + +/// The Chain Sync Handler: handles responses from peers +pub struct SyncHandler; + +impl SyncHandler { + /// Handle incoming packet from peer + pub fn on_packet(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + if packet_id != STATUS_PACKET && !sync.peers.contains_key(&peer) { + debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); + return; + } + let rlp = Rlp::new(data); + let result = match packet_id { + STATUS_PACKET => SyncHandler::on_peer_status(sync, io, peer, &rlp), + TRANSACTIONS_PACKET => SyncHandler::on_peer_transactions(sync, io, peer, &rlp), + BLOCK_HEADERS_PACKET => SyncHandler::on_peer_block_headers(sync, io, peer, &rlp), + BLOCK_BODIES_PACKET => SyncHandler::on_peer_block_bodies(sync, io, peer, &rlp), + RECEIPTS_PACKET => SyncHandler::on_peer_block_receipts(sync, io, peer, &rlp), + NEW_BLOCK_PACKET => SyncHandler::on_peer_new_block(sync, io, peer, &rlp), + NEW_BLOCK_HASHES_PACKET => SyncHandler::on_peer_new_hashes(sync, io, peer, &rlp), + SNAPSHOT_MANIFEST_PACKET => SyncHandler::on_snapshot_manifest(sync, io, peer, &rlp), + SNAPSHOT_DATA_PACKET => SyncHandler::on_snapshot_data(sync, io, peer, &rlp), + PRIVATE_TRANSACTION_PACKET => SyncHandler::on_private_transaction(sync, io, peer, &rlp), + SIGNED_PRIVATE_TRANSACTION_PACKET => SyncHandler::on_signed_private_transaction(sync, io, peer, &rlp), + _ => { + debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id); + Ok(()) + } + }; + result.unwrap_or_else(|e| { + debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); + }) + } + + /// Called when peer sends us new consensus packet + pub fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + trace!(target: "sync", "Received consensus packet from {:?}", peer_id); + io.chain().queue_consensus_message(r.as_raw().to_vec()); + Ok(()) + } + + /// Called by peer when it is disconnecting + pub fn on_peer_aborting(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId) { + trace!(target: "sync", "== Disconnecting {}: {}", peer, io.peer_info(peer)); + sync.handshaking_peers.remove(&peer); + if sync.peers.contains_key(&peer) { + debug!(target: "sync", "Disconnected {}", peer); + sync.clear_peer_download(peer); + sync.peers.remove(&peer); + sync.active_peers.remove(&peer); + sync.continue_sync(io); + } + } + + /// Called when a new peer is connected + pub fn on_peer_connected(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId) { + trace!(target: "sync", "== Connected {}: {}", peer, io.peer_info(peer)); + if let Err(e) = sync.send_status(io, peer) { + debug!(target:"sync", "Error sending status request: {:?}", e); + io.disconnect_peer(peer); + } else { + sync.handshaking_peers.insert(peer, Instant::now()); + } + } + + /// Called by peer once it has new block bodies + pub fn on_peer_new_block(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id); + return Ok(()); + } + let difficulty: U256 = r.val_at(1)?; + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + if peer.difficulty.map_or(true, |pd| difficulty > pd) { + peer.difficulty = Some(difficulty); + } + } + let block_rlp = r.at(0)?; + let header_rlp = block_rlp.at(0)?; + let h = keccak(&header_rlp.as_raw()); + trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); + let header: BlockHeader = header_rlp.as_val()?; + if header.number() > sync.highest_block.unwrap_or(0) { + sync.highest_block = Some(header.number()); + } + let mut unknown = false; + { + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + peer.latest_hash = header.hash(); + } + } + let last_imported_number = sync.new_blocks.last_imported_block_number(); + if last_imported_number > header.number() && last_imported_number - header.number() > MAX_NEW_BLOCK_AGE { + trace!(target: "sync", "Ignored ancient new block {:?}", h); + io.disable_peer(peer_id); + return Ok(()); + } + match io.chain().import_block(block_rlp.as_raw().to_vec()) { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { + trace!(target: "sync", "New block already in chain {:?}", h); + }, + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { + trace!(target: "sync", "New block already queued {:?}", h); + }, + Ok(_) => { + // abort current download of the same block + sync.complete_sync(io); + sync.new_blocks.mark_as_known(&header.hash(), header.number()); + trace!(target: "sync", "New block queued {:?} ({})", h, header.number()); + }, + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => { + unknown = true; + trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); + }, + Err(e) => { + debug!(target: "sync", "Bad new block {:?} : {:?}", h, e); + io.disable_peer(peer_id); + } + }; + if unknown { + if sync.state != SyncState::Idle { + trace!(target: "sync", "NewBlock ignored while seeking"); + } else { + trace!(target: "sync", "New unknown block {:?}", h); + //TODO: handle too many unknown blocks + sync.sync_peer(io, peer_id, true); + } + } + sync.continue_sync(io); + Ok(()) + } + + /// Handles `NewHashes` packet. Initiates headers download for any unknown hashes. + pub fn on_peer_new_hashes(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id); + return Ok(()); + } + let hashes: Vec<_> = r.iter().take(MAX_NEW_HASHES).map(|item| (item.val_at::(0), item.val_at::(1))).collect(); + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + // Peer has new blocks with unknown difficulty + peer.difficulty = None; + if let Some(&(Ok(ref h), _)) = hashes.last() { + peer.latest_hash = h.clone(); + } + } + if sync.state != SyncState::Idle { + trace!(target: "sync", "Ignoring new hashes since we're already downloading."); + let max = r.iter().take(MAX_NEW_HASHES).map(|item| item.val_at::(1).unwrap_or(0)).fold(0u64, cmp::max); + if max > sync.highest_block.unwrap_or(0) { + sync.highest_block = Some(max); + } + sync.continue_sync(io); + return Ok(()); + } + trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count()?); + let mut max_height: BlockNumber = 0; + let mut new_hashes = Vec::new(); + let last_imported_number = sync.new_blocks.last_imported_block_number(); + for (rh, rn) in hashes { + let hash = rh?; + let number = rn?; + if number > sync.highest_block.unwrap_or(0) { + sync.highest_block = Some(number); + } + if sync.new_blocks.is_downloading(&hash) { + continue; + } + if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE { + trace!(target: "sync", "Ignored ancient new block hash {:?}", hash); + io.disable_peer(peer_id); + continue; + } + match io.chain().block_status(BlockId::Hash(hash.clone())) { + BlockStatus::InChain => { + trace!(target: "sync", "New block hash already in chain {:?}", hash); + }, + BlockStatus::Queued => { + trace!(target: "sync", "New hash block already queued {:?}", hash); + }, + BlockStatus::Unknown | BlockStatus::Pending => { + new_hashes.push(hash.clone()); + if number > max_height { + trace!(target: "sync", "New unknown block hash {:?}", hash); + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + peer.latest_hash = hash.clone(); + } + max_height = number; + } + }, + BlockStatus::Bad => { + debug!(target: "sync", "Bad new block hash {:?}", hash); + io.disable_peer(peer_id); + return Ok(()); + } + } + }; + if max_height != 0 { + trace!(target: "sync", "Downloading blocks for new hashes"); + sync.new_blocks.reset_to(new_hashes); + sync.state = SyncState::NewBlocks; + sync.sync_peer(io, peer_id, true); + } + sync.continue_sync(io); + Ok(()) + } + + /// Called by peer once it has new block bodies + fn on_peer_block_bodies(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + sync.clear_peer_download(peer_id); + let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { + trace!(target: "sync", "{}: Ignored unexpected bodies", peer_id); + sync.continue_sync(io); + return Ok(()); + } + let item_count = r.item_count()?; + trace!(target: "sync", "{} -> BlockBodies ({} entries), set = {:?}", peer_id, item_count, block_set); + if item_count == 0 { + sync.deactivate_peer(io, peer_id); + } + else if sync.state == SyncState::Waiting { + trace!(target: "sync", "Ignored block bodies while waiting"); + } + else + { + let result = { + let downloader = match block_set { + BlockSet::NewBlocks => &mut sync.new_blocks, + BlockSet::OldBlocks => match sync.old_blocks { + None => { + trace!(target: "sync", "Ignored block headers while block download is inactive"); + sync.continue_sync(io); + return Ok(()); + }, + Some(ref mut blocks) => blocks, + } + }; + downloader.import_bodies(io, r) + }; + + match result { + Err(DownloaderImportError::Invalid) => { + io.disable_peer(peer_id); + sync.deactivate_peer(io, peer_id); + sync.continue_sync(io); + return Ok(()); + }, + Err(DownloaderImportError::Useless) => { + sync.deactivate_peer(io, peer_id); + }, + Ok(()) => (), + } + + sync.collect_blocks(io, block_set); + sync.sync_peer(io, peer_id, false); + } + sync.continue_sync(io); + Ok(()) + } + + fn on_peer_confirmed(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + sync.sync_peer(io, peer_id, false); + } + + fn on_peer_fork_header(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + { + let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); + peer.asking = PeerAsking::Nothing; + let item_count = r.item_count()?; + let (fork_number, fork_hash) = sync.fork_block.expect("ForkHeader request is sent only fork block is Some; qed").clone(); + + if item_count == 0 || item_count != 1 { + trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id); + io.disable_peer(peer_id); + return Ok(()); + } + + let header = r.at(0)?.as_raw(); + if keccak(&header) != fork_hash { + trace!(target: "sync", "{}: Fork mismatch", peer_id); + io.disable_peer(peer_id); + return Ok(()); + } + + trace!(target: "sync", "{}: Confirmed peer", peer_id); + peer.confirmation = ForkConfirmation::Confirmed; + if !io.chain_overlay().read().contains_key(&fork_number) { + io.chain_overlay().write().insert(fork_number, header.to_vec()); + } + } + SyncHandler::on_peer_confirmed(sync, io, peer_id); + return Ok(()); + } + + /// Called by peer once it has new block headers during sync + fn on_peer_block_headers(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + let is_fork_header_request = match sync.peers.get(&peer_id) { + Some(peer) if peer.asking == PeerAsking::ForkHeader => true, + _ => false, + }; + + if is_fork_header_request { + return SyncHandler::on_peer_fork_header(sync, io, peer_id, r); + } + + sync.clear_peer_download(peer_id); + let expected_hash = sync.peers.get(&peer_id).and_then(|p| p.asking_hash); + let allowed = sync.peers.get(&peer_id).map(|p| p.is_allowed()).unwrap_or(false); + let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockHeaders) || expected_hash.is_none() || !allowed { + trace!(target: "sync", "{}: Ignored unexpected headers, expected_hash = {:?}", peer_id, expected_hash); + sync.continue_sync(io); + return Ok(()); + } + let item_count = r.item_count()?; + trace!(target: "sync", "{} -> BlockHeaders ({} entries), state = {:?}, set = {:?}", peer_id, item_count, sync.state, block_set); + if (sync.state == SyncState::Idle || sync.state == SyncState::WaitingPeers) && sync.old_blocks.is_none() { + trace!(target: "sync", "Ignored unexpected block headers"); + sync.continue_sync(io); + return Ok(()); + } + if sync.state == SyncState::Waiting { + trace!(target: "sync", "Ignored block headers while waiting"); + sync.continue_sync(io); + return Ok(()); + } + + let result = { + let downloader = match block_set { + BlockSet::NewBlocks => &mut sync.new_blocks, + BlockSet::OldBlocks => { + match sync.old_blocks { + None => { + trace!(target: "sync", "Ignored block headers while block download is inactive"); + sync.continue_sync(io); + return Ok(()); + }, + Some(ref mut blocks) => blocks, + } + } + }; + downloader.import_headers(io, r, expected_hash) + }; + + match result { + Err(DownloaderImportError::Useless) => { + sync.deactivate_peer(io, peer_id); + }, + Err(DownloaderImportError::Invalid) => { + io.disable_peer(peer_id); + sync.deactivate_peer(io, peer_id); + sync.continue_sync(io); + return Ok(()); + }, + Ok(DownloadAction::Reset) => { + // mark all outstanding requests as expired + trace!("Resetting downloads for {:?}", block_set); + for (_, ref mut p) in sync.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { + p.reset_asking(); + } + + } + Ok(DownloadAction::None) => {}, + } + + sync.collect_blocks(io, block_set); + // give a task to the same peer first if received valuable headers. + sync.sync_peer(io, peer_id, false); + // give tasks to other peers + sync.continue_sync(io); + Ok(()) + } + + /// Called by peer once it has new block receipts + fn on_peer_block_receipts(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + sync.clear_peer_download(peer_id); + let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { + trace!(target: "sync", "{}: Ignored unexpected receipts", peer_id); + sync.continue_sync(io); + return Ok(()); + } + let item_count = r.item_count()?; + trace!(target: "sync", "{} -> BlockReceipts ({} entries)", peer_id, item_count); + if item_count == 0 { + sync.deactivate_peer(io, peer_id); + } + else if sync.state == SyncState::Waiting { + trace!(target: "sync", "Ignored block receipts while waiting"); + } + else + { + let result = { + let downloader = match block_set { + BlockSet::NewBlocks => &mut sync.new_blocks, + BlockSet::OldBlocks => match sync.old_blocks { + None => { + trace!(target: "sync", "Ignored block headers while block download is inactive"); + sync.continue_sync(io); + return Ok(()); + }, + Some(ref mut blocks) => blocks, + } + }; + downloader.import_receipts(io, r) + }; + + match result { + Err(DownloaderImportError::Invalid) => { + io.disable_peer(peer_id); + sync.deactivate_peer(io, peer_id); + sync.continue_sync(io); + return Ok(()); + }, + Err(DownloaderImportError::Useless) => { + sync.deactivate_peer(io, peer_id); + }, + Ok(()) => (), + } + + sync.collect_blocks(io, block_set); + sync.sync_peer(io, peer_id, false); + } + sync.continue_sync(io); + Ok(()) + } + + /// Called when snapshot manifest is downloaded from a peer. + fn on_snapshot_manifest(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring snapshot manifest from unconfirmed peer {}", peer_id); + return Ok(()); + } + sync.clear_peer_download(peer_id); + if !sync.reset_peer_asking(peer_id, PeerAsking::SnapshotManifest) || sync.state != SyncState::SnapshotManifest { + trace!(target: "sync", "{}: Ignored unexpected/expired manifest", peer_id); + sync.continue_sync(io); + return Ok(()); + } + + let manifest_rlp = r.at(0)?; + let manifest = match ManifestData::from_rlp(manifest_rlp.as_raw()) { + Err(e) => { + trace!(target: "sync", "{}: Ignored bad manifest: {:?}", peer_id, e); + io.disable_peer(peer_id); + sync.continue_sync(io); + return Ok(()); + } + Ok(manifest) => manifest, + }; + + let is_supported_version = io.snapshot_service().supported_versions() + .map_or(false, |(l, h)| manifest.version >= l && manifest.version <= h); + + if !is_supported_version { + trace!(target: "sync", "{}: Snapshot manifest version not supported: {}", peer_id, manifest.version); + io.disable_peer(peer_id); + sync.continue_sync(io); + return Ok(()); + } + sync.snapshot.reset_to(&manifest, &keccak(manifest_rlp.as_raw())); + io.snapshot_service().begin_restore(manifest); + sync.state = SyncState::SnapshotData; + + // give a task to the same peer first. + sync.sync_peer(io, peer_id, false); + // give tasks to other peers + sync.continue_sync(io); + Ok(()) + } + + /// Called when snapshot data is downloaded from a peer. + fn on_snapshot_data(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring snapshot data from unconfirmed peer {}", peer_id); + return Ok(()); + } + sync.clear_peer_download(peer_id); + if !sync.reset_peer_asking(peer_id, PeerAsking::SnapshotData) || (sync.state != SyncState::SnapshotData && sync.state != SyncState::SnapshotWaiting) { + trace!(target: "sync", "{}: Ignored unexpected snapshot data", peer_id); + sync.continue_sync(io); + return Ok(()); + } + + // check service status + let status = io.snapshot_service().status(); + match status { + RestorationStatus::Inactive | RestorationStatus::Failed => { + trace!(target: "sync", "{}: Snapshot restoration aborted", peer_id); + sync.state = SyncState::WaitingPeers; + + // only note bad if restoration failed. + if let (Some(hash), RestorationStatus::Failed) = (sync.snapshot.snapshot_hash(), status) { + trace!(target: "sync", "Noting snapshot hash {} as bad", hash); + sync.snapshot.note_bad(hash); + } + + sync.snapshot.clear(); + sync.continue_sync(io); + return Ok(()); + }, + RestorationStatus::Ongoing { .. } => { + trace!(target: "sync", "{}: Snapshot restoration is ongoing", peer_id); + }, + } + + let snapshot_data: Bytes = r.val_at(0)?; + match sync.snapshot.validate_chunk(&snapshot_data) { + Ok(ChunkType::Block(hash)) => { + trace!(target: "sync", "{}: Processing block chunk", peer_id); + io.snapshot_service().restore_block_chunk(hash, snapshot_data); + } + Ok(ChunkType::State(hash)) => { + trace!(target: "sync", "{}: Processing state chunk", peer_id); + io.snapshot_service().restore_state_chunk(hash, snapshot_data); + } + Err(()) => { + trace!(target: "sync", "{}: Got bad snapshot chunk", peer_id); + io.disconnect_peer(peer_id); + sync.continue_sync(io); + return Ok(()); + } + } + + if sync.snapshot.is_complete() { + // wait for snapshot restoration process to complete + sync.state = SyncState::SnapshotWaiting; + } + // give a task to the same peer first. + sync.sync_peer(io, peer_id, false); + // give tasks to other peers + sync.continue_sync(io); + Ok(()) + } + + /// Called by peer to report status + fn on_peer_status(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + sync.handshaking_peers.remove(&peer_id); + let protocol_version: u8 = r.val_at(0)?; + let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer_id) != 0; + let peer = PeerInfo { + protocol_version: protocol_version, + network_id: r.val_at(1)?, + difficulty: Some(r.val_at(2)?), + latest_hash: r.val_at(3)?, + genesis: r.val_at(4)?, + asking: PeerAsking::Nothing, + asking_blocks: Vec::new(), + asking_hash: None, + ask_time: Instant::now(), + last_sent_transactions: HashSet::new(), + expired: false, + confirmation: if sync.fork_block.is_none() { ForkConfirmation::Confirmed } else { ForkConfirmation::Unconfirmed }, + asking_snapshot_data: None, + snapshot_hash: if warp_protocol { Some(r.val_at(5)?) } else { None }, + snapshot_number: if warp_protocol { Some(r.val_at(6)?) } else { None }, + block_set: None, + }; + + trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{}, snapshot:{:?})", + peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis, peer.snapshot_number); + if io.is_expired() { + trace!(target: "sync", "Status packet from expired session {}:{}", peer_id, io.peer_info(peer_id)); + return Ok(()); + } + + if sync.peers.contains_key(&peer_id) { + debug!(target: "sync", "Unexpected status packet from {}:{}", peer_id, io.peer_info(peer_id)); + return Ok(()); + } + let chain_info = io.chain().chain_info(); + if peer.genesis != chain_info.genesis_hash { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} genesis hash mismatch (ours: {}, theirs: {})", peer_id, chain_info.genesis_hash, peer.genesis); + return Ok(()); + } + if peer.network_id != sync.network_id { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, sync.network_id, peer.network_id); + return Ok(()); + } + if (warp_protocol && peer.protocol_version != PAR_PROTOCOL_VERSION_1 && peer.protocol_version != PAR_PROTOCOL_VERSION_2 && peer.protocol_version != PAR_PROTOCOL_VERSION_3) + || (!warp_protocol && peer.protocol_version != ETH_PROTOCOL_VERSION_63 && peer.protocol_version != ETH_PROTOCOL_VERSION_62) { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); + return Ok(()); + } + + if sync.sync_start_time.is_none() { + sync.sync_start_time = Some(Instant::now()); + } + + sync.peers.insert(peer_id.clone(), peer); + // Don't activate peer immediatelly when searching for common block. + // Let the current sync round complete first. + sync.active_peers.insert(peer_id.clone()); + debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); + if let Some((fork_block, _)) = sync.fork_block { + SyncRequester::request_fork_header(sync, io, peer_id, fork_block); + } else { + SyncHandler::on_peer_confirmed(sync, io, peer_id); + } + Ok(()) + } + + /// Called when peer sends us new transactions + fn on_peer_transactions(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + // Accept transactions only when fully synced + if !io.is_chain_queue_empty() || (sync.state != SyncState::Idle && sync.state != SyncState::NewBlocks) { + trace!(target: "sync", "{} Ignoring transactions while syncing", peer_id); + return Ok(()); + } + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring transactions from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + let item_count = r.item_count()?; + trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count); + let mut transactions = Vec::with_capacity(item_count); + for i in 0 .. item_count { + let rlp = r.at(i)?; + let tx = rlp.as_raw().to_vec(); + transactions.push(tx); + } + io.chain().queue_transactions(transactions, peer_id); + Ok(()) + } + + /// Called when peer sends us signed private transaction packet + fn on_signed_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + trace!(target: "sync", "Received signed private transaction packet from {:?}", peer_id); + if let Err(e) = sync.private_tx_handler.import_signed_private_transaction(r.as_raw()) { + trace!(target: "sync", "Ignoring the message, error queueing: {}", e); + } + Ok(()) + } + + /// Called when peer sends us new private transaction packet + fn on_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + trace!(target: "sync", "Received private transaction packet from {:?}", peer_id); + + if let Err(e) = sync.private_tx_handler.import_private_transaction(r.as_raw()) { + trace!(target: "sync", "Ignoring the message, error queueing: {}", e); + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use ethcore::client::{ChainInfo, EachBlockWith, TestBlockChainClient}; + use parking_lot::RwLock; + use rlp::{Rlp}; + use std::collections::{VecDeque}; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + + use super::*; + use super::super::tests::{ + dummy_sync_with_peer, + get_dummy_block, + get_dummy_blocks, + get_dummy_hashes, + }; + + #[test] + fn handles_peer_new_hashes() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let hashes_data = get_dummy_hashes(); + let hashes_rlp = Rlp::new(&hashes_data); + + let result = SyncHandler::on_peer_new_hashes(&mut sync, &mut io, 0, &hashes_rlp); + + assert!(result.is_ok()); + } + + #[test] + fn handles_peer_new_block_malformed() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + + let block_data = get_dummy_block(11, client.chain_info().best_block_hash); + + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + //sync.have_common_block = true; + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let block = Rlp::new(&block_data); + + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &block); + + assert!(result.is_err()); + } + + #[test] + fn handles_peer_new_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + + let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); + + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let block = Rlp::new(&block_data); + + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &block); + + assert!(result.is_ok()); + } + + #[test] + fn handles_peer_new_block_empty() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let empty_data = vec![]; + let block = Rlp::new(&empty_data); + + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &block); + + assert!(result.is_err()); + } + + #[test] + fn handles_peer_new_hashes_empty() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let empty_hashes_data = vec![]; + let hashes_rlp = Rlp::new(&empty_hashes_data); + + let result = SyncHandler::on_peer_new_hashes(&mut sync, &mut io, 0, &hashes_rlp); + + assert!(result.is_ok()); + } +} diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs new file mode 100644 index 00000000000..abab1da9413 --- /dev/null +++ b/ethcore/sync/src/chain/mod.rs @@ -0,0 +1,1379 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! `BlockChain` synchronization strategy. +//! Syncs to peers and keeps up to date. +//! This implementation uses ethereum protocol v63 +//! +//! Syncing strategy summary. +//! Split the chain into ranges of N blocks each. Download ranges sequentially. Split each range into subchains of M blocks. Download subchains in parallel. +//! State. +//! Sync state consists of the following data: +//! - s: State enum which can be one of the following values: `ChainHead`, `Blocks`, `Idle` +//! - H: A set of downloaded block headers +//! - B: A set of downloaded block bodies +//! - S: Set of block subchain start block hashes to download. +//! - l: Last imported / common block hash +//! - P: A set of connected peers. For each peer we maintain its last known total difficulty and starting block hash being requested if any. +//! General behaviour. +//! We start with all sets empty, l is set to the best block in the block chain, s is set to `ChainHead`. +//! If at any moment a bad block is reported by the block queue, we set s to `ChainHead`, reset l to the best block in the block chain and clear H, B and S. +//! If at any moment P becomes empty, we set s to `ChainHead`, and clear H, B and S. +//! +//! Workflow for `ChainHead` state. +//! In this state we try to get subchain headers with a single `GetBlockHeaders` request. +//! On `NewPeer` / On `Restart`: +//! If peer's total difficulty is higher and there are less than 5 peers downloading, request N/M headers with interval M+1 starting from l +//! On `BlockHeaders(R)`: +//! If R is empty: +//! If l is equal to genesis block hash or l is more than 1000 blocks behind our best hash: +//! Remove current peer from P. set l to the best block in the block chain. Select peer with maximum total difficulty from P and restart. +//! Else +//! Set l to l’s parent and restart. +//! Else if we already have all the headers in the block chain or the block queue: +//! Set s to `Idle`, +//! Else +//! Set S to R, set s to `Blocks`. +//! +//! All other messages are ignored. +//! +//! Workflow for `Blocks` state. +//! In this state we download block headers and bodies from multiple peers. +//! On `NewPeer` / On `Restart`: +//! For all idle peers: +//! Find a set of 256 or less block hashes in H which are not in B and not being downloaded by other peers. If the set is not empty: +//! Request block bodies for the hashes in the set. +//! Else +//! Find an element in S which is not being downloaded by other peers. If found: Request M headers starting from the element. +//! +//! On `BlockHeaders(R)`: +//! If R is empty remove current peer from P and restart. +//! Validate received headers: +//! For each header find a parent in H or R or the blockchain. Restart if there is a block with unknown parent. +//! Find at least one header from the received list in S. Restart if there is none. +//! Go to `CollectBlocks`. +//! +//! On `BlockBodies(R)`: +//! If R is empty remove current peer from P and restart. +//! Add bodies with a matching header in H to B. +//! Go to `CollectBlocks`. +//! +//! `CollectBlocks`: +//! Find a chain of blocks C in H starting from h where h’s parent equals to l. The chain ends with the first block which does not have a body in B. +//! Add all blocks from the chain to the block queue. Remove them from H and B. Set l to the hash of the last block from C. +//! Update and merge subchain heads in S. For each h in S find a chain of blocks in B starting from h. Remove h from S. if the chain does not include an element from S add the end of the chain to S. +//! If H is empty and S contains a single element set s to `ChainHead`. +//! Restart. +//! +//! All other messages are ignored. +//! Workflow for Idle state. +//! On `NewBlock`: +//! Import the block. If the block is unknown set s to `ChainHead` and restart. +//! On `NewHashes`: +//! Set s to `ChainHead` and restart. +//! +//! All other messages are ignored. + +mod handler; +mod propagator; +mod requester; +mod supplier; + +use std::sync::Arc; +use std::collections::{HashSet, HashMap}; +use std::cmp; +use std::time::{Duration, Instant}; +use hash::keccak; +use heapsize::HeapSizeOf; +use ethereum_types::{H256, U256}; +use plain_hasher::H256FastMap; +use parking_lot::RwLock; +use bytes::Bytes; +use rlp::{Rlp, RlpStream, DecoderError}; +use network::{self, PeerId, PacketId}; +use ethcore::header::{BlockNumber}; +use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockQueueInfo}; +use ethcore::snapshot::{RestorationStatus}; +use sync_io::SyncIo; +use super::{WarpSync, SyncConfig}; +use block_sync::{BlockDownloader, BlockDownloaderImportError as DownloaderImportError}; +use rand::Rng; +use snapshot::{Snapshot}; +use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; +use private_tx::PrivateTxHandler; +use transactions_stats::{TransactionsStats, Stats as TransactionStats}; +use transaction::UnverifiedTransaction; + +use self::handler::SyncHandler; +use self::propagator::SyncPropagator; +use self::requester::SyncRequester; +use self::supplier::SyncSupplier; + +known_heap_size!(0, PeerInfo); + +pub type PacketDecodeError = DecoderError; + +/// 63 version of Ethereum protocol. +pub const ETH_PROTOCOL_VERSION_63: u8 = 63; +/// 62 version of Ethereum protocol. +pub const ETH_PROTOCOL_VERSION_62: u8 = 62; +/// 1 version of Parity protocol. +pub const PAR_PROTOCOL_VERSION_1: u8 = 1; +/// 2 version of Parity protocol (consensus messages added). +pub const PAR_PROTOCOL_VERSION_2: u8 = 2; +/// 3 version of Parity protocol (private transactions messages added). +pub const PAR_PROTOCOL_VERSION_3: u8 = 3; + +pub const MAX_BODIES_TO_SEND: usize = 256; +pub const MAX_HEADERS_TO_SEND: usize = 512; +pub const MAX_NODE_DATA_TO_SEND: usize = 1024; +pub const MAX_RECEIPTS_TO_SEND: usize = 1024; +pub const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256; +const MIN_PEERS_PROPAGATION: usize = 4; +const MAX_PEERS_PROPAGATION: usize = 128; +const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20; +const MAX_NEW_HASHES: usize = 64; +const MAX_NEW_BLOCK_AGE: BlockNumber = 20; +// maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). +const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; +// Maximal number of transactions in sent in single packet. +const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; +// Min number of blocks to be behind for a snapshot sync +const SNAPSHOT_RESTORE_THRESHOLD: BlockNumber = 30000; +const SNAPSHOT_MIN_PEERS: usize = 3; + +const STATUS_PACKET: u8 = 0x00; +const NEW_BLOCK_HASHES_PACKET: u8 = 0x01; +const TRANSACTIONS_PACKET: u8 = 0x02; +pub const GET_BLOCK_HEADERS_PACKET: u8 = 0x03; +pub const BLOCK_HEADERS_PACKET: u8 = 0x04; +pub const GET_BLOCK_BODIES_PACKET: u8 = 0x05; +const BLOCK_BODIES_PACKET: u8 = 0x06; +const NEW_BLOCK_PACKET: u8 = 0x07; + +pub const GET_NODE_DATA_PACKET: u8 = 0x0d; +pub const NODE_DATA_PACKET: u8 = 0x0e; +pub const GET_RECEIPTS_PACKET: u8 = 0x0f; +pub const RECEIPTS_PACKET: u8 = 0x10; + +pub const ETH_PACKET_COUNT: u8 = 0x11; + +pub const GET_SNAPSHOT_MANIFEST_PACKET: u8 = 0x11; +pub const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12; +pub const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13; +pub const SNAPSHOT_DATA_PACKET: u8 = 0x14; +pub const CONSENSUS_DATA_PACKET: u8 = 0x15; +const PRIVATE_TRANSACTION_PACKET: u8 = 0x16; +const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17; + +pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; + +const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; + +const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); +const STATUS_TIMEOUT: Duration = Duration::from_secs(5); +const HEADERS_TIMEOUT: Duration = Duration::from_secs(15); +const BODIES_TIMEOUT: Duration = Duration::from_secs(20); +const RECEIPTS_TIMEOUT: Duration = Duration::from_secs(10); +const FORK_HEADER_TIMEOUT: Duration = Duration::from_secs(3); +const SNAPSHOT_MANIFEST_TIMEOUT: Duration = Duration::from_secs(5); +const SNAPSHOT_DATA_TIMEOUT: Duration = Duration::from_secs(120); + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +/// Sync state +pub enum SyncState { + /// Collecting enough peers to start syncing. + WaitingPeers, + /// Waiting for snapshot manifest download + SnapshotManifest, + /// Downloading snapshot data + SnapshotData, + /// Waiting for snapshot restoration progress. + SnapshotWaiting, + /// Downloading new blocks + Blocks, + /// Initial chain sync complete. Waiting for new packets + Idle, + /// Block downloading paused. Waiting for block queue to process blocks and free some space + Waiting, + /// Downloading blocks learned from `NewHashes` packet + NewBlocks, +} + +/// Syncing status and statistics +#[derive(Clone, Copy)] +pub struct SyncStatus { + /// State + pub state: SyncState, + /// Syncing protocol version. That's the maximum protocol version we connect to. + pub protocol_version: u8, + /// The underlying p2p network version. + pub network_id: u64, + /// `BlockChain` height for the moment the sync started. + pub start_block_number: BlockNumber, + /// Last fully downloaded and imported block number (if any). + pub last_imported_block_number: Option, + /// Highest block number in the download queue (if any). + pub highest_block_number: Option, + /// Total number of blocks for the sync process. + pub blocks_total: BlockNumber, + /// Number of blocks downloaded so far. + pub blocks_received: BlockNumber, + /// Total number of connected peers + pub num_peers: usize, + /// Total number of active peers. + pub num_active_peers: usize, + /// Heap memory used in bytes. + pub mem_used: usize, + /// Snapshot chunks + pub num_snapshot_chunks: usize, + /// Snapshot chunks downloaded + pub snapshot_chunks_done: usize, + /// Last fully downloaded and imported ancient block number (if any). + pub last_imported_old_block_number: Option, +} + +impl SyncStatus { + /// Indicates if snapshot download is in progress + pub fn is_snapshot_syncing(&self) -> bool { + self.state == SyncState::SnapshotManifest + || self.state == SyncState::SnapshotData + || self.state == SyncState::SnapshotWaiting + } + + /// Returns max no of peers to display in informants + pub fn current_max_peers(&self, min_peers: u32, max_peers: u32) -> u32 { + if self.num_peers as u32 > min_peers { + max_peers + } else { + min_peers + } + } + + /// Is it doing a major sync? + pub fn is_syncing(&self, queue_info: BlockQueueInfo) -> bool { + let is_syncing_state = match self.state { SyncState::Idle | SyncState::NewBlocks => false, _ => true }; + let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3; + is_verifying || is_syncing_state + } +} + +#[derive(PartialEq, Eq, Debug, Clone)] +/// Peer data type requested +pub enum PeerAsking { + Nothing, + ForkHeader, + BlockHeaders, + BlockBodies, + BlockReceipts, + SnapshotManifest, + SnapshotData, +} + +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +/// Block downloader channel. +pub enum BlockSet { + /// New blocks better than out best blocks + NewBlocks, + /// Missing old blocks + OldBlocks, +} +#[derive(Clone, Eq, PartialEq)] +pub enum ForkConfirmation { + /// Fork block confirmation pending. + Unconfirmed, + /// Fork is confirmed. + Confirmed, +} + +#[derive(Clone)] +/// Syncing peer information +pub struct PeerInfo { + /// eth protocol version + protocol_version: u8, + /// Peer chain genesis hash + genesis: H256, + /// Peer network id + network_id: u64, + /// Peer best block hash + latest_hash: H256, + /// Peer total difficulty if known + difficulty: Option, + /// Type of data currenty being requested from peer. + asking: PeerAsking, + /// A set of block numbers being requested + asking_blocks: Vec, + /// Holds requested header hash if currently requesting block header by hash + asking_hash: Option, + /// Holds requested snapshot chunk hash if any. + asking_snapshot_data: Option, + /// Request timestamp + ask_time: Instant, + /// Holds a set of transactions recently sent to this peer to avoid spamming. + last_sent_transactions: HashSet, + /// Pending request is expired and result should be ignored + expired: bool, + /// Peer fork confirmation status + confirmation: ForkConfirmation, + /// Best snapshot hash + snapshot_hash: Option, + /// Best snapshot block number + snapshot_number: Option, + /// Block set requested + block_set: Option, +} + +impl PeerInfo { + fn can_sync(&self) -> bool { + self.confirmation == ForkConfirmation::Confirmed && !self.expired + } + + fn is_allowed(&self) -> bool { + self.confirmation != ForkConfirmation::Unconfirmed && !self.expired + } + + fn reset_asking(&mut self) { + self.asking_blocks.clear(); + self.asking_hash = None; + // mark any pending requests as expired + if self.asking != PeerAsking::Nothing && self.is_allowed() { + self.expired = true; + } + } +} + +#[cfg(not(test))] +pub mod random { + use rand; + pub fn new() -> rand::ThreadRng { rand::thread_rng() } +} +#[cfg(test)] +pub mod random { + use rand::{self, SeedableRng}; + pub fn new() -> rand::XorShiftRng { rand::XorShiftRng::from_seed([0, 1, 2, 3]) } +} + +pub type RlpResponseResult = Result, PacketDecodeError>; +pub type Peers = HashMap; + +/// Blockchain sync handler. +/// See module documentation for more details. +pub struct ChainSync { + /// Sync state + state: SyncState, + /// Last block number for the start of sync + starting_block: BlockNumber, + /// Highest block number seen + highest_block: Option, + /// All connected peers + peers: Peers, + /// Peers active for current sync round + active_peers: HashSet, + /// Block download process for new blocks + new_blocks: BlockDownloader, + /// Block download process for ancient blocks + old_blocks: Option, + /// Last propagated block number + last_sent_block_number: BlockNumber, + /// Network ID + network_id: u64, + /// Optional fork block to check + fork_block: Option<(BlockNumber, H256)>, + /// Snapshot downloader. + snapshot: Snapshot, + /// Connected peers pending Status message. + /// Value is request timestamp. + handshaking_peers: HashMap, + /// Sync start timestamp. Measured when first peer is connected + sync_start_time: Option, + /// Transactions propagation statistics + transactions_stats: TransactionsStats, + /// Enable ancient block downloading + download_old_blocks: bool, + /// Shared private tx service. + private_tx_handler: Arc, + /// Enable warp sync. + warp_sync: WarpSync, +} + +impl ChainSync { + /// Create a new instance of syncing strategy. + pub fn new(config: SyncConfig, chain: &BlockChainClient, private_tx_handler: Arc) -> ChainSync { + let chain_info = chain.chain_info(); + let best_block = chain.chain_info().best_block_number; + let state = ChainSync::get_init_state(config.warp_sync, chain); + + let mut sync = ChainSync { + state, + starting_block: best_block, + highest_block: None, + peers: HashMap::new(), + handshaking_peers: HashMap::new(), + active_peers: HashSet::new(), + new_blocks: BlockDownloader::new(false, &chain_info.best_block_hash, chain_info.best_block_number), + old_blocks: None, + last_sent_block_number: 0, + network_id: config.network_id, + fork_block: config.fork_block, + download_old_blocks: config.download_old_blocks, + snapshot: Snapshot::new(), + sync_start_time: None, + transactions_stats: TransactionsStats::default(), + private_tx_handler, + warp_sync: config.warp_sync, + }; + sync.update_targets(chain); + sync + } + + fn get_init_state(warp_sync: WarpSync, chain: &BlockChainClient) -> SyncState { + let best_block = chain.chain_info().best_block_number; + match warp_sync { + WarpSync::Enabled => SyncState::WaitingPeers, + WarpSync::OnlyAndAfter(block) if block > best_block => SyncState::WaitingPeers, + _ => SyncState::Idle, + } + } + + /// Returns synchonization status + pub fn status(&self) -> SyncStatus { + let last_imported_number = self.new_blocks.last_imported_block_number(); + SyncStatus { + state: self.state.clone(), + protocol_version: ETH_PROTOCOL_VERSION_63, + network_id: self.network_id, + start_block_number: self.starting_block, + last_imported_block_number: Some(last_imported_number), + last_imported_old_block_number: self.old_blocks.as_ref().map(|d| d.last_imported_block_number()), + highest_block_number: self.highest_block.map(|n| cmp::max(n, last_imported_number)), + blocks_received: if last_imported_number > self.starting_block { last_imported_number - self.starting_block } else { 0 }, + blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, + num_peers: self.peers.values().filter(|p| p.is_allowed()).count(), + num_active_peers: self.peers.values().filter(|p| p.is_allowed() && p.asking != PeerAsking::Nothing).count(), + num_snapshot_chunks: self.snapshot.total_chunks(), + snapshot_chunks_done: self.snapshot.done_chunks(), + mem_used: + self.new_blocks.heap_size() + + self.old_blocks.as_ref().map_or(0, |d| d.heap_size()) + + self.peers.heap_size_of_children(), + } + } + + /// Returns information on peers connections + pub fn peer_info(&self, peer_id: &PeerId) -> Option { + self.peers.get(peer_id).map(|peer_data| { + PeerInfoDigest { + version: peer_data.protocol_version as u32, + difficulty: peer_data.difficulty, + head: peer_data.latest_hash, + } + }) + } + + /// Returns transactions propagation statistics + pub fn transactions_stats(&self) -> &H256FastMap { + self.transactions_stats.stats() + } + + /// Updates transactions were received by a peer + pub fn transactions_received(&mut self, txs: &[UnverifiedTransaction], peer_id: PeerId) { + if let Some(peer_info) = self.peers.get_mut(&peer_id) { + peer_info.last_sent_transactions.extend(txs.iter().map(|tx| tx.hash())); + } + } + + /// Abort all sync activity + pub fn abort(&mut self, io: &mut SyncIo) { + self.reset_and_continue(io); + self.peers.clear(); + } + + /// Reset sync. Clear all downloaded data but keep the queue + fn reset(&mut self, io: &mut SyncIo) { + self.new_blocks.reset(); + let chain_info = io.chain().chain_info(); + for (_, ref mut p) in &mut self.peers { + if p.block_set != Some(BlockSet::OldBlocks) { + p.reset_asking(); + if p.difficulty.is_none() { + // assume peer has up to date difficulty + p.difficulty = Some(chain_info.pending_total_difficulty); + } + } + } + self.state = ChainSync::get_init_state(self.warp_sync, io.chain()); + // Reactivate peers only if some progress has been made + // since the last sync round of if starting fresh. + self.active_peers = self.peers.keys().cloned().collect(); + } + + /// Restart sync + pub fn reset_and_continue(&mut self, io: &mut SyncIo) { + trace!(target: "sync", "Restarting"); + if self.state == SyncState::SnapshotData { + debug!(target:"sync", "Aborting snapshot restore"); + io.snapshot_service().abort_restore(); + } + self.snapshot.clear(); + self.reset(io); + self.continue_sync(io); + } + + /// Remove peer from active peer set. Peer will be reactivated on the next sync + /// round. + fn deactivate_peer(&mut self, _io: &mut SyncIo, peer_id: PeerId) { + trace!(target: "sync", "Deactivating peer {}", peer_id); + self.active_peers.remove(&peer_id); + } + + fn maybe_start_snapshot_sync(&mut self, io: &mut SyncIo) { + if !self.warp_sync.is_enabled() || io.snapshot_service().supported_versions().is_none() { + trace!(target: "sync", "Skipping warp sync. Disabled or not supported."); + return; + } + if self.state != SyncState::WaitingPeers && self.state != SyncState::Blocks && self.state != SyncState::Waiting { + trace!(target: "sync", "Skipping warp sync. State: {:?}", self.state); + return; + } + // Make sure the snapshot block is not too far away from best block and network best block and + // that it is higher than fork detection block + let our_best_block = io.chain().chain_info().best_block_number; + let fork_block = self.fork_block.map_or(0, |(n, _)| n); + + let (best_hash, max_peers, snapshot_peers) = { + let expected_warp_block = match self.warp_sync { + WarpSync::OnlyAndAfter(block) => block, + _ => 0, + }; + //collect snapshot infos from peers + let snapshots = self.peers.iter() + .filter(|&(_, p)| p.is_allowed() && p.snapshot_number.map_or(false, |sn| + // Snapshot must be old enough that it's usefull to sync with it + our_best_block < sn && (sn - our_best_block) > SNAPSHOT_RESTORE_THRESHOLD && + // Snapshot must have been taken after the Fork + sn > fork_block && + // Snapshot must be greater than the warp barrier if any + sn > expected_warp_block && + // If we know a highest block, snapshot must be recent enough + self.highest_block.map_or(true, |highest| { + highest < sn || (highest - sn) <= SNAPSHOT_RESTORE_THRESHOLD + }) + )) + .filter_map(|(p, peer)| peer.snapshot_hash.map(|hash| (p, hash.clone()))) + .filter(|&(_, ref hash)| !self.snapshot.is_known_bad(hash)); + + let mut snapshot_peers = HashMap::new(); + let mut max_peers: usize = 0; + let mut best_hash = None; + for (p, hash) in snapshots { + let peers = snapshot_peers.entry(hash).or_insert_with(Vec::new); + peers.push(*p); + if peers.len() > max_peers { + max_peers = peers.len(); + best_hash = Some(hash); + } + } + (best_hash, max_peers, snapshot_peers) + }; + + let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed() > WAIT_PEERS_TIMEOUT); + + if let (Some(hash), Some(peers)) = (best_hash, best_hash.map_or(None, |h| snapshot_peers.get(&h))) { + if max_peers >= SNAPSHOT_MIN_PEERS { + trace!(target: "sync", "Starting confirmed snapshot sync {:?} with {:?}", hash, peers); + self.start_snapshot_sync(io, peers); + } else if timeout { + trace!(target: "sync", "Starting unconfirmed snapshot sync {:?} with {:?}", hash, peers); + self.start_snapshot_sync(io, peers); + } + } else if timeout && !self.warp_sync.is_warp_only() { + trace!(target: "sync", "No snapshots found, starting full sync"); + self.state = SyncState::Idle; + self.continue_sync(io); + } + } + + fn start_snapshot_sync(&mut self, io: &mut SyncIo, peers: &[PeerId]) { + if !self.snapshot.have_manifest() { + for p in peers { + if self.peers.get(p).map_or(false, |p| p.asking == PeerAsking::Nothing) { + SyncRequester::request_snapshot_manifest(self, io, *p); + } + } + self.state = SyncState::SnapshotManifest; + trace!(target: "sync", "New snapshot sync with {:?}", peers); + } else { + self.state = SyncState::SnapshotData; + trace!(target: "sync", "Resumed snapshot sync with {:?}", peers); + } + } + + /// Restart sync disregarding the block queue status. May end up re-downloading up to QUEUE_SIZE blocks + pub fn restart(&mut self, io: &mut SyncIo) { + self.update_targets(io.chain()); + self.reset_and_continue(io); + } + + /// Update sync after the blockchain has been changed externally. + pub fn update_targets(&mut self, chain: &BlockChainClient) { + // Do not assume that the block queue/chain still has our last_imported_block + let chain = chain.chain_info(); + self.new_blocks = BlockDownloader::new(false, &chain.best_block_hash, chain.best_block_number); + self.old_blocks = None; + if self.download_old_blocks { + if let (Some(ancient_block_hash), Some(ancient_block_number)) = (chain.ancient_block_hash, chain.ancient_block_number) { + + trace!(target: "sync", "Downloading old blocks from {:?} (#{}) till {:?} (#{:?})", ancient_block_hash, ancient_block_number, chain.first_block_hash, chain.first_block_number); + let mut downloader = BlockDownloader::with_unlimited_reorg(true, &ancient_block_hash, ancient_block_number); + if let Some(hash) = chain.first_block_hash { + trace!(target: "sync", "Downloader target set to {:?}", hash); + downloader.set_target(&hash); + } + self.old_blocks = Some(downloader); + } + } + } + + /// Resume downloading + fn continue_sync(&mut self, io: &mut SyncIo) { + // Collect active peers that can sync + let confirmed_peers: Vec<(PeerId, u8)> = self.peers.iter().filter_map(|(peer_id, peer)| + if peer.can_sync() { + Some((*peer_id, peer.protocol_version)) + } else { + None + } + ).collect(); + let mut peers: Vec<(PeerId, u8)> = confirmed_peers.iter().filter(|&&(peer_id, _)| + self.active_peers.contains(&peer_id) + ).map(|v| *v).collect(); + + random::new().shuffle(&mut peers); //TODO: sort by rating + // prefer peers with higher protocol version + peers.sort_by(|&(_, ref v1), &(_, ref v2)| v1.cmp(v2)); + trace!( + target: "sync", + "Syncing with peers: {} active, {} confirmed, {} total", + self.active_peers.len(), confirmed_peers.len(), self.peers.len() + ); + for (peer_id, _) in peers { + self.sync_peer(io, peer_id, false); + } + + if + (self.state == SyncState::Blocks || self.state == SyncState::NewBlocks) && + !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.block_set != Some(BlockSet::OldBlocks) && p.can_sync()) + { + self.complete_sync(io); + } + } + + /// Called after all blocks have been downloaded + fn complete_sync(&mut self, io: &mut SyncIo) { + trace!(target: "sync", "Sync complete"); + self.reset(io); + } + + /// Enter waiting state + fn pause_sync(&mut self) { + trace!(target: "sync", "Block queue full, pausing sync"); + self.state = SyncState::Waiting; + } + + /// Find something to do for a peer. Called for a new peer or when a peer is done with its task. + fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) { + if !self.active_peers.contains(&peer_id) { + trace!(target: "sync", "Skipping deactivated peer {}", peer_id); + return; + } + let (peer_latest, peer_difficulty, peer_snapshot_number, peer_snapshot_hash) = { + if let Some(peer) = self.peers.get_mut(&peer_id) { + if peer.asking != PeerAsking::Nothing || !peer.can_sync() { + trace!(target: "sync", "Skipping busy peer {}", peer_id); + return; + } + if self.state == SyncState::Waiting { + trace!(target: "sync", "Waiting for the block queue"); + return; + } + if self.state == SyncState::SnapshotWaiting { + trace!(target: "sync", "Waiting for the snapshot restoration"); + return; + } + (peer.latest_hash.clone(), peer.difficulty.clone(), peer.snapshot_number.as_ref().cloned().unwrap_or(0), peer.snapshot_hash.as_ref().cloned()) + } else { + return; + } + }; + let chain_info = io.chain().chain_info(); + let syncing_difficulty = chain_info.pending_total_difficulty; + let num_active_peers = self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(); + + let higher_difficulty = peer_difficulty.map_or(true, |pd| pd > syncing_difficulty); + if force || higher_difficulty || self.old_blocks.is_some() { + match self.state { + SyncState::WaitingPeers => { + trace!( + target: "sync", + "Checking snapshot sync: {} vs {} (peer: {})", + peer_snapshot_number, + chain_info.best_block_number, + peer_id + ); + self.maybe_start_snapshot_sync(io); + }, + SyncState::Idle | SyncState::Blocks | SyncState::NewBlocks => { + if io.chain().queue_info().is_full() { + self.pause_sync(); + return; + } + + let have_latest = io.chain().block_status(BlockId::Hash(peer_latest)) != BlockStatus::Unknown; + trace!(target: "sync", "Considering peer {}, force={}, td={:?}, our td={}, latest={}, have_latest={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, peer_latest, have_latest, self.state); + if !have_latest && (higher_difficulty || force || self.state == SyncState::NewBlocks) { + // check if got new blocks to download + trace!(target: "sync", "Syncing with peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); + if let Some(request) = self.new_blocks.request_blocks(io, num_active_peers) { + SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::NewBlocks); + if self.state == SyncState::Idle { + self.state = SyncState::Blocks; + } + return; + } + } + + if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { + SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); + return; + } + }, + SyncState::SnapshotData => { + if let RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } = io.snapshot_service().status() { + if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target: "sync", "Snapshot queue full, pausing sync"); + self.state = SyncState::SnapshotWaiting; + return; + } + } + if peer_snapshot_hash.is_some() && peer_snapshot_hash == self.snapshot.snapshot_hash() { + self.clear_peer_download(peer_id); + SyncRequester::request_snapshot_data(self, io, peer_id); + } + }, + SyncState::SnapshotManifest | //already downloading from other peer + SyncState::Waiting | SyncState::SnapshotWaiting => () + } + } else { + trace!(target: "sync", "Skipping peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); + } + } + + /// Clear all blocks/headers marked as being downloaded by a peer. + fn clear_peer_download(&mut self, peer_id: PeerId) { + if let Some(ref peer) = self.peers.get(&peer_id) { + match peer.asking { + PeerAsking::BlockHeaders => { + if let Some(ref hash) = peer.asking_hash { + self.new_blocks.clear_header_download(hash); + if let Some(ref mut old) = self.old_blocks { + old.clear_header_download(hash); + } + } + }, + PeerAsking::BlockBodies => { + self.new_blocks.clear_body_download(&peer.asking_blocks); + if let Some(ref mut old) = self.old_blocks { + old.clear_body_download(&peer.asking_blocks); + } + }, + PeerAsking::BlockReceipts => { + self.new_blocks.clear_receipt_download(&peer.asking_blocks); + if let Some(ref mut old) = self.old_blocks { + old.clear_receipt_download(&peer.asking_blocks); + } + }, + PeerAsking::SnapshotData => { + if let Some(hash) = peer.asking_snapshot_data { + self.snapshot.clear_chunk_download(&hash); + } + }, + _ => (), + } + } + } + + /// Checks if there are blocks fully downloaded that can be imported into the blockchain and does the import. + fn collect_blocks(&mut self, io: &mut SyncIo, block_set: BlockSet) { + match block_set { + BlockSet::NewBlocks => { + if self.new_blocks.collect_blocks(io, self.state == SyncState::NewBlocks) == Err(DownloaderImportError::Invalid) { + self.restart(io); + } + }, + BlockSet::OldBlocks => { + if self.old_blocks.as_mut().map_or(false, |downloader| { downloader.collect_blocks(io, false) == Err(DownloaderImportError::Invalid) }) { + self.restart(io); + } else if self.old_blocks.as_ref().map_or(false, |downloader| { downloader.is_complete() }) { + trace!(target: "sync", "Background block download is complete"); + self.old_blocks = None; + } + } + } + } + + /// Reset peer status after request is complete. + fn reset_peer_asking(&mut self, peer_id: PeerId, asking: PeerAsking) -> bool { + if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { + peer.expired = false; + peer.block_set = None; + if peer.asking != asking { + trace!(target:"sync", "Asking {:?} while expected {:?}", peer.asking, asking); + peer.asking = PeerAsking::Nothing; + return false; + } else { + peer.asking = PeerAsking::Nothing; + return true; + } + } + false + } + + /// Send Status message + fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), network::Error> { + let warp_protocol_version = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer); + let warp_protocol = warp_protocol_version != 0; + let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63 }; + trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol); + let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 }); + let chain = io.chain().chain_info(); + packet.append(&(protocol as u32)); + packet.append(&self.network_id); + packet.append(&chain.total_difficulty); + packet.append(&chain.best_block_hash); + packet.append(&chain.genesis_hash); + if warp_protocol { + let manifest = match self.old_blocks.is_some() { + true => None, + false => io.snapshot_service().manifest(), + }; + let block_number = manifest.as_ref().map_or(0, |m| m.block_number); + let manifest_hash = manifest.map_or(H256::new(), |m| keccak(m.into_rlp())); + packet.append(&manifest_hash); + packet.append(&block_number); + } + io.respond(STATUS_PACKET, packet.out()) + } + + pub fn maintain_peers(&mut self, io: &mut SyncIo) { + let tick = Instant::now(); + let mut aborting = Vec::new(); + for (peer_id, peer) in &self.peers { + let elapsed = tick - peer.ask_time; + let timeout = match peer.asking { + PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT, + PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT, + PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT, + PeerAsking::Nothing => false, + PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT, + PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT, + PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, + }; + if timeout { + debug!(target:"sync", "Timeout {}", peer_id); + io.disconnect_peer(*peer_id); + aborting.push(*peer_id); + } + } + for p in aborting { + SyncHandler::on_peer_aborting(self, io, p); + } + + // Check for handshake timeouts + for (peer, &ask_time) in &self.handshaking_peers { + let elapsed = (tick - ask_time) / 1_000_000_000; + if elapsed > STATUS_TIMEOUT { + trace!(target:"sync", "Status timeout {}", peer); + io.disconnect_peer(*peer); + } + } + } + + fn check_resume(&mut self, io: &mut SyncIo) { + if self.state == SyncState::Waiting && !io.chain().queue_info().is_full() { + self.state = SyncState::Blocks; + self.continue_sync(io); + } else if self.state == SyncState::SnapshotWaiting { + match io.snapshot_service().status() { + RestorationStatus::Inactive => { + trace!(target:"sync", "Snapshot restoration is complete"); + self.restart(io); + }, + RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { + if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target:"sync", "Resuming snapshot sync"); + self.state = SyncState::SnapshotData; + self.continue_sync(io); + } + }, + RestorationStatus::Failed => { + trace!(target: "sync", "Snapshot restoration aborted"); + self.state = SyncState::WaitingPeers; + self.snapshot.clear(); + self.continue_sync(io); + }, + } + } + } + + /// creates rlp to send for the tree defined by 'from' and 'to' hashes + fn create_new_hashes_rlp(chain: &BlockChainClient, from: &H256, to: &H256) -> Option { + match chain.tree_route(from, to) { + Some(route) => { + let uncles = chain.find_uncles(from).unwrap_or_else(Vec::new); + match route.blocks.len() { + 0 => None, + _ => { + let mut blocks = route.blocks; + blocks.extend(uncles); + let mut rlp_stream = RlpStream::new_list(blocks.len()); + for block_hash in blocks { + let mut hash_rlp = RlpStream::new_list(2); + let number = chain.block_header(BlockId::Hash(block_hash.clone())) + .expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.").number(); + hash_rlp.append(&block_hash); + hash_rlp.append(&number); + rlp_stream.append_raw(hash_rlp.as_raw(), 1); + } + Some(rlp_stream.out()) + } + } + }, + None => None + } + } + + /// creates rlp from block bytes and total difficulty + fn create_block_rlp(bytes: &Bytes, total_difficulty: U256) -> Bytes { + let mut rlp_stream = RlpStream::new_list(2); + rlp_stream.append_raw(bytes, 1); + rlp_stream.append(&total_difficulty); + rlp_stream.out() + } + + /// creates latest block rlp for the given client + fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes { + ChainSync::create_block_rlp( + &chain.block(BlockId::Hash(chain.chain_info().best_block_hash)) + .expect("Best block always exists").into_inner(), + chain.chain_info().total_difficulty + ) + } + + /// creates given hash block rlp for the given client + fn create_new_block_rlp(chain: &BlockChainClient, hash: &H256) -> Bytes { + ChainSync::create_block_rlp( + &chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed").into_inner(), + chain.block_total_difficulty(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed.") + ) + } + + /// returns peer ids that have different blocks than our chain + fn get_lagging_peers(&mut self, chain_info: &BlockChainInfo) -> Vec { + let latest_hash = chain_info.best_block_hash; + self + .peers + .iter_mut() + .filter_map(|(&id, ref mut peer_info)| { + trace!(target: "sync", "Checking peer our best {} their best {}", latest_hash, peer_info.latest_hash); + if peer_info.latest_hash != latest_hash { + Some(id) + } else { + None + } + }) + .collect::>() + } + + fn select_random_peers(peers: &[PeerId]) -> Vec { + // take sqrt(x) peers + let mut peers = peers.to_vec(); + let mut count = (peers.len() as f64).powf(0.5).round() as usize; + count = cmp::min(count, MAX_PEERS_PROPAGATION); + count = cmp::max(count, MIN_PEERS_PROPAGATION); + random::new().shuffle(&mut peers); + peers.truncate(count); + peers + } + + fn get_consensus_peers(&self) -> Vec { + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() + } + + fn get_private_transaction_peers(&self) -> Vec { + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3 { Some(*id) } else { None }).collect() + } + + /// Maintain other peers. Send out any new blocks and transactions + pub fn maintain_sync(&mut self, io: &mut SyncIo) { + self.maybe_start_snapshot_sync(io); + self.check_resume(io); + } + + /// called when block is imported to chain - propagates the blocks and updates transactions sent to peers + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, _imported: &[H256], invalid: &[H256], enacted: &[H256], _retracted: &[H256], sealed: &[H256], proposed: &[Bytes]) { + let queue_info = io.chain().queue_info(); + let is_syncing = self.status().is_syncing(queue_info); + + if !is_syncing || !sealed.is_empty() || !proposed.is_empty() { + trace!(target: "sync", "Propagating blocks, state={:?}", self.state); + SyncPropagator::propagate_latest_blocks(self, io, sealed); + SyncPropagator::propagate_proposed_blocks(self, io, proposed); + } + if !invalid.is_empty() { + trace!(target: "sync", "Bad blocks in the queue, restarting"); + self.restart(io); + } + + if !is_syncing && !enacted.is_empty() && !self.peers.is_empty() { + // Select random peer to re-broadcast transactions to. + let peer = random::new().gen_range(0, self.peers.len()); + trace!(target: "sync", "Re-broadcasting transactions to a random peer."); + self.peers.values_mut().nth(peer).map(|peer_info| + peer_info.last_sent_transactions.clear() + ); + } + } + + /// Dispatch incoming requests and responses + pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + SyncSupplier::dispatch_packet(sync, io, peer, packet_id, data) + } + + pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + debug!(target: "sync", "{} -> Dispatching packet: {}", peer, packet_id); + SyncHandler::on_packet(self, io, peer, packet_id, data); + } + + /// Called when peer sends us new consensus packet + pub fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + SyncHandler::on_consensus_packet(io, peer_id, r) + } + + /// Called by peer when it is disconnecting + pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) { + SyncHandler::on_peer_aborting(self, io, peer); + } + + /// Called when a new peer is connected + pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { + SyncHandler::on_peer_connected(self, io, peer); + } + + /// propagates new transactions to all peers + pub fn propagate_new_transactions(&mut self, io: &mut SyncIo) -> usize { + SyncPropagator::propagate_new_transactions(self, io) + } + + /// Broadcast consensus message to peers. + pub fn propagate_consensus_packet(&mut self, io: &mut SyncIo, packet: Bytes) { + SyncPropagator::propagate_consensus_packet(self, io, packet); + } + + /// Broadcast private transaction message to peers. + pub fn propagate_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { + SyncPropagator::propagate_private_transaction(self, io, packet); + } + + /// Broadcast signed private transaction message to peers. + pub fn propagate_signed_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { + SyncPropagator::propagate_signed_private_transaction(self, io, packet); + } +} + +#[cfg(test)] +pub mod tests { + use std::collections::{HashSet, VecDeque}; + use ethkey; + use network::PeerId; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + use ethereum_types::{H256, U256, Address}; + use parking_lot::RwLock; + use bytes::Bytes; + use rlp::{Rlp, RlpStream}; + use super::*; + use ::SyncConfig; + use super::{PeerInfo, PeerAsking}; + use ethcore::header::*; + use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; + use ethcore::miner::MinerService; + use private_tx::NoopPrivateTxHandler; + + pub fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { + let mut header = Header::new(); + header.set_gas_limit(0.into()); + header.set_difficulty((order * 100).into()); + header.set_timestamp((order * 10) as u64); + header.set_number(order as u64); + header.set_parent_hash(parent_hash); + header.set_state_root(H256::zero()); + + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); + rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); + rlp.out() + } + + pub fn get_dummy_blocks(order: u32, parent_hash: H256) -> Bytes { + let mut rlp = RlpStream::new_list(1); + rlp.append_raw(&get_dummy_block(order, parent_hash), 1); + let difficulty: U256 = (100 * order).into(); + rlp.append(&difficulty); + rlp.out() + } + + pub fn get_dummy_hashes() -> Bytes { + let mut rlp = RlpStream::new_list(5); + for _ in 0..5 { + let mut hash_d_rlp = RlpStream::new_list(2); + let hash: H256 = H256::from(0u64); + let diff: U256 = U256::from(1u64); + hash_d_rlp.append(&hash); + hash_d_rlp.append(&diff); + + rlp.append_raw(&hash_d_rlp.out(), 1); + } + + rlp.out() + } + + fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo { + BlockQueueInfo { + unverified_queue_size: unverified, + verified_queue_size: verified, + verifying_queue_size: 0, + max_queue_size: 1000, + max_mem_use: 1000, + mem_used: 500 + } + } + + fn sync_status(state: SyncState) -> SyncStatus { + SyncStatus { + state: state, + protocol_version: 0, + network_id: 0, + start_block_number: 0, + last_imported_block_number: None, + highest_block_number: None, + blocks_total: 0, + blocks_received: 0, + num_peers: 0, + num_active_peers: 0, + mem_used: 0, + num_snapshot_chunks: 0, + snapshot_chunks_done: 0, + last_imported_old_block_number: None, + } + } + + #[test] + fn is_still_verifying() { + assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(2, 1))); + assert!(sync_status(SyncState::Idle).is_syncing(queue_info(2, 2))); + } + + #[test] + fn is_synced_state() { + assert!(sync_status(SyncState::Blocks).is_syncing(queue_info(0, 0))); + assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(0, 0))); + } + + pub fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync { + let mut sync = ChainSync::new(SyncConfig::default(), client, Arc::new(NoopPrivateTxHandler)); + insert_dummy_peer(&mut sync, 0, peer_latest_hash); + sync + } + + pub fn insert_dummy_peer(sync: &mut ChainSync, peer_id: PeerId, peer_latest_hash: H256) { + sync.peers.insert(peer_id, + PeerInfo { + protocol_version: 0, + genesis: H256::zero(), + network_id: 0, + latest_hash: peer_latest_hash, + difficulty: None, + asking: PeerAsking::Nothing, + asking_blocks: Vec::new(), + asking_hash: None, + ask_time: Instant::now(), + last_sent_transactions: HashSet::new(), + expired: false, + confirmation: super::ForkConfirmation::Confirmed, + snapshot_number: None, + snapshot_hash: None, + asking_snapshot_data: None, + block_set: None, + }); + + } + + #[test] + fn finds_lagging_peers() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10), &client); + let chain_info = client.chain_info(); + + let lagging_peers = sync.get_lagging_peers(&chain_info); + + assert_eq!(1, lagging_peers.len()); + } + + #[test] + fn calculates_tree_for_lagging_peer() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(15, EachBlockWith::Uncle); + + let start = client.block_hash_delta_minus(4); + let end = client.block_hash_delta_minus(2); + + // wrong way end -> start, should be None + let rlp = ChainSync::create_new_hashes_rlp(&client, &end, &start); + assert!(rlp.is_none()); + + let rlp = ChainSync::create_new_hashes_rlp(&client, &start, &end).unwrap(); + // size of three rlp encoded hash-difficulty + assert_eq!(107, rlp.len()); + } + // idea is that what we produce when propagading latest hashes should be accepted in + // on_peer_new_hashes in our code as well + #[test] + fn hashes_rlp_mutually_acceptable() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let peers = sync.get_lagging_peers(&chain_info); + SyncPropagator::propagate_new_hashes(&mut sync, &chain_info, &mut io, &peers); + + let data = &io.packets[0].data.clone(); + let result = SyncHandler::on_peer_new_hashes(&mut sync, &mut io, 0, &Rlp::new(data)); + assert!(result.is_ok()); + } + + // idea is that what we produce when propagading latest block should be accepted in + // on_peer_new_block in our code as well + #[test] + fn block_rlp_mutually_acceptable() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let peers = sync.get_lagging_peers(&chain_info); + SyncPropagator::propagate_blocks(&mut sync, &chain_info, &mut io, &[], &peers); + + let data = &io.packets[0].data.clone(); + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &Rlp::new(data)); + assert!(result.is_ok()); + } + + #[test] + fn should_add_transactions_to_queue() { + fn sender(tx: &UnverifiedTransaction) -> Address { + ethkey::public_to_address(&tx.recover_public().unwrap()) + } + + // given + let mut client = TestBlockChainClient::new(); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + + // Add some balance to clients and reset nonces + for h in &[good_blocks[0], retracted_blocks[0]] { + let block = client.block(BlockId::Hash(*h)).unwrap(); + let sender = sender(&block.transactions()[0]);; + client.set_balance(sender, U256::from(10_000_000_000_000_000_000u64)); + client.set_nonce(sender, U256::from(0)); + } + + + // when + { + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); + assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); + } + // We need to update nonce status (because we say that the block has been imported) + for h in &[good_blocks[0]] { + let block = client.block(BlockId::Hash(*h)).unwrap(); + client.set_nonce(sender(&block.transactions()[0]), U256::from(1)); + } + { + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&client, &ss, &queue, None); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks, false); + sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); + } + + // then + assert_eq!(client.miner.ready_transactions(&client).len(), 1); + } + + #[test] + fn should_not_add_transactions_to_queue_if_not_synced() { + // given + let mut client = TestBlockChainClient::new(); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + // when + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); + assert_eq!(io.chain.miner.queue_status().status.transaction_count, 0); + sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); + + // then + let status = io.chain.miner.queue_status(); + assert_eq!(status.status.transaction_count, 0); + } +} diff --git a/ethcore/sync/src/chain/propagator.rs b/ethcore/sync/src/chain/propagator.rs new file mode 100644 index 00000000000..4ae0518a537 --- /dev/null +++ b/ethcore/sync/src/chain/propagator.rs @@ -0,0 +1,636 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use bytes::Bytes; +use ethereum_types::H256; +use ethcore::client::BlockChainInfo; +use ethcore::header::BlockNumber; +use network::{PeerId, PacketId}; +use rand::Rng; +use rlp::{Encodable, RlpStream}; +use sync_io::SyncIo; +use std::cmp; +use std::collections::HashSet; +use transaction::SignedTransaction; + +use super::{ + random, + ChainSync, + MAX_PEER_LAG_PROPAGATION, + MAX_PEERS_PROPAGATION, + MAX_TRANSACTION_PACKET_SIZE, + MAX_TRANSACTIONS_TO_PROPAGATE, + MIN_PEERS_PROPAGATION, + CONSENSUS_DATA_PACKET, + NEW_BLOCK_HASHES_PACKET, + NEW_BLOCK_PACKET, + PRIVATE_TRANSACTION_PACKET, + SIGNED_PRIVATE_TRANSACTION_PACKET, + TRANSACTIONS_PACKET, +}; + +/// Checks if peer is able to process service transactions +fn accepts_service_transaction(client_id: &str) -> bool { + // Parity versions starting from this will accept service-transactions + const SERVICE_TRANSACTIONS_VERSION: (u32, u32) = (1u32, 6u32); + // Parity client string prefix + const PARITY_CLIENT_ID_PREFIX: &'static str = "Parity/v"; + + if !client_id.starts_with(PARITY_CLIENT_ID_PREFIX) { + return false; + } + let ver: Vec = client_id[PARITY_CLIENT_ID_PREFIX.len()..].split('.') + .take(2) + .filter_map(|s| s.parse().ok()) + .collect(); + ver.len() == 2 && (ver[0] > SERVICE_TRANSACTIONS_VERSION.0 || (ver[0] == SERVICE_TRANSACTIONS_VERSION.0 && ver[1] >= SERVICE_TRANSACTIONS_VERSION.1)) +} + +/// The Chain Sync Propagator: propagates data to peers +pub struct SyncPropagator; + +impl SyncPropagator { + /// propagates latest block to a set of peers + pub fn propagate_blocks(sync: &mut ChainSync, chain_info: &BlockChainInfo, io: &mut SyncIo, blocks: &[H256], peers: &[PeerId]) -> usize { + trace!(target: "sync", "Sending NewBlocks to {:?}", peers); + let mut sent = 0; + for peer_id in peers { + if blocks.is_empty() { + let rlp = ChainSync::create_latest_block_rlp(io.chain()); + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); + } else { + for h in blocks { + let rlp = ChainSync::create_new_block_rlp(io.chain(), h); + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); + } + } + if let Some(ref mut peer) = sync.peers.get_mut(peer_id) { + peer.latest_hash = chain_info.best_block_hash.clone(); + } + sent += 1; + } + sent + } + + /// propagates new known hashes to all peers + pub fn propagate_new_hashes(sync: &mut ChainSync, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize { + trace!(target: "sync", "Sending NewHashes to {:?}", peers); + let mut sent = 0; + let last_parent = *io.chain().best_block_header().parent_hash(); + for peer_id in peers { + sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) { + Some(rlp) => { + { + if let Some(ref mut peer) = sync.peers.get_mut(peer_id) { + peer.latest_hash = chain_info.best_block_hash.clone(); + } + } + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_HASHES_PACKET, rlp); + 1 + }, + None => 0 + } + } + sent + } + + /// propagates new transactions to all peers + pub fn propagate_new_transactions(sync: &mut ChainSync, io: &mut SyncIo) -> usize { + // Early out if nobody to send to. + if sync.peers.is_empty() { + return 0; + } + + let transactions = io.chain().ready_transactions(); + if transactions.is_empty() { + return 0; + } + + let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.iter() + .map(|tx| tx.signed()) + .partition(|tx| !tx.gas_price.is_zero()); + + // usual transactions could be propagated to all peers + let mut affected_peers = HashSet::new(); + if !transactions.is_empty() { + let peers = SyncPropagator::select_peers_for_transactions(sync, |_| true); + affected_peers = SyncPropagator::propagate_transactions_to_peers(sync, io, peers, transactions); + } + + // most of times service_transactions will be empty + // => there's no need to merge packets + if !service_transactions.is_empty() { + let service_transactions_peers = SyncPropagator::select_peers_for_transactions(sync, |peer_id| accepts_service_transaction(&io.peer_info(*peer_id))); + let service_transactions_affected_peers = SyncPropagator::propagate_transactions_to_peers(sync, io, service_transactions_peers, service_transactions); + affected_peers.extend(&service_transactions_affected_peers); + } + + affected_peers.len() + } + + fn propagate_transactions_to_peers(sync: &mut ChainSync, io: &mut SyncIo, peers: Vec, transactions: Vec<&SignedTransaction>) -> HashSet { + let all_transactions_hashes = transactions.iter() + .map(|tx| tx.hash()) + .collect::>(); + let all_transactions_rlp = { + let mut packet = RlpStream::new_list(transactions.len()); + for tx in &transactions { packet.append(&**tx); } + packet.out() + }; + + // Clear old transactions from stats + sync.transactions_stats.retain(&all_transactions_hashes); + + // sqrt(x)/x scaled to max u32 + let block_number = io.chain().chain_info().best_block_number; + + let lucky_peers = { + peers.into_iter() + .filter_map(|peer_id| { + let stats = &mut sync.transactions_stats; + let peer_info = sync.peers.get_mut(&peer_id) + .expect("peer_id is form peers; peers is result of select_peers_for_transactions; select_peers_for_transactions selects peers from self.peers; qed"); + + // Send all transactions + if peer_info.last_sent_transactions.is_empty() { + // update stats + for hash in &all_transactions_hashes { + let id = io.peer_session_info(peer_id).and_then(|info| info.id); + stats.propagated(hash, id, block_number); + } + peer_info.last_sent_transactions = all_transactions_hashes.clone(); + return Some((peer_id, all_transactions_hashes.len(), all_transactions_rlp.clone())); + } + + // Get hashes of all transactions to send to this peer + let to_send = all_transactions_hashes.difference(&peer_info.last_sent_transactions) + .take(MAX_TRANSACTIONS_TO_PROPAGATE) + .cloned() + .collect::>(); + if to_send.is_empty() { + return None; + } + + // Construct RLP + let (packet, to_send) = { + let mut to_send = to_send; + let mut packet = RlpStream::new(); + packet.begin_unbounded_list(); + let mut pushed = 0; + for tx in &transactions { + let hash = tx.hash(); + if to_send.contains(&hash) { + let mut transaction = RlpStream::new(); + tx.rlp_append(&mut transaction); + let appended = packet.append_raw_checked(&transaction.drain(), 1, MAX_TRANSACTION_PACKET_SIZE); + if !appended { + // Maximal packet size reached just proceed with sending + debug!("Transaction packet size limit reached. Sending incomplete set of {}/{} transactions.", pushed, to_send.len()); + to_send = to_send.into_iter().take(pushed).collect(); + break; + } + pushed += 1; + } + } + packet.complete_unbounded_list(); + (packet, to_send) + }; + + // Update stats + let id = io.peer_session_info(peer_id).and_then(|info| info.id); + for hash in &to_send { + // update stats + stats.propagated(hash, id, block_number); + } + + peer_info.last_sent_transactions = all_transactions_hashes + .intersection(&peer_info.last_sent_transactions) + .chain(&to_send) + .cloned() + .collect(); + Some((peer_id, to_send.len(), packet.out())) + }) + .collect::>() + }; + + // Send RLPs + let mut peers = HashSet::new(); + if lucky_peers.len() > 0 { + let mut max_sent = 0; + let lucky_peers_len = lucky_peers.len(); + for (peer_id, sent, rlp) in lucky_peers { + peers.insert(peer_id); + SyncPropagator::send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp); + trace!(target: "sync", "{:02} <- Transactions ({} entries)", peer_id, sent); + max_sent = cmp::max(max_sent, sent); + } + debug!(target: "sync", "Sent up to {} transactions to {} peers.", max_sent, lucky_peers_len); + } + + peers + } + + pub fn propagate_latest_blocks(sync: &mut ChainSync, io: &mut SyncIo, sealed: &[H256]) { + let chain_info = io.chain().chain_info(); + if (((chain_info.best_block_number as i64) - (sync.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { + let mut peers = sync.get_lagging_peers(&chain_info); + if sealed.is_empty() { + let hashes = SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers); + peers = ChainSync::select_random_peers(&peers); + let blocks = SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers); + if blocks != 0 || hashes != 0 { + trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); + } + } else { + SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers); + SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers); + trace!(target: "sync", "Sent sealed block to all peers"); + }; + } + sync.last_sent_block_number = chain_info.best_block_number; + } + + /// Distribute valid proposed blocks to subset of current peers. + pub fn propagate_proposed_blocks(sync: &mut ChainSync, io: &mut SyncIo, proposed: &[Bytes]) { + let peers = sync.get_consensus_peers(); + trace!(target: "sync", "Sending proposed blocks to {:?}", peers); + for block in proposed { + let rlp = ChainSync::create_block_rlp( + block, + io.chain().chain_info().total_difficulty + ); + for peer_id in &peers { + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp.clone()); + } + } + } + + /// Broadcast consensus message to peers. + pub fn propagate_consensus_packet(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&sync.get_consensus_peers()); + trace!(target: "sync", "Sending consensus packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + SyncPropagator::send_packet(io, peer_id, CONSENSUS_DATA_PACKET, packet.clone()); + } + } + + /// Broadcast private transaction message to peers. + pub fn propagate_private_transaction(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&sync.get_private_transaction_peers()); + trace!(target: "sync", "Sending private transaction packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + SyncPropagator::send_packet(io, peer_id, PRIVATE_TRANSACTION_PACKET, packet.clone()); + } + } + + /// Broadcast signed private transaction message to peers. + pub fn propagate_signed_private_transaction(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&sync.get_private_transaction_peers()); + trace!(target: "sync", "Sending signed private transaction packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + SyncPropagator::send_packet(io, peer_id, SIGNED_PRIVATE_TRANSACTION_PACKET, packet.clone()); + } + } + + fn select_peers_for_transactions(sync: &ChainSync, filter: F) -> Vec + where F: Fn(&PeerId) -> bool { + // sqrt(x)/x scaled to max u32 + let fraction = ((sync.peers.len() as f64).powf(-0.5) * (u32::max_value() as f64).round()) as u32; + let small = sync.peers.len() < MIN_PEERS_PROPAGATION; + + let mut random = random::new(); + sync.peers.keys() + .cloned() + .filter(filter) + .filter(|_| small || random.next_u32() < fraction) + .take(MAX_PEERS_PROPAGATION) + .collect() + } + + /// Generic packet sender + fn send_packet(sync: &mut SyncIo, peer_id: PeerId, packet_id: PacketId, packet: Bytes) { + if let Err(e) = sync.send(peer_id, packet_id, packet) { + debug!(target:"sync", "Error sending packet: {:?}", e); + sync.disconnect_peer(peer_id); + } + } +} + +#[cfg(test)] +mod tests { + use ethcore::client::{BlockInfo, ChainInfo, EachBlockWith, TestBlockChainClient}; + use parking_lot::RwLock; + use private_tx::NoopPrivateTxHandler; + use rlp::{Rlp}; + use std::collections::{VecDeque}; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + + use super::{*, super::{*, tests::*}}; + + #[test] + fn sends_new_hashes_to_lagging_peer() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let peers = sync.get_lagging_peers(&chain_info); + let peer_count = SyncPropagator::propagate_new_hashes(&mut sync, &chain_info, &mut io, &peers); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated + assert_eq!(1, peer_count); + // NEW_BLOCK_HASHES_PACKET + assert_eq!(0x01, io.packets[0].packet_id); + } + + #[test] + fn sends_latest_block_to_lagging_peer() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peers = sync.get_lagging_peers(&chain_info); + let peer_count = SyncPropagator::propagate_blocks(&mut sync, &chain_info, &mut io, &[], &peers); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated + assert_eq!(1, peer_count); + // NEW_BLOCK_PACKET + assert_eq!(0x07, io.packets[0].packet_id); + } + + #[test] + fn sends_sealed_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let hash = client.block_hash(BlockId::Number(99)).unwrap(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peers = sync.get_lagging_peers(&chain_info); + let peer_count = SyncPropagator::propagate_blocks(&mut sync ,&chain_info, &mut io, &[hash.clone()], &peers); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated + assert_eq!(1, peer_count); + // NEW_BLOCK_PACKET + assert_eq!(0x07, io.packets[0].packet_id); + } + + #[test] + fn sends_proposed_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(2, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let block = client.block(BlockId::Latest).unwrap().into_inner(); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + sync.peers.insert(0, + PeerInfo { + // Messaging protocol + protocol_version: 2, + genesis: H256::zero(), + network_id: 0, + latest_hash: client.block_hash_delta_minus(1), + difficulty: None, + asking: PeerAsking::Nothing, + asking_blocks: Vec::new(), + asking_hash: None, + ask_time: Instant::now(), + last_sent_transactions: HashSet::new(), + expired: false, + confirmation: ForkConfirmation::Confirmed, + snapshot_number: None, + snapshot_hash: None, + asking_snapshot_data: None, + block_set: None, + }); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + SyncPropagator::propagate_proposed_blocks(&mut sync, &mut io, &[block]); + + // 1 message should be sent + assert_eq!(1, io.packets.len()); + // NEW_BLOCK_PACKET + assert_eq!(0x07, io.packets[0].packet_id); + } + + #[test] + fn propagates_transactions() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + // Try to propagate same transactions for the second time + let peer_count2 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + // Even after new block transactions should not be propagated twice + sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); + // Try to propagate same transactions for the third time + let peer_count3 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated but only once + assert_eq!(1, peer_count); + assert_eq!(0, peer_count2); + assert_eq!(0, peer_count3); + // TRANSACTIONS_PACKET + assert_eq!(0x02, io.packets[0].packet_id); + } + + #[test] + fn does_not_propagate_new_transactions_after_new_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + io.chain.insert_transaction_to_queue(); + // New block import should not trigger propagation. + // (we only propagate on timeout) + sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); + + // 2 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should receive the message + assert_eq!(1, peer_count); + // TRANSACTIONS_PACKET + assert_eq!(0x02, io.packets[0].packet_id); + } + + #[test] + fn does_not_fail_for_no_peers() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + // Sync with no peers + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); + // Try to propagate same transactions for the second time + let peer_count2 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + assert_eq!(0, io.packets.len()); + assert_eq!(0, peer_count); + assert_eq!(0, peer_count2); + } + + #[test] + fn propagates_transactions_without_alternating() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + // should sent some + { + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + assert_eq!(1, io.packets.len()); + assert_eq!(1, peer_count); + } + // Insert some more + client.insert_transaction_to_queue(); + let (peer_count2, peer_count3) = { + let mut io = TestIo::new(&mut client, &ss, &queue, None); + // Propagate new transactions + let peer_count2 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + // And now the peer should have all transactions + let peer_count3 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + (peer_count2, peer_count3) + }; + + // 2 message should be send (in total) + assert_eq!(2, queue.read().len()); + // 1 peer should be updated but only once after inserting new transaction + assert_eq!(1, peer_count2); + assert_eq!(0, peer_count3); + // TRANSACTIONS_PACKET + assert_eq!(0x02, queue.read()[0].packet_id); + assert_eq!(0x02, queue.read()[1].packet_id); + } + + #[test] + fn should_maintain_transations_propagation_stats() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + let stats = sync.transactions_stats(); + assert_eq!(stats.len(), 1, "Should maintain stats for single transaction.") + } + + #[test] + fn should_propagate_service_transaction_to_selected_peers_only() { + let mut client = TestBlockChainClient::new(); + client.insert_transaction_with_gas_price_to_queue(U256::zero()); + let block_hash = client.block_hash_delta_minus(1); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + // when peer#1 is Geth + insert_dummy_peer(&mut sync, 1, block_hash); + io.peers_info.insert(1, "Geth".to_owned()); + // and peer#2 is Parity, accepting service transactions + insert_dummy_peer(&mut sync, 2, block_hash); + io.peers_info.insert(2, "Parity/v1.6".to_owned()); + // and peer#3 is Parity, discarding service transactions + insert_dummy_peer(&mut sync, 3, block_hash); + io.peers_info.insert(3, "Parity/v1.5".to_owned()); + // and peer#4 is Parity, accepting service transactions + insert_dummy_peer(&mut sync, 4, block_hash); + io.peers_info.insert(4, "Parity/v1.7.3-ABCDEFGH".to_owned()); + + // and new service transaction is propagated to peers + SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + // peer#2 && peer#4 are receiving service transaction + assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 2)); // TRANSACTIONS_PACKET + assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 4)); // TRANSACTIONS_PACKET + assert_eq!(io.packets.len(), 2); + } + + #[test] + fn should_propagate_service_transaction_is_sent_as_separate_message() { + let mut client = TestBlockChainClient::new(); + let tx1_hash = client.insert_transaction_to_queue(); + let tx2_hash = client.insert_transaction_with_gas_price_to_queue(U256::zero()); + let block_hash = client.block_hash_delta_minus(1); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + // when peer#1 is Parity, accepting service transactions + insert_dummy_peer(&mut sync, 1, block_hash); + io.peers_info.insert(1, "Parity/v1.6".to_owned()); + + // and service + non-service transactions are propagated to peers + SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + // two separate packets for peer are queued: + // 1) with non-service-transaction + // 2) with service transaction + let sent_transactions: Vec = io.packets.iter() + .filter_map(|p| { + if p.packet_id != 0x02 || p.recipient != 1 { // TRANSACTIONS_PACKET + return None; + } + + let rlp = Rlp::new(&*p.data); + let item_count = rlp.item_count().unwrap_or(0); + if item_count != 1 { + return None; + } + + rlp.at(0).ok().and_then(|r| r.as_val().ok()) + }) + .collect(); + assert_eq!(sent_transactions.len(), 2); + assert!(sent_transactions.iter().any(|tx| tx.hash() == tx1_hash)); + assert!(sent_transactions.iter().any(|tx| tx.hash() == tx2_hash)); + } +} diff --git a/ethcore/sync/src/chain/requester.rs b/ethcore/sync/src/chain/requester.rs new file mode 100644 index 00000000000..e6acf6bc53a --- /dev/null +++ b/ethcore/sync/src/chain/requester.rs @@ -0,0 +1,154 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use api::WARP_SYNC_PROTOCOL_ID; +use block_sync::BlockRequest; +use bytes::Bytes; +use ethcore::header::BlockNumber; +use ethereum_types::H256; +use network::{PeerId, PacketId}; +use rlp::RlpStream; +use std::time::Instant; +use sync_io::SyncIo; + +use super::{ + BlockSet, + ChainSync, + PeerAsking, + ETH_PACKET_COUNT, + GET_BLOCK_BODIES_PACKET, + GET_BLOCK_HEADERS_PACKET, + GET_RECEIPTS_PACKET, + GET_SNAPSHOT_DATA_PACKET, + GET_SNAPSHOT_MANIFEST_PACKET, +}; + +/// The Chain Sync Requester: requesting data to other peers +pub struct SyncRequester; + +impl SyncRequester { + /// Perform block download request` + pub fn request_blocks(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, request: BlockRequest, block_set: BlockSet) { + match request { + BlockRequest::Headers { start, count, skip } => { + SyncRequester::request_headers_by_hash(sync, io, peer_id, &start, count, skip, false, block_set); + }, + BlockRequest::Bodies { hashes } => { + SyncRequester::request_bodies(sync, io, peer_id, hashes, block_set); + }, + BlockRequest::Receipts { hashes } => { + SyncRequester::request_receipts(sync, io, peer_id, hashes, block_set); + }, + } + } + + /// Request block bodies from a peer + fn request_bodies(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { + let mut rlp = RlpStream::new_list(hashes.len()); + trace!(target: "sync", "{} <- GetBlockBodies: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); + for h in &hashes { + rlp.append(&h.clone()); + } + SyncRequester::send_request(sync, io, peer_id, PeerAsking::BlockBodies, GET_BLOCK_BODIES_PACKET, rlp.out()); + let peer = sync.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); + peer.asking_blocks = hashes; + peer.block_set = Some(set); + } + + /// Request headers from a peer by block number + pub fn request_fork_header(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, n: BlockNumber) { + trace!(target: "sync", "{} <- GetForkHeader: at {}", peer_id, n); + let mut rlp = RlpStream::new_list(4); + rlp.append(&n); + rlp.append(&1u32); + rlp.append(&0u32); + rlp.append(&0u32); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::ForkHeader, GET_BLOCK_HEADERS_PACKET, rlp.out()); + } + + /// Find some headers or blocks to download for a peer. + pub fn request_snapshot_data(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + // find chunk data to download + if let Some(hash) = sync.snapshot.needed_chunk() { + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + peer.asking_snapshot_data = Some(hash.clone()); + } + SyncRequester::request_snapshot_chunk(sync, io, peer_id, &hash); + } + } + + /// Request snapshot manifest from a peer. + pub fn request_snapshot_manifest(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + trace!(target: "sync", "{} <- GetSnapshotManifest", peer_id); + let rlp = RlpStream::new_list(0); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::SnapshotManifest, GET_SNAPSHOT_MANIFEST_PACKET, rlp.out()); + } + + /// Request headers from a peer by block hash + fn request_headers_by_hash(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, h: &H256, count: u64, skip: u64, reverse: bool, set: BlockSet) { + trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}, set = {:?}", peer_id, count, h, set); + let mut rlp = RlpStream::new_list(4); + rlp.append(h); + rlp.append(&count); + rlp.append(&skip); + rlp.append(&if reverse {1u32} else {0u32}); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out()); + let peer = sync.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); + peer.asking_hash = Some(h.clone()); + peer.block_set = Some(set); + } + + /// Request block receipts from a peer + fn request_receipts(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { + let mut rlp = RlpStream::new_list(hashes.len()); + trace!(target: "sync", "{} <- GetBlockReceipts: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); + for h in &hashes { + rlp.append(&h.clone()); + } + SyncRequester::send_request(sync, io, peer_id, PeerAsking::BlockReceipts, GET_RECEIPTS_PACKET, rlp.out()); + let peer = sync.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); + peer.asking_blocks = hashes; + peer.block_set = Some(set); + } + + /// Request snapshot chunk from a peer. + fn request_snapshot_chunk(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, chunk: &H256) { + trace!(target: "sync", "{} <- GetSnapshotData {:?}", peer_id, chunk); + let mut rlp = RlpStream::new_list(1); + rlp.append(chunk); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::SnapshotData, GET_SNAPSHOT_DATA_PACKET, rlp.out()); + } + + /// Generic request sender + fn send_request(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) { + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + if peer.asking != PeerAsking::Nothing { + warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking); + } + peer.asking = asking; + peer.ask_time = Instant::now(); + let result = if packet_id >= ETH_PACKET_COUNT { + io.send_protocol(WARP_SYNC_PROTOCOL_ID, peer_id, packet_id, packet) + } else { + io.send(peer_id, packet_id, packet) + }; + if let Err(e) = result { + debug!(target:"sync", "Error sending request: {:?}", e); + io.disconnect_peer(peer_id); + } + } + } +} diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs new file mode 100644 index 00000000000..0bfb8569823 --- /dev/null +++ b/ethcore/sync/src/chain/supplier.rs @@ -0,0 +1,446 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use bytes::Bytes; +use ethcore::client::BlockId; +use ethcore::header::BlockNumber; +use ethereum_types::H256; +use network::{self, PeerId}; +use parking_lot::RwLock; +use rlp::{Rlp, RlpStream}; +use std::cmp; +use sync_io::SyncIo; + +use super::{ + ChainSync, + RlpResponseResult, + PacketDecodeError, + BLOCK_BODIES_PACKET, + BLOCK_HEADERS_PACKET, + CONSENSUS_DATA_PACKET, + GET_BLOCK_BODIES_PACKET, + GET_BLOCK_HEADERS_PACKET, + GET_NODE_DATA_PACKET, + GET_RECEIPTS_PACKET, + GET_SNAPSHOT_DATA_PACKET, + GET_SNAPSHOT_MANIFEST_PACKET, + MAX_BODIES_TO_SEND, + MAX_HEADERS_TO_SEND, + MAX_NODE_DATA_TO_SEND, + MAX_RECEIPTS_HEADERS_TO_SEND, + MAX_RECEIPTS_TO_SEND, + NODE_DATA_PACKET, + RECEIPTS_PACKET, + SNAPSHOT_DATA_PACKET, + SNAPSHOT_MANIFEST_PACKET, +}; + +/// The Chain Sync Supplier: answers requests from peers with available data +pub struct SyncSupplier; + +impl SyncSupplier { + /// Dispatch incoming requests and responses + pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + let rlp = Rlp::new(data); + let result = match packet_id { + GET_BLOCK_BODIES_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_block_bodies, + |e| format!("Error sending block bodies: {:?}", e)), + + GET_BLOCK_HEADERS_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_block_headers, + |e| format!("Error sending block headers: {:?}", e)), + + GET_RECEIPTS_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_receipts, + |e| format!("Error sending receipts: {:?}", e)), + + GET_NODE_DATA_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_node_data, + |e| format!("Error sending nodes: {:?}", e)), + + GET_SNAPSHOT_MANIFEST_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_snapshot_manifest, + |e| format!("Error sending snapshot manifest: {:?}", e)), + + GET_SNAPSHOT_DATA_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_snapshot_data, + |e| format!("Error sending snapshot data: {:?}", e)), + CONSENSUS_DATA_PACKET => ChainSync::on_consensus_packet(io, peer, &rlp), + _ => { + sync.write().on_packet(io, peer, packet_id, data); + Ok(()) + } + }; + result.unwrap_or_else(|e| { + debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); + }) + } + + /// Respond to GetBlockHeaders request + fn return_block_headers(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + // Packet layout: + // [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ] + let max_headers: usize = r.val_at(1)?; + let skip: usize = r.val_at(2)?; + let reverse: bool = r.val_at(3)?; + let last = io.chain().chain_info().best_block_number; + let number = if r.at(0)?.size() == 32 { + // id is a hash + let hash: H256 = r.val_at(0)?; + trace!(target: "sync", "{} -> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", peer_id, hash, max_headers, skip, reverse); + match io.chain().block_header(BlockId::Hash(hash)) { + Some(hdr) => { + let number = hdr.number().into(); + debug_assert_eq!(hdr.hash(), hash); + + if max_headers == 1 || io.chain().block_hash(BlockId::Number(number)) != Some(hash) { + // Non canonical header or single header requested + // TODO: handle single-step reverse hashchains of non-canon hashes + trace!(target:"sync", "Returning single header: {:?}", hash); + let mut rlp = RlpStream::new_list(1); + rlp.append_raw(&hdr.into_inner(), 1); + return Ok(Some((BLOCK_HEADERS_PACKET, rlp))); + } + number + } + None => return Ok(Some((BLOCK_HEADERS_PACKET, RlpStream::new_list(0)))) //no such header, return nothing + } + } else { + trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, r.val_at::(0)?, max_headers, skip, reverse); + r.val_at(0)? + }; + + let mut number = if reverse { + cmp::min(last, number) + } else { + cmp::max(0, number) + }; + let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers); + let mut count = 0; + let mut data = Bytes::new(); + let inc = (skip + 1) as BlockNumber; + let overlay = io.chain_overlay().read(); + + while number <= last && count < max_count { + if let Some(hdr) = overlay.get(&number) { + trace!(target: "sync", "{}: Returning cached fork header", peer_id); + data.extend_from_slice(hdr); + count += 1; + } else if let Some(hdr) = io.chain().block_header(BlockId::Number(number)) { + data.append(&mut hdr.into_inner()); + count += 1; + } else { + // No required block. + break; + } + if reverse { + if number <= inc || number == 0 { + break; + } + number -= inc; + } + else { + number += inc; + } + } + let mut rlp = RlpStream::new_list(count as usize); + rlp.append_raw(&data, count as usize); + trace!(target: "sync", "{} -> GetBlockHeaders: returned {} entries", peer_id, count); + Ok(Some((BLOCK_HEADERS_PACKET, rlp))) + } + + /// Respond to GetBlockBodies request + fn return_block_bodies(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let mut count = r.item_count().unwrap_or(0); + if count == 0 { + debug!(target: "sync", "Empty GetBlockBodies request, ignoring."); + return Ok(None); + } + count = cmp::min(count, MAX_BODIES_TO_SEND); + let mut added = 0usize; + let mut data = Bytes::new(); + for i in 0..count { + if let Some(body) = io.chain().block_body(BlockId::Hash(r.val_at::(i)?)) { + data.append(&mut body.into_inner()); + added += 1; + } + } + let mut rlp = RlpStream::new_list(added); + rlp.append_raw(&data, added); + trace!(target: "sync", "{} -> GetBlockBodies: returned {} entries", peer_id, added); + Ok(Some((BLOCK_BODIES_PACKET, rlp))) + } + + /// Respond to GetNodeData request + fn return_node_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let mut count = r.item_count().unwrap_or(0); + trace!(target: "sync", "{} -> GetNodeData: {} entries", peer_id, count); + if count == 0 { + debug!(target: "sync", "Empty GetNodeData request, ignoring."); + return Ok(None); + } + count = cmp::min(count, MAX_NODE_DATA_TO_SEND); + let mut added = 0usize; + let mut data = Vec::new(); + for i in 0..count { + if let Some(node) = io.chain().state_data(&r.val_at::(i)?) { + data.push(node); + added += 1; + } + } + trace!(target: "sync", "{} -> GetNodeData: return {} entries", peer_id, added); + let mut rlp = RlpStream::new_list(added); + for d in data { + rlp.append(&d); + } + Ok(Some((NODE_DATA_PACKET, rlp))) + } + + fn return_receipts(io: &SyncIo, rlp: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let mut count = rlp.item_count().unwrap_or(0); + trace!(target: "sync", "{} -> GetReceipts: {} entries", peer_id, count); + if count == 0 { + debug!(target: "sync", "Empty GetReceipts request, ignoring."); + return Ok(None); + } + count = cmp::min(count, MAX_RECEIPTS_HEADERS_TO_SEND); + let mut added_headers = 0usize; + let mut added_receipts = 0usize; + let mut data = Bytes::new(); + for i in 0..count { + if let Some(mut receipts_bytes) = io.chain().block_receipts(&rlp.val_at::(i)?) { + data.append(&mut receipts_bytes); + added_receipts += receipts_bytes.len(); + added_headers += 1; + if added_receipts > MAX_RECEIPTS_TO_SEND { break; } + } + } + let mut rlp_result = RlpStream::new_list(added_headers); + rlp_result.append_raw(&data, added_headers); + Ok(Some((RECEIPTS_PACKET, rlp_result))) + } + + /// Respond to GetSnapshotManifest request + fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let count = r.item_count().unwrap_or(0); + trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); + if count != 0 { + debug!(target: "sync", "Invalid GetSnapshotManifest request, ignoring."); + return Ok(None); + } + let rlp = match io.snapshot_service().manifest() { + Some(manifest) => { + trace!(target: "sync", "{} <- SnapshotManifest", peer_id); + let mut rlp = RlpStream::new_list(1); + rlp.append_raw(&manifest.into_rlp(), 1); + rlp + }, + None => { + trace!(target: "sync", "{}: No manifest to return", peer_id); + RlpStream::new_list(0) + } + }; + Ok(Some((SNAPSHOT_MANIFEST_PACKET, rlp))) + } + + /// Respond to GetSnapshotData request + fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let hash: H256 = r.val_at(0)?; + trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); + let rlp = match io.snapshot_service().chunk(hash) { + Some(data) => { + let mut rlp = RlpStream::new_list(1); + trace!(target: "sync", "{} <- SnapshotData", peer_id); + rlp.append(&data); + rlp + }, + None => { + RlpStream::new_list(0) + } + }; + Ok(Some((SNAPSHOT_DATA_PACKET, rlp))) + } + + fn return_rlp(io: &mut SyncIo, rlp: &Rlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> + where FRlp : Fn(&SyncIo, &Rlp, PeerId) -> RlpResponseResult, + FError : FnOnce(network::Error) -> String + { + let response = rlp_func(io, rlp, peer); + match response { + Err(e) => Err(e), + Ok(Some((packet_id, rlp_stream))) => { + io.respond(packet_id, rlp_stream.out()).unwrap_or_else( + |e| debug!(target: "sync", "{:?}", error_func(e))); + Ok(()) + } + _ => Ok(()) + } + } +} + +#[cfg(test)] +mod test { + use std::collections::{VecDeque}; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + use ethereum_types::{H256}; + use parking_lot::RwLock; + use bytes::Bytes; + use rlp::{Rlp, RlpStream}; + use super::{*, super::tests::*}; + use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient}; + + #[test] + fn return_block_headers() { + use ethcore::views::HeaderView; + fn make_hash_req(h: &H256, count: usize, skip: usize, reverse: bool) -> Bytes { + let mut rlp = RlpStream::new_list(4); + rlp.append(h); + rlp.append(&count); + rlp.append(&skip); + rlp.append(&if reverse {1u32} else {0u32}); + rlp.out() + } + + fn make_num_req(n: usize, count: usize, skip: usize, reverse: bool) -> Bytes { + let mut rlp = RlpStream::new_list(4); + rlp.append(&n); + rlp.append(&count); + rlp.append(&skip); + rlp.append(&if reverse {1u32} else {0u32}); + rlp.out() + } + fn to_header_vec(rlp: ::chain::RlpResponseResult) -> Vec { + Rlp::new(&rlp.unwrap().unwrap().1.out()).iter().map(|r| r.as_raw().to_vec()).collect() + } + + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Nothing); + let blocks: Vec<_> = (0 .. 100) + .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); + + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let io = TestIo::new(&mut client, &ss, &queue, None); + + let unknown: H256 = H256::new(); + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); + assert!(to_header_vec(result).is_empty()); + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); + assert!(to_header_vec(result).is_empty()); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); + } + + #[test] + fn return_nodes() { + let mut client = TestBlockChainClient::new(); + let queue = RwLock::new(VecDeque::new()); + let sync = dummy_sync_with_peer(H256::new(), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let mut node_list = RlpStream::new_list(3); + node_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); + node_list.append(&H256::from("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa")); + node_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); + + let node_request = node_list.out(); + // it returns rlp ONLY for hashes started with "f" + let result = SyncSupplier::return_node_data(&io, &Rlp::new(&node_request.clone()), 0); + + assert!(result.is_ok()); + let rlp_result = result.unwrap(); + assert!(rlp_result.is_some()); + + // the length of one rlp-encoded hashe + let rlp = rlp_result.unwrap().1.out(); + let rlp = Rlp::new(&rlp); + assert_eq!(Ok(1), rlp.item_count()); + + io.sender = Some(2usize); + + ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, GET_NODE_DATA_PACKET, &node_request); + assert_eq!(1, io.packets.len()); + } + + #[test] + fn return_receipts_empty() { + let mut client = TestBlockChainClient::new(); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let io = TestIo::new(&mut client, &ss, &queue, None); + + let result = SyncSupplier::return_receipts(&io, &Rlp::new(&[0xc0]), 0); + + assert!(result.is_ok()); + } + + #[test] + fn return_receipts() { + let mut client = TestBlockChainClient::new(); + let queue = RwLock::new(VecDeque::new()); + let sync = dummy_sync_with_peer(H256::new(), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let mut receipt_list = RlpStream::new_list(4); + receipt_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); + receipt_list.append(&H256::from("ff00000000000000000000000000000000000000000000000000000000000000")); + receipt_list.append(&H256::from("fff0000000000000000000000000000000000000000000000000000000000000")); + receipt_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); + + let receipts_request = receipt_list.out(); + // it returns rlp ONLY for hashes started with "f" + let result = SyncSupplier::return_receipts(&io, &Rlp::new(&receipts_request.clone()), 0); + + assert!(result.is_ok()); + let rlp_result = result.unwrap(); + assert!(rlp_result.is_some()); + + // the length of two rlp-encoded receipts + assert_eq!(603, rlp_result.unwrap().1.out().len()); + + io.sender = Some(2usize); + ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, GET_RECEIPTS_PACKET, &receipts_request); + assert_eq!(1, io.packets.len()); + } +} diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index 2f6441f4f28..804ebe9c535 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -22,7 +22,7 @@ use parking_lot::Mutex; use bytes::Bytes; use ethcore::snapshot::{SnapshotService, ManifestData, RestorationStatus}; use ethcore::header::BlockNumber; -use ethcore::client::{EachBlockWith}; +use ethcore::client::EachBlockWith; use super::helpers::*; use {SyncConfig, WarpSync}; @@ -99,7 +99,15 @@ impl SnapshotService for TestSnapshotService { } fn begin_restore(&self, manifest: ManifestData) { - *self.restoration_manifest.lock() = Some(manifest); + let mut restoration_manifest = self.restoration_manifest.lock(); + + if let Some(ref c_manifest) = *restoration_manifest { + if c_manifest.state_root == manifest.state_root { + return; + } + } + + *restoration_manifest = Some(manifest); self.state_restoration_chunks.lock().clear(); self.block_restoration_chunks.lock().clear(); } From 26c518b28386627a2834ed96f3a0237b168d4f04 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 9 May 2018 12:05:56 +0200 Subject: [PATCH 074/147] Decoding headers can fail (#8570) * rlp::decode returns Result * Fix journaldb to handle rlp::decode Result * Fix ethcore to work with rlp::decode returning Result * Light client handles rlp::decode returning Result * Fix tests in rlp_derive * Fix tests * Cleanup * cleanup * Allow panic rather than breaking out of iterator * Let decoding failures when reading from disk blow up * syntax * Fix the trivial grumbles * Fix failing tests * Make Account::from_rlp return Result * Syntx, sigh * Temp-fix for decoding failures * Header::decode returns Result Handle new return type throughout the code base. * Do not continue reading from the DB when a value could not be read * Fix tests * Handle header decoding in light_sync * Handling header decoding errors * Let the DecodeError bubble up unchanged * Remove redundant error conversion --- ethcore/light/src/client/header_chain.rs | 10 ++++--- ethcore/light/src/client/mod.rs | 12 ++++++-- ethcore/src/client/client.rs | 14 ++++++---- ethcore/src/client/test_client.rs | 5 ++-- ethcore/src/encoded.rs | 6 ++-- ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/error.rs | 10 +++++-- ethcore/src/miner/miner.rs | 11 ++++++-- ethcore/src/snapshot/mod.rs | 2 +- ethcore/src/verification/verification.rs | 5 ++-- ethcore/sync/src/light_sync/response.rs | 32 ++++++++++++---------- ethcore/sync/src/light_sync/tests/mod.rs | 2 +- rpc/src/v1/helpers/errors.rs | 13 +++++++++ rpc/src/v1/impls/eth.rs | 13 +++++---- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 2 +- rpc/src/v1/impls/parity.rs | 4 +-- rpc/src/v1/impls/traces.rs | 6 ++-- 18 files changed, 98 insertions(+), 53 deletions(-) diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 02a18a60dfe..b85091e53bf 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -305,7 +305,7 @@ impl HeaderChain { batch.put(col, cht_key(cht_num as u64).as_bytes(), &::rlp::encode(cht_root)); } - let decoded_header = hardcoded_sync.header.decode(); + let decoded_header = hardcoded_sync.header.decode()?; let decoded_header_num = decoded_header.number(); // write the block in the DB. @@ -585,7 +585,7 @@ impl HeaderChain { bail!(ErrorKind::Database(msg.into())); }; - let decoded = header.decode(); + let decoded = header.decode().expect("decoding db value failed"); let entry: Entry = { let bytes = self.db.get(self.col, era_key(h_num).as_bytes())? @@ -815,7 +815,9 @@ impl HeaderChain { for hdr in self.ancestry_iter(BlockId::Hash(parent_hash)) { if let Some(transition) = live_proofs.get(&hdr.hash()).cloned() { - return Some((hdr.decode(), transition.proof)) + return hdr.decode().map(|decoded_hdr| { + (decoded_hdr, transition.proof) + }).ok(); } } @@ -1224,7 +1226,7 @@ mod tests { let hardcoded_sync = chain.read_hardcoded_sync().expect("failed reading hardcoded sync").expect("failed unwrapping hardcoded sync"); assert_eq!(hardcoded_sync.chts.len(), 3); assert_eq!(hardcoded_sync.total_difficulty, total_difficulty); - let decoded: Header = hardcoded_sync.header.decode(); + let decoded: Header = hardcoded_sync.header.decode().expect("decoding failed"); assert_eq!(decoded.number(), h_num); } } diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index cf603d853f0..82b424cc833 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -318,7 +318,7 @@ impl Client { let epoch_proof = self.engine.is_epoch_end( &verified_header, - &|h| self.chain.block_header(BlockId::Hash(h)).map(|hdr| hdr.decode()), + &|h| self.chain.block_header(BlockId::Hash(h)).and_then(|hdr| hdr.decode().ok()), &|h| self.chain.pending_transition(h), ); @@ -426,7 +426,15 @@ impl Client { }; // Verify Block Family - let verify_family_result = self.engine.verify_block_family(&verified_header, &parent_header.decode()); + + let verify_family_result = { + parent_header.decode() + .map_err(|dec_err| dec_err.into()) + .and_then(|decoded| { + self.engine.verify_block_family(&verified_header, &decoded) + }) + + }; if let Err(e) = verify_family_result { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", verified_header.number(), verified_header.hash(), e); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index bffa4e38ba8..76d78e3df63 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1219,8 +1219,7 @@ impl Client { => Some(self.chain.read().best_block_header()), BlockId::Number(number) if number == self.chain.read().best_block_number() => Some(self.chain.read().best_block_header()), - _ - => self.block_header(id).map(|h| h.decode()), + _ => self.block_header(id).and_then(|h| h.decode().ok()) } } } @@ -1915,7 +1914,11 @@ impl BlockChainClient for Client { fn uncle_extra_info(&self, id: UncleId) -> Option> { self.uncle(id) - .map(|header| self.engine.extra_info(&header.decode())) + .and_then(|h| { + h.decode().map(|dh| { + self.engine.extra_info(&dh) + }).ok() + }) } fn pruning_info(&self) -> PruningInfo { @@ -2033,7 +2036,8 @@ impl ReopenBlock for Client { for h in uncles { if !block.uncles().iter().any(|header| header.hash() == h) { let uncle = chain.block_header_data(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed"); - block.push_uncle(uncle.decode()).expect("pushing up to maximum_uncle_count; + let uncle = uncle.decode().expect("decoding failure"); + block.push_uncle(uncle).expect("pushing up to maximum_uncle_count; push_uncle is not ok only if more than maximum_uncle_count is pushed; so all push_uncle are Ok; qed"); @@ -2074,7 +2078,7 @@ impl PrepareOpenBlock for Client { .into_iter() .take(engine.maximum_uncle_count(open_block.header().number())) .foreach(|h| { - open_block.push_uncle(h.decode()).expect("pushing maximum_uncle_count; + open_block.push_uncle(h.decode().expect("decoding failure")).expect("pushing maximum_uncle_count; open_block was just created; push_uncle is not ok only if more than maximum_uncle_count is pushed; so all push_uncle are Ok; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index b229159667d..6a3166f7c04 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -289,7 +289,7 @@ impl TestBlockChainClient { /// Make a bad block by setting invalid extra data. pub fn corrupt_block(&self, n: BlockNumber) { let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode(); + let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode().expect("decoding failed"); header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec()); let mut rlp = RlpStream::new_list(3); rlp.append(&header); @@ -301,7 +301,7 @@ impl TestBlockChainClient { /// Make a bad block by setting invalid parent hash. pub fn corrupt_block_parent(&self, n: BlockNumber) { let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode(); + let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode().expect("decoding failed"); header.set_parent_hash(H256::from(42)); let mut rlp = RlpStream::new_list(3); rlp.append(&header); @@ -479,6 +479,7 @@ impl BlockInfo for TestBlockChainClient { self.block_header(BlockId::Hash(self.chain_info().best_block_hash)) .expect("Best block always has header.") .decode() + .expect("decoding failed") } fn block(&self, id: BlockId) -> Option { diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 01df386cc2e..c436607f8c3 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -28,7 +28,7 @@ use ethereum_types::{H256, Bloom, U256, Address}; use hash::keccak; use header::{BlockNumber, Header as FullHeader}; use heapsize::HeapSizeOf; -use rlp::{Rlp, RlpStream}; +use rlp::{self, Rlp, RlpStream}; use transaction::UnverifiedTransaction; use views::{self, BlockView, HeaderView, BodyView}; @@ -47,7 +47,9 @@ impl Header { pub fn new(encoded: Vec) -> Self { Header(encoded) } /// Upgrade this encoded view to a fully owned `Header` object. - pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0).expect("decoding failure") } + pub fn decode(&self) -> Result { + rlp::decode(&self.0) + } /// Get a borrowed header view onto the data. #[inline] diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index c2aee7c6efc..ed9a9a4f251 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -996,7 +996,7 @@ impl Engine for AuthorityRound { let parent = client.block_header(::client::BlockId::Hash(*block.header().parent_hash())) .expect("hash is from parent; parent header must exist; qed") - .decode(); + .decode()?; let parent_step = header_step(&parent, self.empty_steps_transition)?; let current_step = self.step.load(); diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 561701e7620..bec749297cb 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -290,6 +290,12 @@ error_chain! { description("Unknown engine name") display("Unknown engine name ({})", name) } + + #[doc = "RLP decoding errors"] + Decoder(err: ::rlp::DecoderError) { + description("decoding value failed") + display("decoding value failed with error: {}", err) + } } } @@ -310,11 +316,11 @@ impl From for Error { fn from(err: AccountsError) -> Error { ErrorKind::AccountProvider(err).into() } -} +} impl From<::rlp::DecoderError> for Error { fn from(err: ::rlp::DecoderError) -> Error { - UtilError::from(err).into() + ErrorKind::Decoder(err).into() } } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 76a011343fb..3168ff1a846 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -528,8 +528,8 @@ impl Miner { } /// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal. - fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool where - C: BlockChain + SealedBlockImporter, + fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool + where C: BlockChain + SealedBlockImporter, { { let sealing = self.sealing.lock(); @@ -544,7 +544,12 @@ impl Miner { trace!(target: "miner", "seal_block_internally: attempting internal seal."); let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) { - Some(hdr) => hdr.decode(), + Some(h) => { + match h.decode() { + Ok(decoded_hdr) => decoded_hdr, + Err(_) => return false + } + } None => return false, }; diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 94236e9e95d..8871ced26fa 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -487,7 +487,7 @@ pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &EthEngine, ch if always || rng.gen::() <= POW_VERIFY_RATE { engine.verify_block_unordered(header)?; match chain.block_header_data(header.parent_hash()) { - Some(parent) => engine.verify_block_family(header, &parent.decode()), + Some(parent) => engine.verify_block_family(header, &parent.decode()?), None => Ok(()), } } else { diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 92f3e77f902..03a6d6f8d41 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -224,7 +224,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth return Err(From::from(BlockError::UncleParentNotInChain(uncle_parent.hash()))); } - let uncle_parent = uncle_parent.decode(); + let uncle_parent = uncle_parent.decode()?; verify_parent(&uncle, &uncle_parent, engine)?; engine.verify_block_family(&uncle, &uncle_parent)?; verified.insert(uncle.hash()); @@ -500,10 +500,9 @@ mod tests { // no existing tests need access to test, so having this not function // is fine. let client = ::client::TestBlockChainClient::default(); - let parent = bc.block_header_data(header.parent_hash()) .ok_or(BlockError::UnknownParent(header.parent_hash().clone()))? - .decode(); + .decode()?; let full_params = FullFamilyParams { block_bytes: bytes, diff --git a/ethcore/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs index 4dfb383d466..74665118b7f 100644 --- a/ethcore/sync/src/light_sync/response.rs +++ b/ethcore/sync/src/light_sync/response.rs @@ -16,13 +16,11 @@ //! Helpers for decoding and verifying responses for headers. -use std::fmt; - -use ethcore::encoded; -use ethcore::header::Header; +use ethcore::{self, encoded, header::Header}; +use ethereum_types::H256; use light::request::{HashOrNumber, CompleteHeadersRequest as HeadersRequest}; use rlp::DecoderError; -use ethereum_types::H256; +use std::fmt; /// Errors found when decoding headers and verifying with basic constraints. #[derive(Debug, PartialEq)] @@ -74,19 +72,23 @@ pub trait Constraint { /// Do basic verification of provided headers against a request. pub fn verify(headers: &[encoded::Header], request: &HeadersRequest) -> Result, BasicError> { - let headers: Vec<_> = headers.iter().map(|h| h.decode()).collect(); + let headers: Result, _> = headers.iter().map(|h| h.decode() ).collect(); + match headers { + Ok(headers) => { + let reverse = request.reverse; + + Max(request.max as usize).verify(&headers, reverse)?; + match request.start { + HashOrNumber::Number(ref num) => StartsAtNumber(*num).verify(&headers, reverse)?, + HashOrNumber::Hash(ref hash) => StartsAtHash(*hash).verify(&headers, reverse)?, + } - let reverse = request.reverse; + SkipsBetween(request.skip).verify(&headers, reverse)?; - Max(request.max as usize).verify(&headers, reverse)?; - match request.start { - HashOrNumber::Number(ref num) => StartsAtNumber(*num).verify(&headers, reverse)?, - HashOrNumber::Hash(ref hash) => StartsAtHash(*hash).verify(&headers, reverse)?, + Ok(headers) + }, + Err(e) => Err(e.into()) } - - SkipsBetween(request.skip).verify(&headers, reverse)?; - - Ok(headers) } struct StartsAtNumber(u64); diff --git a/ethcore/sync/src/light_sync/tests/mod.rs b/ethcore/sync/src/light_sync/tests/mod.rs index 9fd270838bf..3fee1c71707 100644 --- a/ethcore/sync/src/light_sync/tests/mod.rs +++ b/ethcore/sync/src/light_sync/tests/mod.rs @@ -45,7 +45,7 @@ fn fork_post_cht() { for id in (0..CHAIN_LENGTH).map(|x| x + 1).map(BlockId::Number) { let (light_peer, full_peer) = (net.peer(0), net.peer(1)); let light_chain = light_peer.light_chain(); - let header = full_peer.chain().block_header(id).unwrap().decode(); + let header = full_peer.chain().block_header(id).unwrap().decode().expect("decoding failure"); let _ = light_chain.import_header(header); light_chain.flush_queue(); light_chain.import_verified(); diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 4f3289a116b..c85beef7d5a 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -360,6 +360,19 @@ pub fn transaction>(error: T) -> Error { } } +pub fn decode>(error: T) -> Error { + let error = error.into(); + match *error.kind() { + ErrorKind::Decoder(ref dec_err) => rlp(dec_err.clone()), + _ => Error { + code: ErrorCode::InternalError, + message: "decoding error".into(), + data: None, + } + + } +} + pub fn rlp(error: DecoderError) -> Error { Error { code: ErrorCode::InvalidParams, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a7ff4916dee..389805c1765 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -343,7 +343,10 @@ impl EthClient hdr.decode(), + Some(hdr) => match hdr.decode() { + Ok(h) => h, + Err(e) => return Err(errors::decode(e)) + }, None => { return Ok(None); } }; @@ -851,9 +854,9 @@ impl Eth for EthClient< }; let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned())); - let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned())); + let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned()).and_then(|h| h.decode().map_err(errors::decode))); - (state, header.decode()) + (state, header) }; let result = self.client.call(&signed, Default::default(), &mut state, &header); @@ -890,9 +893,9 @@ impl Eth for EthClient< }; let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned())); - let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned())); + let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned()).and_then(|h| h.decode().map_err(errors::decode))); - (state, header.decode()) + (state, header) }; Box::new(future::done(self.client.estimate_gas(&signed, &state, &header) diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index eeef12da6e6..35f7792b52c 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -371,7 +371,7 @@ impl Eth for EthClient { } fn send_raw_transaction(&self, raw: Bytes) -> Result { - let best_header = self.client.best_block_header().decode(); + let best_header = self.client.best_block_header().decode().map_err(errors::decode)?; Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 3d31d9e6765..982c7ff3633 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -395,7 +395,7 @@ impl Parity for ParityClient { let engine = self.light_dispatch.client.engine().clone(); let from_encoded = move |encoded: encoded::Header| { - let header = encoded.decode(); + let header = encoded.decode().expect("decoding error"); // REVIEW: not sure what to do here; what is a decent return value for the error case here? let extra_info = engine.extra_info(&header); RichHeader { inner: Header { diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index db66bddc7e9..08d5147202c 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -487,9 +487,9 @@ impl Parity for ParityClient where }; let state = self.client.state_at(id).ok_or(errors::state_pruned())?; - let header = self.client.block_header(id).ok_or(errors::state_pruned())?; + let header = self.client.block_header(id).ok_or(errors::state_pruned())?.decode().map_err(errors::decode)?; - (state, header.decode()) + (state, header) }; self.client.call_many(&requests, &mut state, &header) diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index bf4dc83beb1..0130b3b9c13 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -104,7 +104,7 @@ impl Traces for TracesClient where let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; let header = self.client.block_header(id).ok_or(errors::state_pruned())?; - self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode()) + self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode().map_err(errors::decode)?) .map(TraceResults::from) .map_err(errors::call) } @@ -131,7 +131,7 @@ impl Traces for TracesClient where let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; let header = self.client.block_header(id).ok_or(errors::state_pruned())?; - self.client.call_many(&requests, &mut state, &header.decode()) + self.client.call_many(&requests, &mut state, &header.decode().map_err(errors::decode)?) .map(|results| results.into_iter().map(TraceResults::from).collect()) .map_err(errors::call) } @@ -153,7 +153,7 @@ impl Traces for TracesClient where let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; let header = self.client.block_header(id).ok_or(errors::state_pruned())?; - self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode()) + self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode().map_err(errors::decode)?) .map(TraceResults::from) .map_err(errors::call) } From ad3de8620edd45f4bcc7375fba34e649c6aaf81e Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 9 May 2018 14:11:36 +0200 Subject: [PATCH 075/147] Update CHANGELOG for 1.9, 1.10, and 1.11 (#8556) * Move changelog for 1.10.x * Mark 1.9 EOL * Prepare changelog for 1.10.3 stable * Prepare changelog for 1.11.0 stable * Update changelogs * Update CHANGELOG for 1.10.3 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Format changelog --- CHANGELOG.md | 530 +++++++++++++++++++++-------------------- docs/CHANGELOG-1.10.md | 325 +++++++++++++++++++++++++ docs/CHANGELOG-1.9.md | 2 + 3 files changed, 594 insertions(+), 263 deletions(-) create mode 100644 docs/CHANGELOG-1.10.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6272c32a7e8..0c7dcf878be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,272 +1,276 @@ -## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24) - -Parity 1.10.2 is a bug-fix release to improve performance and stability. - -The full list of included changes: - -- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455)) - - Update Parity beta to 1.10.2 - - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) - - Disable 32-bit targets for Gitlab - - Rename Linux pipelines - - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) - - Fix Cargo.lock -- Backports ([#8450](https://github.com/paritytech/parity/pull/8450)) - - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) - - Remove unused app_dirs dependency in CLI - - Use forked app_dirs crate for reverted Windows dir behavior - - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) - - Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) - - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) - - Improve VM executor stack size estimation rules - - Typo: docs add "(Debug build)" comment - - Fix an off by one typo and set minimal stack size - - Use saturating_sub to avoid potential overflow - -## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) - -Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. - -The full list of included changes: - -- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350)) - - Bump beta to 1.10.1 - - Unflag critical release -- Backports ([#8346](https://github.com/paritytech/parity/pull/8346)) - - Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) - - Warp-only sync with warp-after [blocknumber] flag. - - Fix tests. - - Fix configuration tests. - - Rename to warp barrier. - - Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) - - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) - - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) - - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) - - Include suicided accounts in state diff - - Shorten form match -> if let - - Test suicide trace diff in State - - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) - - Replace_home for password_files, reserved_peers and log_file - - Typo: arg_log_file is Option - - Enable UI by default, but only display info page. - - Fix test. - - Fix naming and remove old todo. - - Change "wallet" with "browser UI" -- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205)) - - Change name Wallet -> UI - - Make warning bold -- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132)) -- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220)) - - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) - - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) -- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203)) -- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181)) - - Updated jsonrpc to include latest backports - - Update dependencies. - -## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22) - -This is the Parity 1.10.0-beta release! Cool! - -### Disabling the Parity Wallet - -The **Parity Wallet (a.k.a. "UI") is now disabled by default**. We are preparing to split the wallet from the core client. - -To reactivate the parity wallet, you have to run Parity either with `parity --force-ui` (not recommended) or `parity ui` (deprecated) from the command line. Or, if you feel super fancy and want to test our pre-releases of the stand-alone electron wallet, head over to the [Parity-JS repositories and check the releases](https://github.com/Parity-JS/shell/releases). - -Further reading: - -- [Docs: Parity Wallet](https://wiki.parity.io/Parity-Wallet) -- [Docs: How to customize Parity UI?](https://wiki.parity.io/FAQ-Customize-Parity-UI.html) -- [Github: Parity-JS](https://github.com/parity-js) - -### Introducing the Wasm VM - -We are excited to announce support for **Wasm Smart Contracts on Kovan network**. The hard-fork to activate the Wasm-VM will take place on block `6_600_000`. - -To enable Wasm contracts on your custom network, just schedule a `wasmActivationTransition` at your favorite block number (e.g., `42`, `666`, or `0xbada55`). To hack your first Wasm smart contracts in Rust, have a look at the [Parity Wasm Tutorials](https://github.com/paritytech/pwasm-tutorial). - -Further reading: - -- [Docs: WebAssembly (wasm)](https://wiki.parity.io/WebAssembly-Home) -- [Docs: Wasm VM Design](https://wiki.parity.io/WebAssembly-Design) -- [Docs: Wasm tutorials and examples](https://wiki.parity.io/WebAssembly-Links) - -### Empty step messages in PoA - -To **reduce blockchain bloat, proof-of-authority networks can now enable _empty step messages_ which replace empty blocks**. Each step message will be signed and broadcasted by the issuing authorities, and included and rewarded in the next non-empty block. - -To enable empty step messages, set the `emptyStepsTransition` to your favorite block number. You can also specify a maximum number of empty steps with `maximumEmptySteps` in your chain spec. - -### Other noteworthy changes - -We removed the old database migrations from 2016. In case you upgrade Parity from a really, really old version, you will have to reset your database manually first with `parity db kill`. - -We fixed DELEGATECALL `from` and `to` fields, see [#7166](https://github.com/paritytech/parity/issues/7166). - -We reduced the default USD per transaction value to 0.0001. Thanks, @MysticRyuujin! - -The Musicoin chain is now enabled with Byzantium features starting at block `2_222_222`. - -### Overview of all changes included +## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-05-09) + +This is the Parity 1.11.0-beta release! Hurray! + +Notable changes in reversed alphabetical order: + +- TOOLING: **Whisper CLI** [#8201](https://github.com/paritytech/parity/pull/8201) + - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. + - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. + - All whisper RPC APIs are enabled and can be directly acessed. +I'm not used to writing these changelogs but I guess that would explain it +- JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) + - This changes the behaviors of `eth_call` to respect VM errors if any. + - In case of `REVERT`, it will also return the reverted return data in hex format. +- ENGINES: **Block reward contract** [#8419](https://github.com/paritytech/parity/pull/8419) + - The _AuRa_ PoA engine has now support for having a contract to calculate the block rewards. + - The engine passes a list of benefactors and reward types to the contract which then returns a list of addresses and respective rewards. +- CORE: **Private transactions integration pr** [#6422](https://github.com/paritytech/parity/pull/6422) + - Parity now provides a private transactions system. + - Please, check out our wiki to get and [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). +- CORE: **New Transaction Queue implementation** [#8074](https://github.com/paritytech/parity/pull/8074) + - Verification is now done in parallel. + - Previous queue had `O(1)` time to get pending set, but `O(n^2)` insertion time. And obviously insertion/removal happens much more often than retrieving the pending set (only for propagation and pending block building) Currently we have `O(n * log(senders))` pending set time (with cache) and `O(tx_per_sender)` (usually within `log(tx_per_sender)`) insertion time. + - `Scoring` and `Readiness` are separated from the pool, so it's easier to customize them or introduce different definitions (for instance for [EIP-859](https://github.com/ethereum/EIPs/issues/859) or private transactions, etc). + - Banning removed, soft-penalization introduced instead: if transaction exceeds the limit other transactions from that sender get lower priority. + - There is no explicit distinction between current and future transactions in the pool - `Readiness` determines that. Because of this we additionally remove `future` transactions that occupy the pool for long time. +- CONFIGURATION: **Warp-only sync with --warp-barrier [block-number] flag.** [#8228](https://github.com/paritytech/parity/pull/8228) + - Enables warp-only sync in case `--warp-barrier [block-number]` is provided. + - This avoids clients to warp to outdated snapshots that are too far away from the best block. + - This avoids clients to fall back to normal sync if there are no recent snapshots available currently. +- CONFIGURATION: **Disable UI by default.** [#8105](https://github.com/paritytech/parity/pull/8105) + - The user interface is now disabled by default. It still can be activated with the `--force-ui` flag. + - To get the stand-alone Parity UI, please check the dedicated [releases page](https://github.com/parity-js/shell/releases). +- CONFIGURATION: **Auto-updater improvements** [#8078](https://github.com/paritytech/parity/pull/8078) + - Added `--auto-update-delay` to randomly delay updates by `n` blocks. This takes into account the number of the block of the update release (old updates aren't delayed). + - Added `--auto-update-check-frequency` to define the periodicity of auto-update checks in number of blocks. + - This is an important improvement to ensure the network does not update all clients at the same time. +- CHAIN SPECS: **Enable WebAssembly and Byzantium for Ellaism** [#8520](https://github.com/paritytech/parity/pull/8520) + - This activates the Ellaism Byzantium hardfork ([2018-0004-byzantium](https://github.com/ellaism/specs/blob/master/specs/2018-0004-byzantium.md)) at block `2_000_000`. + - This enables the Wasm VM on Ellaism ([2018-0003-wasm-hardfork](https://github.com/ellaism/specs/blob/master/specs/2018-0003-wasm-hardfork.md)) at block `2_000_000`. + - Please, upgrade your clients if you run an Ellaism configuration. +- CHAIN SPECS: **Dev chain - increase gasLimit to 8_000_000** [#8362](https://github.com/paritytech/parity/pull/8362) + - This increases the default block gas limit on development chains to `8_000_000`. + - Please note, this makes previous dev chain configurations incompatible. +- CHAIN SPECS: **Add MCIP-6 Byzyantium transition to Musicoin spec** [#7841](https://github.com/paritytech/parity/pull/7841) + - This activates the Musicoin Byzantium hardfork ([MCIP-6](https://github.com/Musicoin/MCIPs/blob/master/MCIPS/mcip-6.md)) at block `2_222_222`. + - Please, upgrade your clients if you run a Musicoin configuration. The full list of included changes: -- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) ([#8168](https://github.com/paritytech/parity/pull/8168)) - - Re-enable signer, even with no UI. - - Fix message. -- Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136)) - - Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) - - updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) - - updater: apply exponential backoff after download failure - - updater: reset backoff on new release - - Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) - - Enable code size limit on kovan - - Fix formatting. - - Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) - - Limit ingress connections - - Optimized handshakes logging - - WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) - - update wasmi, parity-wasm, wasm-utils to latest version - - Update to new wasmi & error handling - - also utilize new stack limiter - - fix typo - - replace dependency url - - Cargo.lock update - - add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) - - revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) - - Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)" - - Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))" - - fixed broken logs - - bring back old lock order - - remove migration v13 - - revert CURRENT_VERSION to 12 in migration.rs - - more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) - - Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) - - Use `subtle::slices_equal` for constant time comparison. - - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 - - Test specifically for InvalidPassword error. - - fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098)) - - network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) - - network: init discovery using healthy nodes - - network: fix style grumble - - network: fix typo - - Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) - - ethcore: postpone Kovan hard fork - - util: update version fork metadata - - Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) - - dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) -- Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135)) -- Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053)) - - CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) - - Fix cache - - Only clean locked cargo cache on windows - - fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) - - fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) - - fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) - - fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) - - Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) - - Add test chain spec for musicoin byzantium testnet - - Add MCIP-6 Byzyantium transition to Musicoin spec - - Update mcip6_byz.json - - ethcore: update musicoin byzantium block number - - ethcore: update musicoin bootnodes - - Update musicoin.json - - More bootnodes. -- Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022)) - - Make 1.10 beta - - Fix gitlab builds -- SecretStore: secretstore_generateDocumentKey RPC ([#7864](https://github.com/paritytech/parity/pull/7864)) -- SecretStore: ECDSA session for cases when 2*t < N ([#7739](https://github.com/paritytech/parity/pull/7739)) -- bump tiny-keccak ([#8019](https://github.com/paritytech/parity/pull/8019)) -- Remove un-necessary comment ([#8014](https://github.com/paritytech/parity/pull/8014)) -- clean up account fmt::Debug ([#7983](https://github.com/paritytech/parity/pull/7983)) -- improve quality of vote_collector module ([#7984](https://github.com/paritytech/parity/pull/7984)) -- ExecutedBlock cleanup ([#7991](https://github.com/paritytech/parity/pull/7991)) -- Hardware-wallet/usb-subscribe-refactor ([#7860](https://github.com/paritytech/parity/pull/7860)) -- remove wildcard imports from views, make tests more idiomatic ([#7986](https://github.com/paritytech/parity/pull/7986)) -- moved PerfTimer to a separate crate - "trace-time" ([#7985](https://github.com/paritytech/parity/pull/7985)) -- clean up ethcore::spec module imports ([#7990](https://github.com/paritytech/parity/pull/7990)) -- rpc: don't include current block in new_block_filter ([#7982](https://github.com/paritytech/parity/pull/7982)) -- fix traces, removed bloomchain crate ([#7979](https://github.com/paritytech/parity/pull/7979)) -- simplify compression and move it out of rlp crate ([#7957](https://github.com/paritytech/parity/pull/7957)) -- removed old migrations ([#7974](https://github.com/paritytech/parity/pull/7974)) -- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977)) -- fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934)) -- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965)) -- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953)) -- Add changelog for 1.8.10 stable and 1.9.3 beta ([#7947](https://github.com/paritytech/parity/pull/7947)) -- kvdb-rocksdb: remove buffered operations when committing transaction ([#7950](https://github.com/paritytech/parity/pull/7950)) -- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952)) -- removed redundant Bloom conversions ([#7932](https://github.com/paritytech/parity/pull/7932)) -- simplify RefInfo fmt ([#7929](https://github.com/paritytech/parity/pull/7929)) -- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849)) -- bring back trie and triehash benches ([#7926](https://github.com/paritytech/parity/pull/7926)) -- removed redundant PodAccount::new method ([#7928](https://github.com/paritytech/parity/pull/7928)) -- removed dummy wrapper structure - LogGroupPosition ([#7922](https://github.com/paritytech/parity/pull/7922)) -- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933)) -- simplify Client::filter_traces method ([#7936](https://github.com/paritytech/parity/pull/7936)) -- gitlab cache ([#7921](https://github.com/paritytech/parity/pull/7921)) -- Fix a division by zero in light client RPC handler ([#7917](https://github.com/paritytech/parity/pull/7917)) -- triehash optimisations ([#7920](https://github.com/paritytech/parity/pull/7920)) -- removed redundant Blockchain::db method ([#7919](https://github.com/paritytech/parity/pull/7919)) -- removed redundant Blockchain::rewind method ([#7918](https://github.com/paritytech/parity/pull/7918)) -- Pending transactions subscription ([#7906](https://github.com/paritytech/parity/pull/7906)) -- removed redundant otry! macro from ethcore ([#7916](https://github.com/paritytech/parity/pull/7916)) -- Make block generator easier to use ([#7888](https://github.com/paritytech/parity/pull/7888)) -- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905)) -- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867)) -- Fix gitlab ([#7901](https://github.com/paritytech/parity/pull/7901)) -- Gitlb snap master patch ([#7900](https://github.com/paritytech/parity/pull/7900)) -- fix snap build master ([#7896](https://github.com/paritytech/parity/pull/7896)) -- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873)) -- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884)) -- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848)) -- SecretStore: fixed test ([#7878](https://github.com/paritytech/parity/pull/7878)) -- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846)) -- Forward-port snap fixes ([#7831](https://github.com/paritytech/parity/pull/7831)) -- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883)) -- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881)) -- Fix string typo: "develoopment" -> "development" ([#7874](https://github.com/paritytech/parity/pull/7874)) -- Update the instructions to install the stable snap ([#7876](https://github.com/paritytech/parity/pull/7876)) -- SecretStore: 'broadcast' decryption session ([#7843](https://github.com/paritytech/parity/pull/7843)) -- Flush keyfiles. Resolves #7632 ([#7868](https://github.com/paritytech/parity/pull/7868)) -- Read registry_address from given block ([#7866](https://github.com/paritytech/parity/pull/7866)) -- Clean up docs formatting for Wasm runtime ([#7869](https://github.com/paritytech/parity/pull/7869)) -- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842)) -- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855)) -- ethabi version 5 ([#7723](https://github.com/paritytech/parity/pull/7723)) -- Light client: randomize the peer we dispatch requests to ([#7844](https://github.com/paritytech/parity/pull/7844)) -- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832)) -- Add new EF ropstens nodes. ([#7824](https://github.com/paritytech/parity/pull/7824)) -- refactor stratum to remove retain cycle ([#7827](https://github.com/paritytech/parity/pull/7827)) -- Bump jsonrpc. ([#7828](https://github.com/paritytech/parity/pull/7828)) -- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830)) -- Update references to UI shell & wallet ([#7808](https://github.com/paritytech/parity/pull/7808)) -- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812)) -- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796)) -- SecretStore: ignore removed authorities when running auto-migration ([#7674](https://github.com/paritytech/parity/pull/7674)) -- Fix build ([#7807](https://github.com/paritytech/parity/pull/7807)) -- Move js & js-old code to github.com/parity-js ([#7685](https://github.com/paritytech/parity/pull/7685)) -- More changelogs :) ([#7782](https://github.com/paritytech/parity/pull/7782)) -- Actualized API set in help ([#7790](https://github.com/paritytech/parity/pull/7790)) -- Removed obsolete file ([#7788](https://github.com/paritytech/parity/pull/7788)) -- Update ropsten bootnodes ([#7776](https://github.com/paritytech/parity/pull/7776)) -- CHANGELOG for 1.9.1 and 1.8.8 ([#7775](https://github.com/paritytech/parity/pull/7775)) -- Enable byzantium features on non-ethash chains ([#7753](https://github.com/paritytech/parity/pull/7753)) -- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695)) -- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716)) -- Removes redundant parentheses ([#7721](https://github.com/paritytech/parity/pull/7721)) -- Transaction-pool fixes ([#7741](https://github.com/paritytech/parity/pull/7741)) -- More visible download link in README.md ([#7707](https://github.com/paritytech/parity/pull/7707)) -- Changelog for 1.9.0 ([#7664](https://github.com/paritytech/parity/pull/7664)) -- Add scroll when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677)) -- SecretStore: return HTTP 403 (access denied) if consensus is unreachable ([#7656](https://github.com/paritytech/parity/pull/7656)) -- Moved StopGaurd to it's own crate ([#7635](https://github.com/paritytech/parity/pull/7635)) +- Backports ([#8558](https://github.com/paritytech/parity/pull/8558)) + - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) + - Fetch logs by hash in blockchain database + - Fix tests + - Add unit test for branch block logs fetching + - Add docs that blocks must already be sorted + - Handle branch block cases properly + - typo: empty -> is_empty + - Remove return_empty_if_none by using a closure + - Use BTreeSet to avoid sorting again + - Move is_canon to BlockChain + - typo: pass value by reference + - Use loop and wrap inside blocks to simplify the code + - typo: missed a comment + - Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity/pull/8491)) + - Pass on storage keys even if it is not modified + - typo: account and storage query + - Fix tests + - Use state query directly because of suicided accounts + - Fix a RefCell borrow issue + - Add tests for unmodified storage trace + - Address grumbles + - typo: remove unwanted empty line + - ensure_cached compiles with the original signature + - Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity/pull/8493)) + - Update wasmi to 0.2 + - Update pwasm-utils to 0.1.5 + - Show imported messages for light client ([#8517](https://github.com/paritytech/parity/pull/8517)) + - Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity/pull/8520)) + - Enable WebAssembly and Byzantium for Ellaism + - Fix indentation + - Remove empty lines + - Don't panic in import_block if invalid rlp ([#8522](https://github.com/paritytech/parity/pull/8522)) + - Don't panic in import_block if invalid rlp + - Remove redundant type annotation + - Replace RLP header view usage with safe decoding + - Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity/pull/8541)) + - network-devp2p: sort nodes in node table using last contact data + - network-devp2p: rename node contact types in node table json output + - network-devp2p: fix node table tests + - network-devp2p: note node failure when failed to establish connection + - network-devp2p: handle UselessPeer error + - network-devp2p: note failure when marking node as useless +- Betalize 1.11 :) ([#8475](https://github.com/paritytech/parity/pull/8475)) + - Betalize 1.11 :) + - Update Gitlab scripts + - Use master as gitlab latest + - Fix snap builds ([#8483](https://github.com/paritytech/parity/pull/8483)) + - Update hardcodedSync for Ethereum, Kovan, and Ropsten ([#8489](https://github.com/paritytech/parity/pull/8489)) +- Fix typos in vm description comment ([#8446](https://github.com/paritytech/parity/pull/8446)) +- Add changelog for 1.9.7 and 1.10.2 ([#8460](https://github.com/paritytech/parity/pull/8460)) +- Fix docker build ([#8462](https://github.com/paritytech/parity/pull/8462)) +- Parityshell::open `Return result` ([#8377](https://github.com/paritytech/parity/pull/8377)) +- Return error in case eth_call returns VM errors ([#8448](https://github.com/paritytech/parity/pull/8448)) +- Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) +- Allow 32 bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) +- Update Cargo hidapi-rs dependency ([#8447](https://github.com/paritytech/parity/pull/8447)) +- Private transactions processing error handling ([#8431](https://github.com/paritytech/parity/pull/8431)) +- Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) +- Block reward contract ([#8419](https://github.com/paritytech/parity/pull/8419)) +- Permission fix ([#8441](https://github.com/paritytech/parity/pull/8441)) +- Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) +- Remove From::from. ([#8390](https://github.com/paritytech/parity/pull/8390)) +- Move ethcore::Error to error_chain ([#8386](https://github.com/paritytech/parity/pull/8386)) +- Changelogs for 1.9.6 and 1.10.1 ([#8411](https://github.com/paritytech/parity/pull/8411)) +- Fix receipts stripping. ([#8414](https://github.com/paritytech/parity/pull/8414)) +- Typo, docs parity_chainId: empty string -> None ([#8434](https://github.com/paritytech/parity/pull/8434)) +- Update zip to 0.3 ([#8381](https://github.com/paritytech/parity/pull/8381)) +- Fix TODO comments ([#8413](https://github.com/paritytech/parity/pull/8413)) +- Replace legacy Rlp with UntrustedRlp and use in ethcore rlp views ([#8316](https://github.com/paritytech/parity/pull/8316)) +- Tokio-core v0.1.16 -> v0.1.17 ([#8408](https://github.com/paritytech/parity/pull/8408)) +- More code refactoring to integrate Duration ([#8322](https://github.com/paritytech/parity/pull/8322)) +- Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) +- Use tokio::spawn in secret_store listener and fix Uri ([#8373](https://github.com/paritytech/parity/pull/8373)) +- Unify and limit rocksdb dependency places ([#8371](https://github.com/paritytech/parity/pull/8371)) +- Clarify that windows need perl and yasm ([#8402](https://github.com/paritytech/parity/pull/8402)) +- New Transaction Queue implementation ([#8074](https://github.com/paritytech/parity/pull/8074)) +- Some tweaks to main.rs for parity as a library ([#8370](https://github.com/paritytech/parity/pull/8370)) +- Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) +- Ci: fix change detection in master builds ([#8382](https://github.com/paritytech/parity/pull/8382)) +- Fix config test by adding no-hardcodec-sync ([#8380](https://github.com/paritytech/parity/pull/8380)) +- Fixed unsafe shell call on windows ([#8372](https://github.com/paritytech/parity/pull/8372)) +- Parity uses winapi 0.3.4 ([#8366](https://github.com/paritytech/parity/pull/8366)) +- No hardcoded client name ([#8368](https://github.com/paritytech/parity/pull/8368)) +- Add `util/mem` to zero out memory on drop. ([#8356](https://github.com/paritytech/parity/pull/8356)) +- Use atty instead of isatty ([#8365](https://github.com/paritytech/parity/pull/8365)) +- Increase gasLimit to 8'000'000 ([#8362](https://github.com/paritytech/parity/pull/8362)) +- Util `fake-fetch` ([#8363](https://github.com/paritytech/parity/pull/8363)) +- Bump snappy and ring, use single rayon version, closes [#8296](https://github.com/paritytech/parity/issues/8296) ([#8364](https://github.com/paritytech/parity/pull/8364)) +- Use async hyper server in secret_store and upgrade igd ([#8359](https://github.com/paritytech/parity/pull/8359)) +- Enable UI by default, but only display deprecation notice ([#8262](https://github.com/paritytech/parity/pull/8262)) +- Ethcrypto renamed to ethcore-crypto and moved to ethcore dir ([#8340](https://github.com/paritytech/parity/pull/8340)) +- Use hyper 0.11 in ethcore-miner and improvements in parity-reactor ([#8335](https://github.com/paritytech/parity/pull/8335)) +- Ethcore-sync ([#8347](https://github.com/paritytech/parity/pull/8347)) +- Rpc, eth_filter: return error if the filter id does not exist ([#8341](https://github.com/paritytech/parity/pull/8341)) +- Ethcore-stratum crate moved to ethcore directory ([#8338](https://github.com/paritytech/parity/pull/8338)) +- Secretstore: get rid of engine.signer dependency ([#8173](https://github.com/paritytech/parity/pull/8173)) +- Whisper cli ([#8201](https://github.com/paritytech/parity/pull/8201)) +- Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) +- Add Ethereum Social support ([#8325](https://github.com/paritytech/parity/pull/8325)) +- Private transactions integration pr ([#6422](https://github.com/paritytech/parity/pull/6422)) +- Decouple rocksdb dependency from ethcore ([#8320](https://github.com/paritytech/parity/pull/8320)) +- Remove the clone operation of code_cache ([#8334](https://github.com/paritytech/parity/pull/8334)) +- Fix the JSONRPC API not running with the light client ([#8326](https://github.com/paritytech/parity/pull/8326)) +- Read registry_address from block with REQUEST_CONFIRMATIONS_REQUIRED ([#8309](https://github.com/paritytech/parity/pull/8309)) +- Tweaks and add a Dockerfile for Android ([#8036](https://github.com/paritytech/parity/pull/8036)) +- Use associated type M::Error instead of Error ([#8308](https://github.com/paritytech/parity/pull/8308)) +- Remove InvalidParentHash in favor of assert! ([#8300](https://github.com/paritytech/parity/pull/8300)) +- Bump proc macro deps ([#8310](https://github.com/paritytech/parity/pull/8310)) +- Decouple timestamp open-block-assignment/verification to Engine ([#8305](https://github.com/paritytech/parity/pull/8305)) +- Validate if gas limit is not zero ([#8307](https://github.com/paritytech/parity/pull/8307)) +- Implement Easthub chain spec ([#8295](https://github.com/paritytech/parity/pull/8295)) +- Update some dependencies ([#8285](https://github.com/paritytech/parity/pull/8285)) +- Ethcore now uses Rayon 1.0 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8304](https://github.com/paritytech/parity/pull/8304)) +- Upgrader `remove raw unwrap` and bump semver ([#8251](https://github.com/paritytech/parity/pull/8251)) +- Cleaner binary shutdown system ([#8284](https://github.com/paritytech/parity/pull/8284)) +- Ethcore now uses rayon to 0.9 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8302](https://github.com/paritytech/parity/pull/8302)) +- Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) +- Remove evmjit ([#8229](https://github.com/paritytech/parity/pull/8229)) +- Build: fix updater rand dependency in Cargo.lock ([#8298](https://github.com/paritytech/parity/pull/8298)) +- Honor --max-peers if --min-peers is not specified ([#8087](https://github.com/paritytech/parity/pull/8087)) +- Auto-updater improvements ([#8078](https://github.com/paritytech/parity/pull/8078)) +- Dapps-fetcher: calculate keccak in-flight while reading the response ([#8294](https://github.com/paritytech/parity/pull/8294)) +- Cleanup Ellaism bootnodes ([#8276](https://github.com/paritytech/parity/pull/8276)) +- Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) +- Remove RefCell from Header ([#8227](https://github.com/paritytech/parity/pull/8227)) +- Typo fix: todo with no content ([#8292](https://github.com/paritytech/parity/pull/8292)) +- Revert "ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118))" ([#8287](https://github.com/paritytech/parity/pull/8287)) +- Bump ethabi & ethereum-types. ([#8258](https://github.com/paritytech/parity/pull/8258)) +- Allow customization of max WS connections. ([#8257](https://github.com/paritytech/parity/pull/8257)) +- Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) +- Return null number for pending block in eth_getBlockByNumber ([#8281](https://github.com/paritytech/parity/pull/8281)) +- Use constant durations ([#8278](https://github.com/paritytech/parity/pull/8278)) +- Typo fix: Mode doc - RLP should be client ([#8283](https://github.com/paritytech/parity/pull/8283)) +- Eth_uninstallfilter should return false for non-existent filter ([#8280](https://github.com/paritytech/parity/pull/8280)) +- Update `app_dirs` to 1.2.1 ([#8268](https://github.com/paritytech/parity/pull/8268)) +- Add missing license header for runtime.rs ([#8252](https://github.com/paritytech/parity/pull/8252)) +- Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) +- Replace all Rlp usages with UntrustedRlp except for ethcore views ([#8233](https://github.com/paritytech/parity/pull/8233)) +- Add test for ethstore-cli, fixes [#8027](https://github.com/paritytech/parity/issues/8027) ([#8187](https://github.com/paritytech/parity/pull/8187)) +- Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) +- Fixed ethcore tx_filter ([#8200](https://github.com/paritytech/parity/pull/8200)) +- Update CLI help for jsonrpc-apis, ws-apis and ipc-apis ([#8234](https://github.com/paritytech/parity/pull/8234)) +- Remove network stats ([#8225](https://github.com/paritytech/parity/pull/8225)) +- Node-filter does not use ChainNotify ([#8231](https://github.com/paritytech/parity/pull/8231)) +- Implement hardcoded sync in the light client ([#8075](https://github.com/paritytech/parity/pull/8075)) +- Update some of the dependencies for WASM ([#8223](https://github.com/paritytech/parity/pull/8223)) +- Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Updated jsonrpc to point to the 1.11 branch ([#8180](https://github.com/paritytech/parity/pull/8180)) +- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) +- Introduce Parity UI ([#8202](https://github.com/paritytech/parity/pull/8202)) +- Update Changelogs ([#8175](https://github.com/paritytech/parity/pull/8175)) +- Returns number of topcis to take fr.. ([#8199](https://github.com/paritytech/parity/pull/8199)) +- Make docopt usage non-const ([#8189](https://github.com/paritytech/parity/pull/8189)) +- Avoid allocations when computing triehash. ([#8176](https://github.com/paritytech/parity/pull/8176)) +- Handle rlp decoding Result in patricia trie ([#8166](https://github.com/paritytech/parity/pull/8166)) +- Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) +- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) +- Update daemonize ([#8165](https://github.com/paritytech/parity/pull/8165)) +- Some tiny modifications. ([#8163](https://github.com/paritytech/parity/pull/8163)) +- Secretstore: store key author address in db ([#7887](https://github.com/paritytech/parity/pull/7887)) +- Rename DatabaseValueView::new to from_rlp ([#8159](https://github.com/paritytech/parity/pull/8159)) +- Dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) +- Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) +- Fix wasmi x32 builds ([#8155](https://github.com/paritytech/parity/pull/8155)) +- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) +- Secretstore: ability to identify requester via Public/Address ([#7886](https://github.com/paritytech/parity/pull/7886)) +- Optional dependency on secp256k1 for ethcrypto ([#8109](https://github.com/paritytech/parity/pull/8109)) +- Network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) +- Check one step deeper if we're on release track branches ([#8134](https://github.com/paritytech/parity/pull/8134)) +- Explicitly mention pruning_history uses RAM ([#8130](https://github.com/paritytech/parity/pull/8130)) +- Remove `ethcrypto::{en,de}crypt_single_message`. ([#8126](https://github.com/paritytech/parity/pull/8126)) +- Fix typo ([#8124](https://github.com/paritytech/parity/pull/8124)) +- Secret_store: use `ecies::encrypt`/`ecies::decrypt`. ([#8125](https://github.com/paritytech/parity/pull/8125)) +- Fix comment for fn gas() in wasm/runtime ([#8122](https://github.com/paritytech/parity/pull/8122)) +- Structured rlp encoding in journaldb ([#8047](https://github.com/paritytech/parity/pull/8047)) +- Ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118)) +- Fix trace filter returning returning unrelated reward calls, closes [#8070](https://github.com/paritytech/parity/issues/8070) ([#8098](https://github.com/paritytech/parity/pull/8098)) +- Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) +- Replace reqwest with hyper ([#8099](https://github.com/paritytech/parity/pull/8099)) +- More dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) +- Remove the time dependency where possible ([#8100](https://github.com/paritytech/parity/pull/8100)) +- Fix comment for gas extern in Wasm runtime ([#8101](https://github.com/paritytech/parity/pull/8101)) +- Replace std::env::temp_dir with tempdir in tests ([#8103](https://github.com/paritytech/parity/pull/8103)) +- Fix Cargo.lock not parsable ([#8102](https://github.com/paritytech/parity/pull/8102)) +- Additional data in EVMTestClient ([#7964](https://github.com/paritytech/parity/pull/7964)) +- Update serde, serde-derive, ethabi-derive, syn, quote and rlp_derive ([#8085](https://github.com/paritytech/parity/pull/8085)) +- Ethcore-service ([#8089](https://github.com/paritytech/parity/pull/8089)) +- [contract-client] refactor ([#7978](https://github.com/paritytech/parity/pull/7978)) +- Revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) +- Ethcore test::helpers cleanup ([#8086](https://github.com/paritytech/parity/pull/8086)) +- Add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) +- Wasm libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) +- Echo back the message hash of a ping in the pong request ([#8042](https://github.com/paritytech/parity/pull/8042)) +- Add Kovan WASM activation blocknumber ([#8057](https://github.com/paritytech/parity/pull/8057)) +- [ethkey] Unify debug/display for Address/Public/Secret ([#8076](https://github.com/paritytech/parity/pull/8076)) +- Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) +- Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) +- Updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) +- Make blockchain functions more idiomatic, avoid needless writes to cache_man ([#8054](https://github.com/paritytech/parity/pull/8054)) +- Make patricia-trie more idiomatic and remove redundant code ([#8056](https://github.com/paritytech/parity/pull/8056)) +- Abstract devp2p ([#8048](https://github.com/paritytech/parity/pull/8048)) +- Update refs to shell ([#8051](https://github.com/paritytech/parity/pull/8051)) +- Fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) +- Prelude to the block module cleanup ([#8025](https://github.com/paritytech/parity/pull/8025)) +- Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) +- Bump master to 1.11.0 ([#8021](https://github.com/paritytech/parity/pull/8021)) +- `client` refactoring ([#7038](https://github.com/paritytech/parity/pull/7038)) +- [hardware wallet] sleeping -> pollling ([#8018](https://github.com/paritytech/parity/pull/8018)) +- Fixed broken link in README ([#8012](https://github.com/paritytech/parity/pull/8012)) +- Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) +- Add changelog for 1.8.11 stable and 1.9.4 beta ([#8017](https://github.com/paritytech/parity/pull/8017)) +- Fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) +- Extract the hard dependency on rocksdb from the light client ([#8034](https://github.com/paritytech/parity/pull/8034)) +- Fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) +- Fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) +- Ci: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) +- Update ref to new shell ([#8024](https://github.com/paritytech/parity/pull/8024)) ## Previous releases -- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (_stable_) +- [CHANGELOG-1.10](docs/CHANGELOG-1.10.md) (_stable_) +- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (EOL: 2018-05-09) - [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (EOL: 2018-03-22) - [CHANGELOG-1.7](docs/CHANGELOG-1.7.md) (EOL: 2018-01-25) - [CHANGELOG-1.6](docs/CHANGELOG-1.6.md) (EOL: 2017-10-15) diff --git a/docs/CHANGELOG-1.10.md b/docs/CHANGELOG-1.10.md new file mode 100644 index 00000000000..4db8f32bb67 --- /dev/null +++ b/docs/CHANGELOG-1.10.md @@ -0,0 +1,325 @@ +## Parity [v1.10.3](https://github.com/paritytech/parity/releases/tag/v1.10.3) (2018-05-08) + +Parity 1.10.3 marks the first stable release on the 1.10 track. Among others, it improves performance and stability. + +The full list of included changes: + +- Backports ([#8557](https://github.com/paritytech/parity/pull/8557)) + - Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity/pull/8493)) + - Update wasmi to 0.2 + - Update pwasm-utils to 0.1.5 + - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) + - Fetch logs by hash in blockchain database + - Fix tests + - Add unit test for branch block logs fetching + - Add docs that blocks must already be sorted + - Handle branch block cases properly + - typo: empty -> is_empty + - Remove return_empty_if_none by using a closure + - Use BTreeSet to avoid sorting again + - Move is_canon to BlockChain + - typo: pass value by reference + - Use loop and wrap inside blocks to simplify the code + - typo: missed a comment + - Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity/pull/8491)) + - Pass on storage keys even if it is not modified + - typo: account and storage query `to_pod_diff` builds both `touched_addresses` merge and storage keys merge. + - Fix tests + - Use state query directly because of suicided accounts + - Fix a RefCell borrow issue + - Add tests for unmodified storage trace + - Address grumbles + - typo: remove unwanted empty line + - ensure_cached compiles with the original signature + - Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity/pull/8520)) + - Enable WebAssembly and Byzantium for Ellaism + - Fix indentation + - Remove empty lines + - Fix compilation. +- Stabilize 1.10.3 ([#8474](https://github.com/paritytech/parity/pull/8474)) + - Stabelize 1.10 + - Bump stable to 1.10.3 + - Update Gitlab scripts + - Fix snap builds ([#8483](https://github.com/paritytech/parity/pull/8483)) + - Fix docker build ([#8462](https://github.com/paritytech/parity/pull/8462)) + - Use `master` as Docker's `latest` (`beta-release` is not used anymore) + +## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24) + +Parity 1.10.2 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455)) + - Update Parity beta to 1.10.2 + - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) + - Disable 32-bit targets for Gitlab + - Rename Linux pipelines + - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) + - Fix Cargo.lock +- Backports ([#8450](https://github.com/paritytech/parity/pull/8450)) + - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) + - Remove unused app_dirs dependency in CLI + - Use forked app_dirs crate for reverted Windows dir behavior + - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) + - Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) + - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) + - Improve VM executor stack size estimation rules + - Typo: docs add "(Debug build)" comment + - Fix an off by one typo and set minimal stack size + - Use saturating_sub to avoid potential overflow + +## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) + +Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. + +The full list of included changes: + +- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350)) + - Bump beta to 1.10.1 + - Unflag critical release +- Backports ([#8346](https://github.com/paritytech/parity/pull/8346)) + - Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) + - Warp-only sync with warp-after [blocknumber] flag. + - Fix tests. + - Fix configuration tests. + - Rename to warp barrier. + - Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) + - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) + - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) + - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) + - Include suicided accounts in state diff + - Shorten form match -> if let + - Test suicide trace diff in State + - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) + - Replace_home for password_files, reserved_peers and log_file + - Typo: arg_log_file is Option + - Enable UI by default, but only display info page. + - Fix test. + - Fix naming and remove old todo. + - Change "wallet" with "browser UI" +- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205)) + - Change name Wallet -> UI + - Make warning bold +- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132)) +- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220)) + - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) + - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203)) +- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181)) + - Updated jsonrpc to include latest backports + - Update dependencies. + +## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22) + +This is the Parity 1.10.0-beta release! Cool! + +### Disabling the Parity Wallet + +The **Parity Wallet (a.k.a. "UI") is now disabled by default**. We are preparing to split the wallet from the core client. + +To reactivate the parity wallet, you have to run Parity either with `parity --force-ui` (not recommended) or `parity ui` (deprecated) from the command line. Or, if you feel super fancy and want to test our pre-releases of the stand-alone electron wallet, head over to the [Parity-JS repositories and check the releases](https://github.com/Parity-JS/shell/releases). + +Further reading: + +- [Docs: Parity Wallet](https://wiki.parity.io/Parity-Wallet) +- [Docs: How to customize Parity UI?](https://wiki.parity.io/FAQ-Customize-Parity-UI.html) +- [Github: Parity-JS](https://github.com/parity-js) + +### Introducing the Wasm VM + +We are excited to announce support for **Wasm Smart Contracts on Kovan network**. The hard-fork to activate the Wasm-VM will take place on block `6_600_000`. + +To enable Wasm contracts on your custom network, just schedule a `wasmActivationTransition` at your favorite block number (e.g., `42`, `666`, or `0xbada55`). To hack your first Wasm smart contracts in Rust, have a look at the [Parity Wasm Tutorials](https://github.com/paritytech/pwasm-tutorial). + +Further reading: + +- [Docs: WebAssembly (wasm)](https://wiki.parity.io/WebAssembly-Home) +- [Docs: Wasm VM Design](https://wiki.parity.io/WebAssembly-Design) +- [Docs: Wasm tutorials and examples](https://wiki.parity.io/WebAssembly-Links) + +### Empty step messages in PoA + +To **reduce blockchain bloat, proof-of-authority networks can now enable _empty step messages_ which replace empty blocks**. Each step message will be signed and broadcasted by the issuing authorities, and included and rewarded in the next non-empty block. + +To enable empty step messages, set the `emptyStepsTransition` to your favorite block number. You can also specify a maximum number of empty steps with `maximumEmptySteps` in your chain spec. + +### Other noteworthy changes + +We removed the old database migrations from 2016. In case you upgrade Parity from a really, really old version, you will have to reset your database manually first with `parity db kill`. + +We fixed DELEGATECALL `from` and `to` fields, see [#7166](https://github.com/paritytech/parity/issues/7166). + +We reduced the default USD per transaction value to 0.0001. Thanks, @MysticRyuujin! + +The Musicoin chain is now enabled with Byzantium features starting at block `2_222_222`. + +### Overview of all changes included + +The full list of included changes: + +- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) ([#8168](https://github.com/paritytech/parity/pull/8168)) + - Re-enable signer, even with no UI. + - Fix message. +- Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136)) + - Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) + - updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) + - updater: apply exponential backoff after download failure + - updater: reset backoff on new release + - Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) + - Enable code size limit on kovan + - Fix formatting. + - Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) + - Limit ingress connections + - Optimized handshakes logging + - WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) + - update wasmi, parity-wasm, wasm-utils to latest version + - Update to new wasmi & error handling + - also utilize new stack limiter + - fix typo + - replace dependency url + - Cargo.lock update + - add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) + - revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) + - Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)" + - Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))" + - fixed broken logs + - bring back old lock order + - remove migration v13 + - revert CURRENT_VERSION to 12 in migration.rs + - more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) + - Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) + - Use `subtle::slices_equal` for constant time comparison. + - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 + - Test specifically for InvalidPassword error. + - fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098)) + - network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) + - network: init discovery using healthy nodes + - network: fix style grumble + - network: fix typo + - Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) + - ethcore: postpone Kovan hard fork + - util: update version fork metadata + - Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) + - dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) +- Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135)) +- Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053)) + - CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) + - Fix cache + - Only clean locked cargo cache on windows + - fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) + - fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) + - fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) + - fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) + - Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) + - Add test chain spec for musicoin byzantium testnet + - Add MCIP-6 Byzyantium transition to Musicoin spec + - Update mcip6_byz.json + - ethcore: update musicoin byzantium block number + - ethcore: update musicoin bootnodes + - Update musicoin.json + - More bootnodes. +- Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022)) + - Make 1.10 beta + - Fix gitlab builds +- SecretStore: secretstore_generateDocumentKey RPC ([#7864](https://github.com/paritytech/parity/pull/7864)) +- SecretStore: ECDSA session for cases when 2*t < N ([#7739](https://github.com/paritytech/parity/pull/7739)) +- bump tiny-keccak ([#8019](https://github.com/paritytech/parity/pull/8019)) +- Remove un-necessary comment ([#8014](https://github.com/paritytech/parity/pull/8014)) +- clean up account fmt::Debug ([#7983](https://github.com/paritytech/parity/pull/7983)) +- improve quality of vote_collector module ([#7984](https://github.com/paritytech/parity/pull/7984)) +- ExecutedBlock cleanup ([#7991](https://github.com/paritytech/parity/pull/7991)) +- Hardware-wallet/usb-subscribe-refactor ([#7860](https://github.com/paritytech/parity/pull/7860)) +- remove wildcard imports from views, make tests more idiomatic ([#7986](https://github.com/paritytech/parity/pull/7986)) +- moved PerfTimer to a separate crate - "trace-time" ([#7985](https://github.com/paritytech/parity/pull/7985)) +- clean up ethcore::spec module imports ([#7990](https://github.com/paritytech/parity/pull/7990)) +- rpc: don't include current block in new_block_filter ([#7982](https://github.com/paritytech/parity/pull/7982)) +- fix traces, removed bloomchain crate ([#7979](https://github.com/paritytech/parity/pull/7979)) +- simplify compression and move it out of rlp crate ([#7957](https://github.com/paritytech/parity/pull/7957)) +- removed old migrations ([#7974](https://github.com/paritytech/parity/pull/7974)) +- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977)) +- fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934)) +- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965)) +- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953)) +- Add changelog for 1.8.10 stable and 1.9.3 beta ([#7947](https://github.com/paritytech/parity/pull/7947)) +- kvdb-rocksdb: remove buffered operations when committing transaction ([#7950](https://github.com/paritytech/parity/pull/7950)) +- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952)) +- removed redundant Bloom conversions ([#7932](https://github.com/paritytech/parity/pull/7932)) +- simplify RefInfo fmt ([#7929](https://github.com/paritytech/parity/pull/7929)) +- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849)) +- bring back trie and triehash benches ([#7926](https://github.com/paritytech/parity/pull/7926)) +- removed redundant PodAccount::new method ([#7928](https://github.com/paritytech/parity/pull/7928)) +- removed dummy wrapper structure - LogGroupPosition ([#7922](https://github.com/paritytech/parity/pull/7922)) +- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933)) +- simplify Client::filter_traces method ([#7936](https://github.com/paritytech/parity/pull/7936)) +- gitlab cache ([#7921](https://github.com/paritytech/parity/pull/7921)) +- Fix a division by zero in light client RPC handler ([#7917](https://github.com/paritytech/parity/pull/7917)) +- triehash optimisations ([#7920](https://github.com/paritytech/parity/pull/7920)) +- removed redundant Blockchain::db method ([#7919](https://github.com/paritytech/parity/pull/7919)) +- removed redundant Blockchain::rewind method ([#7918](https://github.com/paritytech/parity/pull/7918)) +- Pending transactions subscription ([#7906](https://github.com/paritytech/parity/pull/7906)) +- removed redundant otry! macro from ethcore ([#7916](https://github.com/paritytech/parity/pull/7916)) +- Make block generator easier to use ([#7888](https://github.com/paritytech/parity/pull/7888)) +- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905)) +- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867)) +- Fix gitlab ([#7901](https://github.com/paritytech/parity/pull/7901)) +- Gitlb snap master patch ([#7900](https://github.com/paritytech/parity/pull/7900)) +- fix snap build master ([#7896](https://github.com/paritytech/parity/pull/7896)) +- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873)) +- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884)) +- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848)) +- SecretStore: fixed test ([#7878](https://github.com/paritytech/parity/pull/7878)) +- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846)) +- Forward-port snap fixes ([#7831](https://github.com/paritytech/parity/pull/7831)) +- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883)) +- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881)) +- Fix string typo: "develoopment" -> "development" ([#7874](https://github.com/paritytech/parity/pull/7874)) +- Update the instructions to install the stable snap ([#7876](https://github.com/paritytech/parity/pull/7876)) +- SecretStore: 'broadcast' decryption session ([#7843](https://github.com/paritytech/parity/pull/7843)) +- Flush keyfiles. Resolves #7632 ([#7868](https://github.com/paritytech/parity/pull/7868)) +- Read registry_address from given block ([#7866](https://github.com/paritytech/parity/pull/7866)) +- Clean up docs formatting for Wasm runtime ([#7869](https://github.com/paritytech/parity/pull/7869)) +- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842)) +- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855)) +- ethabi version 5 ([#7723](https://github.com/paritytech/parity/pull/7723)) +- Light client: randomize the peer we dispatch requests to ([#7844](https://github.com/paritytech/parity/pull/7844)) +- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832)) +- Add new EF ropstens nodes. ([#7824](https://github.com/paritytech/parity/pull/7824)) +- refactor stratum to remove retain cycle ([#7827](https://github.com/paritytech/parity/pull/7827)) +- Bump jsonrpc. ([#7828](https://github.com/paritytech/parity/pull/7828)) +- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830)) +- Update references to UI shell & wallet ([#7808](https://github.com/paritytech/parity/pull/7808)) +- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812)) +- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796)) +- SecretStore: ignore removed authorities when running auto-migration ([#7674](https://github.com/paritytech/parity/pull/7674)) +- Fix build ([#7807](https://github.com/paritytech/parity/pull/7807)) +- Move js & js-old code to github.com/parity-js ([#7685](https://github.com/paritytech/parity/pull/7685)) +- More changelogs :) ([#7782](https://github.com/paritytech/parity/pull/7782)) +- Actualized API set in help ([#7790](https://github.com/paritytech/parity/pull/7790)) +- Removed obsolete file ([#7788](https://github.com/paritytech/parity/pull/7788)) +- Update ropsten bootnodes ([#7776](https://github.com/paritytech/parity/pull/7776)) +- CHANGELOG for 1.9.1 and 1.8.8 ([#7775](https://github.com/paritytech/parity/pull/7775)) +- Enable byzantium features on non-ethash chains ([#7753](https://github.com/paritytech/parity/pull/7753)) +- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695)) +- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716)) +- Removes redundant parentheses ([#7721](https://github.com/paritytech/parity/pull/7721)) +- Transaction-pool fixes ([#7741](https://github.com/paritytech/parity/pull/7741)) +- More visible download link in README.md ([#7707](https://github.com/paritytech/parity/pull/7707)) +- Changelog for 1.9.0 ([#7664](https://github.com/paritytech/parity/pull/7664)) +- Add scroll when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677)) +- SecretStore: return HTTP 403 (access denied) if consensus is unreachable ([#7656](https://github.com/paritytech/parity/pull/7656)) +- Moved StopGaurd to it's own crate ([#7635](https://github.com/paritytech/parity/pull/7635)) + +## Previous releases + +- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (_stable_) +- [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (EOL: 2018-03-22) +- [CHANGELOG-1.7](docs/CHANGELOG-1.7.md) (EOL: 2018-01-25) +- [CHANGELOG-1.6](docs/CHANGELOG-1.6.md) (EOL: 2017-10-15) +- [CHANGELOG-1.5](docs/CHANGELOG-1.5.md) (EOL: 2017-07-28) +- [CHANGELOG-1.4](docs/CHANGELOG-1.4.md) (EOL: 2017-03-13) +- [CHANGELOG-1.3](docs/CHANGELOG-1.3.md) (EOL: 2017-01-19) +- [CHANGELOG-1.2](docs/CHANGELOG-1.2.md) (EOL: 2016-11-07) +- [CHANGELOG-1.1](docs/CHANGELOG-1.1.md) (EOL: 2016-08-12) +- [CHANGELOG-1.0](docs/CHANGELOG-1.0.md) (EOL: 2016-06-24) +- [CHANGELOG-0.9](docs/CHANGELOG-0.9.md) (EOL: 2016-05-02) diff --git a/docs/CHANGELOG-1.9.md b/docs/CHANGELOG-1.9.md index 133c93c4770..2be3fcf27b2 100644 --- a/docs/CHANGELOG-1.9.md +++ b/docs/CHANGELOG-1.9.md @@ -1,3 +1,5 @@ +Note: Parity 1.9 reached End-of-Life on 2018-05-09 (EOL). + ## Parity [v1.9.7](https://github.com/paritytech/parity/releases/tag/v1.9.7) (2018-04-23) Parity 1.9.7 is a bug-fix release to improve performance and stability. From f2eaafd1a708382a780c7e24349199e43378c8a5 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 9 May 2018 15:58:02 +0200 Subject: [PATCH 076/147] Handle socket address parsing errors (#8545) Unpack errors and check for io::ErrorKind::InvalidInput and return our own AddressParse error. Remove the foreign link to std::net::AddrParseError and add an `impl From` for that error. Test parsing properly. --- Cargo.lock | 7 ++++ util/network-devp2p/Cargo.toml | 1 + util/network-devp2p/src/lib.rs | 2 ++ util/network-devp2p/src/node_table.rs | 52 ++++++++++++++++++++++----- util/network/src/error.rs | 11 +++++- 5 files changed, 63 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b02fcbd24e5..edd76f9f4de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,11 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "assert_matches" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aster" version = "0.41.0" @@ -699,6 +704,7 @@ name = "ethcore-network-devp2p" version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", @@ -3767,6 +3773,7 @@ dependencies = [ "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "664470abf00fae0f31c0eb6e1ca12d82961b2a2541ef898bc9dd51a9254d218b" "checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index a8207ca615b..3ec96843931 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -38,6 +38,7 @@ error-chain = { version = "0.11", default-features = false } [dev-dependencies] tempdir = "0.3" +assert_matches = "1.2" [features] default = [] diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 8faf21e465c..239763cbe18 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -95,6 +95,8 @@ extern crate serde_derive; #[cfg(test)] extern crate tempdir; +#[cfg(test)] #[macro_use] +extern crate assert_matches; mod host; mod connection; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 5079455866c..8640901cd09 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use discovery::{TableUpdates, NodeEntry}; +use ethereum_types::H512; +use ip_utils::*; +use network::{Error, ErrorKind, AllowIP, IpFilter}; +use rlp::{Rlp, RlpStream, DecoderError}; +use serde_json; use std::collections::{HashMap, HashSet}; use std::fmt::{self, Display, Formatter}; use std::hash::{Hash, Hasher}; @@ -23,12 +29,6 @@ use std::str::FromStr; use std::{fs, mem, slice}; use std::time::{self, Duration, SystemTime}; use rand::{self, Rng}; -use ethereum_types::H512; -use rlp::{Rlp, RlpStream, DecoderError}; -use network::{Error, ErrorKind, AllowIP, IpFilter}; -use discovery::{TableUpdates, NodeEntry}; -use ip_utils::*; -use serde_json; /// Node public key pub type NodeId = H512; @@ -124,8 +124,8 @@ impl FromStr for NodeEndpoint { address: a, udp_port: a.port() }), - Ok(_) => Err(ErrorKind::AddressResolve(None).into()), - Err(e) => Err(ErrorKind::AddressResolve(Some(e)).into()) + Ok(None) => bail!(ErrorKind::AddressResolve(None)), + Err(_) => Err(ErrorKind::AddressParse.into()) // always an io::Error of InvalidInput kind } } } @@ -534,11 +534,34 @@ mod tests { assert!(endpoint.is_ok()); let v4 = match endpoint.unwrap().address { SocketAddr::V4(v4address) => v4address, - _ => panic!("should ve v4 address") + _ => panic!("should be v4 address") }; assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4); } + #[test] + fn endpoint_parse_empty_ip_string_returns_error() { + let endpoint = NodeEndpoint::from_str(""); + assert!(endpoint.is_err()); + assert_matches!(endpoint.unwrap_err().kind(), &ErrorKind::AddressParse); + } + + #[test] + fn endpoint_parse_invalid_ip_string_returns_error() { + let endpoint = NodeEndpoint::from_str("beef"); + assert!(endpoint.is_err()); + assert_matches!(endpoint.unwrap_err().kind(), &ErrorKind::AddressParse); + } + + #[test] + fn endpoint_parse_valid_ip_without_port_returns_error() { + let endpoint = NodeEndpoint::from_str("123.123.123.123"); + assert!(endpoint.is_err()); + assert_matches!(endpoint.unwrap_err().kind(), &ErrorKind::AddressParse); + let endpoint = NodeEndpoint::from_str("123.123.123.123:123"); + assert!(endpoint.is_ok()) + } + #[test] fn node_parse() { assert!(validate_node_url("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").is_none()); @@ -555,6 +578,17 @@ mod tests { node.id); } + #[test] + fn node_parse_fails_for_invalid_urls() { + let node = Node::from_str("foo"); + assert!(node.is_err()); + assert_matches!(node.unwrap_err().kind(), &ErrorKind::AddressParse); + + let node = Node::from_str("enode://foo@bar"); + assert!(node.is_err()); + assert_matches!(node.unwrap_err().kind(), &ErrorKind::AddressParse); + } + #[test] fn table_last_contact_order() { let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 6342bfe4ad6..61044866966 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -84,11 +84,16 @@ error_chain! { foreign_links { SocketIo(IoError) #[doc = "Socket IO error."]; Io(io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; - AddressParse(net::AddrParseError) #[doc = "Error concerning the network address parsing subsystem."]; Decompression(snappy::InvalidInput) #[doc = "Decompression error."]; } errors { + #[doc = "Error concerning the network address parsing subsystem."] + AddressParse { + description("Failed to parse network address"), + display("Failed to parse network address"), + } + #[doc = "Error concerning the network address resolution subsystem."] AddressResolve(err: Option) { description("Failed to resolve network address"), @@ -163,6 +168,10 @@ impl From for Error { } } +impl From for Error { + fn from(_err: net::AddrParseError) -> Self { ErrorKind::AddressParse.into() } +} + #[test] fn test_errors() { assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8)); From 596dc1c4a1e4a2cdbaccc393719701880618ac99 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 10 May 2018 00:41:56 +0800 Subject: [PATCH 077/147] Remove unnecessary cloning in overwrite_with (#8580) * Remove unnecessary cloning in overwrite_with * Remove into_iter --- ethcore/src/state/account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index ff7d70bd3aa..5c1dd403969 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -460,7 +460,7 @@ impl Account { self.address_hash = other.address_hash; let mut cache = self.storage_cache.borrow_mut(); for (k, v) in other.storage_cache.into_inner() { - cache.insert(k.clone() , v.clone()); //TODO: cloning should not be required here + cache.insert(k, v); } self.storage_changes = other.storage_changes; } From a5669aefc6f6132082c1989fc1bc1e0d49567903 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 9 May 2018 23:21:16 +0200 Subject: [PATCH 078/147] changelog nit (#8585) --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c7dcf878be..f839802e7cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ Notable changes in reversed alphabetical order: - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. - All whisper RPC APIs are enabled and can be directly acessed. -I'm not used to writing these changelogs but I guess that would explain it - JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) - This changes the behaviors of `eth_call` to respect VM errors if any. - In case of `REVERT`, it will also return the reverted return data in hex format. From 9748b5364fa27c94f93f2a47c2a885c620ade0be Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 9 May 2018 23:25:58 +0200 Subject: [PATCH 079/147] Rename `whisper-cli binary` to `whisper` (#8579) * rename whisper-cli binary to whisper * fix tests --- whisper/cli/Cargo.toml | 4 +++- whisper/cli/src/main.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/whisper/cli/Cargo.toml b/whisper/cli/Cargo.toml index 363471a1a34..9aea1a8776e 100644 --- a/whisper/cli/Cargo.toml +++ b/whisper/cli/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "whisper-cli" +description = "Whisper command line interface" version = "0.1.0" authors = ["Parity Technologies "] +license = "GPL-3.0" [dependencies] ethcore-network-devp2p = { path = "../../util/network-devp2p" } @@ -18,5 +20,5 @@ jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branc log = "0.3" [[bin]] -name = "whisper-cli" +name = "whisper" path = "src/main.rs" diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index d0866cd66a8..f9211b993b4 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -46,7 +46,7 @@ use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation}; const POOL_UNIT: usize = 1024 * 1024; const USAGE: &'static str = r#" Whisper CLI. - Copyright 2017 Parity Technologies (UK) Ltd + Copyright 2018 Parity Technologies (UK) Ltd Usage: whisper [options] @@ -56,7 +56,7 @@ Options: --whisper-pool-size SIZE Specify Whisper pool size [default: 10]. -p, --port PORT Specify which RPC port to use [default: 8545]. -a, --address ADDRESS Specify which address to use [default: 127.0.0.1]. - -l, --log LEVEL Specify the logging level. Must conform to the same format as RUST_LOG [default: Error]. + -l, --log LEVEL Specify the logging level. Must conform to the same format as RUST_LOG [default: Error]. -h, --help Display this message and exit. "#; @@ -259,7 +259,7 @@ mod tests { #[test] fn invalid_argument() { - let command = vec!["whisper-cli", "--foo=12"] + let command = vec!["whisper", "--foo=12"] .into_iter() .map(Into::into) .collect::>(); @@ -270,7 +270,7 @@ mod tests { #[test] #[ignore] fn privileged_port() { - let command = vec!["whisper-cli", "--port=3"] + let command = vec!["whisper", "--port=3"] .into_iter() .map(Into::into) .collect::>(); @@ -280,7 +280,7 @@ mod tests { #[test] fn invalid_ip_address() { - let command = vec!["whisper-cli", "--address=x.x.x.x"] + let command = vec!["whisper", "--address=x.x.x.x"] .into_iter() .map(Into::into) .collect::>(); @@ -290,7 +290,7 @@ mod tests { #[test] fn invalid_whisper_pool_size() { - let command = vec!["whisper-cli", "--whisper-pool-size=-100000000000000000000000000000000000000"] + let command = vec!["whisper", "--whisper-pool-size=-100000000000000000000000000000000000000"] .into_iter() .map(Into::into) .collect::>(); From 152a5b8831cacc93bc3b527bf170335845185418 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 9 May 2018 23:26:30 +0200 Subject: [PATCH 080/147] Add whisper CLI to the pipelines (#8578) * Add whisper CLI to the pipelines * Address todo, ref #8579 --- scripts/gitlab-build.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/gitlab-build.sh b/scripts/gitlab-build.sh index 89fa2a08541..2f1b7b8d086 100755 --- a/scripts/gitlab-build.sh +++ b/scripts/gitlab-build.sh @@ -62,13 +62,16 @@ build () { cargo build --target $PLATFORM --release -p ethstore-cli echo "Build ethkey-cli:" cargo build --target $PLATFORM --release -p ethkey-cli + echo "Build whisper-cli:" + cargo build --target $PLATFORM --release -p whisper-cli } strip_binaries () { echo "Strip binaries:" $STRIP_BIN -v target/$PLATFORM/release/parity $STRIP_BIN -v target/$PLATFORM/release/parity-evm $STRIP_BIN -v target/$PLATFORM/release/ethstore - $STRIP_BIN -v target/$PLATFORM/release/ethkey; + $STRIP_BIN -v target/$PLATFORM/release/ethkey + $STRIP_BIN -v target/$PLATFORM/release/whisper; } calculate_checksums () { echo "Checksum calculation:" @@ -89,6 +92,8 @@ calculate_checksums () { $SHA256_BIN target/$PLATFORM/release/ethstore$S3WIN > ethstore$S3WIN.sha256 $MD5_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.md5 $SHA256_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.sha256 + $MD5_BIN target/$PLATFORM/release/whisper$S3WIN > whisper$S3WIN.md5 + $SHA256_BIN target/$PLATFORM/release/whisper$S3WIN > whisper$S3WIN.sha256 } make_deb () { rm -rf deb @@ -122,6 +127,7 @@ make_deb () { cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey + cp target/$PLATFORM/release/whisper deb/usr/bin/whisper dpkg-deb -b deb "parity_"$VER"_"$IDENT"_"$ARC".deb" $MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.md5" $SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.sha256" @@ -133,6 +139,7 @@ make_rpm () { cp target/$PLATFORM/release/parity-evm /install/usr/bin/parity-evm cp target/$PLATFORM/release/ethstore /install/usr/bin/ethstore cp target/$PLATFORM/release/ethkey /install/usr/bin/ethkey + cp target/$PLATFORM/release/whisper /install/usr/bin/whisper rm -rf "parity-"$VER"-1."$ARC".rpm" || true fpm -s dir -t rpm -n parity -v $VER --epoch 1 --license GPLv3 -d openssl --provides parity --url https://parity.io --vendor "Parity Technologies" -a x86_64 -m "" --description "Ethereum network client by Parity Technologies" -C /install/ @@ -146,6 +153,7 @@ make_pkg () { cp target/$PLATFORM/release/parity-evm target/release/parity-evm cp target/$PLATFORM/release/ethstore target/release/ethstore cp target/$PLATFORM/release/ethkey target/release/ethkey + cp target/$PLATFORM/release/whisper target/release/whisper cd mac xcodebuild -configuration Release cd .. @@ -194,6 +202,9 @@ push_binaries () { aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN --body target/$PLATFORM/release/ethkey$S3WIN aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.md5 --body ethkey$S3WIN.md5 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.sha256 --body ethkey$S3WIN.sha256 + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN --body target/$PLATFORM/release/whisper$S3WIN + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN.md5 --body whisper$S3WIN.md5 + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN.sha256 --body whisper$S3WIN.sha256 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" @@ -201,7 +212,7 @@ push_binaries () { make_archive () { echo "add artifacts to archive" rm -rf parity.zip - zip -r parity.zip target/$PLATFORM/release/parity$S3WIN target/$PLATFORM/release/parity-evm$S3WIN target/$PLATFORM/release/ethstore$S3WIN target/$PLATFORM/release/ethkey$S3WIN parity$S3WIN.md5 parity-evm$S3WIN.md5 ethstore$S3WIN.md5 ethkey$S3WIN.md5 parity$S3WIN.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256 + zip -r parity.zip target/$PLATFORM/release/parity$S3WIN target/$PLATFORM/release/parity-evm$S3WIN target/$PLATFORM/release/ethstore$S3WIN target/$PLATFORM/release/ethkey$S3WIN target/$PLATFORM/release/whisper$S3WIN parity$S3WIN.md5 parity-evm$S3WIN.md5 ethstore$S3WIN.md5 ethkey$S3WIN.md5 whisper$S3WIN.md5 parity$S3WIN.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256 whisper$S3WIN.sha256 } updater_push_release () { From 455eead3b0a58c483702328f6c7e5950781b9cc9 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 9 May 2018 23:28:16 +0200 Subject: [PATCH 081/147] Added Dockerfile for alpine linux by @andresilva, closes #3565 (#8587) --- docker/alpine/Dockerfile | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 docker/alpine/Dockerfile diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile new file mode 100644 index 00000000000..ad8879ecf73 --- /dev/null +++ b/docker/alpine/Dockerfile @@ -0,0 +1,29 @@ +FROM alpine:3.7 + +WORKDIR /build + +# install tools and dependencies +RUN apk add --no-cache gcc musl-dev openssl-dev pkgconfig g++ make curl \ + eudev-dev rust cargo git file binutils libusb-dev \ + linux-headers + +# show backtraces +ENV RUST_BACKTRACE 1 + +# show tools +RUN rustc -vV && \ +cargo -V && \ +gcc -v &&\ +g++ -v + +# build parity +ADD . /build/parity +RUN cd parity && \ + cargo build --release --verbose && \ + ls /build/parity/target/release/parity && \ + strip /build/parity/target/release/parity + +RUN file /build/parity/target/release/parity + +EXPOSE 8080 8545 8180 +ENTRYPOINT ["/build/parity/target/release/parity"] From 7701b64fd97a136705bd8699ad0e2678b4d6ae3b Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Thu, 10 May 2018 12:33:40 +0200 Subject: [PATCH 082/147] Changelog and Readme (#8591) * Move changelog for 1.10.x * Mark 1.9 EOL * Prepare changelog for 1.10.3 stable * Prepare changelog for 1.11.0 stable * Update changelogs * Update CHANGELOG for 1.10.3 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Format changelog * Update README for 1.11 * Fix typo --- README.md | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index bfa7bde7bf6..36e855fe420 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,7 @@ Get in touch with us on Gitter: Or join our community on Matrix: [![Riot: +Parity](https://img.shields.io/badge/riot-%2Bparity%3Amatrix.parity.io-orange.svg)](https://riot.im/app/#/group/+parity:matrix.parity.io) -Official website: https://parity.io - -Be sure to check out [our wiki](https://wiki.parity.io) for more information. +Official website: https://parity.io | Be sure to check out [our wiki](https://wiki.parity.io) for more information. ---- @@ -29,28 +27,19 @@ Be sure to check out [our wiki](https://wiki.parity.io) for more information. Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. -Parity comes with a built-in wallet, to install it please follow [these instructions](https://wiki.parity.io/Parity-Wallet). It includes various functionality allowing you to: - -- create and manage your Ethereum accounts; -- manage your Ether and any Ethereum tokens; -- create and register your own tokens; -- and much more. - -From Parity Ethereum client version >=1.10, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want). +From Parity Ethereum client version 1.10.0, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want). By default, Parity will also run a JSONRPC server on `127.0.0.1:8545` and a websockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs. -If you run into an issue while using Parity, feel free to file one in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! - -**For security-critical issues**, please refer to the security policy outlined in [SECURITY.MD](SECURITY.md). +If you run into an issue while using Parity, feel free to file one in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! **For security-critical issues**, please refer to the security policy outlined in [SECURITY.MD](SECURITY.md). -Parity's current release is 1.9. You can download it at https://github.com/paritytech/parity/releases or follow the instructions below to build from source. +Parity's current beta-release is 1.11. You can download it at https://github.com/paritytech/parity/releases or follow the instructions below to build from source. ---- ## Build dependencies -**Parity requires Rust version 1.23.0 to build** +**Parity requires Rust version 1.26.0 to build** We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this: @@ -124,13 +113,7 @@ Note: if cargo fails to parse manifest try: $ ~/.cargo/bin/cargo build --release ``` -Note: When compiling a crate and you receive the following error: - -``` -error: the crate is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` -``` - -Cleaning the repository will most likely solve the issue, try: +Note, when compiling a crate and you receive errors, it's in most cases your outdated version of Rust, or some of your crates have to be recompiled. Cleaning the repository will most likely solve the issue if you are on the latest stable version of Rust, try: ```bash $ cargo clean From 17e2a25ef3f8d78ac228a79cd05fb4715e147437 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 10 May 2018 12:33:56 +0200 Subject: [PATCH 083/147] Attempt to fix intermittent test failures (#8584) Occasionally should_return_correct_nonces_when_dropped_because_of_limit fails, possibly because of multiple threads competing to finish. See CI logs here for an example: https://gitlab.parity.io/parity/parity/-/jobs/86738 --- miner/src/pool/tests/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 0d8e38a6e11..5d80c2d5bf6 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -63,8 +63,10 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() { let nonce = tx1.nonce; // when - let result = txq.import(TestClient::new(), vec![tx1, tx2].local()); - assert_eq!(result, vec![Ok(()), Err(transaction::Error::LimitReached)]); + let r1= txq.import(TestClient::new(), vec![tx1].local()); + let r2= txq.import(TestClient::new(), vec![tx2].local()); + assert_eq!(r1, vec![Ok(())]); + assert_eq!(r2, vec![Err(transaction::Error::LimitReached)]); assert_eq!(txq.status().status.transaction_count, 1); // then From 5c65cabd331e4198a6b1b61275caaf34c7c420ac Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 10 May 2018 12:34:36 +0200 Subject: [PATCH 084/147] Make mio optional in ethcore-io (#8537) * Make mio optional in ethcore-io * Add some annotations, plus a check for features * Increase timer for test --- Cargo.lock | 46 ++- ethcore/sync/Cargo.toml | 1 + test.sh | 2 + util/io/Cargo.toml | 9 +- util/io/src/lib.rs | 145 +++++++-- util/io/src/{service.rs => service_mio.rs} | 16 +- util/io/src/service_non_mio.rs | 334 +++++++++++++++++++++ util/io/src/worker.rs | 11 +- util/network-devp2p/Cargo.toml | 2 +- 9 files changed, 508 insertions(+), 58 deletions(-) rename util/io/src/{service.rs => service_mio.rs} (97%) create mode 100644 util/io/src/service_non_mio.rs diff --git a/Cargo.lock b/Cargo.lock index edd76f9f4de..b4d6bd315f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -209,6 +209,16 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "chrono" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cid" version = "0.2.3" @@ -542,7 +552,7 @@ dependencies = [ "memory-cache 0.1.0", "memorydb 0.1.1", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-machine 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", @@ -597,10 +607,14 @@ name = "ethcore-io" version = "1.12.0" dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -991,7 +1005,7 @@ dependencies = [ "dir 0.1.0", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethstore 0.2.0", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1117,7 +1131,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1483,7 +1497,7 @@ dependencies = [ "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)", @@ -1888,7 +1902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1981,7 +1995,7 @@ dependencies = [ "migration-rocksdb 0.1.0", "node-filter 1.12.0", "node-health 0.1.0", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parity-dapps 1.12.0", @@ -2680,7 +2694,7 @@ dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3183,7 +3197,7 @@ name = "threadpool" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3197,6 +3211,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "timer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tiny-keccak" version = "1.4.1" @@ -3350,7 +3372,7 @@ dependencies = [ "crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3795,6 +3817,7 @@ dependencies = [ "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" "checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" @@ -3903,7 +3926,7 @@ dependencies = [ "checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" -"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" +"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902" "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efa535d5117d3661134dbf1719b6f0ffe06f2375843b13935db186cd094105eb" @@ -4001,6 +4024,7 @@ dependencies = [ "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" +"checksum timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b" "checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" "checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index ba03075d0e3..cf163cc7bd5 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -34,6 +34,7 @@ trace-time = { path = "../../util/trace-time" } ipnetwork = "0.12.6" [dev-dependencies] +ethcore-io = { path = "../../util/io", features = ["mio"] } ethkey = { path = "../../ethkey" } kvdb-memorydb = { path = "../../util/kvdb-memorydb" } ethcore-private-tx = { path = "../private-tx" } diff --git a/test.sh b/test.sh index 6dcd258ea36..9bb527b7083 100755 --- a/test.sh +++ b/test.sh @@ -33,6 +33,8 @@ if [ "$VALIDATE" -eq "1" ]; then # Validate --no-default-features build echo "________Validate build________" cargo check --no-default-features +cargo check --manifest-path util/io/Cargo.toml --no-default-features +cargo check --manifest-path util/io/Cargo.toml --features "mio" # Validate chainspecs echo "________Validate chainspecs________" diff --git a/util/io/Cargo.toml b/util/io/Cargo.toml index 8538863d03e..71688661605 100644 --- a/util/io/Cargo.toml +++ b/util/io/Cargo.toml @@ -7,9 +7,12 @@ version = "1.12.0" authors = ["Parity Technologies "] [dependencies] -mio = "0.6.8" +fnv = "1.0" +mio = { version = "0.6.8", optional = true } crossbeam = "0.3" parking_lot = "0.5" log = "0.3" -slab = "0.2" - +slab = "0.4" +num_cpus = "1.8" +timer = "0.2" +time = "0.1" diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index 9232b2a909a..ef8c3adc7ec 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -54,30 +54,59 @@ //! // Drop the service //! } //! ``` +//! +//! # Mio vs non-mio +//! +//! This library has two modes: mio and not mio. The `mio` feature can be activated or deactivated +//! when compiling or depending on the library. +//! +//! Without mio, only timers and message-passing are available. With mio, you can also use +//! low-level sockets provided by mio. +//! +//! The non-mio mode exists because the `mio` library doesn't compile on platforms such as +//! emscripten. //TODO: use Poll from mio #![allow(deprecated)] +#[cfg(feature = "mio")] extern crate mio; #[macro_use] extern crate log as rlog; extern crate slab; extern crate crossbeam; extern crate parking_lot; +extern crate num_cpus; +extern crate timer; +extern crate fnv; +extern crate time; -mod service; +#[cfg(feature = "mio")] +mod service_mio; +#[cfg(not(feature = "mio"))] +mod service_non_mio; +#[cfg(feature = "mio")] mod worker; +use std::cell::Cell; use std::{fmt, error}; +#[cfg(feature = "mio")] use mio::deprecated::{EventLoop, NotifyError}; +#[cfg(feature = "mio")] use mio::Token; -pub use worker::LOCAL_STACK_SIZE; +thread_local! { + /// Stack size + /// Should be modified if it is changed in Rust since it is no way + /// to know or get it + pub static LOCAL_STACK_SIZE: Cell = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024)); +} #[derive(Debug)] /// IO Error pub enum IoError { /// Low level error from mio crate + #[cfg(feature = "mio")] Mio(::std::io::Error), /// Error concerning the Rust standard library's IO subsystem. StdIo(::std::io::Error), @@ -88,6 +117,7 @@ impl fmt::Display for IoError { // just defer to the std implementation for now. // we can refine the formatting when more variants are added. match *self { + #[cfg(feature = "mio")] IoError::Mio(ref std_err) => std_err.fmt(f), IoError::StdIo(ref std_err) => std_err.fmt(f), } @@ -106,8 +136,9 @@ impl From<::std::io::Error> for IoError { } } -impl From>> for IoError where Message: Send { - fn from(_err: NotifyError>) -> IoError { +#[cfg(feature = "mio")] +impl From>> for IoError where Message: Send { + fn from(_err: NotifyError>) -> IoError { IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error")) } } @@ -123,58 +154,120 @@ pub trait IoHandler: Send + Sync where Message: Send + Sync + 'static { /// Called when a broadcasted message is received. The message can only be sent from a different IO handler. fn message(&self, _io: &IoContext, _message: &Message) {} /// Called when an IO stream gets closed + #[cfg(feature = "mio")] fn stream_hup(&self, _io: &IoContext, _stream: StreamToken) {} /// Called when an IO stream can be read from + #[cfg(feature = "mio")] fn stream_readable(&self, _io: &IoContext, _stream: StreamToken) {} /// Called when an IO stream can be written to + #[cfg(feature = "mio")] fn stream_writable(&self, _io: &IoContext, _stream: StreamToken) {} /// Register a new stream with the event loop + #[cfg(feature = "mio")] fn register_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop>) {} /// Re-register a stream with the event loop + #[cfg(feature = "mio")] fn update_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop>) {} /// Deregister a stream. Called whenstream is removed from event loop + #[cfg(feature = "mio")] fn deregister_stream(&self, _stream: StreamToken, _event_loop: &mut EventLoop>) {} } -pub use service::TimerToken; -pub use service::StreamToken; -pub use service::IoContext; -pub use service::IoService; -pub use service::IoChannel; -pub use service::IoManager; -pub use service::TOKENS_PER_HANDLER; +#[cfg(feature = "mio")] +pub use service_mio::{TimerToken, StreamToken, IoContext, IoService, IoChannel, IoManager, TOKENS_PER_HANDLER}; +#[cfg(not(feature = "mio"))] +pub use service_non_mio::{TimerToken, IoContext, IoService, IoChannel, TOKENS_PER_HANDLER}; #[cfg(test)] mod tests { - use std::sync::Arc; + use std::sync::atomic; + use std::thread; use std::time::Duration; use super::*; - struct MyHandler; + #[test] + fn send_message_to_handler() { + struct MyHandler(atomic::AtomicBool); - #[derive(Clone)] - struct MyMessage { - data: u32 - } + #[derive(Clone)] + struct MyMessage { + data: u32 + } - impl IoHandler for MyHandler { - fn initialize(&self, io: &IoContext) { - io.register_timer(0, Duration::from_secs(1)).unwrap(); + impl IoHandler for MyHandler { + fn message(&self, _io: &IoContext, message: &MyMessage) { + assert_eq!(message.data, 5); + self.0.store(true, atomic::Ordering::SeqCst); + } } - fn timeout(&self, _io: &IoContext, timer: TimerToken) { - println!("Timeout {}", timer); + let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false))); + + let service = IoService::::start().expect("Error creating network service"); + service.register_handler(handler.clone()).unwrap(); + + service.send_message(MyMessage { data: 5 }).unwrap(); + + thread::sleep(Duration::from_secs(5)); + assert!(handler.0.load(atomic::Ordering::SeqCst)); + } + + #[test] + fn timeout_working() { + struct MyHandler(atomic::AtomicBool); + + #[derive(Clone)] + struct MyMessage { + data: u32 } - fn message(&self, _io: &IoContext, message: &MyMessage) { - println!("Message {}", message.data); + impl IoHandler for MyHandler { + fn initialize(&self, io: &IoContext) { + io.register_timer_once(1234, Duration::from_millis(500)).unwrap(); + } + + fn timeout(&self, _io: &IoContext, timer: TimerToken) { + assert_eq!(timer, 1234); + assert!(!self.0.swap(true, atomic::Ordering::SeqCst)); + } } + + let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false))); + + let service = IoService::::start().expect("Error creating network service"); + service.register_handler(handler.clone()).unwrap(); + + thread::sleep(Duration::from_secs(2)); + assert!(handler.0.load(atomic::Ordering::SeqCst)); } #[test] - fn test_service_register_handler () { + fn multi_timeout_working() { + struct MyHandler(atomic::AtomicUsize); + + #[derive(Clone)] + struct MyMessage { + data: u32 + } + + impl IoHandler for MyHandler { + fn initialize(&self, io: &IoContext) { + io.register_timer(1234, Duration::from_millis(500)).unwrap(); + } + + fn timeout(&self, _io: &IoContext, timer: TimerToken) { + assert_eq!(timer, 1234); + self.0.fetch_add(1, atomic::Ordering::SeqCst); + } + } + + let handler = Arc::new(MyHandler(atomic::AtomicUsize::new(0))); + let service = IoService::::start().expect("Error creating network service"); - service.register_handler(Arc::new(MyHandler)).unwrap(); + service.register_handler(handler.clone()).unwrap(); + + thread::sleep(Duration::from_secs(2)); + assert!(handler.0.load(atomic::Ordering::SeqCst) >= 2); } } diff --git a/util/io/src/service.rs b/util/io/src/service_mio.rs similarity index 97% rename from util/io/src/service.rs rename to util/io/src/service_mio.rs index 0de674ae121..f7c9f1976cf 100644 --- a/util/io/src/service.rs +++ b/util/io/src/service_mio.rs @@ -181,7 +181,7 @@ struct UserTimer { /// Root IO handler. Manages user handlers, messages and IO timers. pub struct IoManager where Message: Send + Sync { timers: Arc>>, - handlers: Arc>, HandlerId>>>, + handlers: Arc>>>>, workers: Vec, worker_channel: chase_lev::Worker>, work_ready: Arc, @@ -191,7 +191,7 @@ impl IoManager where Message: Send + Sync + 'static { /// Creates a new instance and registers it with the event loop. pub fn start( event_loop: &mut EventLoop>, - handlers: Arc>, HandlerId>>> + handlers: Arc>>>> ) -> Result<(), IoError> { let (worker, stealer) = chase_lev::deque(); let num_workers = 4; @@ -267,7 +267,8 @@ impl Handler for IoManager where Message: Send + Sync + 'stati event_loop.shutdown(); }, IoMessage::AddHandler { handler } => { - let handler_id = self.handlers.write().insert(handler.clone()).unwrap_or_else(|_| panic!("Too many handlers registered")); + let handler_id = self.handlers.write().insert(handler.clone()); + assert!(handler_id <= MAX_HANDLERS, "Too many handlers registered"); handler.initialize(&IoContext::new(IoChannel::new(event_loop.channel(), Arc::downgrade(&self.handlers)), handler_id)); }, IoMessage::RemoveHandler { handler_id } => { @@ -332,7 +333,7 @@ impl Handler for IoManager where Message: Send + Sync + 'stati } enum Handlers where Message: Send { - SharedCollection(Weak>, HandlerId>>>), + SharedCollection(Weak>>>>), Single(Weak>), } @@ -417,7 +418,7 @@ impl IoChannel where Message: Send + Sync + 'static { handlers: Handlers::Single(handler), } } - fn new(channel: Sender>, handlers: Weak>, HandlerId>>>) -> IoChannel { + fn new(channel: Sender>, handlers: Weak>>>>) -> IoChannel { IoChannel { channel: Some(channel), handlers: Handlers::SharedCollection(handlers), @@ -430,7 +431,7 @@ impl IoChannel where Message: Send + Sync + 'static { pub struct IoService where Message: Send + Sync + 'static { thread: Mutex>>, host_channel: Mutex>>, - handlers: Arc>, HandlerId>>>, + handlers: Arc>>>>, } impl IoService where Message: Send + Sync + 'static { @@ -440,7 +441,7 @@ impl IoService where Message: Send + Sync + 'static { config.messages_per_tick(1024); let mut event_loop = config.build().expect("Error creating event loop"); let channel = event_loop.channel(); - let handlers = Arc::new(RwLock::new(Slab::new(MAX_HANDLERS))); + let handlers = Arc::new(RwLock::new(Slab::with_capacity(MAX_HANDLERS))); let h = handlers.clone(); let thread = thread::spawn(move || { IoManager::::start(&mut event_loop, h).expect("Error starting IO service"); @@ -491,4 +492,3 @@ impl Drop for IoService where Message: Send + Sync { self.stop() } } - diff --git a/util/io/src/service_non_mio.rs b/util/io/src/service_non_mio.rs new file mode 100644 index 00000000000..22a795e4e8d --- /dev/null +++ b/util/io/src/service_non_mio.rs @@ -0,0 +1,334 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::{Arc, Weak}; +use std::thread; +use crossbeam::sync::chase_lev; +use slab::Slab; +use fnv::FnvHashMap; +use {IoError, IoHandler}; +use parking_lot::{RwLock, Mutex}; +use num_cpus; +use std::time::Duration; +use timer::{Timer, Guard as TimerGuard}; +use time::Duration as TimeDuration; + +/// Timer ID +pub type TimerToken = usize; +/// IO Handler ID +pub type HandlerId = usize; + +/// Maximum number of tokens a handler can use +pub const TOKENS_PER_HANDLER: usize = 16384; +const MAX_HANDLERS: usize = 8; + +/// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem. +pub struct IoContext where Message: Send + Sync + 'static { + handler: HandlerId, + shared: Arc>, +} + +impl IoContext where Message: Send + Sync + 'static { + /// Register a new recurring IO timer. 'IoHandler::timeout' will be called with the token. + pub fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { + let channel = self.channel(); + + let msg = WorkTask::TimerTrigger { + handler_id: self.handler, + token: token, + }; + + let delay = TimeDuration::from_std(delay) + .map_err(|e| ::std::io::Error::new(::std::io::ErrorKind::Other, e))?; + let guard = self.shared.timer.lock().schedule_repeating(delay, move || { + channel.send_raw(msg.clone()); + }); + + self.shared.timers.lock().insert(token, guard); + + Ok(()) + } + + /// Register a new IO timer once. 'IoHandler::timeout' will be called with the token. + pub fn register_timer_once(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { + let channel = self.channel(); + + let msg = WorkTask::TimerTrigger { + handler_id: self.handler, + token: token, + }; + + let delay = TimeDuration::from_std(delay) + .map_err(|e| ::std::io::Error::new(::std::io::ErrorKind::Other, e))?; + let guard = self.shared.timer.lock().schedule_with_delay(delay, move || { + channel.send_raw(msg.clone()); + }); + + self.shared.timers.lock().insert(token, guard); + + Ok(()) + } + + /// Delete a timer. + pub fn clear_timer(&self, token: TimerToken) -> Result<(), IoError> { + self.shared.timers.lock().remove(&token); + Ok(()) + } + + /// Broadcast a message to other IO clients + pub fn message(&self, message: Message) -> Result<(), IoError> { + if let Some(ref channel) = *self.shared.channel.lock() { + channel.push(WorkTask::UserMessage(Arc::new(message))); + } + for thread in self.shared.threads.read().iter() { + thread.unpark(); + } + + Ok(()) + } + + /// Get message channel + pub fn channel(&self) -> IoChannel { + IoChannel { shared: Arc::downgrade(&self.shared) } + } + + /// Unregister current IO handler. + pub fn unregister_handler(&self) -> Result<(), IoError> { + self.shared.handlers.write().remove(self.handler); + Ok(()) + } +} + +/// Allows sending messages into the event loop. All the IO handlers will get the message +/// in the `message` callback. +pub struct IoChannel where Message: Send + Sync + 'static { + shared: Weak>, +} + +impl Clone for IoChannel where Message: Send + Sync + 'static { + fn clone(&self) -> IoChannel { + IoChannel { + shared: self.shared.clone(), + } + } +} + +impl IoChannel where Message: Send + Sync + 'static { + /// Send a message through the channel + pub fn send(&self, message: Message) -> Result<(), IoError> { + if let Some(shared) = self.shared.upgrade() { + match *shared.channel.lock() { + Some(ref channel) => channel.push(WorkTask::UserMessage(Arc::new(message))), + None => self.send_sync(message)? + }; + + for thread in shared.threads.read().iter() { + thread.unpark(); + } + } + + Ok(()) + } + + /// Send a message through the channel and handle it synchronously + pub fn send_sync(&self, message: Message) -> Result<(), IoError> { + if let Some(shared) = self.shared.upgrade() { + for id in 0 .. MAX_HANDLERS { + if let Some(h) = shared.handlers.read().get(id) { + let handler = h.clone(); + let ctxt = IoContext { handler: id, shared: shared.clone() }; + handler.message(&ctxt, &message); + } + } + } + + Ok(()) + } + + // Send low level io message + fn send_raw(&self, message: WorkTask) { + if let Some(shared) = self.shared.upgrade() { + if let Some(ref channel) = *shared.channel.lock() { + channel.push(message); + } + + for thread in shared.threads.read().iter() { + thread.unpark(); + } + } + } + + /// Create a new channel disconnected from an event loop. + pub fn disconnected() -> IoChannel { + IoChannel { + shared: Weak::default(), + } + } +} + +/// General IO Service. Starts an event loop and dispatches IO requests. +/// 'Message' is a notification message type +pub struct IoService where Message: Send + Sync + 'static { + thread_joins: Mutex>>, + shared: Arc>, +} + +// Struct shared throughout the whole implementation. +struct Shared where Message: Send + Sync + 'static { + // All the I/O handlers that have been registered. + handlers: RwLock>>>, + // All the background threads, so that we can unpark them. + threads: RwLock>, + // Used to create timeouts. + timer: Mutex, + // List of created timers. We need to keep them in a data struct so that we can cancel them if + // necessary. + timers: Mutex>, + // Channel used to send work to the worker threads. + channel: Mutex>>>, +} + +// Messages used to communicate with the event loop from other threads. +enum WorkTask where Message: Send + Sized { + Shutdown, + TimerTrigger { + handler_id: HandlerId, + token: TimerToken, + }, + UserMessage(Arc) +} + +impl Clone for WorkTask where Message: Send + Sized { + fn clone(&self) -> WorkTask { + match *self { + WorkTask::Shutdown => WorkTask::Shutdown, + WorkTask::TimerTrigger { handler_id, token } => WorkTask::TimerTrigger { handler_id, token }, + WorkTask::UserMessage(ref msg) => WorkTask::UserMessage(msg.clone()), + } + } +} + +impl IoService where Message: Send + Sync + 'static { + /// Starts IO event loop + pub fn start() -> Result, IoError> { + let (tx, rx) = chase_lev::deque(); + + let shared = Arc::new(Shared { + handlers: RwLock::new(Slab::with_capacity(MAX_HANDLERS)), + threads: RwLock::new(Vec::new()), + timer: Mutex::new(Timer::new()), + timers: Mutex::new(FnvHashMap::default()), + channel: Mutex::new(Some(tx)), + }); + + let thread_joins = (0 .. num_cpus::get()).map(|_| { + let rx = rx.clone(); + let shared = shared.clone(); + thread::spawn(move || { + do_work(&shared, rx) + }) + }).collect::>(); + + *shared.threads.write() = thread_joins.iter().map(|t| t.thread().clone()).collect(); + + Ok(IoService { + thread_joins: Mutex::new(thread_joins), + shared, + }) + } + + /// Stops the IO service. + pub fn stop(&self) { + trace!(target: "shutdown", "[IoService] Closing..."); + // Clear handlers so that shared pointers are not stuck on stack + // in Channel::send_sync + self.shared.handlers.write().clear(); + let channel = self.shared.channel.lock().take(); + let mut thread_joins = self.thread_joins.lock(); + if let Some(channel) = channel { + for _ in 0 .. thread_joins.len() { + channel.push(WorkTask::Shutdown); + } + } + for thread in thread_joins.drain(..) { + thread.thread().unpark(); + thread.join().unwrap_or_else(|e| { + debug!(target: "shutdown", "Error joining IO service worker thread: {:?}", e); + }); + } + trace!(target: "shutdown", "[IoService] Closed."); + } + + /// Register an IO handler with the event loop. + pub fn register_handler(&self, handler: Arc+Send>) -> Result<(), IoError> { + let id = self.shared.handlers.write().insert(handler.clone()); + assert!(id <= MAX_HANDLERS, "Too many handlers registered"); + let ctxt = IoContext { handler: id, shared: self.shared.clone() }; + handler.initialize(&ctxt); + Ok(()) + } + + /// Send a message over the network. Normaly `HostIo::send` should be used. This can be used from non-io threads. + pub fn send_message(&self, message: Message) -> Result<(), IoError> { + if let Some(ref channel) = *self.shared.channel.lock() { + channel.push(WorkTask::UserMessage(Arc::new(message))); + } + for thread in self.shared.threads.read().iter() { + thread.unpark(); + } + Ok(()) + } + + /// Create a new message channel + #[inline] + pub fn channel(&self) -> IoChannel { + IoChannel { + shared: Arc::downgrade(&self.shared) + } + } +} + +impl Drop for IoService where Message: Send + Sync { + fn drop(&mut self) { + self.stop() + } +} + +fn do_work(shared: &Arc>, rx: chase_lev::Stealer>) + where Message: Send + Sync + 'static +{ + loop { + match rx.steal() { + chase_lev::Steal::Abort => continue, + chase_lev::Steal::Empty => thread::park(), + chase_lev::Steal::Data(WorkTask::Shutdown) => break, + chase_lev::Steal::Data(WorkTask::UserMessage(message)) => { + for id in 0 .. MAX_HANDLERS { + if let Some(handler) = shared.handlers.read().get(id) { + let ctxt = IoContext { handler: id, shared: shared.clone() }; + handler.message(&ctxt, &message); + } + } + }, + chase_lev::Steal::Data(WorkTask::TimerTrigger { handler_id, token }) => { + if let Some(handler) = shared.handlers.read().get(handler_id) { + let ctxt = IoContext { handler: handler_id, shared: shared.clone() }; + handler.timeout(&ctxt, token); + } + }, + } + } +} diff --git a/util/io/src/worker.rs b/util/io/src/worker.rs index 0f0d448ecb4..89657810dcf 100644 --- a/util/io/src/worker.rs +++ b/util/io/src/worker.rs @@ -18,21 +18,14 @@ use std::sync::Arc; use std::thread::{JoinHandle, self}; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use crossbeam::sync::chase_lev; -use service::{HandlerId, IoChannel, IoContext}; +use service_mio::{HandlerId, IoChannel, IoContext}; use IoHandler; -use std::cell::Cell; +use LOCAL_STACK_SIZE; use std::sync::{Condvar as SCondvar, Mutex as SMutex}; const STACK_SIZE: usize = 16*1024*1024; -thread_local! { - /// Stack size - /// Should be modified if it is changed in Rust since it is no way - /// to know or get it - pub static LOCAL_STACK_SIZE: Cell = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024)); -} - pub enum WorkType { Readable, Writable, diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 3ec96843931..f4889fe26d4 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -19,7 +19,7 @@ libc = "0.2.7" parking_lot = "0.5" ansi_term = "0.10" rustc-hex = "1.0" -ethcore-io = { path = "../io" } +ethcore-io = { path = "../io", features = ["mio"] } ethcore-bytes = { path = "../bytes" } ethcore-crypto = { path = "../../ethcore/crypto" } ethcore-logger = { path ="../../logger" } From 3ec9cdefb2c405764d11eab716f9031b6af944ff Mon Sep 17 00:00:00 2001 From: Thibaut S <33178835+Tbaut@users.noreply.github.com> Date: Fri, 11 May 2018 08:04:04 +0100 Subject: [PATCH 085/147] Fix Parity UI link (#8600) Fix link https://github.com/paritytech/parity/issues/8599 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36e855fe420..9255d014b6c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Official website: https://parity.io | Be sure to check out [our wiki](https://wi Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. -From Parity Ethereum client version 1.10.0, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want). +From Parity Ethereum client version 1.10.0, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization#the-parity-ui-application-isnt-working-the-way-i-want). By default, Parity will also run a JSONRPC server on `127.0.0.1:8545` and a websockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs. From 03ea13da9e169861d11f96538c55fa0d8f39ba2c Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 11 May 2018 11:23:19 +0200 Subject: [PATCH 086/147] fix compiler warning (#8590) --- ethcore/sync/src/light_sync/response.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs index 74665118b7f..3629613224d 100644 --- a/ethcore/sync/src/light_sync/response.rs +++ b/ethcore/sync/src/light_sync/response.rs @@ -16,7 +16,7 @@ //! Helpers for decoding and verifying responses for headers. -use ethcore::{self, encoded, header::Header}; +use ethcore::{encoded, header::Header}; use ethereum_types::H256; use light::request::{HashOrNumber, CompleteHeadersRequest as HeadersRequest}; use rlp::DecoderError; From 83ded3594ca175e7cf81d87ad38dd089e4d8e625 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 11 May 2018 11:33:13 +0200 Subject: [PATCH 087/147] Block::decode() returns Result (#8586) --- ethcore/src/encoded.rs | 2 +- ethcore/src/snapshot/consensus/authority.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index c436607f8c3..5a2d376a2a3 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -206,7 +206,7 @@ impl Block { pub fn header_view(&self) -> HeaderView { self.view().header_view() } /// Decode to a full block. - pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0).expect("decoding failure") } + pub fn decode(&self) -> Result { rlp::decode(&self.0) } /// Decode the header. pub fn decode_header(&self) -> FullHeader { self.view().rlp().val_at(0) } diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index 474f5d350c1..38d2c184ca1 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -100,7 +100,7 @@ impl SnapshotComponents for PoaSnapshot { let (block, receipts) = chain.block(&block_at) .and_then(|b| chain.block_receipts(&block_at).map(|r| (b, r))) .ok_or(Error::BlockNotFound(block_at))?; - let block = block.decode(); + let block = block.decode()?; let parent_td = chain.block_details(block.header.parent_hash()) .map(|d| d.total_difficulty) From 6d99bcb6fcd516fc467def6ff4858fc034c62c3d Mon Sep 17 00:00:00 2001 From: David Date: Fri, 11 May 2018 11:34:07 +0200 Subject: [PATCH 088/147] block_header can fail so return Result (#8581) * block_header can fail so return Result * Restore previous return type based on feedback * Fix failing doc tests running on non-code --- rpc/src/v1/impls/light/parity.rs | 9 ++++----- util/journaldb/src/earlymergedb.rs | 6 +++--- util/journaldb/src/refcounteddb.rs | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 982c7ff3633..025538fc427 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -395,9 +395,9 @@ impl Parity for ParityClient { let engine = self.light_dispatch.client.engine().clone(); let from_encoded = move |encoded: encoded::Header| { - let header = encoded.decode().expect("decoding error"); // REVIEW: not sure what to do here; what is a decent return value for the error case here? + let header = encoded.decode().map_err(errors::decode)?; let extra_info = engine.extra_info(&header); - RichHeader { + Ok(RichHeader { inner: Header { hash: Some(header.hash().into()), size: Some(encoded.rlp().as_raw().len().into()), @@ -418,9 +418,8 @@ impl Parity for ParityClient { extra_data: Bytes::new(header.extra_data().clone()), }, extra_info: extra_info, - } + }) }; - // Note: Here we treat `Pending` as `Latest`. // Since light clients don't produce pending blocks // (they don't have state) we can safely fallback to `Latest`. @@ -430,7 +429,7 @@ impl Parity for ParityClient { BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, }; - Box::new(self.fetcher().header(id).map(from_encoded)) + Box::new(self.fetcher().header(id).and_then(from_encoded)) } fn ipfs_cid(&self, content: Bytes) -> Result { diff --git a/util/journaldb/src/earlymergedb.rs b/util/journaldb/src/earlymergedb.rs index e76cdcd313a..c26a67e0ad2 100644 --- a/util/journaldb/src/earlymergedb.rs +++ b/util/journaldb/src/earlymergedb.rs @@ -57,7 +57,7 @@ enum RemoveFrom { /// the removals actually take effect. /// /// journal format: -/// ``` +/// ```text /// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, n] => [ ... ] @@ -76,7 +76,7 @@ enum RemoveFrom { /// which includes an original key, if any. /// /// The semantics of the `counter` are: -/// ``` +/// ```text /// insert key k: /// counter already contains k: count += 1 /// counter doesn't contain k: @@ -92,7 +92,7 @@ enum RemoveFrom { /// /// Practically, this means that for each commit block turning from recent to ancient we do the /// following: -/// ``` +/// ```text /// is_canonical: /// inserts: Ignored (left alone in the backing database). /// deletes: Enacted; however, recent history queue is checked for ongoing references. This is diff --git a/util/journaldb/src/refcounteddb.rs b/util/journaldb/src/refcounteddb.rs index 944d81d3733..d182d5cf803 100644 --- a/util/journaldb/src/refcounteddb.rs +++ b/util/journaldb/src/refcounteddb.rs @@ -40,7 +40,7 @@ use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef}; /// the removals actually take effect. /// /// journal format: -/// ``` +/// ```text /// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, n] => [ ... ] From ce5525f62761adc8ef73fcd6f403f61ad7ad61bc Mon Sep 17 00:00:00 2001 From: Axel Chalon Date: Fri, 11 May 2018 12:09:42 +0200 Subject: [PATCH 089/147] Remove inject.js server-side injection for dapps (#8539) * Remove inject.js server-side injection for dapps * Remove dapps test `should_inject_js` Parity doesn't inject a "#, - apps::UTILS_PATH, - ); - - content.as_bytes().to_vec() - } else { - Vec::new() - }; - - let (reader, body) = Reader::pair(file.into_reader(), initial_content); + let (reader, body) = Reader::pair(file.into_reader(), Vec::new()); res.set_body(body); (Some(reader), res) } diff --git a/dapps/src/tests/home.rs b/dapps/src/tests/home.rs index 0ee06536482..fa5c5b4c465 100644 --- a/dapps/src/tests/home.rs +++ b/dapps/src/tests/home.rs @@ -60,32 +60,3 @@ fn should_serve_home() { response.assert_header("Content-Type", "text/html"); assert_security_headers(&response.headers); } - - -#[test] -fn should_inject_js() { - // given - let server = serve_ui(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "text/html"); - assert_eq!( - response.body.contains(r#"/inject.js">"#), - true, - "Expected inject script tag in: {}", - response.body - ); - assert_security_headers(&response.headers); -} From b9b4fd95d5cbc68947ef92c8534a90e525df5d9f Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 11 May 2018 13:45:07 +0200 Subject: [PATCH 090/147] Fix the mio test again (#8602) --- util/io/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index ef8c3adc7ec..cd635121fff 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -186,7 +186,12 @@ mod tests { use std::time::Duration; use super::*; + // Mio's behaviour is too unstable for this test. Sometimes we have to wait a few milliseconds, + // sometimes more than 5 seconds for the message to arrive. + // Therefore we ignore this test in order to not have spurious failure when running continuous + // integration. #[test] + #[cfg_attr(feature = "mio", ignore)] fn send_message_to_handler() { struct MyHandler(atomic::AtomicBool); @@ -209,7 +214,7 @@ mod tests { service.send_message(MyMessage { data: 5 }).unwrap(); - thread::sleep(Duration::from_secs(5)); + thread::sleep(Duration::from_secs(1)); assert!(handler.0.load(atomic::Ordering::SeqCst)); } From 5f28e2e8105e769a83354e9dbb39c320192209f1 Mon Sep 17 00:00:00 2001 From: lihuafeng <31607114+EighteenZi@users.noreply.github.com> Date: Sun, 13 May 2018 04:46:08 +0800 Subject: [PATCH 091/147] 2 tiny modification on snapshot (#8601) * Some tiny modifications. 1. fix some typo in the comment. 2. sort the order of methods in 'impl state::Backend for StateDB` * Remove the clone of code_cache, as it has been done in clone_basic. * remove From::from. It seems not necessary. * change mode: remove rust files' executable mode. * 2 tiny modifications on snapshot. --- ethcore/src/snapshot/consensus/work.rs | 2 +- ethcore/src/snapshot/service.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index 5414ed59634..b71f7b9d1da 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -229,7 +229,7 @@ impl Rebuilder for PowRebuilder { let item_count = rlp.item_count()?; let num_blocks = (item_count - 3) as u64; - trace!(target: "snapshot", "restoring block chunk with {} blocks.", item_count - 3); + trace!(target: "snapshot", "restoring block chunk with {} blocks.", num_blocks); if self.fed_blocks + num_blocks > self.snapshot_blocks { return Err(Error::TooManyBlocks(self.snapshot_blocks, self.fed_blocks + num_blocks).into()) diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 9cfb2eb63f4..c5b9123e10f 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -176,7 +176,7 @@ impl Restoration { // verify final state root. let root = self.state.state_root(); if root != self.final_state_root { - warn!("Final restored state has wrong state root: expected {:?}, got {:?}", root, self.final_state_root); + warn!("Final restored state has wrong state root: expected {:?}, got {:?}", self.final_state_root, root); return Err(TrieError::InvalidStateRoot(root).into()); } From 474468c701a5737e1d1062ba034ac9be70d4f681 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 15:22:59 +0800 Subject: [PATCH 092/147] Use full qualified syntax for itertools::Itertools::flatten (#8606) --- ethstore/src/accounts_dir/memory.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethstore/src/accounts_dir/memory.rs b/ethstore/src/accounts_dir/memory.rs index bd162b5ef0c..5cfdba0e5c7 100644 --- a/ethstore/src/accounts_dir/memory.rs +++ b/ethstore/src/accounts_dir/memory.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use parking_lot::RwLock; -use itertools::Itertools; +use itertools; use ethkey::Address; use {SafeAccount, Error}; @@ -30,7 +30,7 @@ pub struct MemoryDirectory { impl KeyDirectory for MemoryDirectory { fn load(&self) -> Result, Error> { - Ok(self.accounts.read().values().cloned().flatten().collect()) + Ok(itertools::Itertools::flatten(self.accounts.read().values().cloned()).collect()) } fn update(&self, account: SafeAccount) -> Result { From fcca7ad3d506f3d20b4196af0473231375abac57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 14 May 2018 10:09:05 +0200 Subject: [PATCH 093/147] Fix packet count when talking with PAR2 peers (#8555) * Support diferent packet counts in different protocol versions. * Fix light timeouts and eclipse protection. * Fix devp2p tests. * Fix whisper-cli compilation. * Fix compilation. * Fix ethcore-sync tests. * Revert "Fix light timeouts and eclipse protection." This reverts commit 06285ea8c1d9d184d809f64b5507aece633da6cc. * Increase timeouts. --- ethcore/light/src/net/mod.rs | 17 ++++++++++------- ethcore/sync/src/api.rs | 17 +++++++---------- ethcore/sync/src/chain/handler.rs | 8 +++++--- ethcore/sync/src/chain/mod.rs | 24 ++++++++++-------------- ethcore/sync/src/chain/requester.rs | 5 +++-- ethcore/sync/src/tests/helpers.rs | 4 ++-- parity/whisper.rs | 2 -- util/network-devp2p/src/host.rs | 13 +++++++++---- util/network-devp2p/src/lib.rs | 2 +- util/network-devp2p/src/service.rs | 13 +++++++++---- util/network-devp2p/tests/tests.rs | 4 ++-- util/network/src/lib.rs | 6 ++---- whisper/cli/src/main.rs | 4 ++-- whisper/src/net/mod.rs | 10 ++++++---- 14 files changed, 68 insertions(+), 61 deletions(-) diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index d58d90fac45..27d5c12a5fa 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -75,14 +75,17 @@ const RECALCULATE_COSTS_INTERVAL: Duration = Duration::from_secs(60 * 60); // minimum interval between updates. const UPDATE_INTERVAL: Duration = Duration::from_millis(5000); +/// Packet count for PIP. +const PACKET_COUNT_V1: u8 = 9; + /// Supported protocol versions. -pub const PROTOCOL_VERSIONS: &'static [u8] = &[1]; +pub const PROTOCOL_VERSIONS: &'static [(u8, u8)] = &[ + (1, PACKET_COUNT_V1), +]; /// Max protocol version. pub const MAX_PROTOCOL_VERSION: u8 = 1; -/// Packet count for PIP. -pub const PACKET_COUNT: u8 = 9; // packet ID definitions. mod packet { @@ -111,9 +114,9 @@ mod packet { mod timeout { use std::time::Duration; - pub const HANDSHAKE: Duration = Duration::from_millis(2500); - pub const ACKNOWLEDGE_UPDATE: Duration = Duration::from_millis(5000); - pub const BASE: u64 = 1500; // base timeout for packet. + pub const HANDSHAKE: Duration = Duration::from_millis(4_000); + pub const ACKNOWLEDGE_UPDATE: Duration = Duration::from_millis(5_000); + pub const BASE: u64 = 2_500; // base timeout for packet. // timeouts per request within packet. pub const HEADERS: u64 = 250; // per header? @@ -688,7 +691,7 @@ impl LightProtocol { Err(e) => { punish(*peer, io, e); return } }; - if PROTOCOL_VERSIONS.iter().find(|x| **x == proto_version).is_none() { + if PROTOCOL_VERSIONS.iter().find(|x| x.0 == proto_version).is_none() { punish(*peer, io, Error::UnsupportedProtocolVersion(proto_version)); return; } diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 4fd0cbb54dd..e901528e411 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -33,7 +33,7 @@ use chain::{ChainSync, SyncStatus as EthSyncStatus}; use std::net::{SocketAddr, AddrParseError}; use std::str::FromStr; use parking_lot::RwLock; -use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT, ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_62, +use chain::{ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_62, PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3}; use light::client::AsLightClient; use light::Provider; @@ -202,10 +202,8 @@ pub struct AttachedProtocol { pub handler: Arc, /// 3-character ID for the protocol. pub protocol_id: ProtocolId, - /// Packet count. - pub packet_count: u8, - /// Supported versions. - pub versions: &'static [u8], + /// Supported versions and their packet counts. + pub versions: &'static [(u8, u8)], } impl AttachedProtocol { @@ -213,7 +211,6 @@ impl AttachedProtocol { let res = network.register_protocol( self.handler.clone(), self.protocol_id, - self.packet_count, self.versions ); @@ -459,15 +456,15 @@ impl ChainNotify for EthSync { Err(err) => warn!("Error starting network: {}", err), _ => {}, } - self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, ETH_PACKET_COUNT, &[ETH_PROTOCOL_VERSION_62, ETH_PROTOCOL_VERSION_63]) + self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, &[ETH_PROTOCOL_VERSION_62, ETH_PROTOCOL_VERSION_63]) .unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e)); // register the warp sync subprotocol - self.network.register_protocol(self.eth_handler.clone(), WARP_SYNC_PROTOCOL_ID, SNAPSHOT_SYNC_PACKET_COUNT, &[PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3]) + self.network.register_protocol(self.eth_handler.clone(), WARP_SYNC_PROTOCOL_ID, &[PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3]) .unwrap_or_else(|e| warn!("Error registering snapshot sync protocol: {:?}", e)); // register the light protocol. if let Some(light_proto) = self.light_proto.as_ref().map(|x| x.clone()) { - self.network.register_protocol(light_proto, self.light_subprotocol_name, ::light::net::PACKET_COUNT, ::light::net::PROTOCOL_VERSIONS) + self.network.register_protocol(light_proto, self.light_subprotocol_name, ::light::net::PROTOCOL_VERSIONS) .unwrap_or_else(|e| warn!("Error registering light client protocol: {:?}", e)); } @@ -827,7 +824,7 @@ impl ManageNetwork for LightSync { let light_proto = self.proto.clone(); - self.network.register_protocol(light_proto, self.subprotocol_name, ::light::net::PACKET_COUNT, ::light::net::PROTOCOL_VERSIONS) + self.network.register_protocol(light_proto, self.subprotocol_name, ::light::net::PROTOCOL_VERSIONS) .unwrap_or_else(|e| warn!("Error registering light client protocol: {:?}", e)); for proto in &self.attached_protos { proto.register(&self.network) } diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index 966b7ce20ad..a55c0319b37 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -45,7 +45,6 @@ use super::{ MAX_NEW_BLOCK_AGE, MAX_NEW_HASHES, PAR_PROTOCOL_VERSION_1, - PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3, BLOCK_BODIES_PACKET, BLOCK_HEADERS_PACKET, @@ -641,8 +640,11 @@ impl SyncHandler { trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, sync.network_id, peer.network_id); return Ok(()); } - if (warp_protocol && peer.protocol_version != PAR_PROTOCOL_VERSION_1 && peer.protocol_version != PAR_PROTOCOL_VERSION_2 && peer.protocol_version != PAR_PROTOCOL_VERSION_3) - || (!warp_protocol && peer.protocol_version != ETH_PROTOCOL_VERSION_63 && peer.protocol_version != ETH_PROTOCOL_VERSION_62) { + + if false + || (warp_protocol && (peer.protocol_version < PAR_PROTOCOL_VERSION_1.0 || peer.protocol_version > PAR_PROTOCOL_VERSION_3.0)) + || (!warp_protocol && (peer.protocol_version < ETH_PROTOCOL_VERSION_62.0 || peer.protocol_version > ETH_PROTOCOL_VERSION_63.0)) + { io.disable_peer(peer_id); trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); return Ok(()); diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index abab1da9413..381936949bd 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -127,15 +127,15 @@ known_heap_size!(0, PeerInfo); pub type PacketDecodeError = DecoderError; /// 63 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_63: u8 = 63; +pub const ETH_PROTOCOL_VERSION_63: (u8, u8) = (63, 0x11); /// 62 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_62: u8 = 62; -/// 1 version of Parity protocol. -pub const PAR_PROTOCOL_VERSION_1: u8 = 1; +pub const ETH_PROTOCOL_VERSION_62: (u8, u8) = (62, 0x11); +/// 1 version of Parity protocol and the packet count. +pub const PAR_PROTOCOL_VERSION_1: (u8, u8) = (1, 0x15); /// 2 version of Parity protocol (consensus messages added). -pub const PAR_PROTOCOL_VERSION_2: u8 = 2; +pub const PAR_PROTOCOL_VERSION_2: (u8, u8) = (2, 0x16); /// 3 version of Parity protocol (private transactions messages added). -pub const PAR_PROTOCOL_VERSION_3: u8 = 3; +pub const PAR_PROTOCOL_VERSION_3: (u8, u8) = (3, 0x18); pub const MAX_BODIES_TO_SEND: usize = 256; pub const MAX_HEADERS_TO_SEND: usize = 512; @@ -169,8 +169,6 @@ pub const NODE_DATA_PACKET: u8 = 0x0e; pub const GET_RECEIPTS_PACKET: u8 = 0x0f; pub const RECEIPTS_PACKET: u8 = 0x10; -pub const ETH_PACKET_COUNT: u8 = 0x11; - pub const GET_SNAPSHOT_MANIFEST_PACKET: u8 = 0x11; pub const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12; pub const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13; @@ -179,8 +177,6 @@ pub const CONSENSUS_DATA_PACKET: u8 = 0x15; const PRIVATE_TRANSACTION_PACKET: u8 = 0x16; const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17; -pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; - const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); @@ -453,7 +449,7 @@ impl ChainSync { let last_imported_number = self.new_blocks.last_imported_block_number(); SyncStatus { state: self.state.clone(), - protocol_version: ETH_PROTOCOL_VERSION_63, + protocol_version: ETH_PROTOCOL_VERSION_63.0, network_id: self.network_id, start_block_number: self.starting_block, last_imported_block_number: Some(last_imported_number), @@ -855,7 +851,7 @@ impl ChainSync { fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), network::Error> { let warp_protocol_version = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer); let warp_protocol = warp_protocol_version != 0; - let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63 }; + let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63.0 }; trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol); let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 }); let chain = io.chain().chain_info(); @@ -1019,11 +1015,11 @@ impl ChainSync { } fn get_consensus_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2.0 { Some(*id) } else { None }).collect() } fn get_private_transaction_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3 { Some(*id) } else { None }).collect() + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3.0 { Some(*id) } else { None }).collect() } /// Maintain other peers. Send out any new blocks and transactions diff --git a/ethcore/sync/src/chain/requester.rs b/ethcore/sync/src/chain/requester.rs index e6acf6bc53a..a85874d2927 100644 --- a/ethcore/sync/src/chain/requester.rs +++ b/ethcore/sync/src/chain/requester.rs @@ -28,7 +28,7 @@ use super::{ BlockSet, ChainSync, PeerAsking, - ETH_PACKET_COUNT, + ETH_PROTOCOL_VERSION_63, GET_BLOCK_BODIES_PACKET, GET_BLOCK_HEADERS_PACKET, GET_RECEIPTS_PACKET, @@ -140,7 +140,8 @@ impl SyncRequester { } peer.asking = asking; peer.ask_time = Instant::now(); - let result = if packet_id >= ETH_PACKET_COUNT { + // TODO [ToDr] This seems quite fragile. Be careful when protocol is updated. + let result = if packet_id >= ETH_PROTOCOL_VERSION_63.1 { io.send_protocol(WARP_SYNC_PROTOCOL_ID, peer_id, packet_id, packet) } else { io.send(peer_id, packet_id, packet) diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 3a4697cc093..407f699e0e6 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -134,11 +134,11 @@ impl<'p, C> SyncIo for TestIo<'p, C> where C: FlushingBlockChainClient, C: 'p { } fn eth_protocol_version(&self, _peer: PeerId) -> u8 { - ETH_PROTOCOL_VERSION_63 + ETH_PROTOCOL_VERSION_63.0 } fn protocol_version(&self, protocol: &ProtocolId, peer_id: PeerId) -> u8 { - if protocol == &WARP_SYNC_PROTOCOL_ID { PAR_PROTOCOL_VERSION_3 } else { self.eth_protocol_version(peer_id) } + if protocol == &WARP_SYNC_PROTOCOL_ID { PAR_PROTOCOL_VERSION_3.0 } else { self.eth_protocol_version(peer_id) } } fn chain_overlay(&self) -> &RwLock> { diff --git a/parity/whisper.rs b/parity/whisper.rs index c7acd8f9d6f..bb9aebf0b9b 100644 --- a/parity/whisper.rs +++ b/parity/whisper.rs @@ -89,7 +89,6 @@ pub fn setup(target_pool_size: usize, protos: &mut Vec) protos.push(AttachedProtocol { handler: net.clone() as Arc<_>, - packet_count: whisper_net::PACKET_COUNT, versions: whisper_net::SUPPORTED_VERSIONS, protocol_id: whisper_net::PROTOCOL_ID, }); @@ -97,7 +96,6 @@ pub fn setup(target_pool_size: usize, protos: &mut Vec) // parity-only extensions to whisper. protos.push(AttachedProtocol { handler: Arc::new(whisper_net::ParityExtensions), - packet_count: whisper_net::PACKET_COUNT, versions: whisper_net::SUPPORTED_VERSIONS, protocol_id: whisper_net::PARITY_PROTOCOL_ID, }); diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 2de9a1884c8..3c8643fe62d 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -79,7 +79,9 @@ const NODE_TABLE_TIMEOUT: Duration = Duration::from_secs(300); #[derive(Debug, PartialEq, Eq)] /// Protocol info pub struct CapabilityInfo { + /// Protocol ID pub protocol: ProtocolId, + /// Protocol version pub version: u8, /// Total number of packet IDs this protocol support. pub packet_count: u8, @@ -687,7 +689,7 @@ impl Host { Err(e) => { let s = session.lock(); trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); - if let ErrorKind::Disconnect(DisconnectReason::UselessPeer) = *e.kind() { + if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() { if let Some(id) = s.id() { if !self.reserved_nodes.read().contains(id) { let mut nodes = self.nodes.write(); @@ -990,7 +992,6 @@ impl IoHandler for Host { ref handler, ref protocol, ref versions, - ref packet_count, } => { let h = handler.clone(); let reserved = self.reserved_nodes.read(); @@ -1000,8 +1001,12 @@ impl IoHandler for Host { ); self.handlers.write().insert(*protocol, h); let mut info = self.info.write(); - for v in versions { - info.capabilities.push(CapabilityInfo { protocol: *protocol, version: *v, packet_count: *packet_count }); + for &(version, packet_count) in versions { + info.capabilities.push(CapabilityInfo { + protocol: *protocol, + version, + packet_count, + }); } }, NetworkIoMessage::AddTimer { diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 239763cbe18..e5bb95f2207 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -49,7 +49,7 @@ //! fn main () { //! let mut service = NetworkService::new(NetworkConfiguration::new_local(), None).expect("Error creating network service"); //! service.start().expect("Error starting service"); -//! service.register_protocol(Arc::new(MyHandler), *b"myp", 1, &[1u8]); +//! service.register_protocol(Arc::new(MyHandler), *b"myp", &[(1u8, 1u8)]); //! //! // Wait for quit condition //! // ... diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 711ee95cf3b..10a1e9abc85 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -67,12 +67,17 @@ impl NetworkService { } /// Regiter a new protocol handler with the event loop. - pub fn register_protocol(&self, handler: Arc, protocol: ProtocolId, packet_count: u8, versions: &[u8]) -> Result<(), Error> { + pub fn register_protocol( + &self, + handler: Arc, + protocol: ProtocolId, + // version id + packet count + versions: &[(u8, u8)] + ) -> Result<(), Error> { self.io_service.send_message(NetworkIoMessage::AddHandler { - handler: handler, - protocol: protocol, + handler, + protocol, versions: versions.to_vec(), - packet_count: packet_count, })?; Ok(()) } diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index 4788e0d442a..e8c8eddde4b 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -52,7 +52,7 @@ impl TestProtocol { /// Creates and register protocol with the network service pub fn register(service: &mut NetworkService, drop_session: bool) -> Arc { let handler = Arc::new(TestProtocol::new(drop_session)); - service.register_protocol(handler.clone(), *b"tst", 1, &[42u8, 43u8]).expect("Error registering test protocol handler"); + service.register_protocol(handler.clone(), *b"tst", &[(42u8, 1u8), (43u8, 1u8)]).expect("Error registering test protocol handler"); handler } @@ -104,7 +104,7 @@ impl NetworkProtocolHandler for TestProtocol { fn net_service() { let service = NetworkService::new(NetworkConfiguration::new_local(), None).expect("Error creating network service"); service.start().unwrap(); - service.register_protocol(Arc::new(TestProtocol::new(false)), *b"myp", 1, &[1u8]).unwrap(); + service.register_protocol(Arc::new(TestProtocol::new(false)), *b"myp", &[(1u8, 1u8)]).unwrap(); } #[test] diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 5077a953d48..673e4dab357 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -64,10 +64,8 @@ pub enum NetworkIoMessage { handler: Arc, /// Protocol Id. protocol: ProtocolId, - /// Supported protocol versions. - versions: Vec, - /// Number of packet IDs reserved by the protocol. - packet_count: u8, + /// Supported protocol versions and number of packet IDs reserved by the protocol (packet count). + versions: Vec<(u8, u8)>, }, /// Register a new protocol timer AddTimer { diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index f9211b993b4..c3a4dc8c3a2 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -218,10 +218,10 @@ fn execute(command: I) -> Result<(), Error> where I: IntoIterator, network.start()?; // Attach whisper protocol to the network service - network.register_protocol(whisper_network_handler.clone(), whisper::net::PROTOCOL_ID, whisper::net::PACKET_COUNT, + network.register_protocol(whisper_network_handler.clone(), whisper::net::PROTOCOL_ID, whisper::net::SUPPORTED_VERSIONS)?; network.register_protocol(Arc::new(whisper::net::ParityExtensions), whisper::net::PARITY_PROTOCOL_ID, - whisper::net::PACKET_COUNT, whisper::net::SUPPORTED_VERSIONS)?; + whisper::net::SUPPORTED_VERSIONS)?; // Request handler let mut io = MetaIoHandler::default(); diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index fc6138cf1dd..c462baa9d72 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -41,15 +41,17 @@ const RALLY_TIMEOUT: Duration = Duration::from_millis(2500); /// Current protocol version. pub const PROTOCOL_VERSION: usize = 6; +/// Number of packets. A bunch are reserved. +const PACKET_COUNT: u8 = 128; + /// Supported protocol versions. -pub const SUPPORTED_VERSIONS: &'static [u8] = &[PROTOCOL_VERSION as u8]; +pub const SUPPORTED_VERSIONS: &'static [(u8, u8)] = &[ + (PROTOCOL_VERSION as u8, PACKET_COUNT) +]; // maximum tolerated delay between messages packets. const MAX_TOLERATED_DELAY: Duration = Duration::from_millis(5000); -/// Number of packets. A bunch are reserved. -pub const PACKET_COUNT: u8 = 128; - /// Whisper protocol ID pub const PROTOCOL_ID: ::network::ProtocolId = *b"shh"; From 11228b98ad327fc41cc9e0f6494387a8e857552e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 16:10:11 +0800 Subject: [PATCH 094/147] typo: wrong indentation in kovan config (#8610) --- ethcore/res/ethereum/kovan.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 1cd74d973c7..02d22bb4196 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -4,8 +4,8 @@ "engine": { "authorityRound": { "params": { - "stepDuration": "4", - "blockReward": "0x4563918244F40000", + "stepDuration": "4", + "blockReward": "0x4563918244F40000", "validators" : { "list": [ "0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED", From 30393d962cfbafc2cfa2ee08e41e8adea9be9ec9 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 16:10:28 +0800 Subject: [PATCH 095/147] Fix account list double 0x display (#8596) * Remove unused self import * Fix account list double 0x display --- parity/account.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/account.rs b/parity/account.rs index 3db1844a1b4..676cf93e735 100644 --- a/parity/account.rs +++ b/parity/account.rs @@ -94,7 +94,7 @@ fn new(n: NewAccount) -> Result { let secret_store = Box::new(secret_store(dir, Some(n.iterations))?); let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default()); let new_account = acc_provider.new_account(&password).map_err(|e| format!("Could not create new account: {}", e))?; - Ok(format!("0x{:?}", new_account)) + Ok(format!("0x{:x}", new_account)) } fn list(list_cmd: ListAccounts) -> Result { @@ -103,7 +103,7 @@ fn list(list_cmd: ListAccounts) -> Result { let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default()); let accounts = acc_provider.accounts().map_err(|e| format!("{}", e))?; let result = accounts.into_iter() - .map(|a| format!("0x{:?}", a)) + .map(|a| format!("0x{:x}", a)) .collect::>() .join("\n"); From eacfacc8169ee7dc82767c9955129da75725347b Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 14 May 2018 10:11:10 +0200 Subject: [PATCH 096/147] Remove manually added text to the errors (#8595) These messages were confusing for the users especially the help message. --- whisper/cli/src/main.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index c3a4dc8c3a2..f245e99e482 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -170,12 +170,12 @@ impl From for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { - Error::SockAddr(ref e) => write!(f, "SockAddrError: {}", e), - Error::Docopt(ref e) => write!(f, "DocoptError: {}", e), - Error::Io(ref e) => write!(f, "IoError: {}", e), - Error::JsonRpc(ref e) => write!(f, "JsonRpcError: {:?}", e), - Error::Network(ref e) => write!(f, "NetworkError: {}", e), - Error::Logger(ref e) => write!(f, "LoggerError: {}", e), + Error::SockAddr(ref e) => write!(f, "{}", e), + Error::Docopt(ref e) => write!(f, "{}", e), + Error::Io(ref e) => write!(f, "{}", e), + Error::JsonRpc(ref e) => write!(f, "{:?}", e), + Error::Network(ref e) => write!(f, "{}", e), + Error::Logger(ref e) => write!(f, "{}", e), } } } @@ -252,7 +252,6 @@ fn initialize_logger(log_level: String) -> Result<(), String> { Ok(()) } - #[cfg(test)] mod tests { use super::execute; From 345db57b4699b211db7924f3ed69a3145ea48150 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Mon, 14 May 2018 11:28:41 +0200 Subject: [PATCH 097/147] Gitlab test script fixes (#8573) * Exclude /docs from modified files. * Ensure all references in the working tree are available * Remove duplicated line from test script --- scripts/gitlab-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/gitlab-test.sh b/scripts/gitlab-test.sh index a617f68e227..57cf7c6b6c5 100755 --- a/scripts/gitlab-test.sh +++ b/scripts/gitlab-test.sh @@ -7,8 +7,8 @@ if [[ "$CI_COMMIT_REF_NAME" = "master" || "$CI_COMMIT_REF_NAME" = "beta" || "$CI else export GIT_COMPARE=master; fi -export RUST_FILES_MODIFIED="$(git --no-pager diff --name-only $GIT_COMPARE...$CI_COMMIT_SHA | grep -v -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e ^mac/ -e ^nsis/ | wc -l)" -echo "RUST_FILES_MODIFIED: $RUST_FILES_MODIFIED" +git fetch -a +export RUST_FILES_MODIFIED="$(git --no-pager diff --name-only $GIT_COMPARE...$CI_COMMIT_SHA | grep -v -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e ^mac/ -e ^nsis/ -e ^docs/ | wc -l)" echo "RUST_FILES_MODIFIED: $RUST_FILES_MODIFIED" TEST_SWITCH=$1 rust_test () { From 7de2a13b1d340319c3dbcef69a81268009960117 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 22:26:18 +0800 Subject: [PATCH 098/147] Fix BlockReward contract "arithmetic operation overflow" (#8611) * Fix BlockReward contract "arithmetic operation overflow" * Add docs on how execute_as_system works * Fix typo --- ethcore/src/machine.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 4aa72b50d92..d0d434b1de0 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -122,7 +122,13 @@ impl EthereumMachine { } impl EthereumMachine { - /// Execute a call as the system address. + /// Execute a call as the system address. Block environment information passed to the + /// VM is modified to have its gas limit bounded at the upper limit of possible used + /// gases including this system call, capped at the maximum value able to be + /// represented by U256. This system call modifies the block state, but discards other + /// information. If suicides, logs or refunds happen within the system call, they + /// will not be executed or recorded. Gas used by this system call will not be counted + /// on the block. pub fn execute_as_system( &self, block: &mut ExecutedBlock, @@ -132,7 +138,7 @@ impl EthereumMachine { ) -> Result, Error> { let env_info = { let mut env_info = block.env_info(); - env_info.gas_limit = env_info.gas_used + gas; + env_info.gas_limit = env_info.gas_used.saturating_add(gas); env_info }; From 1666cabe7011f85b06883c11599190194de997aa Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 15 May 2018 07:46:37 +0200 Subject: [PATCH 099/147] =?UTF-8?q?=C2=B4main.rs=C2=B4=20typo=20(#8629)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Typo * Update main.rs --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index e489ad865e4..03b04a8c82f 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -71,7 +71,7 @@ fn take_spec_name_override() -> Option { #[cfg(windows)] fn global_cleanup() { - // We need to cleanup all sockets before spawning another Parity process. This makes shure everything is cleaned up. + // We need to cleanup all sockets before spawning another Parity process. This makes sure everything is cleaned up. // The loop is required because of internal reference counter for winsock dll. We don't know how many crates we use do // initialize it. There's at least 2 now. for _ in 0.. 10 { From 9bceb6d2402f9c18fe897b26620e742da2cbd0bd Mon Sep 17 00:00:00 2001 From: David Date: Tue, 15 May 2018 12:57:32 +0200 Subject: [PATCH 100/147] Store morden db and keys in "path/to/parity/data/Morden" (ropsten uses "test", like before) (#8621) * Store morden db and keys in "path/to/parity/data/morden" (ropsten uses "test", like before) --- .gitignore | 2 +- ethcore/res/ethereum/morden.json | 2 +- util/dir/src/lib.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 0675bc41ebf..3bc041c9081 100644 --- a/.gitignore +++ b/.gitignore @@ -40,5 +40,5 @@ node_modules out/ .vscode - +rls/ /parity.* diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 04c5a124441..bca9919903e 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -1,6 +1,6 @@ { "name": "Morden", - "dataDir": "test", + "dataDir": "morden", "engine": { "Ethash": { "params": { diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index b2ffed329c1..bb36a46a834 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -104,9 +104,9 @@ impl Directories { DatabaseDirectories { path: self.db.clone(), legacy_path: self.base.clone(), - genesis_hash: genesis_hash, - fork_name: fork_name, - spec_name: spec_name, + genesis_hash, + fork_name, + spec_name, } } From ea74e516f754ccecd87b99e2d2ff69ba9af48fd4 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 15 May 2018 15:35:52 +0200 Subject: [PATCH 101/147] Fix light sync with initial validator-set contract (#8528) * Fix #8468 * Use U256::max_value() instead * Fix again * Also change initial transaction gas --- ethcore/src/spec/spec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index ef69f4847bc..1ee8cf70323 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -783,7 +783,7 @@ impl Spec { author: *genesis.author(), timestamp: genesis.timestamp(), difficulty: *genesis.difficulty(), - gas_limit: *genesis.gas_limit(), + gas_limit: U256::max_value(), last_hashes: Arc::new(Vec::new()), gas_used: 0.into(), }; @@ -792,7 +792,7 @@ impl Spec { let tx = Transaction { nonce: self.engine.account_start_nonce(0), action: Action::Call(a), - gas: U256::from(50_000_000), // TODO: share with client. + gas: U256::max_value(), gas_price: U256::default(), value: U256::default(), data: d, From 1426d3b9e260c6decb5730d6ede8920737d3adb5 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 15 May 2018 17:03:09 +0200 Subject: [PATCH 102/147] Remove NetworkContext::io_channel() (#8625) * Remove io_channel() * Fix warning --- util/network-devp2p/src/host.rs | 4 ---- util/network/src/lib.rs | 8 -------- 2 files changed, 12 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 3c8643fe62d..4cca2e6e5a7 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -153,10 +153,6 @@ impl<'s> NetworkContextTrait for NetworkContext<'s> { self.session_id.map_or_else(|| Err(ErrorKind::Expired.into()), |id| self.send(id, packet_id, data)) } - fn io_channel(&self) -> IoChannel { - self.io.channel() - } - fn disable_peer(&self, peer: PeerId) { self.io.message(NetworkIoMessage::DisablePeer(peer)) .unwrap_or_else(|e| warn!("Error sending network IO message: {:?}", e)); diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 673e4dab357..1327a9ad59f 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -39,7 +39,6 @@ use std::str::{self, FromStr}; use std::sync::Arc; use std::time::Duration; use ipnetwork::{IpNetwork, IpNetworkError}; -use io::IoChannel; use ethkey::Secret; use ethereum_types::{H256, H512}; use rlp::{Decodable, DecoderError, Rlp}; @@ -257,9 +256,6 @@ pub trait NetworkContext { /// Respond to a current network message. Panics if no there is no packet in the context. If the session is expired returns nothing. fn respond(&self, packet_id: PacketId, data: Vec) -> Result<(), Error>; - /// Get an IoChannel. - fn io_channel(&self) -> IoChannel; - /// Disconnect a peer and prevent it from connecting again. fn disable_peer(&self, peer: PeerId); @@ -298,10 +294,6 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { (**self).respond(packet_id, data) } - fn io_channel(&self) -> IoChannel { - (**self).io_channel() - } - fn disable_peer(&self, peer: PeerId) { (**self).disable_peer(peer) } From 5adf9936f8afe61932aa209e1f9edf5bca24c7e6 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 15 May 2018 23:11:14 +0200 Subject: [PATCH 103/147] Check that the Android build doesn't dep on c++_shared (#8538) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 347b5a57ba4..95a7ebcb5e4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -190,7 +190,7 @@ android-armv7: - triggers script: - cargo build --target=armv7-linux-androideabi - # TODO: check that `arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/release/parity | grep c++_shared` is empty + - if [ $(arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/debug/parity | grep -i 'c++_shared' | wc -l) -ne 0]; then echo "FAIL!!" fi tags: - rust-arm artifacts: From 0ddc685e99b33639268ac62851372939c9be15dd Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 16 May 2018 14:58:01 +0800 Subject: [PATCH 104/147] Fork choice and metadata framework for Engine (#8401) * Add light client TODO item * Move existing total-difficulty-based fork choice check to Engine * Abstract total difficulty and block provider as Machine::BlockMetadata and Machine::BlockProvider * Decouple "generate_metadata" logic to Engine * Use fixed BlockMetadata and BlockProvider type for null and instantseal In this way they can use total difficulty fork choice check * Extend blockdetails with metadatas and finalized info * Extra data update: mark_finalized and update_metadatas * Check finalized block in Blockchain * Fix a test constructor in verification mod * Add total difficulty trait * Fix type import * Db migration to V13 with metadata column * Address grumbles * metadatas -> metadata * Use generic type for update_metadata to avoid passing HashMap all around * Remove metadata in blockdetails * [WIP] Implement a generic metadata architecture * [WIP] Metadata insertion logic in BlockChain * typo: Value -> Self::Value * [WIP] Temporarily remove Engine::is_new_best interface So that we don't have too many type errors. * [WIP] Fix more type errors * [WIP] ExtendedHeader::PartialEq * [WIP] Change metadata type Option> to Vec * [WIP] Remove Metadata Error * [WIP] Clean up error conversion * [WIP] finalized -> is_finalized * [WIP] Mark all fields in ExtrasInsert as pub * [WIP] Remove unused import * [WIP] Keep only local metadata info * Mark metadata as optional * [WIP] Revert metadata db change in BlockChain * [WIP] Put finalization in unclosed state * Use metadata interface in BlockDetail * [WIP] Fix current build failures * [WIP] Remove unused blockmetadata struct * Remove DB migration info * [WIP] Typo * Use ExtendedHeader to implement fork choice check * Implement is_new_best using Ancestry iterator * Use expect instead of panic * [WIP] Add ancestry Engine support via on_new_block * Fix tests * Emission of ancestry actions * use_short_version should take account of metadata * Engine::is_new_best -> Engine::fork_choice * Use proper expect format as defined in #1026 * panic -> expect * ancestry_header -> ancestry_with_metadata * Boxed iterator -> &mut iterator * Fix tests * is_new_best -> primitive_fork_choice * Document how fork_choice works * Engine::fork_choice -> Engine::primitive_fork_choice * comment: clarify types of finalization where Engine::primitive_fork_choice works * Expose FinalizationInfo to Engine * Fix tests due to merging * Remove TotalDifficulty trait * Do not pass FinalizationInfo to Engine If there's finalized blocks in from route, choose the old branch without calling `Engine::fork_choice`. * Fix compile * Fix unused import * Remove is_to_route_finalized When no block reorg passes a finalized block, this variable is always false. * Address format grumbles * Fix docs: mark_finalized returns None if block hash is not found `blockchain` mod does not yet have an Error type, so we still temporarily use None here. * Fix inaccurate tree_route None expect description --- ethcore/light/src/client/header_chain.rs | 1 + ethcore/src/block.rs | 51 +++- ethcore/src/blockchain/blockchain.rs | 258 ++++++++++++++------ ethcore/src/blockchain/extras.rs | 54 +++- ethcore/src/blockchain/mod.rs | 1 + ethcore/src/blockchain/update.rs | 10 + ethcore/src/client/client.rs | 67 ++++- ethcore/src/client/test_client.rs | 4 +- ethcore/src/engines/authority_round/mod.rs | 33 ++- ethcore/src/engines/basic_authority.rs | 8 +- ethcore/src/engines/instant_seal.rs | 12 +- ethcore/src/engines/mod.rs | 31 ++- ethcore/src/engines/null_engine.rs | 11 +- ethcore/src/engines/tendermint/mod.rs | 10 +- ethcore/src/ethereum/ethash.rs | 20 +- ethcore/src/header.rs | 48 +++- ethcore/src/machine.rs | 4 +- ethcore/src/snapshot/tests/proof_of_work.rs | 8 +- ethcore/src/test_helpers.rs | 17 +- ethcore/src/tests/trace.rs | 5 +- ethcore/src/verification/verification.rs | 2 + ethcore/types/src/ancestry_action.rs | 27 ++ ethcore/types/src/lib.rs | 1 + ethcore/types/src/tree_route.rs | 2 + machine/src/lib.rs | 48 +++- 25 files changed, 592 insertions(+), 141 deletions(-) create mode 100644 ethcore/types/src/ancestry_action.rs diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index b85091e53bf..60c7d288a76 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -445,6 +445,7 @@ impl HeaderChain { let raw = header.encoded().into_inner(); transaction.put_vec(self.col, &hash[..], raw); + // TODO: For engines when required, use cryptoeconomic guarantees. let (best_num, is_new_best) = { let cur_best = self.best_block.read(); if cur_best.total_difficulty < total_difficulty { diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d9f3d27afb0..4c470896773 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -31,7 +31,7 @@ use vm::{EnvInfo, LastHashes}; use engines::EthEngine; use error::{Error, BlockError}; use factory::Factories; -use header::Header; +use header::{Header, ExtendedHeader}; use receipt::{Receipt, TransactionOutcome}; use state::State; use state_db::StateDB; @@ -94,6 +94,8 @@ pub struct ExecutedBlock { state: State, traces: Tracing, last_hashes: Arc, + is_finalized: bool, + metadata: Option>, } impl ExecutedBlock { @@ -112,6 +114,8 @@ impl ExecutedBlock { Tracing::Disabled }, last_hashes: last_hashes, + is_finalized: false, + metadata: None, } } @@ -206,6 +210,26 @@ impl ::parity_machine::Transactions for ExecutedBlock { } } +impl ::parity_machine::Finalizable for ExecutedBlock { + fn is_finalized(&self) -> bool { + self.is_finalized + } + + fn mark_finalized(&mut self) { + self.is_finalized = true; + } +} + +impl ::parity_machine::WithMetadata for ExecutedBlock { + fn metadata(&self) -> Option<&[u8]> { + self.metadata.as_ref().map(|v| v.as_ref()) + } + + fn set_metadata(&mut self, value: Option>) { + self.metadata = value; + } +} + /// Block that is ready for transactions to be added. /// /// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and @@ -224,6 +248,8 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, unclosed_state: State, + unclosed_finalization_state: bool, + unclosed_metadata: Option>, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. @@ -245,7 +271,7 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new `OpenBlock` ready for transaction pushing. - pub fn new( + pub fn new<'a>( engine: &'x EthEngine, factories: Factories, tracing: bool, @@ -256,6 +282,7 @@ impl<'x> OpenBlock<'x> { gas_range_target: (U256, U256), extra_data: Bytes, is_epoch_begin: bool, + ancestry: &mut Iterator, ) -> Result { let number = parent.number() + 1; let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?; @@ -277,7 +304,7 @@ impl<'x> OpenBlock<'x> { engine.populate_from_parent(&mut r.block.header, parent); engine.machine().on_new_block(&mut r.block)?; - engine.on_new_block(&mut r.block, is_epoch_begin)?; + engine.on_new_block(&mut r.block, is_epoch_begin, ancestry)?; Ok(r) } @@ -387,6 +414,8 @@ impl<'x> OpenBlock<'x> { let mut s = self; let unclosed_state = s.block.state.clone(); + let unclosed_metadata = s.block.metadata.clone(); + let unclosed_finalization_state = s.block.is_finalized; if let Err(e) = s.engine.on_close_block(&mut s.block) { warn!("Encountered error on closing the block: {}", e); @@ -410,6 +439,8 @@ impl<'x> OpenBlock<'x> { block: s.block, uncle_bytes, unclosed_state, + unclosed_metadata, + unclosed_finalization_state, } } @@ -483,6 +514,8 @@ impl ClosedBlock { // revert rewards (i.e. set state back at last transaction's state). let mut block = self.block; block.state = self.unclosed_state; + block.metadata = self.unclosed_metadata; + block.is_finalized = self.unclosed_finalization_state; OpenBlock { block: block, engine: engine, @@ -588,6 +621,7 @@ fn enact( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, + ancestry: &mut Iterator, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { @@ -608,6 +642,7 @@ fn enact( (3141562.into(), 31415620.into()), vec![], is_epoch_begin, + ancestry, )?; b.populate_from(&header); @@ -630,6 +665,7 @@ pub fn enact_verified( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, + ancestry: &mut Iterator, ) -> Result { let view = view!(BlockView, &block.bytes); @@ -644,6 +680,7 @@ pub fn enact_verified( last_hashes, factories, is_epoch_begin, + ancestry, ) } @@ -701,6 +738,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), )?; b.populate_from(&header); @@ -734,7 +772,7 @@ mod tests { 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()]); - let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); let _ = b.seal(&*spec.engine, vec![]); } @@ -748,7 +786,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap() + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap() .close_and_lock().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -772,7 +810,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let mut uncle1_header = Header::new(); uncle1_header.set_extra_data(b"uncle1".to_vec()); let mut uncle2_header = Header::new(); @@ -797,4 +835,3 @@ mod tests { assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); } } - diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 0e18c5f889c..f2621d00e1b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -38,11 +38,12 @@ use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainD use blockchain::extras::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions}; use types::blockchain_info::BlockChainInfo; use types::tree_route::TreeRoute; -use blockchain::update::ExtrasUpdate; +use blockchain::update::{ExtrasUpdate, ExtrasInsert}; use blockchain::{CacheSize, ImportRoute, Config}; use db::{self, Writable, Readable, CacheUpdatePolicy}; use cache_manager::CacheManager; use encoded; +use engines::ForkChoice; use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition}; use rayon::prelude::*; use ansi_term::Colour; @@ -417,6 +418,42 @@ impl<'a> Iterator for AncestryIter<'a> { } } +/// An iterator which walks the blockchain towards the genesis, with metadata information. +pub struct AncestryWithMetadataIter<'a> { + current: H256, + chain: &'a BlockChain, +} + +impl<'a> Iterator for AncestryWithMetadataIter<'a> { + type Item = ExtendedHeader; + fn next(&mut self) -> Option { + if self.current.is_zero() { + None + } else { + let details = self.chain.block_details(&self.current); + let header = self.chain.block_header_data(&self.current) + .map(|h| h.decode().expect("Stored block header data is valid RLP; qed")); + + match (details, header) { + (Some(details), Some(header)) => { + self.current = details.parent; + Some(ExtendedHeader { + parent_total_difficulty: details.total_difficulty - *header.difficulty(), + is_finalized: details.is_finalized, + metadata: details.metadata, + + header: header, + }) + }, + _ => { + self.current = H256::default(); + None + }, + } + } + } +} + /// An iterator which walks all epoch transitions. /// Returns epoch transitions. pub struct EpochTransitionIter<'a> { @@ -510,6 +547,8 @@ impl BlockChain { total_difficulty: header.difficulty(), parent: header.parent_hash(), children: vec![], + is_finalized: false, + metadata: None, }; let mut batch = DBTransaction::new(); @@ -649,6 +688,7 @@ impl BlockChain { /// `None` is returned. pub fn tree_route(&self, from: H256, to: H256) -> Option { let mut from_branch = vec![]; + let mut is_from_route_finalized = false; let mut to_branch = vec![]; let mut from_details = self.block_details(&from)?; @@ -661,6 +701,7 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; + is_from_route_finalized = is_from_route_finalized || from_details.is_finalized; } while to_details.number > from_details.number { @@ -676,6 +717,7 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; + is_from_route_finalized = is_from_route_finalized || from_details.is_finalized; to_branch.push(current_to); current_to = to_details.parent.clone(); @@ -689,7 +731,8 @@ impl BlockChain { Some(TreeRoute { blocks: from_branch, ancestor: current_from, - index: index + index: index, + is_from_route_finalized: is_from_route_finalized, }) } @@ -733,7 +776,7 @@ impl BlockChain { self.prepare_update(batch, ExtrasUpdate { block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info, false, None), block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), @@ -769,11 +812,14 @@ impl BlockChain { location: BlockLocation::CanonChain, }; + // TODO [sorpaas] support warp sync insertion of finalization and metadata. let block_details = BlockDetails { number: header.number(), total_difficulty: info.total_difficulty, parent: header.parent_hash(), children: Vec::new(), + is_finalized: false, + metadata: None, }; let mut update = HashMap::new(); @@ -898,7 +944,22 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec) -> ImportRoute { + pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras: ExtrasInsert) -> ImportRoute { + let block = view!(BlockView, bytes); + let header = block.header_view(); + + let parent_hash = header.parent_hash(); + let best_hash = self.best_block_hash(); + + let route = self.tree_route(best_hash, parent_hash).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); + + self.insert_block_with_route(batch, bytes, receipts, route, extras) + } + + /// Inserts the block into backing cache database with already generated route information. + /// Expects the block to be valid and already verified and route is tree route information from current best block to new block's parent. + /// If the block is already known, does nothing. + pub fn insert_block_with_route(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, route: TreeRoute, extras: ExtrasInsert) -> ImportRoute { // create views onto rlp let block = view!(BlockView, bytes); let header = block.header_view(); @@ -917,7 +978,7 @@ impl BlockChain { batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header); + let info = self.block_info(&header, route, &extras); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -930,7 +991,7 @@ impl BlockChain { self.prepare_update(batch, ExtrasUpdate { block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info, extras.is_finalized, extras.metadata), block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), @@ -942,45 +1003,59 @@ impl BlockChain { } /// Get inserted block info which is critical to prepare extras updates. - fn block_info(&self, header: &HeaderView) -> BlockInfo { + fn block_info(&self, header: &HeaderView, route: TreeRoute, extras: &ExtrasInsert) -> BlockInfo { let hash = header.hash(); let number = header.number(); let parent_hash = header.parent_hash(); let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - let is_new_best = parent_details.total_difficulty + header.difficulty() > self.best_block_total_difficulty(); BlockInfo { hash: hash, number: number, total_difficulty: parent_details.total_difficulty + header.difficulty(), - location: if is_new_best { - // on new best block we need to make sure that all ancestors - // are moved to "canon chain" - // find the route between old best block and the new one - let best_hash = self.best_block_hash(); - let route = self.tree_route(best_hash, parent_hash) - .expect("blocks being imported always within recent history; qed"); - - assert_eq!(number, parent_details.number + 1); - - match route.blocks.len() { - 0 => BlockLocation::CanonChain, - _ => { - let retracted = route.blocks.iter().take(route.index).cloned().collect::>().into_iter().collect::>(); - let enacted = route.blocks.into_iter().skip(route.index).collect::>(); - BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { - ancestor: route.ancestor, - enacted: enacted, - retracted: retracted, - }) + location: match extras.fork_choice { + ForkChoice::New => { + // On new best block we need to make sure that all ancestors + // are moved to "canon chain" + // find the route between old best block and the new one + match route.blocks.len() { + 0 => BlockLocation::CanonChain, + _ => { + let retracted = route.blocks.iter().take(route.index).cloned().collect::>().into_iter().collect::>(); + let enacted = route.blocks.into_iter().skip(route.index).collect::>(); + BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { + ancestor: route.ancestor, + enacted: enacted, + retracted: retracted, + }) + } } - } - } else { - BlockLocation::Branch - } + }, + ForkChoice::Old => BlockLocation::Branch, + }, } } + /// Mark a block to be considered finalized. Returns `Some(())` if the operation succeeds, and `None` if the block + /// hash is not found. + pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) -> Option<()> { + let mut block_details = self.block_details(&block_hash)?; + block_details.is_finalized = true; + + self.update_block_details(batch, block_hash, block_details); + Some(()) + } + + /// Prepares extras block detail update. + fn update_block_details(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) { + let mut details_map = HashMap::new(); + details_map.insert(block_hash, block_details); + + // We're only updating one existing value. So it shouldn't suffer from cache decoherence problem. + let mut write_details = self.pending_block_details.write(); + batch.extend_with_cache(db::COL_EXTRA, &mut *write_details, details_map, CacheUpdatePolicy::Overwrite); + } + /// Prepares extras update. fn prepare_update(&self, batch: &mut DBTransaction, update: ExtrasUpdate, is_best: bool) { @@ -1101,6 +1176,18 @@ impl BlockChain { } } + /// Iterator that lists `first` and then all of `first`'s ancestors, by extended header. + pub fn ancestry_with_metadata_iter<'a>(&'a self, first: H256) -> AncestryWithMetadataIter { + AncestryWithMetadataIter { + current: if self.is_known(&first) { + first + } else { + H256::default() // zero hash + }, + chain: self + } + } + /// Given a block's `parent`, find every block header which represents a valid possible uncle. pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { self.find_uncle_hashes(parent, uncle_generations) @@ -1166,7 +1253,7 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. - fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, is_finalized: bool, metadata: Option>) -> HashMap { let block = view!(BlockView, block_bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); @@ -1181,6 +1268,8 @@ impl BlockChain { total_difficulty: info.total_difficulty, parent: parent_hash, children: vec![], + is_finalized: is_finalized, + metadata: metadata, }; // write to batch @@ -1418,7 +1507,7 @@ mod tests { use std::sync::Arc; use rustc_hex::FromHex; use hash::keccak; - use kvdb::KeyValueDB; + use kvdb::{KeyValueDB, DBTransaction}; use kvdb_memorydb; use ethereum_types::*; use receipt::{Receipt, TransactionOutcome}; @@ -1441,6 +1530,42 @@ mod tests { BlockChain::new(Config::default(), genesis, db) } + fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { + insert_block_commit(db, bc, bytes, receipts, true) + } + + fn insert_block_commit(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec, commit: bool) -> ImportRoute { + let mut batch = db.transaction(); + let res = insert_block_batch(&mut batch, bc, bytes, receipts); + db.write(batch).unwrap(); + if commit { + bc.commit(); + } + res + } + + fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { + use views::BlockView; + use blockchain::ExtrasInsert; + + let block = view!(BlockView, bytes); + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); + let fork_choice = if block_total_difficulty > bc.best_block_total_difficulty() { + ::engines::ForkChoice::New + } else { + ::engines::ForkChoice::Old + }; + + bc.insert_block(batch, bytes, receipts, ExtrasInsert { + fork_choice: fork_choice, + is_finalized: false, + metadata: None + }) + } + #[test] fn should_cache_best_block() { // given @@ -1452,8 +1577,7 @@ mod tests { assert_eq!(bc.best_block_number(), 0); // when - let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![]); + insert_block_commit(&db, &bc, &first.last().encoded(), vec![], false); assert_eq!(bc.best_block_number(), 0); bc.commit(); // NOTE no db.write here (we want to check if best block is cached) @@ -1483,7 +1607,7 @@ mod tests { assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &first.encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); @@ -1509,7 +1633,7 @@ mod tests { let mut batch = db.transaction(); for block in generator { block_hashes.push(block.hash()); - bc.insert_block(&mut batch, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.commit(); } db.write(batch).unwrap(); @@ -1549,14 +1673,10 @@ mod tests { let db = new_db(); let bc = new_chain(&genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); for b in generator { - bc.insert_block(&mut batch, &b.encoded(), vec![]); - bc.commit(); + insert_block(&db, &bc, &b.encoded(), vec![]); } - db.write(batch).unwrap(); - assert_eq!(uncle_headers, bc.find_uncle_headers(&b4a_hash, 3).unwrap()); // TODO: insert block that already includes one of them as an uncle to check it's not allowed. } @@ -1590,9 +1710,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1604,7 +1724,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1665,9 +1785,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1683,7 +1803,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1723,16 +1843,16 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let ir1 = bc.insert_block(&mut batch, &b1.last().encoded(), vec![]); + let ir1 = insert_block_batch(&mut batch, &bc, &b1.last().encoded(), vec![]); bc.commit(); - let ir2 = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let ir2 = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); - let ir3b = bc.insert_block(&mut batch, &b3b.last().encoded(), vec![]); + let ir3b = insert_block_batch(&mut batch, &bc, &b3b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.block_hash(3).unwrap(), b3b_hash); let mut batch = db.transaction(); - let ir3a = bc.insert_block(&mut batch, &b3a.last().encoded(), vec![]); + let ir3a = insert_block_batch(&mut batch, &bc, &b3a.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1837,7 +1957,7 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &first.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); assert_eq!(bc.best_block_hash(), first_hash); @@ -1896,7 +2016,7 @@ mod tests { let db = new_db(); let bc = new_chain(&genesis, db.clone()); let mut batch =db.transaction(); - bc.insert_block(&mut batch, &b1, vec![]); + insert_block_batch(&mut batch, &bc, &b1, vec![]); db.write(batch).unwrap(); bc.commit(); @@ -1907,14 +2027,6 @@ mod tests { } } - fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { - let mut batch = db.transaction(); - let res = bc.insert_block(&mut batch, bytes, receipts); - db.write(batch).unwrap(); - bc.commit(); - res - } - #[test] fn test_logs() { let t1 = Transaction { @@ -2198,12 +2310,12 @@ mod tests { let mut batch = db.transaction(); // create a longer fork for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.commit(); } assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); } @@ -2230,7 +2342,7 @@ mod tests { // create a longer fork for (i, block) in generator.into_iter().enumerate() { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.insert_epoch_transition(&mut batch, i as u64, EpochTransition { block_hash: block.hash(), block_number: i as u64 + 1, @@ -2241,7 +2353,7 @@ mod tests { assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); bc.insert_epoch_transition(&mut batch, 999, EpochTransition { block_hash: uncle.last().hash(), block_number: 1, @@ -2291,11 +2403,7 @@ mod tests { // and a non-canonical fork of 8 from genesis. let fork_hash = { for block in fork_generator { - let mut batch = db.transaction(); - - bc.insert_block(&mut batch, &block.encoded(), vec![]); - bc.commit(); - db.write(batch).unwrap(); + insert_block(&db, &bc, &block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 7); @@ -2303,11 +2411,7 @@ mod tests { }; for block in next_generator { - let mut batch = db.transaction(); - bc.insert_block(&mut batch, &block.encoded(), vec![]); - bc.commit(); - - db.write(batch).unwrap(); + insert_block(&db, &bc, &block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 10); diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 97583a693a6..3fb25e7b1b1 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -23,6 +23,7 @@ use db::Key; use engines::epoch::{Transition as EpochTransition}; use header::BlockNumber; use receipt::Receipt; +use rlp; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; @@ -167,7 +168,7 @@ impl Key for u64 { } /// Familial details concerning a block -#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] +#[derive(Debug, Clone)] pub struct BlockDetails { /// Block number pub number: BlockNumber, @@ -177,6 +178,57 @@ pub struct BlockDetails { pub parent: H256, /// List of children block hashes pub children: Vec, + /// Whether the block is considered finalized + pub is_finalized: bool, + /// Additional block metadata + pub metadata: Option>, +} + +impl rlp::Encodable for BlockDetails { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + let use_short_version = self.metadata.is_none() && !self.is_finalized; + + match use_short_version { + true => { stream.begin_list(4); }, + false => { stream.begin_list(6); }, + } + + stream.append(&self.number); + stream.append(&self.total_difficulty); + stream.append(&self.parent); + stream.append_list(&self.children); + if !use_short_version { + stream.append(&self.is_finalized); + stream.append(&self.metadata); + } + } +} + +impl rlp::Decodable for BlockDetails { + fn decode(rlp: &rlp::Rlp) -> Result { + let use_short_version = match rlp.item_count()? { + 4 => true, + 6 => false, + _ => return Err(rlp::DecoderError::RlpIncorrectListLen), + }; + + Ok(BlockDetails { + number: rlp.val_at(0)?, + total_difficulty: rlp.val_at(1)?, + parent: rlp.val_at(2)?, + children: rlp.list_at(3)?, + is_finalized: if use_short_version { + false + } else { + rlp.val_at(4)? + }, + metadata: if use_short_version { + None + } else { + rlp.val_at(5)? + }, + }) + } } impl HeapSizeOf for BlockDetails { diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 062068c704d..f991692dedf 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -33,4 +33,5 @@ pub use self::cache::CacheSize; pub use self::config::Config; pub use self::extras::{BlockReceipts, BlockDetails, TransactionAddress}; pub use self::import_route::ImportRoute; +pub use self::update::ExtrasInsert; pub use types::tree_route::TreeRoute; diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index a5251c1ed8e..b695b9236b0 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -22,3 +22,13 @@ pub struct ExtrasUpdate<'a> { /// Modified transaction addresses (None signifies removed transactions). pub transactions_addresses: HashMap>, } + +/// Extra information in block insertion. +pub struct ExtrasInsert { + /// The primitive fork choice before applying finalization rules. + pub fork_choice: ::engines::ForkChoice, + /// Is the inserted block considered finalized. + pub is_finalized: bool, + /// New block local metadata. + pub metadata: Option>, +} diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 76d78e3df63..993ecdda216 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -33,7 +33,7 @@ use util_error::UtilError; // other use ethereum_types::{H256, Address, U256}; use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert}; use client::ancient_import::AncientVerifier; use client::Error as ClientError; use client::{ @@ -50,13 +50,13 @@ use client::{ IoClient, }; use encoded; -use engines::{EthEngine, EpochTransition}; +use engines::{EthEngine, EpochTransition, ForkChoice}; use error::{ImportErrorKind, BlockImportErrorKind, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use vm::{EnvInfo, LastHashes}; use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; use factory::{Factories, VmFactory}; -use header::{BlockNumber, Header}; +use header::{BlockNumber, Header, ExtendedHeader}; use io::{IoChannel, IoError}; use log_entry::LocalizedLogEntry; use miner::{Miner, MinerService}; @@ -73,10 +73,12 @@ use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Databa use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, Action}; use types::filter::Filter; use types::mode::Mode as IpcMode; +use types::ancestry_action::AncestryAction; use verification; use verification::{PreverifiedBlock, Verifier}; use verification::queue::BlockQueue; use views::BlockView; +use parity_machine::{Finalizable, WithMetadata}; // re-export pub use types::blockchain_info::BlockChainInfo; @@ -396,6 +398,7 @@ impl Importer { last_hashes, client.factories.clone(), is_epoch_begin, + &mut chain.ancestry_with_metadata_iter(*header.parent_hash()), ); let mut locked_block = enact_result.map_err(|e| { @@ -467,6 +470,44 @@ impl Importer { let mut batch = DBTransaction::new(); + let ancestry_actions = self.engine.ancestry_actions(block.block(), &mut chain.ancestry_with_metadata_iter(*parent)); + + let best_hash = chain.best_block_hash(); + let metadata = block.block().metadata().map(Into::into); + let is_finalized = block.block().is_finalized(); + + let new = ExtendedHeader { + header: header.clone(), + is_finalized: is_finalized, + metadata: metadata, + parent_total_difficulty: chain.block_details(&parent).expect("Parent block is in the database; qed").total_difficulty + }; + + let best = { + let hash = best_hash; + let header = chain.block_header_data(&hash) + .expect("Best block is in the database; qed") + .decode() + .expect("Stored block header is valid RLP; qed"); + let details = chain.block_details(&hash) + .expect("Best block is in the database; qed"); + + ExtendedHeader { + parent_total_difficulty: details.total_difficulty - *header.difficulty(), + is_finalized: details.is_finalized, + metadata: details.metadata, + + header: header, + } + }; + + let route = chain.tree_route(best_hash, *parent).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); + let fork_choice = if route.is_from_route_finalized { + ForkChoice::Old + } else { + self.engine.fork_choice(&new, &best) + }; + // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. // TODO: Prove it with a test. @@ -485,7 +526,17 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); - let route = chain.insert_block(&mut batch, block_data, receipts.clone()); + + for ancestry_action in ancestry_actions { + let AncestryAction::MarkFinalized(ancestry) = ancestry_action; + chain.mark_finalized(&mut batch, ancestry).expect("Engine's ancestry action must be known blocks; qed"); + } + + let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { + fork_choice: fork_choice, + is_finalized: is_finalized, + metadata: new.metadata, + }); client.tracedb.read().import(&mut batch, TraceImportRequest { traces: traces.into(), @@ -2069,6 +2120,7 @@ impl PrepareOpenBlock for Client { gas_range_target, extra_data, is_epoch_begin, + &mut chain.ancestry_with_metadata_iter(best_header.hash()), ).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed"); // Add uncles @@ -2284,6 +2336,7 @@ mod tests { use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use kvdb::DBTransaction; + use blockchain::ExtrasInsert; let client = generate_dummy_client(0); let genesis = client.chain_info().best_block_hash; @@ -2296,7 +2349,11 @@ mod tests { let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new()); + another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); go_thread.store(true, Ordering::SeqCst); }); go diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 6a3166f7c04..fab32346572 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -392,6 +392,7 @@ impl PrepareOpenBlock for TestBlockChainClient { gas_range_target, extra_data, false, + &mut Vec::new().into_iter(), ).expect("Opening block for tests will not fail."); // TODO [todr] Override timestamp for predictability open_block.set_timestamp(*self.latest_block_timestamp.read()); @@ -739,7 +740,8 @@ impl BlockChainClient for TestBlockChainClient { } } if adding { Vec::new() } else { blocks } - } + }, + is_from_route_finalized: false, }) } diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index ed9a9a4f251..02bb88c51f2 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -33,7 +33,7 @@ use error::{Error, BlockError}; use ethjson; use machine::{AuxiliaryData, Call, EthereumMachine}; use hash::keccak; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; @@ -957,6 +957,7 @@ impl Engine for AuthorityRound { &self, block: &mut ExecutedBlock, epoch_begin: bool, + _ancestry: &mut Iterator, ) -> Result<(), Error> { // with immediate transitions, we don't use the epoch mechanism anyway. // the genesis is always considered an epoch, but we ignore it intentionally. @@ -1348,6 +1349,10 @@ impl Engine for AuthorityRound { Some(Box::new(::snapshot::PoaSnapshot)) } } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -1407,9 +1412,9 @@ mod tests { 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 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1441,9 +1446,9 @@ mod tests { 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 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1696,7 +1701,7 @@ mod tests { 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(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); let client = generate_dummy_client(0); @@ -1731,7 +1736,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1740,7 +1745,7 @@ mod tests { engine.step(); // step 3 - let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); b2.push_transaction(Transaction { action: Action::Create, nonce: U256::from(0), @@ -1779,7 +1784,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1788,7 +1793,7 @@ mod tests { 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 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr2, "0".into()); assert_eq!(engine.generate_seal(b2.block(), &genesis_header), Seal::None); @@ -1796,7 +1801,7 @@ mod tests { // step 4 // the spec sets the maximum_empty_steps to 2 so we will now seal an empty block and include the empty step messages - let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b3 = b3.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1829,7 +1834,7 @@ mod tests { engine.register_client(Arc::downgrade(&client) as _); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1839,7 +1844,7 @@ mod tests { // step 3 // the signer of the accumulated empty step message should be rewarded - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let addr1_balance = b2.block().state().balance(&addr1).unwrap(); // after closing the block `addr1` should be reward twice, one for the included empty step message and another for block creation @@ -1962,6 +1967,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); let b1 = b1.close_and_lock(); @@ -1983,6 +1989,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); let addr1_balance = b2.block().state().balance(&addr1).unwrap(); diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index bbefddccb74..e99fd88dcbc 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -25,7 +25,7 @@ use block::*; use engines::{Engine, Seal, ConstructedVerifier, EngineError}; use error::{BlockError, Error}; use ethjson; -use header::Header; +use header::{Header, ExtendedHeader}; use client::EngineClient; use machine::{AuxiliaryData, Call, EthereumMachine}; use super::signer::EngineSigner; @@ -191,6 +191,10 @@ impl Engine for BasicAuthority { fn snapshot_components(&self) -> Option> { None } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -247,7 +251,7 @@ mod tests { 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()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 40a96e2b713..c16203f1053 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use engines::{Engine, Seal}; -use parity_machine::{Machine, Transactions}; +use parity_machine::{Machine, Transactions, TotalScoredHeader}; /// An engine which does not provide any consensus mechanism, just seals blocks internally. /// Only seals blocks which have transactions. @@ -33,7 +33,9 @@ impl InstantSeal { } impl Engine for InstantSeal - where M::LiveBlock: Transactions + where M::LiveBlock: Transactions, + M::ExtendedHeader: TotalScoredHeader, + ::Value: Ord { fn name(&self) -> &str { "InstantSeal" @@ -61,6 +63,10 @@ impl Engine for InstantSeal fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp >= parent_timestamp } + + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -80,7 +86,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index e019636f53a..0878b4595f1 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -52,15 +52,25 @@ use spec::CommonParams; use transaction::{self, UnverifiedTransaction, SignedTransaction}; use ethkey::Signature; -use parity_machine::{Machine, LocalizedMachine as Localized}; +use parity_machine::{Machine, LocalizedMachine as Localized, TotalScoredHeader}; use ethereum_types::{H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; use bytes::Bytes; +use types::ancestry_action::AncestryAction; /// Default EIP-210 contract code. /// As defined in https://github.com/ethereum/EIPs/pull/210 pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b"; +/// Fork choice. +#[derive(Debug, PartialEq, Eq)] +pub enum ForkChoice { + /// Choose the new block. + New, + /// Choose the current best block. + Old, +} + /// Voting errors. #[derive(Debug)] pub enum EngineError { @@ -208,6 +218,7 @@ pub trait Engine: Sync + Send { &self, _block: &mut M::LiveBlock, _epoch_begin: bool, + _ancestry: &mut Iterator, ) -> Result<(), M::Error> { Ok(()) } @@ -348,6 +359,24 @@ pub trait Engine: Sync + Send { fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp > parent_timestamp } + + /// Gather all ancestry actions. Called at the last stage when a block is committed. The Engine must guarantee that + /// the ancestry exists. + fn ancestry_actions(&self, _block: &M::LiveBlock, _ancestry: &mut Iterator) -> Vec { + Vec::new() + } + + /// Check whether the given new block is the best block, after finalization check. + fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; +} + +/// Check whether a given block is the best block based on the default total difficulty rule. +pub fn total_difficulty_fork_choice(new: &T, best: &T) -> ForkChoice where ::Value: Ord { + if new.total_score() > best.total_score() { + ForkChoice::New + } else { + ForkChoice::Old + } } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 278eb037c06..c6025e62471 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -19,7 +19,7 @@ use engines::Engine; use engines::block_reward::{self, RewardKind}; use header::BlockNumber; use machine::WithRewards; -use parity_machine::{Header, LiveBlock, WithBalances}; +use parity_machine::{Header, LiveBlock, WithBalances, TotalScoredHeader}; /// Params for a null engine. #[derive(Clone, Default)] @@ -58,7 +58,10 @@ impl Default for NullEngine { } } -impl Engine for NullEngine { +impl Engine for NullEngine + where M::ExtendedHeader: TotalScoredHeader, + ::Value: Ord +{ fn name(&self) -> &str { "NullEngine" } @@ -101,4 +104,8 @@ impl Engine for NullEngine { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } + + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 93fc347e942..52bf5ff67b8 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -35,7 +35,7 @@ use unexpected::{OutOfBounds, Mismatch}; use client::EngineClient; use bytes::Bytes; use error::{Error, BlockError}; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use rlp::Rlp; use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; @@ -530,7 +530,7 @@ impl Engine for Tendermint { Ok(()) } - fn on_new_block(&self, block: &mut ExecutedBlock, epoch_begin: bool) -> Result<(), Error> { + fn on_new_block(&self, block: &mut ExecutedBlock, epoch_begin: bool, _ancestry: &mut Iterator) -> Result<(), Error> { if !epoch_begin { return Ok(()) } // genesis is never a new block, but might as well check. @@ -765,6 +765,10 @@ impl Engine for Tendermint { *self.client.write() = Some(client.clone()); self.validators.register_client(client); } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -800,7 +804,7 @@ mod tests { let db = spec.ensure_db_good(db, &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block(), &genesis_header) { (b, seal) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 09151415c87..9b3945e38b1 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -25,7 +25,7 @@ use ethereum_types::{H256, H64, U256, Address}; use unexpected::{OutOfBounds, Mismatch}; use block::*; use error::{BlockError, Error}; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use engines::{self, Engine}; use ethjson; use rlp::Rlp; @@ -222,14 +222,6 @@ impl Engine for Arc { header.set_difficulty(difficulty); } - fn on_new_block( - &self, - _block: &mut ExecutedBlock, - _begins_epoch: bool, - ) -> Result<(), Error> { - Ok(()) - } - /// Apply the block reward on finalisation of the block. /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { @@ -364,6 +356,10 @@ impl Engine for Arc { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> engines::ForkChoice { + engines::total_difficulty_fork_choice(new, current) + } } impl Ethash { @@ -538,7 +534,7 @@ mod tests { 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()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap()); } @@ -587,7 +583,7 @@ mod tests { 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()]); - let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let mut uncle = Header::new(); let uncle_author: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into(); uncle.set_author(uncle_author); @@ -605,7 +601,7 @@ mod tests { 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()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); let ubi_contract: Address = "00efdd5883ec628983e9063c7d969fe268bbf310".into(); diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index ba71eb30497..3e9675aa35b 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -34,6 +34,19 @@ enum Seal { Without, } +/// Extended block header, wrapping `Header` with finalized and total difficulty information. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExtendedHeader { + /// The actual header. + pub header: Header, + /// Whether the block underlying this header is considered finalized. + pub is_finalized: bool, + /// The parent block difficulty. + pub parent_total_difficulty: U256, + /// The block metadata information. + pub metadata: Option>, +} + /// A block header. /// /// Reflects the specific RLP fields of a block in the chain with additional room for the seal @@ -368,21 +381,48 @@ impl HeapSizeOf for Header { impl ::parity_machine::Header for Header { fn bare_hash(&self) -> H256 { Header::bare_hash(self) } - fn hash(&self) -> H256 { Header::hash(self) } - fn seal(&self) -> &[Vec] { Header::seal(self) } - fn author(&self) -> &Address { Header::author(self) } - fn number(&self) -> BlockNumber { Header::number(self) } } impl ::parity_machine::ScoredHeader for Header { + type Value = U256; + fn score(&self) -> &U256 { self.difficulty() } fn set_score(&mut self, score: U256) { self.set_difficulty(score) } } +impl ::parity_machine::Header for ExtendedHeader { + fn bare_hash(&self) -> H256 { self.header.bare_hash() } + fn hash(&self) -> H256 { self.header.hash() } + fn seal(&self) -> &[Vec] { self.header.seal() } + fn author(&self) -> &Address { self.header.author() } + fn number(&self) -> BlockNumber { self.header.number() } +} + +impl ::parity_machine::ScoredHeader for ExtendedHeader { + type Value = U256; + + fn score(&self) -> &U256 { self.header.difficulty() } + fn set_score(&mut self, score: U256) { self.header.set_difficulty(score) } +} + +impl ::parity_machine::TotalScoredHeader for ExtendedHeader { + type Value = U256; + + fn total_score(&self) -> U256 { self.parent_total_difficulty + *self.header.difficulty() } +} + +impl ::parity_machine::FinalizableHeader for ExtendedHeader { + fn is_finalized(&self) -> bool { self.is_finalized } +} + +impl ::parity_machine::WithMetadataHeader for ExtendedHeader { + fn metadata(&self) -> Option<&[u8]> { self.metadata.as_ref().map(|v| v.as_ref()) } +} + #[cfg(test)] mod tests { use rustc_hex::FromHex; diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index d0d434b1de0..1bd3805ef3b 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -25,7 +25,7 @@ use builtin::Builtin; use client::{BlockInfo, CallContract}; use error::Error; use executive::Executive; -use header::{BlockNumber, Header}; +use header::{BlockNumber, Header, ExtendedHeader}; use spec::CommonParams; use state::{CleanupMode, Substate}; use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType, Tracing}; @@ -422,10 +422,12 @@ pub enum AuxiliaryRequest { impl ::parity_machine::Machine for EthereumMachine { type Header = Header; + type ExtendedHeader = ExtendedHeader; type LiveBlock = ExecutedBlock; type EngineClient = ::client::EngineClient; type AuxiliaryRequest = AuxiliaryRequest; + type AncestryAction = ::types::ancestry_action::AncestryAction; type Error = Error; } diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index ae1805e85bd..3c3b47ce9c5 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -22,7 +22,7 @@ use tempdir::TempDir; use error::{Error, ErrorKind}; use blockchain::generator::{BlockGenerator, BlockBuilder}; -use blockchain::BlockChain; +use blockchain::{BlockChain, ExtrasInsert}; use snapshot::{chunk_secondary, Error as SnapshotError, Progress, SnapshotComponents}; use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; @@ -49,7 +49,11 @@ fn chunk_and_restore(amount: u64) { // build the blockchain. let mut batch = DBTransaction::new(); for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![], ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); bc.commit(); } diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 32b8beab830..e57d16a6549 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -19,7 +19,7 @@ use account_provider::AccountProvider; use ethereum_types::{H256, U256, Address}; use block::{OpenBlock, Drain}; -use blockchain::{BlockChain, Config as BlockChainConfig}; +use blockchain::{BlockChain, Config as BlockChainConfig, ExtrasInsert}; use bytes::Bytes; use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify, ChainMessageType, PrepareOpenBlock}; use ethkey::KeyPair; @@ -148,6 +148,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; b.set_timestamp(rolling_timestamp); @@ -265,7 +266,12 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![]); + // Total difficulty is always 0 here. + bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); bc.commit(); } db.write(batch).unwrap(); @@ -280,7 +286,12 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![]); + // Total difficulty is always 0 here. + bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); bc.commit(); } db.write(batch).unwrap(); diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 72d0d473716..a98667b1423 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -87,6 +87,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; root_block.set_timestamp(rolling_timestamp); @@ -115,6 +116,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; parent_block.set_timestamp(rolling_timestamp); @@ -141,7 +143,8 @@ fn can_trace_block_and_uncle_reward() { author.clone(), (3141562.into(), 31415620.into()), vec![], - false + false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; block.set_timestamp(rolling_timestamp); diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 03a6d6f8d41..de2f6c7195d 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -455,6 +455,8 @@ mod tests { total_difficulty: header.difficulty().clone(), parent: header.parent_hash().clone(), children: Vec::new(), + is_finalized: false, + metadata: None, } }) } diff --git a/ethcore/types/src/ancestry_action.rs b/ethcore/types/src/ancestry_action.rs new file mode 100644 index 00000000000..d9915cfee42 --- /dev/null +++ b/ethcore/types/src/ancestry_action.rs @@ -0,0 +1,27 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Actions on ancestry blocks when working on a new block. + +use ethereum_types::H256; + +#[derive(Debug, PartialEq, Eq, Clone)] +/// Actions on a live block's parent block. Only committed when the live block is committed. Those actions here must +/// respect the normal blockchain reorganization rules. +pub enum AncestryAction { + /// Mark an ancestry block as finalized. + MarkFinalized(H256), +} diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 83a1cc65579..18e0dde86ad 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -46,6 +46,7 @@ pub mod state_diff; pub mod trace_filter; pub mod tree_route; pub mod verification_queue_info; +pub mod ancestry_action; /// Type for block number. pub type BlockNumber = u64; diff --git a/ethcore/types/src/tree_route.rs b/ethcore/types/src/tree_route.rs index b3fe431ab99..5d1bddd87b3 100644 --- a/ethcore/types/src/tree_route.rs +++ b/ethcore/types/src/tree_route.rs @@ -27,4 +27,6 @@ pub struct TreeRoute { pub ancestor: H256, /// An index where best common ancestor would be. pub index: usize, + /// Whether it has finalized blocks from `from` (inclusive) to `ancestor` (exclusive). + pub is_from_route_finalized: bool, } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 54ee403d954..075a42d7319 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -40,13 +40,35 @@ pub trait Header { fn number(&self) -> u64; } -/// a header with an associated score (difficulty in PoW terms) +/// A header with an associated score (difficulty in PoW terms) pub trait ScoredHeader: Header { + type Value; + /// Get the score of this header. - fn score(&self) -> &U256; + fn score(&self) -> &Self::Value; /// Set the score of this header. - fn set_score(&mut self, score: U256); + fn set_score(&mut self, score: Self::Value); +} + +/// A header with associated total score. +pub trait TotalScoredHeader: Header { + type Value; + + /// Get the total score of this header. + fn total_score(&self) -> Self::Value; +} + +/// A header with finalized information. +pub trait FinalizableHeader: Header { + /// Get whether this header is considered finalized, so that it will never be replaced in reorganization. + fn is_finalized(&self) -> bool; +} + +/// A header with metadata information. +pub trait WithMetadataHeader: Header { + /// Get the current header metadata. + fn metadata(&self) -> Option<&[u8]>; } /// A "live" block is one which is in the process of the transition. @@ -73,16 +95,36 @@ pub trait Transactions: LiveBlock { fn transactions(&self) -> &[Self::Transaction]; } +/// Trait for blocks which have finalized information. +pub trait Finalizable: LiveBlock { + /// Get whether the block is finalized. + fn is_finalized(&self) -> bool; + /// Mark the block as finalized. + fn mark_finalized(&mut self); +} + +/// A state machine with block metadata. +pub trait WithMetadata: LiveBlock { + /// Get the current live block metadata. + fn metadata(&self) -> Option<&[u8]>; + /// Set the current live block metadata. + fn set_metadata(&mut self, value: Option>); +} + /// Generalization of types surrounding blockchain-suitable state machines. pub trait Machine: for<'a> LocalizedMachine<'a> { /// The block header type. type Header: Header; /// The live block type. type LiveBlock: LiveBlock; + /// Block header with metadata information. + type ExtendedHeader: Header; /// A handle to a blockchain client for this machine. type EngineClient: ?Sized; /// A description of needed auxiliary data. type AuxiliaryRequest; + /// Actions taken on ancestry blocks when commiting a new block. + type AncestryAction; /// Errors which can occur when querying or interacting with the machine. type Error; From 295d81b718c10262d9ac1aef660a44361ddc854c Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 16 May 2018 20:09:59 +0200 Subject: [PATCH 105/147] typo (#8640) --- parity/main.rs | 6 +++--- secret_store/src/acl_storage.rs | 2 +- secret_store/src/key_server_set.rs | 10 +++++----- secret_store/src/key_storage.rs | 2 +- secret_store/src/serialization.rs | 2 +- secret_store/src/traits.rs | 2 +- secret_store/src/types/all.rs | 2 +- secret_store/src/types/error.rs | 8 ++++---- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 03b04a8c82f..06671cbfebf 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -54,15 +54,15 @@ fn latest_exe_path() -> Option { fn set_spec_name_override(spec_name: String) { if let Err(e) = create_dir_all(default_hypervisor_path()) - .and_then(|_| File::create(updates_path("spec_name_overide")) + .and_then(|_| File::create(updates_path("spec_name_override")) .and_then(|mut f| f.write_all(spec_name.as_bytes()))) { - warn!("Couldn't override chain spec: {} at {:?}", e, updates_path("spec_name_overide")); + warn!("Couldn't override chain spec: {} at {:?}", e, updates_path("spec_name_override")); } } fn take_spec_name_override() -> Option { - let p = updates_path("spec_name_overide"); + let p = updates_path("spec_name_override"); let r = File::open(p.clone()).ok() .and_then(|mut f| { let mut spec_name = String::new(); f.read_to_string(&mut spec_name).ok().map(|_| spec_name) }); let _ = remove_file(p); diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index b3427fa1b20..bc75cfec44c 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -106,7 +106,7 @@ impl CachedContract { pub fn check(&mut self, requester: Address, document: &ServerKeyId) -> Result { if let Some(client) = self.client.get() { - // call contract to check accesss + // call contract to check access match self.contract_addr { Some(contract_address) => { let do_call = |data| client.call_contract(BlockId::Latest, contract_address, data); diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index d13017261c4..8a0d786af98 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -271,7 +271,7 @@ impl CachedContract { pub fn update(&mut self, enacted: Vec, retracted: Vec) { if let Some(client) = self.client.get() { - // read new snapshot from reqistry (if something has chnaged) + // read new snapshot from registry (if something has changed) self.read_from_registry_if_required(&*client, enacted, retracted); // update number of confirmations (if there's future new set) @@ -371,7 +371,7 @@ impl CachedContract { None => { // no contract installed => empty snapshot // WARNING: after restart current_set will be reset to the set from configuration file - // even though we have reset to empty set here. We are not considerning this as an issue + // even though we have reset to empty set here. We are not considering this as an issue // because it is actually the issue of administrator. self.snapshot = Default::default(); self.future_new_set = None; @@ -540,7 +540,7 @@ fn update_number_of_confirmations H256, F2: Fn(H256) -> Option> // not enough confirmations => do nothing Some(_) => return, // if number of confirmations is None, then reorg has happened && we need to reset block - // (some more intelligent startegy is possible, but let's stick to simplest one) + // (some more intelligent strategy is possible, but let's stick to simplest one) None => { future_new_set.block = latest_block(); return; @@ -556,9 +556,9 @@ fn update_number_of_confirmations H256, F2: Fn(H256) -> Option> fn update_last_transaction_block(client: &Client, migration_id: &H256, previous_transaction: &mut Option) -> bool { let last_block = client.block_number(BlockId::Latest).unwrap_or_default(); match previous_transaction.as_ref() { - // no previous transaction => send immideately + // no previous transaction => send immediately None => (), - // previous transaction has been sent for other migration process => send immideately + // previous transaction has been sent for other migration process => send immediately Some(tx) if tx.migration_id != *migration_id => (), // if we have sent the same type of transaction recently => do nothing (hope it will be mined eventually) // if we have sent the same transaction some time ago => diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index 4f78bc338c2..848e6bf2a52 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -108,7 +108,7 @@ pub struct SerializableDocumentKeyShareV0 { /// V1 of encrypted key share, as it is stored by key storage on the single key server. #[derive(Serialize, Deserialize)] struct SerializableDocumentKeyShareV1 { - /// Authore of the entry. + /// Author of the entry. pub author: SerializablePublic, /// Decryption threshold (at least threshold + 1 nodes are required to decrypt data). pub threshold: usize, diff --git a/secret_store/src/serialization.rs b/secret_store/src/serialization.rs index 42209e0de4a..f3e9aa1d76d 100644 --- a/secret_store/src/serialization.rs +++ b/secret_store/src/serialization.rs @@ -117,7 +117,7 @@ impl_bytes!(SerializableSignature, Signature, false, ()); /// Serializable shadow decryption result. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SerializableEncryptedDocumentKeyShadow { - /// Decrypted secret point. It is partially decrypted if shadow decrpytion was requested. + /// Decrypted secret point. It is partially decrypted if shadow decryption was requested. pub decrypted_secret: SerializablePublic, /// Shared common point. pub common_point: SerializablePublic, diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs index 04f2fa1294e..704be1c2545 100644 --- a/secret_store/src/traits.rs +++ b/secret_store/src/traits.rs @@ -94,7 +94,7 @@ pub trait MessageSigner: ServerKeyGenerator { /// Administrative sessions server. pub trait AdminSessionsServer { /// Change servers set so that nodes in new_servers_set became owners of shares for all keys. - /// And old nodes (i.e. cluste nodes except new_servers_set) have clear databases. + /// And old nodes (i.e. cluster nodes except new_servers_set) have clear databases. /// WARNING: newly generated keys will be distributed among all cluster nodes. So this session /// must be followed with cluster nodes change (either via contract, or config files). fn change_servers_set(&self, old_set_signature: RequestSignature, new_set_signature: RequestSignature, new_servers_set: BTreeSet) -> Result<(), Error>; diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index bfc58779a6b..ab0aea1b133 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -94,7 +94,7 @@ pub struct ClusterConfiguration { /// Shadow decryption result. #[derive(Clone, Debug, PartialEq)] pub struct EncryptedDocumentKeyShadow { - /// Decrypted secret point. It is partially decrypted if shadow decrpytion was requested. + /// Decrypted secret point. It is partially decrypted if shadow decryption was requested. pub decrypted_secret: ethkey::Public, /// Shared common point. pub common_point: Option, diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs index 1fceb120e82..eae914ec866 100644 --- a/secret_store/src/types/error.rs +++ b/secret_store/src/types/error.rs @@ -60,7 +60,7 @@ pub enum Error { /// Document key with this ID is not yet stored. DocumentKeyIsNotFound, /// Consensus is temporary unreachable. Means that something is currently blocking us from either forming - /// consensus group (like disconnecting from too many nodes, which are AGREE to partticipate in consensus) + /// consensus group (like disconnecting from too many nodes, which are AGREE to participate in consensus) /// or from rejecting request (disconnecting from AccessDenied-nodes). ConsensusTemporaryUnreachable, /// Consensus is unreachable. It doesn't mean that it will ALWAYS remain unreachable, but right NOW we have @@ -78,9 +78,9 @@ pub enum Error { InsufficientRequesterData(String), /// Cryptographic error. EthKey(String), - /// I/O error has occured. + /// I/O error has occurred. Io(String), - /// Deserialization error has occured. + /// Deserialization error has occurred. Serde(String), /// Hyper error. Hyper(String), @@ -148,7 +148,7 @@ impl fmt::Display for Error { Error::DocumentKeyIsNotFound => write!(f, "Document key with this ID is not found"), Error::ConsensusUnreachable => write!(f, "Consensus unreachable"), Error::ConsensusTemporaryUnreachable => write!(f, "Consensus temporary unreachable"), - Error::AccessDenied => write!(f, "Access dened"), + Error::AccessDenied => write!(f, "Access denied"), Error::ExclusiveSessionActive => write!(f, "Exclusive session active"), Error::HasActiveSessions => write!(f, "Unable to start exclusive session"), Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), From 555103c739b807b3bd52e09e950d282bcf11f1a4 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 16 May 2018 22:00:33 +0200 Subject: [PATCH 106/147] Changelog for 1.10.4-stable and 1.11.1-beta (#8637) * Add changelog for 1.10.4 * Add changelog for 1.11.1 * Fix Typos --- CHANGELOG.md | 119 ++++++++++++++++++++++++++++++++++++++--- docs/CHANGELOG-1.10.md | 23 ++++++++ 2 files changed, 136 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f839802e7cd..ee66149ed00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,22 @@ -## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-05-09) +## Parity [v1.11.1](https://github.com/paritytech/parity/releases/tag/v1.11.1) (2018-05-15) -This is the Parity 1.11.0-beta release! Hurray! +This is the Parity 1.11.1-beta release! Hurray! Notable changes in reversed alphabetical order: - TOOLING: **Whisper CLI** [#8201](https://github.com/paritytech/parity/pull/8201) - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. - - All whisper RPC APIs are enabled and can be directly acessed. + - All whisper RPC APIs are enabled and can be directly accessed. - JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) - This changes the behaviors of `eth_call` to respect VM errors if any. - In case of `REVERT`, it will also return the reverted return data in hex format. -- ENGINES: **Block reward contract** [#8419](https://github.com/paritytech/parity/pull/8419) +- ENGINES: **Block Reward Contract** [#8419](https://github.com/paritytech/parity/pull/8419) - The _AuRa_ PoA engine has now support for having a contract to calculate the block rewards. - The engine passes a list of benefactors and reward types to the contract which then returns a list of addresses and respective rewards. -- CORE: **Private transactions integration pr** [#6422](https://github.com/paritytech/parity/pull/6422) +- CORE: **Private Transactions** [#6422](https://github.com/paritytech/parity/pull/6422) - Parity now provides a private transactions system. - - Please, check out our wiki to get and [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). + - Please, check out our wiki to get an [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). - CORE: **New Transaction Queue implementation** [#8074](https://github.com/paritytech/parity/pull/8074) - Verification is now done in parallel. - Previous queue had `O(1)` time to get pending set, but `O(n^2)` insertion time. And obviously insertion/removal happens much more often than retrieving the pending set (only for propagation and pending block building) Currently we have `O(n * log(senders))` pending set time (with cache) and `O(tx_per_sender)` (usually within `log(tx_per_sender)`) insertion time. @@ -47,6 +47,113 @@ Notable changes in reversed alphabetical order: The full list of included changes: +- Backports ([#8624](https://github.com/paritytech/parity/pull/8624)) + - Trace precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity/pull/8486)) + - Trace precompiled contracts when the transfer value is not zero + - Add tests for precompiled CALL tracing + - Use byzantium test machine for the new test + - Add notes in comments on why we don't trace all precompiles + - Use is_transferred instead of transferred + - Return error if RLP size of transaction exceeds the limit ([#8473](https://github.com/paritytech/parity/pull/8473)) + - Return error if RLP size of transaction exceeds the limit + - Review comments fixed + - RLP check moved to verifier, corresponding pool test added + - Don't block sync when importing old blocks ([#8530](https://github.com/paritytech/parity/pull/8530)) + - Alter IO queueing. + - Don't require IoMessages to be Clone + - Ancient blocks imported via IoChannel. + - Get rid of private transactions io message. + - Get rid of deadlock and fix disconnected handler. + - Revert to old disconnect condition. + - Fix tests. + - Fix deadlock. + - Refactoring `ethcore-sync` - Fixing warp-sync barrier ([#8543](https://github.com/paritytech/parity/pull/8543)) + - Start dividing sync chain : first supplier method + - WIP - updated chain sync supplier + - Finish refactoring the Chain Sync Supplier + - Create Chain Sync Requester + - Add Propagator for Chain Sync + - Add the Chain Sync Handler + - Move tests from mod -> handler + - Move tests to propagator + - Refactor SyncRequester arguments + - Refactoring peer fork header handler + - Fix wrong highest block number in snapshot sync + - Small refactor... + - Address PR grumbles + - Retry failed CI job + - Fix tests + - PR Grumbles + - Handle socket address parsing errors ([#8545](https://github.com/paritytech/parity/pull/8545)) + - Fix packet count when talking with PAR2 peers ([#8555](https://github.com/paritytech/parity/pull/8555)) + - Support diferent packet counts in different protocol versions. + - Fix light timeouts and eclipse protection. + - Fix devp2p tests. + - Fix whisper-cli compilation. + - Fix compilation. + - Fix ethcore-sync tests. + - Revert "Fix light timeouts and eclipse protection." + - Increase timeouts. + - Add whisper CLI to the pipelines ([#8578](https://github.com/paritytech/parity/pull/8578)) + - Add whisper CLI to the pipelines + - Address todo, ref [#8579](https://github.com/paritytech/parity/pull/8579) + - Rename `whisper-cli binary` to `whisper` ([#8579](https://github.com/paritytech/parity/pull/8579)) + - Rename whisper-cli binary to whisper + - Fix tests + - Remove manually added text to the errors ([#8595](https://github.com/paritytech/parity/pull/8595)) + - Fix account list double 0x display ([#8596](https://github.com/paritytech/parity/pull/8596)) + - Remove unused self import + - Fix account list double 0x display + - Fix BlockReward contract "arithmetic operation overflow" ([#8611](https://github.com/paritytech/parity/pull/8611)) + - Fix BlockReward contract "arithmetic operation overflow" + - Add docs on how execute_as_system works + - Fix typo + - Rlp decode returns Result ([#8527](https://github.com/paritytech/parity/pull/8527)) + - Remove expect ([#8536](https://github.com/paritytech/parity/pull/8536)) + - Remove expect and propagate rlp::DecoderErrors as TrieErrors + - Decoding headers can fail ([#8570](https://github.com/paritytech/parity/pull/8570)) + - Rlp::decode returns Result + - Fix journaldb to handle rlp::decode Result + - Fix ethcore to work with rlp::decode returning Result + - Light client handles rlp::decode returning Result + - Fix tests in rlp_derive + - Fix tests + - Cleanup + - Cleanup + - Allow panic rather than breaking out of iterator + - Let decoding failures when reading from disk blow up + - Syntax + - Fix the trivial grumbles + - Fix failing tests + - Make Account::from_rlp return Result + - Syntx, sigh + - Temp-fix for decoding failures + - Header::decode returns Result + - Do not continue reading from the DB when a value could not be read + - Fix tests + - Handle header decoding in light_sync + - Handling header decoding errors + - Let the DecodeError bubble up unchanged + - Remove redundant error conversion + - Fix compiler warning ([#8590](https://github.com/paritytech/parity/pull/8590)) + - Attempt to fix intermittent test failures ([#8584](https://github.com/paritytech/parity/pull/8584)) + - Block_header can fail so return Result ([#8581](https://github.com/paritytech/parity/pull/8581)) + - Block_header can fail so return Result + - Restore previous return type based on feedback + - Fix failing doc tests running on non-code + - Block::decode() returns Result ([#8586](https://github.com/paritytech/parity/pull/8586)) + - Gitlab test script fixes ([#8573](https://github.com/paritytech/parity/pull/8573)) + - Exclude /docs from modified files. + - Ensure all references in the working tree are available + - Remove duplicated line from test script +- Bump beta to 1.11.1 ([#8627](https://github.com/paritytech/parity/pull/8627)) + +## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.11.0) (2018-05-09) + +This is the Parity 1.11.0-beta release! ~~Hurray!~~ This release has been pulled due to peering issues, please use 1.11.1-beta. + +The full list of included changes: + - Backports ([#8558](https://github.com/paritytech/parity/pull/8558)) - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) - Fetch logs by hash in blockchain database diff --git a/docs/CHANGELOG-1.10.md b/docs/CHANGELOG-1.10.md index 4db8f32bb67..a8c7ad20a75 100644 --- a/docs/CHANGELOG-1.10.md +++ b/docs/CHANGELOG-1.10.md @@ -1,3 +1,26 @@ +## Parity [v1.10.4](https://github.com/paritytech/parity/releases/tag/v1.10.4) (2018-05-15) + +Parity 1.10.4 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Backports ([#8623](https://github.com/paritytech/parity/pull/8623)) + - Fix account list double 0x display ([#8596](https://github.com/paritytech/parity/pull/8596)) + - Remove unused self import + - Fix account list double 0x display + - Trace precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity/pull/8486)) + - Trace precompiled contracts when the transfer value is not zero + - Add tests for precompiled CALL tracing + - Use byzantium test machine for the new test + - Add notes in comments on why we don't trace all precompileds + - Use is_transferred instead of transferred + - Gitlab test script fixes ([#8573](https://github.com/paritytech/parity/pull/8573)) + - Exclude /docs from modified files. + - Ensure all references in the working tree are available + - Remove duplicated line from test script +- Bump stable to 1.10.4 ([#8626](https://github.com/paritytech/parity/pull/8626)) +- Allow stable snaps to be stable. ([#8582](https://github.com/paritytech/parity/pull/8582)) + ## Parity [v1.10.3](https://github.com/paritytech/parity/releases/tag/v1.10.3) (2018-05-08) Parity 1.10.3 marks the first stable release on the 1.10 track. Among others, it improves performance and stability. From d4683d16206eed1ab8092c25b792250af12b9c43 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 16 May 2018 22:01:11 +0200 Subject: [PATCH 107/147] Don't open Browser post-install on Mac (#8641) Since we start parity with the UI disabled per default now, opening the browser post installation will show an annoying error message, confusing the user. This patch removes opening the browser to prevent that annoyance. fixes #8194 --- mac/post-install.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/mac/post-install.sh b/mac/post-install.sh index a364878d889..fc71ee1de6d 100755 --- a/mac/post-install.sh +++ b/mac/post-install.sh @@ -3,6 +3,4 @@ test -f /usr/local/libexec/uninstall-parity.sh && /usr/local/libexec/uninstall-parity.sh || true killall -9 parity && sleep 5 su $USER -c "open /Applications/Parity\ Ethereum.app" -sleep 5 -su $USER -c "open http://127.0.0.1:8180/" exit 0 From e9c602bb4bd4b9f0ce019f9bf1223f5f87d72943 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 16 May 2018 22:01:55 +0200 Subject: [PATCH 108/147] Resumable warp-sync / Seed downloaded snapshots (#8544) * Start dividing sync chain : first supplier method * WIP - updated chain sync supplier * Finish refactoring the Chain Sync Supplier * Create Chain Sync Requester * Add Propagator for Chain Sync * Add the Chain Sync Handler * Move tests from mod -> handler * Move tests to propagator * Refactor SyncRequester arguments * Refactoring peer fork header handler * Fix wrong highest block number in snapshot sync * Small refactor... * Resume warp-sync downloaded chunks * Add comments * Refactoring the previous chunks import * Fix tests * Address PR grumbles * Fix not seeding current snapshot * Address PR Grumbles * Address PR grumble * Retry failed CI job * Update SnapshotService readiness check Fix restoration locking issue for previous chunks restoration * Fix tests * Fix tests * Fix test * Early abort importing previous chunks * PR Grumbles * Update Gitlab CI config * SyncState back to Waiting when Manifest peers disconnect * Move fix * Better fix * Revert GitLab CI changes * Fix Warning * Refactor resuming snapshots * Fix string construction * Revert "Refactor resuming snapshots" This reverts commit 75fd4b553a38e4a49dc5d6a878c70e830ff382eb. * Update informant log * Fix string construction * Refactor resuming snapshots * Fix informant * PR Grumbles * Update informant message : show chunks done * PR Grumbles * Fix * Fix Warning * PR Grumbles --- ethcore/src/snapshot/service.rs | 165 ++++++++++++++++--- ethcore/src/snapshot/tests/service.rs | 8 +- ethcore/src/snapshot/traits.rs | 3 + ethcore/sync/src/chain/handler.rs | 52 ++++-- ethcore/sync/src/chain/mod.rs | 104 +++++++----- ethcore/sync/src/chain/supplier.rs | 26 +-- ethcore/sync/src/snapshot.rs | 71 ++++++-- ethcore/sync/src/tests/snapshot.rs | 4 + ethcore/types/src/restoration_status.rs | 5 + parity/informant.rs | 23 ++- parity/snapshot.rs | 1 + rpc/src/v1/tests/helpers/snapshot_service.rs | 1 + 12 files changed, 361 insertions(+), 102 deletions(-) diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index c5b9123e10f..17c362e0440 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -17,8 +17,8 @@ //! Snapshot network service implementation. use std::collections::HashSet; -use std::io::ErrorKind; -use std::fs; +use std::io::{self, Read, ErrorKind}; +use std::fs::{self, File}; use std::path::PathBuf; use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; @@ -30,6 +30,7 @@ use blockchain::BlockChain; use client::{Client, ChainInfo, ClientIoMessage}; use engines::EthEngine; use error::Error; +use hash::keccak; use ids::BlockId; use io::IoChannel; @@ -270,8 +271,8 @@ impl Service { } } - // delete the temporary restoration dir if it does exist. - if let Err(e) = fs::remove_dir_all(service.restoration_dir()) { + // delete the temporary restoration DB dir if it does exist. + if let Err(e) = fs::remove_dir_all(service.restoration_db()) { if e.kind() != ErrorKind::NotFound { return Err(e.into()) } @@ -325,6 +326,13 @@ impl Service { dir } + // previous snapshot chunks path. + fn prev_chunks_dir(&self) -> PathBuf { + let mut dir = self.snapshot_root.clone(); + dir.push("prev_chunks"); + dir + } + // replace one the client's database with our own. fn replace_client_db(&self) -> Result<(), Error> { let our_db = self.restoration_db(); @@ -406,9 +414,26 @@ impl Service { /// Initialize the restoration synchronously. /// The recover flag indicates whether to recover the restored snapshot. pub fn init_restore(&self, manifest: ManifestData, recover: bool) -> Result<(), Error> { + let mut res = self.restoration.lock(); + let rest_dir = self.restoration_dir(); + let rest_db = self.restoration_db(); + let recovery_temp = self.temp_recovery_dir(); + let prev_chunks = self.prev_chunks_dir(); - let mut res = self.restoration.lock(); + // delete and restore the restoration dir. + if let Err(e) = fs::remove_dir_all(&prev_chunks) { + match e.kind() { + ErrorKind::NotFound => {}, + _ => return Err(e.into()), + } + } + + // Move the previous recovery temp directory + // to `prev_chunks` to be able to restart restoring + // with previously downloaded blocks + // This step is optional, so don't fail on error + fs::rename(&recovery_temp, &prev_chunks).ok(); self.state_chunks.store(0, Ordering::SeqCst); self.block_chunks.store(0, Ordering::SeqCst); @@ -424,29 +449,38 @@ impl Service { } } + *self.status.lock() = RestorationStatus::Initializing { + chunks_done: 0, + }; + fs::create_dir_all(&rest_dir)?; // make new restoration. let writer = match recover { - true => Some(LooseWriter::new(self.temp_recovery_dir())?), + true => Some(LooseWriter::new(recovery_temp)?), false => None }; let params = RestorationParams { - manifest: manifest, + manifest: manifest.clone(), pruning: self.pruning, - db: self.restoration_db_handler.open(&self.restoration_db())?, + db: self.restoration_db_handler.open(&rest_db)?, writer: writer, genesis: &self.genesis_block, - guard: Guard::new(rest_dir), + guard: Guard::new(rest_db), engine: &*self.engine, }; - let state_chunks = params.manifest.state_hashes.len(); - let block_chunks = params.manifest.block_hashes.len(); + let state_chunks = manifest.state_hashes.len(); + let block_chunks = manifest.block_hashes.len(); *res = Some(Restoration::new(params)?); + self.restoring_snapshot.store(true, Ordering::SeqCst); + + // Import previous chunks, continue if it fails + self.import_prev_chunks(&mut res, manifest).ok(); + *self.status.lock() = RestorationStatus::Ongoing { state_chunks: state_chunks as u32, block_chunks: block_chunks as u32, @@ -454,10 +488,65 @@ impl Service { block_chunks_done: self.block_chunks.load(Ordering::SeqCst) as u32, }; - self.restoring_snapshot.store(true, Ordering::SeqCst); Ok(()) } + /// Import the previous chunks into the current restoration + fn import_prev_chunks(&self, restoration: &mut Option, manifest: ManifestData) -> Result<(), Error> { + let prev_chunks = self.prev_chunks_dir(); + + // Restore previous snapshot chunks + let files = fs::read_dir(prev_chunks.as_path())?; + let mut num_temp_chunks = 0; + + for prev_chunk_file in files { + // Don't go over all the files if the restoration has been aborted + if !self.restoring_snapshot.load(Ordering::SeqCst) { + trace!(target:"snapshot", "Aborting importing previous chunks"); + return Ok(()); + } + // Import the chunk, don't fail and continue if one fails + match self.import_prev_chunk(restoration, &manifest, prev_chunk_file) { + Ok(true) => num_temp_chunks += 1, + Err(e) => trace!(target: "snapshot", "Error importing chunk: {:?}", e), + _ => (), + } + } + + trace!(target:"snapshot", "Imported {} previous chunks", num_temp_chunks); + + // Remove the prev temp directory + fs::remove_dir_all(&prev_chunks)?; + + Ok(()) + } + + /// Import a previous chunk at the given path. Returns whether the block was imported or not + fn import_prev_chunk(&self, restoration: &mut Option, manifest: &ManifestData, file: io::Result) -> Result { + let file = file?; + let path = file.path(); + + let mut file = File::open(path.clone())?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer)?; + + let hash = keccak(&buffer); + + let is_state = if manifest.block_hashes.contains(&hash) { + false + } else if manifest.state_hashes.contains(&hash) { + true + } else { + return Ok(false); + }; + + self.feed_chunk_with_restoration(restoration, hash, &buffer, is_state)?; + + trace!(target: "snapshot", "Fed chunk {:?}", hash); + + Ok(true) + } + // finalize the restoration. this accepts an already-locked // restoration as an argument -- so acquiring it again _will_ // lead to deadlock. @@ -499,12 +588,19 @@ impl Service { /// Feed a chunk of either kind. no-op if no restoration or status is wrong. fn feed_chunk(&self, hash: H256, chunk: &[u8], is_state: bool) -> Result<(), Error> { // TODO: be able to process block chunks and state chunks at same time? - let (result, db) = { - let mut restoration = self.restoration.lock(); + let mut restoration = self.restoration.lock(); + self.feed_chunk_with_restoration(&mut restoration, hash, chunk, is_state) + } + /// Feed a chunk with the Restoration + fn feed_chunk_with_restoration(&self, restoration: &mut Option, hash: H256, chunk: &[u8], is_state: bool) -> Result<(), Error> { + let (result, db) = { match self.status() { - RestorationStatus::Inactive | RestorationStatus::Failed => return Ok(()), - RestorationStatus::Ongoing { .. } => { + RestorationStatus::Inactive | RestorationStatus::Failed => { + trace!(target: "snapshot", "Tried to restore chunk {:x} while inactive or failed", hash); + return Ok(()); + }, + RestorationStatus::Ongoing { .. } | RestorationStatus::Initializing { .. } => { let (res, db) = { let rest = match *restoration { Some(ref mut r) => r, @@ -583,11 +679,41 @@ impl SnapshotService for Service { self.reader.read().as_ref().and_then(|r| r.chunk(hash).ok()) } + fn completed_chunks(&self) -> Option> { + let restoration = self.restoration.lock(); + + match *restoration { + Some(ref restoration) => { + let completed_chunks = restoration.manifest.block_hashes + .iter() + .filter(|h| !restoration.block_chunks_left.contains(h)) + .chain( + restoration.manifest.state_hashes + .iter() + .filter(|h| !restoration.state_chunks_left.contains(h)) + ) + .map(|h| *h) + .collect(); + + Some(completed_chunks) + }, + None => None, + } + } + fn status(&self) -> RestorationStatus { let mut cur_status = self.status.lock(); - if let RestorationStatus::Ongoing { ref mut state_chunks_done, ref mut block_chunks_done, .. } = *cur_status { - *state_chunks_done = self.state_chunks.load(Ordering::SeqCst) as u32; - *block_chunks_done = self.block_chunks.load(Ordering::SeqCst) as u32; + + match *cur_status { + RestorationStatus::Initializing { ref mut chunks_done } => { + *chunks_done = self.state_chunks.load(Ordering::SeqCst) as u32 + + self.block_chunks.load(Ordering::SeqCst) as u32; + } + RestorationStatus::Ongoing { ref mut state_chunks_done, ref mut block_chunks_done, .. } => { + *state_chunks_done = self.state_chunks.load(Ordering::SeqCst) as u32; + *block_chunks_done = self.block_chunks.load(Ordering::SeqCst) as u32; + }, + _ => (), } cur_status.clone() @@ -600,6 +726,7 @@ impl SnapshotService for Service { } fn abort_restore(&self) { + trace!(target: "snapshot", "Aborting restore"); self.restoring_snapshot.store(false, Ordering::SeqCst); *self.restoration.lock() = None; *self.status.lock() = RestorationStatus::Inactive; diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 3e3087f2bf7..3fcb0addfab 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -130,12 +130,16 @@ fn guards_delete_folders() { service.init_restore(manifest.clone(), true).unwrap(); assert!(path.exists()); + // The `db` folder should have been deleted, + // while the `temp` one kept service.abort_restore(); - assert!(!path.exists()); + assert!(!path.join("db").exists()); + assert!(path.join("temp").exists()); service.init_restore(manifest.clone(), true).unwrap(); assert!(path.exists()); drop(service); - assert!(!path.exists()); + assert!(!path.join("db").exists()); + assert!(path.join("temp").exists()); } diff --git a/ethcore/src/snapshot/traits.rs b/ethcore/src/snapshot/traits.rs index a81c14f08d5..2b6ee9df9f4 100644 --- a/ethcore/src/snapshot/traits.rs +++ b/ethcore/src/snapshot/traits.rs @@ -30,6 +30,9 @@ pub trait SnapshotService : Sync + Send { /// `None` indicates warp sync isn't supported by the consensus engine. fn supported_versions(&self) -> Option<(u64, u64)>; + /// Returns a list of the completed chunks + fn completed_chunks(&self) -> Option>; + /// Get raw chunk for a given hash. fn chunk(&self, hash: H256) -> Option; diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index a55c0319b37..7668a645945 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -100,14 +100,27 @@ impl SyncHandler { } /// Called by peer when it is disconnecting - pub fn on_peer_aborting(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId) { - trace!(target: "sync", "== Disconnecting {}: {}", peer, io.peer_info(peer)); - sync.handshaking_peers.remove(&peer); - if sync.peers.contains_key(&peer) { - debug!(target: "sync", "Disconnected {}", peer); - sync.clear_peer_download(peer); - sync.peers.remove(&peer); - sync.active_peers.remove(&peer); + pub fn on_peer_aborting(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + trace!(target: "sync", "== Disconnecting {}: {}", peer_id, io.peer_info(peer_id)); + sync.handshaking_peers.remove(&peer_id); + if sync.peers.contains_key(&peer_id) { + debug!(target: "sync", "Disconnected {}", peer_id); + sync.clear_peer_download(peer_id); + sync.peers.remove(&peer_id); + sync.active_peers.remove(&peer_id); + + if sync.state == SyncState::SnapshotManifest { + // Check if we are asking other peers for + // the snapshot manifest as well. + // If not, return to initial state + let still_asking_manifest = sync.peers.iter() + .filter(|&(id, p)| sync.active_peers.contains(id) && p.asking == PeerAsking::SnapshotManifest) + .next().is_none(); + + if still_asking_manifest { + sync.state = ChainSync::get_init_state(sync.warp_sync, io.chain()); + } + } sync.continue_sync(io); } } @@ -320,6 +333,10 @@ impl SyncHandler { } fn on_peer_confirmed(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + { + let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); + peer.confirmation = ForkConfirmation::Confirmed; + } sync.sync_peer(io, peer_id, false); } @@ -344,8 +361,8 @@ impl SyncHandler { } trace!(target: "sync", "{}: Confirmed peer", peer_id); - peer.confirmation = ForkConfirmation::Confirmed; if !io.chain_overlay().read().contains_key(&fork_number) { + trace!(target: "sync", "Inserting (fork) block {} header", fork_number); io.chain_overlay().write().insert(fork_number, header.to_vec()); } } @@ -560,6 +577,10 @@ impl SyncHandler { sync.continue_sync(io); return Ok(()); }, + RestorationStatus::Initializing { .. } => { + trace!(target: "warp", "{}: Snapshot restoration is initializing", peer_id); + return Ok(()); + } RestorationStatus::Ongoing { .. } => { trace!(target: "sync", "{}: Snapshot restoration is ongoing", peer_id); }, @@ -659,11 +680,16 @@ impl SyncHandler { // Let the current sync round complete first. sync.active_peers.insert(peer_id.clone()); debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); - if let Some((fork_block, _)) = sync.fork_block { - SyncRequester::request_fork_header(sync, io, peer_id, fork_block); - } else { - SyncHandler::on_peer_confirmed(sync, io, peer_id); + + match sync.fork_block { + Some((fork_block, _)) => { + SyncRequester::request_fork_header(sync, io, peer_id, fork_block); + }, + _ => { + SyncHandler::on_peer_confirmed(sync, io, peer_id); + } } + Ok(()) } diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 381936949bd..5af28925493 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -245,9 +245,12 @@ pub struct SyncStatus { impl SyncStatus { /// Indicates if snapshot download is in progress pub fn is_snapshot_syncing(&self) -> bool { - self.state == SyncState::SnapshotManifest - || self.state == SyncState::SnapshotData - || self.state == SyncState::SnapshotWaiting + match self.state { + SyncState::SnapshotManifest | + SyncState::SnapshotData | + SyncState::SnapshotWaiting => true, + _ => false, + } } /// Returns max no of peers to display in informants @@ -643,7 +646,7 @@ impl ChainSync { } } - /// Resume downloading + /// Resume downloading fn continue_sync(&mut self, io: &mut SyncIo) { // Collect active peers that can sync let confirmed_peers: Vec<(PeerId, u8)> = self.peers.iter().filter_map(|(peer_id, peer)| @@ -751,26 +754,45 @@ impl ChainSync { } } - if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { - SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); - return; + // Only ask for old blocks if the peer has a higher difficulty + if force || higher_difficulty { + if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { + SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); + return; + } + } else { + trace!(target: "sync", "peer {} is not suitable for asking old blocks", peer_id); + self.deactivate_peer(io, peer_id); } }, SyncState::SnapshotData => { - if let RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } = io.snapshot_service().status() { - if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target: "sync", "Snapshot queue full, pausing sync"); - self.state = SyncState::SnapshotWaiting; + match io.snapshot_service().status() { + RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { + // Initialize the snapshot if not already done + self.snapshot.initialize(io.snapshot_service()); + if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target: "sync", "Snapshot queue full, pausing sync"); + self.state = SyncState::SnapshotWaiting; + return; + } + }, + RestorationStatus::Initializing { .. } => { + trace!(target: "warp", "Snapshot is stil initializing."); return; - } + }, + _ => { + return; + }, } + if peer_snapshot_hash.is_some() && peer_snapshot_hash == self.snapshot.snapshot_hash() { self.clear_peer_download(peer_id); SyncRequester::request_snapshot_data(self, io, peer_id); } }, SyncState::SnapshotManifest | //already downloading from other peer - SyncState::Waiting | SyncState::SnapshotWaiting => () + SyncState::Waiting | + SyncState::SnapshotWaiting => () } } else { trace!(target: "sync", "Skipping peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); @@ -861,10 +883,7 @@ impl ChainSync { packet.append(&chain.best_block_hash); packet.append(&chain.genesis_hash); if warp_protocol { - let manifest = match self.old_blocks.is_some() { - true => None, - false => io.snapshot_service().manifest(), - }; + let manifest = io.snapshot_service().manifest(); let block_number = manifest.as_ref().map_or(0, |m| m.block_number); let manifest_hash = manifest.map_or(H256::new(), |m| keccak(m.into_rlp())); packet.append(&manifest_hash); @@ -908,29 +927,36 @@ impl ChainSync { } fn check_resume(&mut self, io: &mut SyncIo) { - if self.state == SyncState::Waiting && !io.chain().queue_info().is_full() { - self.state = SyncState::Blocks; - self.continue_sync(io); - } else if self.state == SyncState::SnapshotWaiting { - match io.snapshot_service().status() { - RestorationStatus::Inactive => { - trace!(target:"sync", "Snapshot restoration is complete"); - self.restart(io); - }, - RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { - if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target:"sync", "Resuming snapshot sync"); - self.state = SyncState::SnapshotData; + match self.state { + SyncState::Waiting if !io.chain().queue_info().is_full() => { + self.state = SyncState::Blocks; + self.continue_sync(io); + }, + SyncState::SnapshotWaiting => { + match io.snapshot_service().status() { + RestorationStatus::Inactive => { + trace!(target:"sync", "Snapshot restoration is complete"); + self.restart(io); + }, + RestorationStatus::Initializing { .. } => { + trace!(target:"sync", "Snapshot restoration is initializing"); + }, + RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { + if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target:"sync", "Resuming snapshot sync"); + self.state = SyncState::SnapshotData; + self.continue_sync(io); + } + }, + RestorationStatus::Failed => { + trace!(target: "sync", "Snapshot restoration aborted"); + self.state = SyncState::WaitingPeers; + self.snapshot.clear(); self.continue_sync(io); - } - }, - RestorationStatus::Failed => { - trace!(target: "sync", "Snapshot restoration aborted"); - self.state = SyncState::WaitingPeers; - self.snapshot.clear(); - self.continue_sync(io); - }, - } + }, + } + }, + _ => (), } } diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs index 0bfb8569823..e0245fdbcd9 100644 --- a/ethcore/sync/src/chain/supplier.rs +++ b/ethcore/sync/src/chain/supplier.rs @@ -120,8 +120,9 @@ impl SyncSupplier { None => return Ok(Some((BLOCK_HEADERS_PACKET, RlpStream::new_list(0)))) //no such header, return nothing } } else { - trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, r.val_at::(0)?, max_headers, skip, reverse); - r.val_at(0)? + let number = r.val_at::(0)?; + trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, number, max_headers, skip, reverse); + number }; let mut number = if reverse { @@ -135,7 +136,10 @@ impl SyncSupplier { let inc = (skip + 1) as BlockNumber; let overlay = io.chain_overlay().read(); - while number <= last && count < max_count { + // We are checking the `overlay` as well since it's where the ForkBlock + // header is cached : so peers can confirm we are on the right fork, + // even if we are not synced until the fork block + while (number <= last || overlay.contains_key(&number)) && count < max_count { if let Some(hdr) = overlay.get(&number) { trace!(target: "sync", "{}: Returning cached fork header", peer_id); data.extend_from_slice(hdr); @@ -152,8 +156,7 @@ impl SyncSupplier { break; } number -= inc; - } - else { + } else { number += inc; } } @@ -237,20 +240,20 @@ impl SyncSupplier { /// Respond to GetSnapshotManifest request fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let count = r.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); + trace!(target: "warp", "{} -> GetSnapshotManifest", peer_id); if count != 0 { - debug!(target: "sync", "Invalid GetSnapshotManifest request, ignoring."); + debug!(target: "warp", "Invalid GetSnapshotManifest request, ignoring."); return Ok(None); } let rlp = match io.snapshot_service().manifest() { Some(manifest) => { - trace!(target: "sync", "{} <- SnapshotManifest", peer_id); + trace!(target: "warp", "{} <- SnapshotManifest", peer_id); let mut rlp = RlpStream::new_list(1); rlp.append_raw(&manifest.into_rlp(), 1); rlp }, None => { - trace!(target: "sync", "{}: No manifest to return", peer_id); + trace!(target: "warp", "{}: No snapshot manifest to return", peer_id); RlpStream::new_list(0) } }; @@ -260,15 +263,16 @@ impl SyncSupplier { /// Respond to GetSnapshotData request fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let hash: H256 = r.val_at(0)?; - trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); + trace!(target: "warp", "{} -> GetSnapshotData {:?}", peer_id, hash); let rlp = match io.snapshot_service().chunk(hash) { Some(data) => { let mut rlp = RlpStream::new_list(1); - trace!(target: "sync", "{} <- SnapshotData", peer_id); + trace!(target: "warp", "{} <- SnapshotData", peer_id); rlp.append(&data); rlp }, None => { + trace!(target: "warp", "{}: No snapshot data to return", peer_id); RlpStream::new_list(0) } }; diff --git a/ethcore/sync/src/snapshot.rs b/ethcore/sync/src/snapshot.rs index 917e84c8846..b603a2a007a 100644 --- a/ethcore/sync/src/snapshot.rs +++ b/ethcore/sync/src/snapshot.rs @@ -14,10 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use hash::keccak; +use ethcore::snapshot::{ManifestData, SnapshotService}; use ethereum_types::H256; +use hash::keccak; +use rand::{thread_rng, Rng}; + use std::collections::HashSet; -use ethcore::snapshot::ManifestData; +use std::iter::FromIterator; #[derive(PartialEq, Eq, Debug)] pub enum ChunkType { @@ -32,6 +35,7 @@ pub struct Snapshot { completed_chunks: HashSet, snapshot_hash: Option, bad_hashes: HashSet, + initialized: bool, } impl Snapshot { @@ -44,7 +48,27 @@ impl Snapshot { completed_chunks: HashSet::new(), snapshot_hash: None, bad_hashes: HashSet::new(), + initialized: false, + } + } + + /// Sync the Snapshot completed chunks with the Snapshot Service + pub fn initialize(&mut self, snapshot_service: &SnapshotService) { + if self.initialized { + return; + } + + if let Some(completed_chunks) = snapshot_service.completed_chunks() { + self.completed_chunks = HashSet::from_iter(completed_chunks); } + + trace!( + target: "snapshot", + "Snapshot is now initialized with {} completed chunks.", + self.completed_chunks.len(), + ); + + self.initialized = true; } /// Clear everything. @@ -54,6 +78,7 @@ impl Snapshot { self.downloading_chunks.clear(); self.completed_chunks.clear(); self.snapshot_hash = None; + self.initialized = false; } /// Check if currently downloading a snapshot. @@ -89,18 +114,35 @@ impl Snapshot { Err(()) } - /// Find a chunk to download + /// Find a random chunk to download pub fn needed_chunk(&mut self) -> Option { - // check state chunks first - let chunk = self.pending_state_chunks.iter() - .chain(self.pending_block_chunks.iter()) - .find(|&h| !self.downloading_chunks.contains(h) && !self.completed_chunks.contains(h)) - .cloned(); + // Find all random chunks: first blocks, then state + let needed_chunks = { + let chunk_filter = |h| !self.downloading_chunks.contains(h) && !self.completed_chunks.contains(h); + + let needed_block_chunks = self.pending_block_chunks.iter() + .filter(|&h| chunk_filter(h)) + .map(|h| *h) + .collect::>(); + + // If no block chunks to download, get the state chunks + if needed_block_chunks.len() == 0 { + self.pending_state_chunks.iter() + .filter(|&h| chunk_filter(h)) + .map(|h| *h) + .collect::>() + } else { + needed_block_chunks + } + }; + + // Get a random chunk + let chunk = thread_rng().choose(&needed_chunks); if let Some(hash) = chunk { self.downloading_chunks.insert(hash.clone()); } - chunk + chunk.map(|h| *h) } pub fn clear_chunk_download(&mut self, hash: &H256) { @@ -185,8 +227,15 @@ mod test { let requested: Vec = (0..40).map(|_| snapshot.needed_chunk().unwrap()).collect(); assert!(snapshot.needed_chunk().is_none()); - assert_eq!(&requested[0..20], &manifest.state_hashes[..]); - assert_eq!(&requested[20..40], &manifest.block_hashes[..]); + + let requested_all_block_chunks = manifest.block_hashes.iter() + .all(|h| requested.iter().any(|rh| rh == h)); + assert!(requested_all_block_chunks); + + let requested_all_state_chunks = manifest.state_hashes.iter() + .all(|h| requested.iter().any(|rh| rh == h)); + assert!(requested_all_state_chunks); + assert_eq!(snapshot.downloading_chunks.len(), 40); assert_eq!(snapshot.validate_chunk(&state_chunks[4]), Ok(ChunkType::State(manifest.state_hashes[4].clone()))); diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index 804ebe9c535..864f3d4dc6e 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -80,6 +80,10 @@ impl SnapshotService for TestSnapshotService { Some((1, 2)) } + fn completed_chunks(&self) -> Option> { + Some(vec![]) + } + fn chunk(&self, hash: H256) -> Option { self.chunks.get(&hash).cloned() } diff --git a/ethcore/types/src/restoration_status.rs b/ethcore/types/src/restoration_status.rs index 0cc7fccc08e..51f5b8aa0a3 100644 --- a/ethcore/types/src/restoration_status.rs +++ b/ethcore/types/src/restoration_status.rs @@ -21,6 +21,11 @@ pub enum RestorationStatus { /// No restoration. Inactive, + /// Restoration is initalizing + Initializing { + /// Number of chunks done/imported + chunks_done: u32, + }, /// Ongoing restoration. Ongoing { /// Total number of state chunks. diff --git a/parity/informant.rs b/parity/informant.rs index beeb258b522..a4d2727c359 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -278,15 +278,12 @@ impl Informant { } = full_report; let rpc_stats = self.rpc_stats.as_ref(); - - let (snapshot_sync, snapshot_current, snapshot_total) = self.snapshot.as_ref().map_or((false, 0, 0), |s| + let snapshot_sync = sync_info.as_ref().map_or(false, |s| s.snapshot_sync) && self.snapshot.as_ref().map_or(false, |s| match s.status() { - RestorationStatus::Ongoing { state_chunks, block_chunks, state_chunks_done, block_chunks_done } => - (true, state_chunks_done + block_chunks_done, state_chunks + block_chunks), - _ => (false, 0, 0), + RestorationStatus::Ongoing { .. } | RestorationStatus::Initializing { .. } => true, + _ => false, } ); - let snapshot_sync = snapshot_sync && sync_info.as_ref().map_or(false, |s| s.snapshot_sync); if !importing && !snapshot_sync && elapsed < Duration::from_secs(30) { return; } @@ -318,7 +315,19 @@ impl Informant { paint(Green.bold(), format!("{:5}", queue_info.unverified_queue_size)), paint(Green.bold(), format!("{:5}", queue_info.verified_queue_size)) ), - true => format!("Syncing snapshot {}/{}", snapshot_current, snapshot_total), + true => { + self.snapshot.as_ref().map_or(String::new(), |s| + match s.status() { + RestorationStatus::Ongoing { state_chunks, block_chunks, state_chunks_done, block_chunks_done } => { + format!("Syncing snapshot {}/{}", state_chunks_done + block_chunks_done, state_chunks + block_chunks) + }, + RestorationStatus::Initializing { chunks_done } => { + format!("Snapshot initializing ({} chunks restored)", chunks_done) + }, + _ => String::new(), + } + ) + }, }, false => String::new(), }, diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 423864679a2..3c0dadedaa3 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -122,6 +122,7 @@ fn restore_using(snapshot: Arc, reader: &R, match snapshot.status() { RestorationStatus::Ongoing { .. } => Err("Snapshot file is incomplete and missing chunks.".into()), + RestorationStatus::Initializing { .. } => Err("Snapshot restoration is still initializing.".into()), RestorationStatus::Failed => Err("Snapshot restoration failed.".into()), RestorationStatus::Inactive => { info!("Restoration complete."); diff --git a/rpc/src/v1/tests/helpers/snapshot_service.rs b/rpc/src/v1/tests/helpers/snapshot_service.rs index 25abab578e9..099773ab522 100644 --- a/rpc/src/v1/tests/helpers/snapshot_service.rs +++ b/rpc/src/v1/tests/helpers/snapshot_service.rs @@ -43,6 +43,7 @@ impl TestSnapshotService { impl SnapshotService for TestSnapshotService { fn manifest(&self) -> Option { None } fn supported_versions(&self) -> Option<(u64, u64)> { None } + fn completed_chunks(&self) -> Option> { Some(vec![]) } fn chunk(&self, _hash: H256) -> Option { None } fn status(&self) -> RestorationStatus { self.status.lock().clone() } fn begin_restore(&self, _manifest: ManifestData) { } From 54c0fedb70da9f754ea7ba1e97b19e9f34ac312b Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 17 May 2018 10:58:35 +0200 Subject: [PATCH 109/147] Fix not downloading old blocks (#8642) --- ethcore/src/client/client.rs | 62 +++++++++++++++++++++++------------- ethcore/sync/src/blocks.rs | 2 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 993ecdda216..5cfe8fce82c 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -17,7 +17,7 @@ use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; use std::fmt; use std::str::FromStr; -use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; +use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Arc, Weak}; use std::time::{Instant, Duration}; @@ -210,6 +210,8 @@ pub struct Client { queue_transactions: IoChannelQueue, /// Ancient blocks import queue queue_ancient_blocks: IoChannelQueue, + /// Hashes of pending ancient block wainting to be included + pending_ancient_blocks: RwLock>, /// Consensus messages import queue queue_consensus_message: IoChannelQueue, @@ -433,6 +435,7 @@ impl Importer { let hash = header.hash(); let _import_lock = self.import_lock.lock(); + trace!(target: "client", "Trying to import old block #{}", header.number()); { trace_time!("import_old_block"); // verify the block, passing the chain for updating the epoch verifier. @@ -761,6 +764,7 @@ impl Client { notify: RwLock::new(Vec::new()), queue_transactions: IoChannelQueue::new(MAX_TX_QUEUE_SIZE), queue_ancient_blocks: IoChannelQueue::new(MAX_ANCIENT_BLOCKS_QUEUE_SIZE), + pending_ancient_blocks: RwLock::new(HashSet::new()), queue_consensus_message: IoChannelQueue::new(usize::max_value()), last_hashes: RwLock::new(VecDeque::new()), factories: factories, @@ -2008,7 +2012,7 @@ impl BlockChainClient for Client { impl IoClient for Client { fn queue_transactions(&self, transactions: Vec, peer_id: usize) { let len = transactions.len(); - self.queue_transactions.queue(&mut self.io_channel.lock(), len, move |client| { + self.queue_transactions.queue(&mut self.io_channel.lock(), move |client| { trace_time!("import_queued_transactions"); let txs: Vec = transactions @@ -2032,23 +2036,32 @@ impl IoClient for Client { { // check block order - if self.chain.read().is_known(&header.hash()) { + if self.chain.read().is_known(&hash) { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } - let status = self.block_status(BlockId::Hash(*header.parent_hash())); - if status == BlockStatus::Unknown || status == BlockStatus::Pending { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); + + let parent_hash = *header.parent_hash(); + let parent_pending = self.pending_ancient_blocks.read().contains(&parent_hash); + let status = self.block_status(BlockId::Hash(parent_hash)); + if !parent_pending && (status == BlockStatus::Unknown || status == BlockStatus::Pending) { + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(parent_hash))); } } - match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), 1, move |client| { - client.importer.import_old_block( + self.pending_ancient_blocks.write().insert(hash); + + trace!(target: "client", "Queuing old block #{}", header.number()); + match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), move |client| { + let result = client.importer.import_old_block( &header, &block_bytes, &receipts_bytes, &**client.db.read(), &*client.chain.read() - ).map(|_| ()).unwrap_or_else(|e| { + ); + + client.pending_ancient_blocks.write().remove(&hash); + result.map(|_| ()).unwrap_or_else(|e| { error!(target: "client", "Error importing ancient block: {}", e); }); }) { @@ -2058,7 +2071,7 @@ impl IoClient for Client { } fn queue_consensus_message(&self, message: Bytes) { - match self.queue_consensus_message.queue(&mut self.io_channel.lock(), 1, move |client| { + match self.queue_consensus_message.queue(&mut self.io_channel.lock(), move |client| { if let Err(e) = client.engine().handle_message(&message) { debug!(target: "poa", "Invalid message received: {}", e); } @@ -2471,35 +2484,38 @@ impl fmt::Display for QueueError { /// Queue some items to be processed by IO client. struct IoChannelQueue { - currently_queued: Arc, + queue: Arc>>>, limit: usize, } impl IoChannelQueue { pub fn new(limit: usize) -> Self { IoChannelQueue { - currently_queued: Default::default(), + queue: Default::default(), limit, } } - pub fn queue(&self, channel: &mut IoChannel, count: usize, fun: F) -> Result<(), QueueError> where - F: Fn(&Client) + Send + Sync + 'static, + pub fn queue(&self, channel: &mut IoChannel, fun: F) -> Result<(), QueueError> + where F: Fn(&Client) + Send + Sync + 'static { - let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed); - ensure!(queue_size < self.limit, QueueError::Full(self.limit)); + { + let mut queue = self.queue.lock(); + let queue_size = queue.len(); + ensure!(queue_size < self.limit, QueueError::Full(self.limit)); - let currently_queued = self.currently_queued.clone(); + queue.push_back(Box::new(fun)); + } + + let queue = self.queue.clone(); let result = channel.send(ClientIoMessage::execute(move |client| { - currently_queued.fetch_sub(count, AtomicOrdering::SeqCst); - fun(client); + while let Some(fun) = queue.lock().pop_front() { + fun(client); + } })); match result { - Ok(_) => { - self.currently_queued.fetch_add(count, AtomicOrdering::SeqCst); - Ok(()) - }, + Ok(_) => Ok(()), Err(e) => Err(QueueError::Channel(e)), } } diff --git a/ethcore/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs index 321c783b4db..283f4ed610d 100644 --- a/ethcore/sync/src/blocks.rs +++ b/ethcore/sync/src/blocks.rs @@ -266,7 +266,7 @@ impl BlockCollection { } } - /// Get a valid chain of blocks ordered in descending order and ready for importing into blockchain. + /// Get a valid chain of blocks ordered in ascending order and ready for importing into blockchain. pub fn drain(&mut self) -> Vec { if self.blocks.is_empty() || self.head.is_none() { return Vec::new(); From d4cbedcbaf7f0c92e628c5ca2a69c2fc31e8fc3f Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 18 May 2018 08:04:25 +0200 Subject: [PATCH 110/147] Remove HostInfo::next_nonce (#8644) --- util/network-devp2p/src/host.rs | 12 +++++++----- util/network/src/lib.rs | 2 -- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 4cca2e6e5a7..f3446845fb1 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -210,6 +210,13 @@ pub struct HostInfo { pub public_endpoint: Option, } +impl HostInfo { + fn next_nonce(&mut self) -> H256 { + self.nonce = keccak(&self.nonce); + self.nonce + } +} + impl HostInfoTrait for HostInfo { fn id(&self) -> &NodeId { self.keys.public() @@ -219,11 +226,6 @@ impl HostInfoTrait for HostInfo { self.keys.secret() } - fn next_nonce(&mut self) -> H256 { - self.nonce = keccak(&self.nonce); - self.nonce - } - fn client_version(&self) -> &str { &self.config.client_version } diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 1327a9ad59f..0137543fdd5 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -332,8 +332,6 @@ pub trait HostInfo { fn id(&self) -> &NodeId; /// Returns secret key fn secret(&self) -> &Secret; - /// Increments and returns connection nonce. - fn next_nonce(&mut self) -> H256; /// Returns the client version. fn client_version(&self) -> &str; } From fdfbe7b00627eb35f303716d58a86e09293ab80a Mon Sep 17 00:00:00 2001 From: David Date: Sun, 20 May 2018 06:27:59 +0200 Subject: [PATCH 111/147] Remove the Keccak C library and use the pure Rust impl (#8657) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add license and readme * Use pure rust implementation * Bump version to 0.1.1 * Don't use C, prefer the pure Rust implementation * Add test for `write_keccak` * Bump version * Add benchmarks * Add benchmarks * Add keccak_256, keccak_512, keccak_256_unchecked and keccak_512_unchecked – mostly for compatibility with ethash * Remove failed git merge attempt from external git repo Cargo.lock updates * whitespace * Mark unsafe function unsafe * Unsafe calls in unsafe block * Document unsafety invariants * Revert unintended changes to Cargo.lock --- Cargo.lock | 53 +++++----- ethash/src/keccak.rs | 20 ++-- util/hash/Cargo.toml | 11 +- util/hash/benches/keccak_256.rs | 36 +++++++ util/hash/build.rs | 26 ----- util/hash/src/lib.rs | 55 +++++++--- util/hash/src/tinykeccak.c | 177 -------------------------------- 7 files changed, 119 insertions(+), 259 deletions(-) create mode 100644 util/hash/benches/keccak_256.rs delete mode 100644 util/hash/build.rs delete mode 100644 util/hash/src/tinykeccak.c diff --git a/Cargo.lock b/Cargo.lock index b4d6bd315f2..e4c80310c1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", "rlp_derive 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -487,7 +487,7 @@ version = "1.12.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -541,7 +541,7 @@ dependencies = [ "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "kvdb-rocksdb 0.1.0", @@ -633,7 +633,7 @@ dependencies = [ "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -685,7 +685,7 @@ dependencies = [ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", @@ -730,7 +730,7 @@ dependencies = [ "ethkey 0.3.0", "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -769,7 +769,7 @@ dependencies = [ "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", @@ -803,7 +803,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -851,7 +851,7 @@ dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -875,7 +875,7 @@ dependencies = [ "ethkey 0.3.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -900,7 +900,7 @@ dependencies = [ "ethkey 0.3.0", "evm 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unexpected 0.1.0", @@ -1021,7 +1021,7 @@ dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memory-cache 0.1.0", @@ -1345,7 +1345,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1454,9 +1454,8 @@ dependencies = [ [[package]] name = "keccak-hash" -version = "0.1.0" +version = "0.1.2" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1648,7 +1647,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "plain_hasher 0.1.0", "rlp 0.2.1", ] @@ -1987,7 +1986,7 @@ dependencies = [ "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2051,7 +2050,7 @@ dependencies = [ "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2115,7 +2114,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2208,7 +2207,7 @@ dependencies = [ "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "macros 0.1.0", @@ -2244,7 +2243,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.12.0", @@ -2332,7 +2331,7 @@ dependencies = [ "ethcore-bytes 0.1.0", "ethcore-sync 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2440,7 +2439,7 @@ dependencies = [ "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memorydb 0.1.1", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2736,7 +2735,7 @@ dependencies = [ "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", ] [[package]] @@ -3472,7 +3471,7 @@ version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", ] @@ -3482,7 +3481,7 @@ version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", "trie-standardmap 0.1.0", ] @@ -3630,7 +3629,7 @@ dependencies = [ "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", "rlp 0.2.1", diff --git a/ethash/src/keccak.rs b/ethash/src/keccak.rs index 8ca4f543844..36fb1735470 100644 --- a/ethash/src/keccak.rs +++ b/ethash/src/keccak.rs @@ -21,32 +21,36 @@ pub type H256 = [u8; 32]; pub mod keccak_512 { use super::hash; - pub use self::hash::keccak_512 as unchecked; + pub use self::hash::keccak_512_unchecked as unchecked; pub fn write(input: &[u8], output: &mut [u8]) { - unsafe { hash::keccak_512(output.as_mut_ptr(), output.len(), input.as_ptr(), input.len()) }; + hash::keccak_512(input, output); } pub fn inplace(input: &mut [u8]) { - // This is safe since `sha3_*` uses an internal buffer and copies the result to the output. This + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This // means that we can reuse the input buffer for both input and output. - unsafe { hash::keccak_512(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()) }; + unsafe { + hash::keccak_512_unchecked(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()); + } } } pub mod keccak_256 { use super::hash; - pub use self::hash::keccak_256 as unchecked; + pub use self::hash::keccak_256_unchecked as unchecked; #[allow(dead_code)] pub fn write(input: &[u8], output: &mut [u8]) { - unsafe { hash::keccak_256(output.as_mut_ptr(), output.len(), input.as_ptr(), input.len()) }; + hash::keccak_256(input, output); } pub fn inplace(input: &mut [u8]) { - // This is safe since `sha3_*` uses an internal buffer and copies the result to the output. This + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This // means that we can reuse the input buffer for both input and output. - unsafe { hash::keccak_256(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()) }; + unsafe { + hash::keccak_256_unchecked(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()); + } } } diff --git a/util/hash/Cargo.toml b/util/hash/Cargo.toml index da91cd733cb..e136ada305a 100644 --- a/util/hash/Cargo.toml +++ b/util/hash/Cargo.toml @@ -1,18 +1,15 @@ [package] description = "Rust bindings for tinykeccak C library" -homepage = "http://parity.io" +homepage = "https://github.com/paritytech/keccak-hash" +readme = "README.md" license = "GPL-3.0" name = "keccak-hash" -version = "0.1.0" +version = "0.1.2" authors = ["Parity Technologies "] -build = "build.rs" [dependencies] ethereum-types = "0.3" -tiny-keccak = "1.3" - -[build-dependencies] -cc = "1.0" +tiny-keccak = "1.4.1" [dev-dependencies] tempdir = "0.3" diff --git a/util/hash/benches/keccak_256.rs b/util/hash/benches/keccak_256.rs new file mode 100644 index 00000000000..8b398417d8b --- /dev/null +++ b/util/hash/benches/keccak_256.rs @@ -0,0 +1,36 @@ +#![feature(test)] + +extern crate test; +extern crate ethereum_types; +extern crate keccak_hash; + +use keccak_hash::{keccak, write_keccak}; +use test::Bencher; + +#[bench] +fn bench_keccak_256_with_empty_input(b: &mut Bencher) { + let empty = [0u8;0]; + b.bytes = empty.len() as u64; + b.iter(|| { + let _out = keccak(empty); + }) +} + +#[bench] +fn bench_keccak_256_with_typical_input(b: &mut Bencher) { + let data: Vec = From::from("some medum length string with important information"); + b.bytes = data.len() as u64; + b.iter(|| { + let _out = keccak(&data); + }) +} + +#[bench] +fn bench_keccak_256_with_large_input(b: &mut Bencher) { + // 4096 chars + let data: Vec = From::from("IGxcKBr1Qp7tuqtpSVhAbvt7UgWLEi7mCA6Wa185seLSIJLFS8K1aAFO9AwtO9b3n9SM3Qg136JMmy9Mj9gZ84IaUm8XioPtloabFDU5ZR1wvauJT6jNTkvBVBpUigIsyU7C1u3s99vKP64LpXqvo1hwItZKtISxmUAgzzjv5q14V4G9bkKAnmc4M5xixgLsDGZmnj6HcOMY3XRkWtxN3RscSKwPA0bfpgtz27ZVHplbXwloYRgRLpjRhZJc7sqO8RFnTHKasVkxVRcUoDBvWNJK27TbLvQQcfxETI2Q1H6c2cBAchi8unSiuxqy5rIvVxcl9rsmmRY4IXLEG9qKntUGbiIRLjEffIP9ODoWog0GbWLmMtfvtf24hWVwXz6Ap5oUAR0kLgb7HYIYrOwKjvfV25iEF7GW8cjhl8yowXx1zcgW4t6NJNqJlGzRKx8MvRWQXvHz8h8JxcHl7S64i6PAkxI9eCLXLvs8cpbEQQHt05Zu6GKm6IInjc9mSh52WFuGhgjbno69XzfkBufJs6c9tZuBf6ErVPj4UxmT82ajCruDusk79Tlvb8oQMLjoplQc1alQaLQwSsMac9iVp9MiE3PeYnTTepJ1V10tp79fciDAnNPJgPcRfDYv0REcSFgR9Q7yWhbpPpyBjO7HwOykDQVGtV0ZbDFrFRygLAXagAIkOPc9HDfcBNID1Q2MGk8ijVWMyvmGz1wzbpNfFcQaSOm8olhwoLyHUGvkyXegh44iNsPBUvSicNxTTDowtMqO5azleuWEjzxCobYbASDopvl6JeJjRtEBBO5YCQJiHsYjlXh9QR5Q543GsqhzRLgcHNRSZYLMZqDmIABXZi8VRNJMZyWXDRKHOGDmcHWe55uZomW6FnyU0uSRKxxz66K0JWfxuFzzxAR0vR4ZZCTemgDRQuDwL1loC3KUMjDpU13jUgoPc4UJUVfwQ4f4BUY3X51Cfw9FLw4oX39KoFoiCP2Z6z27gZUY1IlE59WoXGLj4KjTp4C16ZihG080gfDIWlXnDEk3VwBuBFyKWARB63sGLrGnn27b1gHWMaop6sPvkQgWxkEKIqsxDIvXLZJg2s23V8Gqtt0FeA7R3RCvBysF4jNjQ7NiQTIQWQZ8G9gO4mEsftolSZv6FlSpNeBKIIwYWSO2R6vkgeiz06euE9bwwnenOjwPNGTGk8WHIOZBJ1hIP0ejVU2i2ca9ON0phSAnewqjo5W3PtZf2Q7mDvp9imuVWoy4t8XcZq8I2Un9jVjes9Xi0FLN2t71vLFWLWZmGDzwXxpqEgkARS1WjtJoYXCBmRnXEPj6jQfwMZWKPYSIrmOogxMVoWvA8wrof6utfJna9JezyTnrBJSCuGTSNmwwAXRLoFYxF1RITyN8mI2KmHSfvLXBrbE6kmAkjsm4XJb6kria7oUQQ1gzJuCyB7oNHjZTBFNhNa7VeQ1s1xLOwZXLOAjZ4MDTYKnF7giGJGyswb5KQxkOV9orbuAu6pJsjtql6h1UD3BcNUkG3oz8kJNepbuCN3vNCJcZOX1VrQi0PWkDwyvECrQ2E1CgbU6GpWatpg2sCTpo9W62pCcWBK2FKUFWqU3qo2T7T1Mk2ZtM6hE9I8op0M7xlGE91Mn7ea6aq93MWp7nvFlBvbaMIoeU4MpDx0BeOSkROY03ZBJ0x7K8nJrNUhAtvxp17c9oFk0VxLiuRbAAcwDUormOmpVXZNIcqnap4twEVYaSIowfcNojyUSrFL5nPc8ZG93WgNNl9rpUPZhssVml3DvXghI80A9SW3QauzohTQAX2bkWelFBHnuG2LKrsJ8en51N6CkjcS5b87y1DVMZELcZ1n5s8PCAA1wyn7OSZlgw00GRzch1YwMoHzBBgIUtMO9HrMyuhgqIPJP7KcKbQkKhtvBXKplX8SCfSlOwUkLwHNKm3HYVE0uVfJ91NAsUrGoCOjYiXYpoRT8bjAPWTm6fDlTq2sbPOyTMoc4xRasmiOJ7B0PT6UxPzCPImM4100sPFxp7Kofv4okKZWTPKTefeYiPefI3jRgfDtEIP9E6a35LZD75lBNMXYlAqL3qlnheUQD1WQimFTHiDsW6bmURptNvtkMjEXzXzpWbnyxBskUGTvP2YQjtSAhWliDXkv6t1x71cYav7TQbqvbIzMRQQsguSGYMbs8YIC4DC9ep5reWAfanlTxcxksbEhQ7FGzXOvcufeGnDl2C85gWfryVzwN7kOZiSEktFMOQ1ngRC23y1fCOiHQVQJ2nLnaW7GILb9wkN1mBTRuHsOefRJST0TnRxcn4bBq4MIibIitVyjPRy7G5XvPEcL4pFaW1HCPGm6pUOEEwTer32JObNGCyTFB1BI2cRLJu5BHPjgG3mmb0gGkGlIfh8D2b2amogpivqEn2r9Y1KOKQ8ufJvG2mYfkevco9DuEZ9Nmzkm6XkCTZaFMNHqbfQaKqsEYK7i2N1KfkBct1leW2H9MQ9QO7AHCqXHK47b1kWVIm6pSJA1yV4funzCqXnIJCEURQgHiKf38YpN7ylLhe1J4UvSG3KeesZNeFFIZOEP9HZUSFMpnN1MOrwejojK0D4qzwucYWtXrTQ8I7UP5QhlijIsCKckUa9C1Osjrq8cgSclYNGt19wpy0onUbX1rOQBUlAAUJs4CyXNU0wmVUjw7tG1LUC8my4s9KZDUj4R5UcPz3VaZRrx1RqYu6YxjroJW70I1LyG4WEiQbOkCoLmaiWo9WzbUS2cErlOo2RPymlkWHxbNnZawX2Bc872ivRHSWqNpRHyuR5QewXmcyghH3EhESBAxTel5E2xuQXfLCEVK0kEk0Mj22KPsckKKyH7sVYC1F4YItQh5hj9Titb7KflQb9vnXQ44UHxY3zBhTQT5PSYv1Kv8HxXCsnpmhZCiBru16iX9oEB33icBVB2KKcZZEEKnCGPVxJlM9RTlyNyQmjHf7z4GeTDuMAUrsMO31WvgZBnWcAOtn6ulBTUCAaqxJiWqzlMx2FSANAlyAjAxqzmQjzPLvQRjskUnBFN3woKB1m2bSo2c5thwA1fKiPvN5LW8tl1rnfNy3rJ0GJpK8nZjkzHMztYrKYAe56pX4SvplpTyibTIiRXLyEVsmuByTHCZhO3fvGoFsav3ZuRhe9eAAWeqAh13eKDTcA0ufME3ZnmJheXEZ3OwrxnFjSf3U0clkWYVont3neh77ODKHhYnX0bOmnJJlr4RqFoLBitskY0kcGMKcZlaej21SENjDcFgaka3CfHbAH5vIFqnoX1JZrZPkQ65PZqQWImP79U3gXWKvz96lElyJZAFqn0Mbltllqw4MhlI766AvHraOmMsJoNvjv1QR7pCSnC0iX6nbqW1eVPaUSZDuZRtRIxfLA8HC9VbxufT2KZV3qG0l7wrZna5Di2MNcBE9uthuVLZcqp8vCmEhINDhRRlipR7tC2iRBHecS5WtxBCpbEm1y1kgNG5o60UKgAswxxuJ3RQ9Y49mPIApBMmp4LFpuKRfcrZb4UJnCfR3pNbQ70nnZ6Be2M7tuJUCoFfHrhqHXNz5A0uWMgxUS50c60zLl6QAELxHaCGba4WCMOHIo5nSKcUuYtDyDoDlrezALW5mZR4PRPRxnjrXxbJI14qrpymRReC3QgFDJp6sT5TLwvSHaavPlEbt2Eu0Kh5SXklGHXP9YuF3glGuJzSob3NakW1RXF5786U1MHhtJby64LyGWvNn4QXie3VjeL3QQu4C9crEAxSSiOJOfnL3DYIVOY4ipUkKFlF7Rp2q6gZazDvcUCp1cbcr7T7B4s22rXzjN7mHYWOyWuZGwlImeorY3aVKi7BaXbhgOFw6BUmIc1HeGFELHIEnPE9MwOjZam3LOm0rhBHlvJJZkXvJKmDUJrGlyqC5GtC5lDWLfXewyDWDqq7PY0atVQily5GWqib6wub6u6LZ3HZDNP8gK64Nf4kC259AE4V2hCohDnSsXAIoOkehwXyp6CkDT42NJb6sXHUv2N6cm292MiKA22PKWrwUGsan599KI2V67YRDfcfiB4ZHRDiSe62MBE0fGLIgXLIWw1xTWYbPQ9YAj3xovBvmewbJ1De4k6uS"); + b.bytes = data.len() as u64; + b.iter(|| { + let _out = keccak(&data); + }) +} \ No newline at end of file diff --git a/util/hash/build.rs b/util/hash/build.rs deleted file mode 100644 index eecb804f90d..00000000000 --- a/util/hash/build.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - // build.rs - -// Bring in a dependency on an externally maintained `cc` package which manages -// invoking the C compiler. -extern crate cc; - -fn main() { - cc::Build::new().file("src/tinykeccak.c").compile("libtinykeccak.a"); -} - diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs index 526d22aeda7..b75e095a681 100644 --- a/util/hash/src/lib.rs +++ b/util/hash/src/lib.rs @@ -18,7 +18,9 @@ extern crate ethereum_types; extern crate tiny_keccak; use std::io; +use std::slice; use tiny_keccak::Keccak; + pub use ethereum_types::H256; /// Get the KECCAK (i.e. Keccak) hash of the empty bytes string. @@ -30,12 +32,6 @@ pub const KECCAK_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x5 /// The KECCAK of the RLP encoding of empty list. pub const KECCAK_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47] ); -extern { - /// Hashes input. Returns -1 if either out or input does not exist. Otherwise returns 0. - pub fn keccak_256(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32; - /// Hashes input. Returns -1 if either out or input does not exist. Otherwise returns 0. - pub fn keccak_512(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32; -} pub fn keccak>(s: T) -> H256 { let mut result = [0u8; 32]; @@ -43,15 +39,30 @@ pub fn keccak>(s: T) -> H256 { H256(result) } -pub fn write_keccak>(s: T, dest: &mut [u8]) { - let input = s.as_ref(); - unsafe { - // we can safely ignore keccak_256 output, cause we know that both input - // and dest are properly allocated - keccak_256(dest.as_mut_ptr(), dest.len(), input.as_ptr(), input.len()); - } +pub unsafe fn keccak_256_unchecked(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) { + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This + // means that we can reuse the input buffer for both input and output. + Keccak::keccak256( + slice::from_raw_parts(input, inputlen), + slice::from_raw_parts_mut(out, outlen) + ); } +pub unsafe fn keccak_512_unchecked(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) { + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This + // means that we can reuse the input buffer for both input and output. + Keccak::keccak512( + slice::from_raw_parts(input, inputlen), + slice::from_raw_parts_mut(out, outlen) + ); +} + +pub fn keccak_256(input: &[u8], mut output: &mut [u8]) { Keccak::keccak256(input, &mut output); } + +pub fn keccak_512(input: &[u8], mut output: &mut [u8]) { Keccak::keccak512(input, &mut output); } + +pub fn write_keccak>(s: T, dest: &mut [u8]) { Keccak::keccak256(s.as_ref(), dest); } + pub fn keccak_pipe(r: &mut io::BufRead, w: &mut io::Write) -> Result { let mut output = [0u8; 32]; let mut input = [0u8; 1024]; @@ -82,17 +93,33 @@ mod tests { use std::fs; use std::io::{Write, BufReader}; use self::tempdir::TempDir; - use super::{keccak, keccak_buffer, KECCAK_EMPTY}; + use super::{keccak, write_keccak, keccak_buffer, KECCAK_EMPTY}; #[test] fn keccak_empty() { assert_eq!(keccak([0u8; 0]), KECCAK_EMPTY); } + #[test] fn keccak_as() { assert_eq!(keccak([0x41u8; 32]), From::from("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8")); } + #[test] + fn write_keccak_with_content() { + let data: Vec = From::from("hello world"); + let expected = vec![ + 0x47, 0x17, 0x32, 0x85, 0xa8, 0xd7, 0x34, 0x1e, + 0x5e, 0x97, 0x2f, 0xc6, 0x77, 0x28, 0x63, 0x84, + 0xf8, 0x02, 0xf8, 0xef, 0x42, 0xa5, 0xec, 0x5f, + 0x03, 0xbb, 0xfa, 0x25, 0x4c, 0xb0, 0x1f, 0xad + ]; + let mut dest = [0u8;32]; + write_keccak(data, &mut dest); + + assert_eq!(dest, expected.as_ref()); + } + #[test] fn should_keccak_a_file() { // given diff --git a/util/hash/src/tinykeccak.c b/util/hash/src/tinykeccak.c deleted file mode 100644 index bfe172e5f6d..00000000000 --- a/util/hash/src/tinykeccak.c +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include - -/** libkeccak-tiny - * - * A single-file implementation of SHA-3 and SHAKE. - * - * Implementor: David Leon Gil - * License: CC0, attribution kindly requested. Blame taken too, - * but not liability. - */ - -#define decshake(bits) \ - int shake##bits(uint8_t*, size_t, const uint8_t*, size_t); - -#define deckeccak(bits) \ - int keccak_##bits(uint8_t*, size_t, const uint8_t*, size_t); - -decshake(128) -decshake(256) -deckeccak(224) -deckeccak(256) -deckeccak(384) -deckeccak(512) - -/******** The Keccak-f[1600] permutation ********/ - -/*** Constants. ***/ -static const uint8_t rho[24] = \ - { 1, 3, 6, 10, 15, 21, - 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, - 62, 18, 39, 61, 20, 44}; -static const uint8_t pi[24] = \ - {10, 7, 11, 17, 18, 3, - 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, - 20, 14, 22, 9, 6, 1}; -static const uint64_t RC[24] = \ - {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, - 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, - 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, - 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, - 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, - 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; - -/*** Helper macros to unroll the permutation. ***/ -#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) -#define REPEAT6(e) e e e e e e -#define REPEAT24(e) REPEAT6(e e e e) -#define REPEAT5(e) e e e e e -#define FOR5(v, s, e) \ - v = 0; \ - REPEAT5(e; v += s;) - -/*** Keccak-f[1600] ***/ -static inline void keccakf(void* state) { - uint64_t* a = (uint64_t*)state; - uint64_t b[5] = {0}; - uint64_t t = 0; - uint8_t x, y; - int i; - - for (i = 0; i < 24; i++) { - // Theta - FOR5(x, 1, - b[x] = 0; - FOR5(y, 5, - b[x] ^= a[x + y]; )) - FOR5(x, 1, - FOR5(y, 5, - a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) - // Rho and pi - t = a[1]; - x = 0; - REPEAT24(b[0] = a[pi[x]]; - a[pi[x]] = rol(t, rho[x]); - t = b[0]; - x++; ) - // Chi - FOR5(y, - 5, - FOR5(x, 1, - b[x] = a[y + x];) - FOR5(x, 1, - a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) - // Iota - a[0] ^= RC[i]; - } -} - -/******** The FIPS202-defined functions. ********/ - -/*** Some helper macros. ***/ - -#define _(S) do { S } while (0) -#define FOR(i, ST, L, S) \ - _({size_t i; for (i = 0; i < L; i += ST) { S; }}) -#define mkapply_ds(NAME, S) \ - static inline void NAME(uint8_t* dst, \ - const uint8_t* src, \ - size_t len) { \ - FOR(i, 1, len, S); \ - } -#define mkapply_sd(NAME, S) \ - static inline void NAME(const uint8_t* src, \ - uint8_t* dst, \ - size_t len) { \ - FOR(i, 1, len, S); \ - } - -mkapply_ds(xorin, dst[i] ^= src[i]) // xorin -mkapply_sd(setout, dst[i] = src[i]) // setout - -#define P keccakf -#define Plen 200 - -// Fold P*F over the full blocks of an input. -#define foldP(I, L, F) \ - while (L >= rate) { \ - F(a, I, rate); \ - P(a); \ - I += rate; \ - L -= rate; \ - } - -/** The sponge-based hash construction. **/ -static inline int hash(uint8_t* out, size_t outlen, - const uint8_t* in, size_t inlen, - size_t rate, uint8_t delim) { - if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { - return -1; - } - uint8_t a[Plen] = {0}; - // Absorb input. - foldP(in, inlen, xorin); - // Xor in the DS and pad frame. - a[inlen] ^= delim; - a[rate - 1] ^= 0x80; - // Xor in the last block. - xorin(a, in, inlen); - // Apply P - P(a); - // Squeeze output. - foldP(out, outlen, setout); - setout(a, out, outlen); - memset(a, 0, 200); - return 0; -} - -/*** Helper macros to define SHA3 and SHAKE instances. ***/ -#define defshake(bits) \ - int shake##bits(uint8_t* out, size_t outlen, \ - const uint8_t* in, size_t inlen) { \ - return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ - } -#define defkeccak(bits) \ - int keccak_##bits(uint8_t* out, size_t outlen, \ - const uint8_t* in, size_t inlen) { \ - if (outlen > (bits/8)) { \ - return -1; \ - } \ - return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ - } - -/*** FIPS202 SHAKE VOFs ***/ -defshake(128) -defshake(256) - -/*** FIPS202 SHA3 FOFs ***/ -defkeccak(224) -defkeccak(256) -defkeccak(384) -defkeccak(512) - - - From 72edf7585b165611d54401f0b367708840b76a13 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 21 May 2018 15:33:47 +0800 Subject: [PATCH 112/147] updated tiny-keccak to 1.4.2 (#8669) --- Cargo.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4c80310c1c..e2fa0a9db8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,7 +462,7 @@ dependencies = [ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -504,7 +504,7 @@ dependencies = [ "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -595,7 +595,7 @@ dependencies = [ "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -746,7 +746,7 @@ dependencies = [ "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -780,7 +780,7 @@ dependencies = [ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -814,7 +814,7 @@ dependencies = [ "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -955,7 +955,7 @@ dependencies = [ "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -995,7 +995,7 @@ dependencies = [ "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1458,7 +1458,7 @@ version = "0.1.2" dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1776,7 +1776,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ring 0.12.1 (git+https://github.com/paritytech/ring)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2229,7 +2229,7 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "stats 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "transaction-pool 1.12.0", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2392,7 +2392,7 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3220,7 +3220,7 @@ dependencies = [ [[package]] name = "tiny-keccak" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4024,7 +4024,7 @@ dependencies = [ "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b" -"checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" +"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" "checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" From c514180f20b6d4c4330a690813d283c80ef6f9f7 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Tue, 22 May 2018 04:19:00 +0200 Subject: [PATCH 113/147] parity: improve cli help and logging (#8665) * parity: indicate disabling ancient blocks is not recommended * parity: display decimals for stats in informant --- parity/cli/mod.rs | 6 +++--- parity/informant.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index c7c484e2bda..34e3bf03a11 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -424,7 +424,7 @@ usage! { FLAG flag_no_ancient_blocks: (bool) = false, or |_| None, "--no-ancient-blocks", - "Disable downloading old blocks after snapshot restoration or warp sync.", + "Disable downloading old blocks after snapshot restoration or warp sync. Not recommended.", FLAG flag_no_serve_light: (bool) = false, or |c: &Config| c.network.as_ref()?.no_serve_light.clone(), "--no-serve-light", @@ -894,7 +894,7 @@ usage! { ["Legacy options"] FLAG flag_warp: (bool) = false, or |_| None, "--warp", - "Does nothing; warp sync is enabled by default.", + "Does nothing; warp sync is enabled by default. Use --no-warp to disable.", FLAG flag_dapps_apis_all: (bool) = false, or |_| None, "--dapps-apis-all", diff --git a/parity/informant.rs b/parity/informant.rs index a4d2727c359..e2f3960b679 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -303,13 +303,13 @@ impl Informant { paint(White.bold(), format!("{}", chain_info.best_block_hash)), if self.target.executes_transactions() { format!("{} blk/s {} tx/s {} Mgas/s", - paint(Yellow.bold(), format!("{:4}", (client_report.blocks_imported * 1000) as u64 / elapsed.as_milliseconds())), - paint(Yellow.bold(), format!("{:4}", (client_report.transactions_applied * 1000) as u64 / elapsed.as_milliseconds())), - paint(Yellow.bold(), format!("{:3}", (client_report.gas_processed / From::from(elapsed.as_milliseconds() * 1000)).low_u64())) + paint(Yellow.bold(), format!("{:5.2}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)), + paint(Yellow.bold(), format!("{:6.1}", (client_report.transactions_applied * 1000) as f64 / elapsed.as_milliseconds() as f64)), + paint(Yellow.bold(), format!("{:4}", (client_report.gas_processed / From::from(elapsed.as_milliseconds() * 1000)).low_u64())) ) } else { format!("{} hdr/s", - paint(Yellow.bold(), format!("{:4}", (client_report.blocks_imported * 1000) as u64 / elapsed.as_milliseconds())) + paint(Yellow.bold(), format!("{:6.1}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)) ) }, paint(Green.bold(), format!("{:5}", queue_info.unverified_queue_size)), @@ -350,8 +350,8 @@ impl Informant { Some(ref rpc_stats) => format!( "RPC: {} conn, {} req/s, {} µs", paint(Blue.bold(), format!("{:2}", rpc_stats.sessions())), - paint(Blue.bold(), format!("{:2}", rpc_stats.requests_rate())), - paint(Blue.bold(), format!("{:3}", rpc_stats.approximated_roundtrip())), + paint(Blue.bold(), format!("{:4}", rpc_stats.requests_rate())), + paint(Blue.bold(), format!("{:4}", rpc_stats.approximated_roundtrip())), ), _ => String::new(), }, From 3697a05a16a852b81a533ad920726247361b8b82 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 22 May 2018 12:24:09 +0800 Subject: [PATCH 114/147] Refactor EIP150, EIP160 and EIP161 forks to be specified in CommonParams (#8614) * Allow post-homestead forks to be specified in CommonParams * Fix all json configs * Fix test in json crate * Fix test in ethcore * Fix all chain configs to use tabs Given we use tabs in .editorconfig and the majority of chain configs. This change is done in Emacs using `mark-whole-buffer` and `indent-region`. --- ...authority_round_block_reward_contract.json | 112 +- ethcore/res/ethereum/byzantium_test.json | 8 +- ethcore/res/ethereum/classic.json | 8 +- ethcore/res/ethereum/constantinople_test.json | 8 +- ethcore/res/ethereum/easthub.json | 174 +- ethcore/res/ethereum/eip150_test.json | 10 +- ethcore/res/ethereum/eip161_test.json | 10 +- ethcore/res/ethereum/ellaism.json | 144 +- ethcore/res/ethereum/expanse.json | 8 +- ethcore/res/ethereum/foundation.json | 8 +- ethcore/res/ethereum/frontier_like_test.json | 10 +- ethcore/res/ethereum/frontier_test.json | 10 +- ethcore/res/ethereum/homestead_test.json | 12 +- ethcore/res/ethereum/mcip3_test.json | 332 +- ethcore/res/ethereum/mcip6_byz.json | 318 +- ethcore/res/ethereum/morden.json | 8 +- ethcore/res/ethereum/musicoin.json | 324 +- ethcore/res/ethereum/olympic.json | 10 +- ethcore/res/ethereum/ropsten.json | 8 +- ethcore/res/ethereum/social.json | 17710 ++++++++-------- ethcore/res/ethereum/transition_test.json | 8 +- ethcore/src/machine.rs | 29 +- ethcore/src/spec/spec.rs | 29 +- json/src/spec/ethash.rs | 29 +- json/src/spec/params.rs | 15 + 25 files changed, 9663 insertions(+), 9679 deletions(-) diff --git a/ethcore/res/authority_round_block_reward_contract.json b/ethcore/res/authority_round_block_reward_contract.json index e008de117f7..31957731232 100644 --- a/ethcore/res/authority_round_block_reward_contract.json +++ b/ethcore/res/authority_round_block_reward_contract.json @@ -1,61 +1,61 @@ { - "name": "TestAuthorityRoundBlockRewardContract", - "engine": { - "authorityRound": { - "params": { - "stepDuration": 1, - "startStep": 2, - "validators": { - "list": [ - "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e", - "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1" - ] + "name": "TestAuthorityRoundBlockRewardContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "list": [ + "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e", + "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1" + ] + }, + "immediateTransitions": true, + "emptyStepsTransition": "1", + "maximumEmptySteps": "2", + "blockRewardContractAddress": "0x0000000000000000000000000000000000000042" + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "eip140Transition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0" + }, + "genesis": { + "seal": { + "authorityRound": { + "step": "0x0", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } }, - "immediateTransitions": true, - "emptyStepsTransition": "1", - "maximumEmptySteps": "2", - "blockRewardContractAddress": "0x0000000000000000000000000000000000000042" - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID" : "0x69", - "eip140Transition": "0x0", - "eip211Transition": "0x0", - "eip214Transition": "0x0", - "eip658Transition": "0x0" - }, - "genesis": { - "seal": { - "authorityRound": { - "step": "0x0", - "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" }, - "difficulty": "0x20000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x222222" - }, - "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, - "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, - "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, - "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, - "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }, - "0000000000000000000000000000000000000042": { - "balance": "1", - "constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029" + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, + "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }, + "0000000000000000000000000000000000000042": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029" + } } - } } diff --git a/ethcore/res/ethereum/byzantium_test.json b/ethcore/res/ethereum/byzantium_test.json index 40c7e465991..90c92bbff55 100644 --- a/ethcore/res/ethereum/byzantium_test.json +++ b/ethcore/res/ethereum/byzantium_test.json @@ -8,10 +8,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "eip161abcTransition": "0x0", - "eip161dTransition": "0x0", "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": "0x0", "eip649Transition": "0x0" @@ -27,6 +23,10 @@ "networkID" : "0x1", "maxCodeSize": 24576, "maxCodeSizeTransition": "0x0", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", "eip98Transition": "0xffffffffffffffff", "eip140Transition": "0x0", "eip211Transition": "0x0", diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index a4c6fe9f227..928c056d660 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -9,13 +9,9 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": 1150000, - "eip150Transition": 2500000, - "eip160Transition": 3000000, "ecip1010PauseTransition": 3000000, "ecip1010ContinueTransition": 5000000, "ecip1017EraRounds": 5000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff", "bombDefuseTransition": 5900000 } } @@ -30,6 +26,10 @@ "chainID": "0x3d", "forkBlock": "0x1d4c00", "forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f", + "eip150Transition": 2500000, + "eip160Transition": 3000000, + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip155Transition": 3000000, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" diff --git a/ethcore/res/ethereum/constantinople_test.json b/ethcore/res/ethereum/constantinople_test.json index 7b137e86fa0..155b06507d0 100644 --- a/ethcore/res/ethereum/constantinople_test.json +++ b/ethcore/res/ethereum/constantinople_test.json @@ -8,10 +8,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "eip161abcTransition": "0x0", - "eip161dTransition": "0x0", "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": "0x0", "eip649Transition": "0x0" @@ -28,6 +24,10 @@ "maxCodeSize": 24576, "maxCodeSizeTransition": "0x0", "eip98Transition": "0xffffffffffffffff", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", "eip140Transition": "0x0", "eip210Transition": "0x0", "eip211Transition": "0x0", diff --git a/ethcore/res/ethereum/easthub.json b/ethcore/res/ethereum/easthub.json index ddc170d8a67..e7e1a6e708e 100644 --- a/ethcore/res/ethereum/easthub.json +++ b/ethcore/res/ethereum/easthub.json @@ -1,89 +1,89 @@ { - "name": "Easthub", - "dataDir": "easthub", - "engine": { - "Ethash": { - "params": { - "minimumDifficulty": "0x020000", - "difficultyBoundDivisor": "0x0800", - "durationLimit": "0x0d", - "blockReward": "0x2B5E3AF16B1880000", - "homesteadTransition": "0x0", - "bombDefuseTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "ecip1017EraRounds": 5000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "registrar": "0x0000000000000000000000000000000000000000", - "accountStartNonce": "0x00", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID": "0x7", - "chainID": "0x7", - "eip155Transition": "0x0", - "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" - }, - "genesis": { - "seal": { - "ethereum": { - "nonce": "0x0000000000000042", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "difficulty": "0x0400000000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x323031382045617374636f696e2050726f6a656374", - "gasLimit": "0x1388" - }, - "nodes": [ - "enode://ca57e40edb95a08a81b85a91e91099a0aaab777ad329ea7f3f772bc0fd511a276a5d84944725d181ff80f8c7dc1034814bff25b9723b03363d48617fed4b15f0@13.125.109.174:30303", - "enode://57254e23a7e5fe1e081ee5d1b236e37735a120660daeb4bf1fec6943a82c915c5b6fad23eeb1a43a27c23f236e084e8051aaa28f7d4139149f844747facb62bb@18.217.39.51:30303", - "enode://ef248f327c73c0318f4d51a62270b0612f3c4a4fd04b77d04854dc355980e137708d1e48811bc91387b0d7eb85cf447d8bbc095404f39bb7064e76751bda9cd4@52.221.160.236:30303", - "enode://bf6f0e37dd733cf04f2b079c753d2dea7cc7c59d8637eff9a8e63e17d08e2bfc91229fbb2dff08fe6ee12e51c1b6f8ed969d7042b89d77029e7ea02b05e17be3@18.197.47.177:30303" - ], - "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "20c1252a8cb33a7a9a257b2a4cfeed8daf87c847": { - "balance": "100000000000000000000000000" - }, - "9dcd37c8e5aea3a0d37c5d0a2db683362d81febd": { - "balance": "100000000000000000000000000" - }, - "9eff080302333f44a60bfd8c33bd63015c6d921b": { - "balance": "100000000000000000000000000" - }, - "c1df2e5de98d5c41fec0642dc302971f5d3500bd": { - "balance": "100000000000000000000000000" - }, - "2e0fb67cd1d029cbaea4b74c361efcc06b3105fd": { - "balance": "100000000000000000000000000" - }, - "2b6425cc3cd90654f077889ef7262ac2f5846460": { - "balance": "100000000000000000000000000" - }, - "28562041230c6d575e233e4ed1b35c514884d964": { - "balance": "100000000000000000000000000" - }, - "16eb6896a5a83d39ac762d79d21f825f5f980d12": { - "balance": "100000000000000000000000000" - }, - "f09e3f1de27dd03a1ac0a021b2d9e45bde1b360c": { - "balance": "100000000000000000000000000" - }, - "2d87547819c6433f208ee3096161cdb2835a2333": { - "balance": "100000000000000000000000000" - } - } + "name": "Easthub", + "dataDir": "easthub", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x2B5E3AF16B1880000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "ecip1017EraRounds": 5000000 + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x0000000000000000000000000000000000000000", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x7", + "chainID": "0x7", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip155Transition": "0x0", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x0400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x323031382045617374636f696e2050726f6a656374", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://ca57e40edb95a08a81b85a91e91099a0aaab777ad329ea7f3f772bc0fd511a276a5d84944725d181ff80f8c7dc1034814bff25b9723b03363d48617fed4b15f0@13.125.109.174:30303", + "enode://57254e23a7e5fe1e081ee5d1b236e37735a120660daeb4bf1fec6943a82c915c5b6fad23eeb1a43a27c23f236e084e8051aaa28f7d4139149f844747facb62bb@18.217.39.51:30303", + "enode://ef248f327c73c0318f4d51a62270b0612f3c4a4fd04b77d04854dc355980e137708d1e48811bc91387b0d7eb85cf447d8bbc095404f39bb7064e76751bda9cd4@52.221.160.236:30303", + "enode://bf6f0e37dd733cf04f2b079c753d2dea7cc7c59d8637eff9a8e63e17d08e2bfc91229fbb2dff08fe6ee12e51c1b6f8ed969d7042b89d77029e7ea02b05e17be3@18.197.47.177:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "20c1252a8cb33a7a9a257b2a4cfeed8daf87c847": { + "balance": "100000000000000000000000000" + }, + "9dcd37c8e5aea3a0d37c5d0a2db683362d81febd": { + "balance": "100000000000000000000000000" + }, + "9eff080302333f44a60bfd8c33bd63015c6d921b": { + "balance": "100000000000000000000000000" + }, + "c1df2e5de98d5c41fec0642dc302971f5d3500bd": { + "balance": "100000000000000000000000000" + }, + "2e0fb67cd1d029cbaea4b74c361efcc06b3105fd": { + "balance": "100000000000000000000000000" + }, + "2b6425cc3cd90654f077889ef7262ac2f5846460": { + "balance": "100000000000000000000000000" + }, + "28562041230c6d575e233e4ed1b35c514884d964": { + "balance": "100000000000000000000000000" + }, + "16eb6896a5a83d39ac762d79d21f825f5f980d12": { + "balance": "100000000000000000000000000" + }, + "f09e3f1de27dd03a1ac0a021b2d9e45bde1b360c": { + "balance": "100000000000000000000000000" + }, + "2d87547819c6433f208ee3096161cdb2835a2333": { + "balance": "100000000000000000000000000" + } + } } diff --git a/ethcore/res/ethereum/eip150_test.json b/ethcore/res/ethereum/eip150_test.json index 60157c57168..baf9c1b7bfc 100644 --- a/ethcore/res/ethereum/eip150_test.json +++ b/ethcore/res/ethereum/eip150_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x0" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x0", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffffff", "eip86Transition": "0x7fffffffffffffff", "eip155Transition": "0x7fffffffffffffff", diff --git a/ethcore/res/ethereum/eip161_test.json b/ethcore/res/ethereum/eip161_test.json index ac1c0a5d1e3..079ce7d55a2 100644 --- a/ethcore/res/ethereum/eip161_test.json +++ b/ethcore/res/ethereum/eip161_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "eip161abcTransition": "0x0", - "eip161dTransition": "0x0" + "homesteadTransition": "0x0" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", "eip98Transition": "0x7fffffffffffffff", "eip86Transition": "0x7fffffffffffffff", "eip155Transition": "0x7fffffffffffffff", diff --git a/ethcore/res/ethereum/ellaism.json b/ethcore/res/ethereum/ellaism.json index 96c2016e55a..c3107bbe469 100644 --- a/ethcore/res/ethereum/ellaism.json +++ b/ethcore/res/ethereum/ellaism.json @@ -1,74 +1,74 @@ { - "name": "Ellaism", - "dataDir": "ellaism", - "engine": { - "Ethash": { - "params": { - "minimumDifficulty": "0x020000", - "difficultyBoundDivisor": "0x0800", - "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "bombDefuseTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "ecip1017EraRounds": 10000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff", - "eip100bTransition": 2000000 - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "registrar": "0x3bb2bb5c6c9c9b7f4EF430b47Dc7e026310042ea", - "accountStartNonce": "0x00", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID": "0x40", - "chainID": "0x40", - "eip155Transition": "0x0", - "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff", - "wasmActivationTransition": 2000000, - "eip140Transition": 2000000, - "eip211Transition": 2000000, - "eip214Transition": 2000000, - "eip658Transition": 2000000 - }, - "genesis": { - "seal": { - "ethereum": { - "nonce": "0x0000000000000040", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "difficulty": "0x40000000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0x1388" - }, - "nodes": [ - "enode://0d88e242aa0b01ee306ca43e956174677c96ec8eba4197f4d8be6fd7d4f2e57731e95d533b88229b66eb1a44399d870e99b7a4fe6547c8c80cdf00407a986e14@94.130.237.158:30303", - "enode://4be9e419d3efb0214faf3ef1794a0c33ebbd7633ece734a0a956faa166fefc496b2692a2a485adc66af805e461ba3e12f8d3941ec207e56bb9f3d3626787a705@94.130.237.158:60606", - "enode://834246cc2a7584df29ccdcf3b5366f118a0e291264980376769e809665a02c4caf0d68c43eecf8390dbeaf861823b05583807af0a62542a1f3f717046b958a76@45.77.106.33:30303", - "enode://d8059dcb137cb52b8960ca82613eeba1d121105572decd8f1d3ea22b09070645eeab548d2a3cd2914f206e1331c7870bd2bd5a231ebac6b3d4886ec3b8e627e5@173.212.216.105:30303", - "enode://9215ad77bd081e35013cb42a8ceadff9d8e94a78fcc680dff1752a54e7484badff0904e331c4b40a68be593782e55acfd800f076d22f9d2832e8483733ade149@213.14.82.125:30303", - "enode://5dd35866da95aea15211fb1f98684f6e8c4e355e6aa3cc17585680ed53fa164477b8c52cb6ca4b24ec4d80f3d48ff9212b53feb131d825c7945a3abaaf02d24d@178.79.189.58:60606", - "enode://6c585c18024eb902ca093278af73b04863ac904caabc39ac2920c23532307c572ad92afd828a990c980d272b1f26307f2409cc97aec3ff9fe866732cae49a8c2@144.217.163.224:31337", - "enode://edd90c4cc64528802ad52fd127d80b641ff80fd43fa5292fb111c8bd2914482dffee288fd1b0d26440c6b2c669b10a53cbcd37c895ba0d6194110e100a965b2d@188.166.179.159:30303", - "enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303" - ], - "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } }, - "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, - "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, - "0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } } - } + "name": "Ellaism", + "dataDir": "ellaism", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "ecip1017EraRounds": 10000000, + "eip100bTransition": 2000000 + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x3bb2bb5c6c9c9b7f4EF430b47Dc7e026310042ea", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x40", + "chainID": "0x40", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff", + "wasmActivationTransition": 2000000, + "eip140Transition": 2000000, + "eip211Transition": 2000000, + "eip214Transition": 2000000, + "eip658Transition": 2000000 + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000040", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x40000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://0d88e242aa0b01ee306ca43e956174677c96ec8eba4197f4d8be6fd7d4f2e57731e95d533b88229b66eb1a44399d870e99b7a4fe6547c8c80cdf00407a986e14@94.130.237.158:30303", + "enode://4be9e419d3efb0214faf3ef1794a0c33ebbd7633ece734a0a956faa166fefc496b2692a2a485adc66af805e461ba3e12f8d3941ec207e56bb9f3d3626787a705@94.130.237.158:60606", + "enode://834246cc2a7584df29ccdcf3b5366f118a0e291264980376769e809665a02c4caf0d68c43eecf8390dbeaf861823b05583807af0a62542a1f3f717046b958a76@45.77.106.33:30303", + "enode://d8059dcb137cb52b8960ca82613eeba1d121105572decd8f1d3ea22b09070645eeab548d2a3cd2914f206e1331c7870bd2bd5a231ebac6b3d4886ec3b8e627e5@173.212.216.105:30303", + "enode://9215ad77bd081e35013cb42a8ceadff9d8e94a78fcc680dff1752a54e7484badff0904e331c4b40a68be593782e55acfd800f076d22f9d2832e8483733ade149@213.14.82.125:30303", + "enode://5dd35866da95aea15211fb1f98684f6e8c4e355e6aa3cc17585680ed53fa164477b8c52cb6ca4b24ec4d80f3d48ff9212b53feb131d825c7945a3abaaf02d24d@178.79.189.58:60606", + "enode://6c585c18024eb902ca093278af73b04863ac904caabc39ac2920c23532307c572ad92afd828a990c980d272b1f26307f2409cc97aec3ff9fe866732cae49a8c2@144.217.163.224:31337", + "enode://edd90c4cc64528802ad52fd127d80b641ff80fd43fa5292fb111c8bd2914482dffee288fd1b0d26440c6b2c669b10a53cbcd37c895ba0d6194110e100a965b2d@188.166.179.159:30303", + "enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } } + } } diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json index b9b734e313d..2061231c60d 100644 --- a/ethcore/res/ethereum/expanse.json +++ b/ethcore/res/ethereum/expanse.json @@ -13,10 +13,6 @@ "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", "bombDefuseTransition": "0x30d40", - "eip150Transition": "0x927C0", - "eip160Transition": "0x927C0", - "eip161abcTransition": "0x927C0", - "eip161dTransition": "0x927C0", "eip100bTransition": "0xC3500", "metropolisDifficultyIncrementDivisor": "0x1E", "eip649Transition": "0xC3500", @@ -37,6 +33,10 @@ "forkBlock": "0xDBBA0", "forkCanonHash": "0x8e7bed51e24f5174090408664ac476b90b5e1199a947af7442f1ac88263fc8c7", "subprotocolName": "exp", + "eip150Transition": "0x927C0", + "eip160Transition": "0x927C0", + "eip161abcTransition": "0x927C0", + "eip161dTransition": "0x927C0", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x927C0", diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 6658b5e5227..b725c9f7c02 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -129,10 +129,6 @@ "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], - "eip150Transition": "0x259518", - "eip160Transition": 2675000, - "eip161abcTransition": 2675000, - "eip161dTransition": 2675000, "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": 4370000, "eip649Transition": 4370000 @@ -148,6 +144,10 @@ "networkID" : "0x1", "forkBlock": "0x1d4c00", "forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb", + "eip150Transition": "0x259518", + "eip160Transition": 2675000, + "eip161abcTransition": 2675000, + "eip161dTransition": 2675000, "eip155Transition": 2675000, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 6d2ea3693df..7eac5acbd0a 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -127,11 +127,7 @@ "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" - ], - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + ] } } }, @@ -142,6 +138,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x7fffffffffffffff" diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index aae59cb071e..7e52f6ecf97 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x7fffffffffffffff", - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x7fffffffffffffff" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x7fffffffffffffff" diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index c6d49b54556..817bf5ff57f 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x0" } } }, @@ -24,7 +20,11 @@ "networkID" : "0x1", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", - "eip155Transition": "0x7fffffffffffffff" + "eip155Transition": "0x7fffffffffffffff", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/mcip3_test.json b/ethcore/res/ethereum/mcip3_test.json index d2e5ec8b6bc..391a625730a 100644 --- a/ethcore/res/ethereum/mcip3_test.json +++ b/ethcore/res/ethereum/mcip3_test.json @@ -1,168 +1,168 @@ { - "name":"MCIP3 Test", - "dataDir":"mcip3test", - "engine":{ - "Ethash":{ - "params":{ - "minimumDifficulty":"0x020000", - "difficultyBoundDivisor":"0x0800", - "durationLimit":"0x0d", - "homesteadTransition":"0x118c30", - "eip100bTransition":"0x7fffffffffffff", - "eip150Transition":"0x7fffffffffffff", - "eip160Transition":"0x7fffffffffffff", - "eip161abcTransition":"0x7fffffffffffff", - "eip161dTransition":"0x7fffffffffffff", - "eip649Transition":"0x7fffffffffffff", - "blockReward":"0x1105a0185b50a80000", - "mcip3Transition":"0x00", - "mcip3MinerReward":"0xd8d726b7177a80000", - "mcip3UbiReward":"0x2b5e3af16b1880000", - "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", - "mcip3DevReward":"0xc249fdd327780000", - "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" - } - } - }, - "params":{ - "gasLimitBoundDivisor":"0x0400", - "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", - "accountStartNonce":"0x00", - "maximumExtraDataSize":"0x20", - "minGasLimit":"0x1388", - "networkID":"0x76740b", - "forkBlock":"0x5b6", - "forkCanonHash":"0xa5e88ad9e34d113e264e307bc27e8471452c8fc13780324bb3abb96fd0558343", - "eip86Transition":"0x7fffffffffffff", - "eip98Transition":"0x7fffffffffffff", - "eip140Transition":"0x7fffffffffffff", - "eip155Transition":"0x7fffffffffffff", - "eip211Transition":"0x7fffffffffffff", - "eip214Transition":"0x7fffffffffffff", - "eip658Transition":"0x7fffffffffffff", - "maxCodeSize":"0x6000", - "maxCodeSizeTransition": "0x7fffffffffffff" - }, - "genesis":{ - "seal":{ - "ethereum":{ - "nonce":"0x000000000000002a", - "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" - } - }, - "difficulty":"0x3d0900", - "author":"0x0000000000000000000000000000000000000000", - "timestamp":"0x00", - "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData":"", - "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://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", - "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", - "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" - ], - "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":"0x7fffffffffffff", - "pricing":{ - "modexp":{ - "divisor":20 - } - } - } - }, - "0000000000000000000000000000000000000006":{ - "builtin":{ - "name":"alt_bn128_add", - "activate_at":"0x7fffffffffffff", - "pricing":{ - "linear":{ - "base":500, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000007":{ - "builtin":{ - "name":"alt_bn128_mul", - "activate_at":"0x7fffffffffffff", - "pricing":{ - "linear":{ - "base":40000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000008":{ - "builtin":{ - "name":"alt_bn128_pairing", - "activate_at":"0x7fffffffffffff", - "pricing":{ - "alt_bn128_pairing":{ - "base":100000, - "pair":80000 - } - } - } - } - } + "name":"MCIP3 Test", + "dataDir":"mcip3test", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x020000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "homesteadTransition":"0x118c30", + "eip100bTransition":"0x7fffffffffffff", + "eip649Transition":"0x7fffffffffffff", + "blockReward":"0x1105a0185b50a80000", + "mcip3Transition":"0x00", + "mcip3MinerReward":"0xd8d726b7177a80000", + "mcip3UbiReward":"0x2b5e3af16b1880000", + "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", + "mcip3DevReward":"0xc249fdd327780000", + "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" + } + } + }, + "params":{ + "gasLimitBoundDivisor":"0x0400", + "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", + "accountStartNonce":"0x00", + "maximumExtraDataSize":"0x20", + "minGasLimit":"0x1388", + "networkID":"0x76740b", + "forkBlock":"0x5b6", + "forkCanonHash":"0xa5e88ad9e34d113e264e307bc27e8471452c8fc13780324bb3abb96fd0558343", + "eip150Transition":"0x7fffffffffffff", + "eip160Transition":"0x7fffffffffffff", + "eip161abcTransition":"0x7fffffffffffff", + "eip161dTransition":"0x7fffffffffffff", + "eip86Transition":"0x7fffffffffffff", + "eip98Transition":"0x7fffffffffffff", + "eip140Transition":"0x7fffffffffffff", + "eip155Transition":"0x7fffffffffffff", + "eip211Transition":"0x7fffffffffffff", + "eip214Transition":"0x7fffffffffffff", + "eip658Transition":"0x7fffffffffffff", + "maxCodeSize":"0x6000", + "maxCodeSizeTransition": "0x7fffffffffffff" + }, + "genesis":{ + "seal":{ + "ethereum":{ + "nonce":"0x000000000000002a", + "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty":"0x3d0900", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x00", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"", + "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://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", + "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", + "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" + ], + "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":"0x7fffffffffffff", + "pricing":{ + "modexp":{ + "divisor":20 + } + } + } + }, + "0000000000000000000000000000000000000006":{ + "builtin":{ + "name":"alt_bn128_add", + "activate_at":"0x7fffffffffffff", + "pricing":{ + "linear":{ + "base":500, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000007":{ + "builtin":{ + "name":"alt_bn128_mul", + "activate_at":"0x7fffffffffffff", + "pricing":{ + "linear":{ + "base":40000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000008":{ + "builtin":{ + "name":"alt_bn128_pairing", + "activate_at":"0x7fffffffffffff", + "pricing":{ + "alt_bn128_pairing":{ + "base":100000, + "pair":80000 + } + } + } + } + } } diff --git a/ethcore/res/ethereum/mcip6_byz.json b/ethcore/res/ethereum/mcip6_byz.json index 8028e6b1bbb..a12df7c7115 100644 --- a/ethcore/res/ethereum/mcip6_byz.json +++ b/ethcore/res/ethereum/mcip6_byz.json @@ -1,161 +1,161 @@ { - "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", - "maxCodeSizeTransition": "0x7fffffffffffff" - }, - "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 - } - } - } - } - } + "name":"Musicoin Byzantium Test", + "dataDir":"mcip6test", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x020000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "homesteadTransition":"0x17", + "eip100bTransition":"0x2a", + "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", + "eip150Transition":"0x2a", + "eip160Transition":"0x7fffffffffffff", + "eip161abcTransition":"0x7fffffffffffff", + "eip161dTransition":"0x7fffffffffffff", + "eip86Transition":"0x7fffffffffffff", + "eip98Transition":"0x7fffffffffffff", + "eip140Transition":"0x2a", + "eip155Transition":"0x2a", + "eip211Transition":"0x2a", + "eip214Transition":"0x2a", + "eip658Transition":"0x2a", + "maxCodeSize":"0x6000", + "maxCodeSizeTransition": "0x7fffffffffffff" + }, + "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/morden.json b/ethcore/res/ethereum/morden.json index bca9919903e..b61799c0c9d 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -9,13 +9,9 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": 494000, - "eip150Transition": 1783000, - "eip160Transition": 1915000, "ecip1010PauseTransition": 1915000, "ecip1010ContinueTransition": 3415000, "ecip1017EraRounds": 2000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff", "bombDefuseTransition": 2300000 } } @@ -30,6 +26,10 @@ "chainID": "0x3e", "forkBlock": "0x1b34d8", "forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145", + "eip150Transition": 1783000, + "eip160Transition": 1915000, + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip155Transition": 1915000, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" diff --git a/ethcore/res/ethereum/musicoin.json b/ethcore/res/ethereum/musicoin.json index 6d5f6835bd9..724f11478bf 100644 --- a/ethcore/res/ethereum/musicoin.json +++ b/ethcore/res/ethereum/musicoin.json @@ -1,164 +1,164 @@ { - "name":"Musicoin", - "dataDir":"musicoin", - "engine":{ - "Ethash":{ - "params":{ - "minimumDifficulty":"0x020000", - "difficultyBoundDivisor":"0x0800", - "durationLimit":"0x0d", - "homesteadTransition":"0x118c30", - "eip100bTransition":"0x21e88e", - "eip150Transition":"0x21e88e", - "eip160Transition":"0x21e88e", - "eip161abcTransition":"0x21e88e", - "eip161dTransition":"0x21e88e", - "eip649Transition":"0x21e88e", - "blockReward":"0x1105a0185b50a80000", - "mcip3Transition":"0x124f81", - "mcip3MinerReward":"0xd8d726b7177a80000", - "mcip3UbiReward":"0x2b5e3af16b1880000", - "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", - "mcip3DevReward":"0xc249fdd327780000", - "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" - } - } - }, - "params":{ - "gasLimitBoundDivisor":"0x0400", - "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", - "accountStartNonce":"0x00", - "maximumExtraDataSize":"0x20", - "minGasLimit":"0x1388", - "networkID":"0x76740f", - "forkBlock":"0x1d8015", - "forkCanonHash":"0x380602acf82b629a0be6b5adb2b4a801e960a07dc8261bf196d21befdbb8f2f9", - "eip86Transition":"0x7fffffffffffff", - "eip98Transition":"0x7fffffffffffff", - "eip140Transition":"0x21e88e", - "eip155Transition":"0x21e88e", - "eip211Transition":"0x21e88e", - "eip214Transition":"0x21e88e", - "eip658Transition":"0x21e88e", - "maxCodeSize":"0x6000" - }, - "genesis":{ - "seal":{ - "ethereum":{ - "nonce":"0x000000000000002a", - "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" - } - }, - "difficulty":"0x3d0900", - "author":"0x0000000000000000000000000000000000000000", - "timestamp":"0x00", - "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData":"", - "gasLimit":"0x7a1200" - }, - "nodes":[ - "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" - ], - "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":"0x21e88e", - "pricing":{ - "modexp":{ - "divisor":20 - } - } - } - }, - "0000000000000000000000000000000000000006":{ - "builtin":{ - "name":"alt_bn128_add", - "activate_at":"0x21e88e", - "pricing":{ - "linear":{ - "base":500, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000007":{ - "builtin":{ - "name":"alt_bn128_mul", - "activate_at":"0x21e88e", - "pricing":{ - "linear":{ - "base":40000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000008":{ - "builtin":{ - "name":"alt_bn128_pairing", - "activate_at":"0x21e88e", - "pricing":{ - "alt_bn128_pairing":{ - "base":100000, - "pair":80000 - } - } - } - } - } + "name":"Musicoin", + "dataDir":"musicoin", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x020000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "homesteadTransition":"0x118c30", + "eip100bTransition":"0x21e88e", + "eip649Transition":"0x21e88e", + "blockReward":"0x1105a0185b50a80000", + "mcip3Transition":"0x124f81", + "mcip3MinerReward":"0xd8d726b7177a80000", + "mcip3UbiReward":"0x2b5e3af16b1880000", + "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", + "mcip3DevReward":"0xc249fdd327780000", + "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" + } + } + }, + "params":{ + "gasLimitBoundDivisor":"0x0400", + "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", + "accountStartNonce":"0x00", + "maximumExtraDataSize":"0x20", + "minGasLimit":"0x1388", + "networkID":"0x76740f", + "forkBlock":"0x1d8015", + "forkCanonHash":"0x380602acf82b629a0be6b5adb2b4a801e960a07dc8261bf196d21befdbb8f2f9", + "eip150Transition":"0x21e88e", + "eip160Transition":"0x21e88e", + "eip161abcTransition":"0x21e88e", + "eip161dTransition":"0x21e88e", + "eip86Transition":"0x7fffffffffffff", + "eip98Transition":"0x7fffffffffffff", + "eip140Transition":"0x21e88e", + "eip155Transition":"0x21e88e", + "eip211Transition":"0x21e88e", + "eip214Transition":"0x21e88e", + "eip658Transition":"0x21e88e", + "maxCodeSize":"0x6000" + }, + "genesis":{ + "seal":{ + "ethereum":{ + "nonce":"0x000000000000002a", + "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty":"0x3d0900", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x00", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"", + "gasLimit":"0x7a1200" + }, + "nodes":[ + "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" + ], + "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":"0x21e88e", + "pricing":{ + "modexp":{ + "divisor":20 + } + } + } + }, + "0000000000000000000000000000000000000006":{ + "builtin":{ + "name":"alt_bn128_add", + "activate_at":"0x21e88e", + "pricing":{ + "linear":{ + "base":500, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000007":{ + "builtin":{ + "name":"alt_bn128_mul", + "activate_at":"0x21e88e", + "pricing":{ + "linear":{ + "base":40000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000008":{ + "builtin":{ + "name":"alt_bn128_pairing", + "activate_at":"0x21e88e", + "pricing":{ + "alt_bn128_pairing":{ + "base":100000, + "pair":80000 + } + } + } + } + } } diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index 6854f2b78a9..3ae9baddf2b 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x08", "blockReward": "0x14D1120D7B160000", - "homesteadTransition": "0x7fffffffffffffff", - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x7fffffffffffffff" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x0400", "minGasLimit": "125000", "networkID" : "0x0", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x7fffffffffffffff" diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 065e3364438..bddf5c0084f 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -9,10 +9,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": 0, - "eip150Transition": 0, - "eip160Transition": 10, - "eip161abcTransition": 10, - "eip161dTransition": 10, "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": 1700000, "eip649Transition": 1700000 @@ -30,6 +26,10 @@ "forkCanonHash": "0x8033403e9fe5811a7b6d6b469905915de1c59207ce2172cbcf5d6ff14fa6a2eb", "maxCodeSize": 24576, "maxCodeSizeTransition": 10, + "eip150Transition": 0, + "eip160Transition": 10, + "eip161abcTransition": 10, + "eip161dTransition": 10, "eip155Transition": 10, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", diff --git a/ethcore/res/ethereum/social.json b/ethcore/res/ethereum/social.json index 87d1f2e4b1f..52b442d0886 100644 --- a/ethcore/res/ethereum/social.json +++ b/ethcore/res/ethereum/social.json @@ -1,8857 +1,8857 @@ { - "name": "Ethereum Social", - "dataDir": "social", - "engine": { - "Ethash": { - "params": { - "minimumDifficulty": "0x020000", - "difficultyBoundDivisor": "0x0800", - "durationLimit": "0x0d", - "blockReward": "0x2B5E3AF16B1880000", - "homesteadTransition": "0x0", - "bombDefuseTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "ecip1017EraRounds": 5000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "registrar": "0x0000000000000000000000000000000000000000", - "accountStartNonce": "0x00", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID": "0x1C", - "chainID": "0x1C", - "eip155Transition": "0x0", - "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" - }, - "genesis": { - "seal": { - "ethereum": { - "nonce": "0x0000000000000042", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "difficulty": "0x0400000000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x3230313820457468657265756d20536f6369616c2050726f6a656374", - "gasLimit": "0x1388" - }, - "nodes": [ - "enode://54d0824a268747046b6cabc7ee3afda48edba319f0d175e9e505aa9d425a1872b8b6f9ebf8f3b0a10dc7611a4c44ddec0fc691e5a5cde23e06fc4e4b3ff9dbef@13.125.185.147:30303", - "enode://7e150d47637177f675e20d663fc2500987f2149332caf23da522d92363be8a7880ef9150a6183e9031288a441e0457239474967a111eafce17e19a4288076ea9@18.219.40.235:30303", - "enode://6244c9d9cd288015d7ff165e90f3bb5649e34467e095a47c6d3c56e8fb8c849b3b4db683ff3c7ae8a654bbdc07ef12ee2fd7d72831ac213723281c1b0cc90599@13.250.220.98:30303", - "enode://e39f162b9f4b6ed6f098550f7867c2fb068fc66f362b3db0f45124c43ea18508f5ceef4e0e4de53d301e14a6f1683226aeb931d7401b4e83b5a583153ffdd7fd@52.57.98.157:30303", - "enode://54b4a117d66dc3aa93358dec1b31d4f38e72e4381b3e28a65ac6f1aaac3b304ebbe41d32cc864fa69a9a6815c34cf9b8965690dc174a5f72af14547b601b7924@222.239.255.71:30303", - "enode://851f14c5cc86cbc0a81acfcbe5dd99ad5c823435357219df736932c5f89ad4318f6973a553857a32d97a71793f5a35c062d46320be282aa0a80b06b9c6b624e4@13.125.232.71:30303" - ], - "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "ceed1c8254abaf069669fc6045e90482543d1f2e": { - "balance": "38000000000000000000000000" - }, - "6f22d7f8c38e0135e36be87e77fc8d4ae4b3d965": { - "balance": "38000000000000000000000000" - }, - "d016e982b7886302428d7c741392c658337513d2": { - "balance": "38000000000000000000000000" - }, - "defa96db5c8a41772bc56f68f95e307ff71a2c60": { - "balance": "38000000000000000000000000" - }, - "951ffd4253ffcf31b2895dd3f7f2a8a9bb2933e5": { - "balance": "38000000000000000000000000" - }, - "b7071dba21cfbe1b70abd7ddfd2f0f83d5d19a61": { - "balance": "38000000000000000000000000" - }, - "6ca420cd8d5407c61a9b14adcb38bee0f26e2848": { - "balance": "38000000000000000000000000" - }, - "b50d185b6cd04499a38afc0fcfcb59eaa74d0956": { - "balance": "38000000000000000000000000" - }, - "7ba8c49a444c117f2d2a50650b3f700d4ee659fe": { - "balance": "38000000000000000000000000" - }, - "83f9959ecc532dce071fcd0c62dc23cd571b689b": { - "balance": "38000000000000000000000000" - }, - "001327afce7ebb623a7d0f17b2ffc358fb863b5a": { - "balance": "9844198127334000000000" - }, - "0015ac7f8bb2a2c7d954fc2dbd4e20c0db5942a5": { - "balance": "1000000000000000000000000" - }, - "0021e69c041be2d28744b69361105ff51295da59": { - "balance": "1379639894000000000" - }, - "002cfd27bbb8164681b8762e71b2891beb127fdd": { - "balance": "25105286685000000000" - }, - "0033cf217bc765ccfc338869451588ce448fde65": { - "balance": "23425485280069000000000" - }, - "0048f1d1735979cd8ac9c0886088336b2d4a43a6": { - "balance": "10000000000000000000" - }, - "006a79cc154917cf204d8097728f290e29716d43": { - "balance": "20000000000000000000000" - }, - "007c8db36e4f649b14516dd78202670b671ba753": { - "balance": "1000000000000000000" - }, - "007d131b58388f251075a3c61020ce301106c5cf": { - "balance": "381079535880476000000000" - }, - "008e8fbffc2fdbefaa7e3be4f4a9160db826d05f": { - "balance": "10000000000000000000000" - }, - "0126d86b9814b0e78c4e01a3916bee6a7778145b": { - "balance": "10000000000000000000000" - }, - "012cb961297c837630251a173b7861e77724856d": { - "balance": "494562376059000000000" - }, - "0145886dfab5ef4f2def50a56b4a074cf5b18acf": { - "balance": "680585022951000000000" - }, - "0167918bab62aa2118cfa4d3eb80da0e71c71d8b": { - "balance": "122395119468000000000" - }, - "0182f7286ae9d4d6bc514d5175d14685d520bde7": { - "balance": "10000000000000000000000" - }, - "0184e9c8fe99d85100fe28a0e8877b14768b372a": { - "balance": "193295614762000000000" - }, - "019eff7dce7f31c2d4f7318da71d212cbf89d36e": { - "balance": "64004138198000000000" - }, - "01f3351ea66c352346244dbb79189066bed62fc5": { - "balance": "937056266523000000000" - }, - "0202ddd7f4f32bc575f7df24612f8aa9f9a7ae42": { - "balance": "106905151080000000000" - }, - "022b8c65e959cab71f56688b7073257b58bbef4a": { - "balance": "9682681149566000000000" - }, - "0245ff6382eb93ab1e8ed2e3c0bce7a1b9a9713d": { - "balance": "289000000000000000000" - }, - "025e117a69ca9244ed430732c11e550e3ee67577": { - "balance": "1861905310567000000000" - }, - "026e7457eeaeaec7898fdee1ad39be89e92733b3": { - "balance": "7529030978000000000" - }, - "028d2def8c54fcc77bf0191b183c0bc4570ec1c5": { - "balance": "9056720934000000000" - }, - "0291a087605b516e465134797b5459436d320e6a": { - "balance": "481100929805000000000" - }, - "02a4b18b3e13ec79307e712fba1867cbf7fb6155": { - "balance": "9000000000000000000" - }, - "02a812d4cebcac1a92ae470ade92fde7bead127d": { - "balance": "66793603497000000000" - }, - "02f718c94b2c8e8d62752f8632443504c1e4b6e2": { - "balance": "1000000000000000000000000" - }, - "030dab52b47b37505b72e5ca0985f65ead590816": { - "balance": "1376851176362000000000" - }, - "031c59846f75de1aefb0e8a95e0fb822fd06555b": { - "balance": "140978338628000000000" - }, - "031ee87c672d83ec73059c86a312a9e972142054": { - "balance": "96406273341000000000" - }, - "033182e860564cf695cb403c8c0f078053368d7d": { - "balance": "1504349255824000000000" - }, - "03788dc6528fa33a90e90e03295ae4b792d56644": { - "balance": "24356250426000000000" - }, - "037aae119047028157c5b3bc9d3d202b02cbce42": { - "balance": "105627739575000000000" - }, - "037d45b323cbc5cbac999c5001169646e690b94c": { - "balance": "2000000000000000000" - }, - "0390ba35c454a24519d845405a7e24df71250748": { - "balance": "1872501898509000000000" - }, - "03ab8c1e7f904db62437b16d28aeb539b2dee55e": { - "balance": "55000000000000000000000000" - }, - "03af4c69728a888fa26b1aefa439005989771fdf": { - "balance": "27704588237757000000000" - }, - "03b33fb19d165e5e33bcfbbfc009f418d71f30fb": { - "balance": "1999139000000000000" - }, - "03b34c79f8167a4e8be0f6133254d2b50cbd878d": { - "balance": "111065050160000000000" - }, - "03d7e8638b74ae44a2770287285489a95fa1ea11": { - "balance": "20000000000000000000000" - }, - "03d870bf719f03250c0dc5156a36751b3aa21f18": { - "balance": "981119649953000000000" - }, - "03de52c12b05fb8bcba3a1cfe02a0ad1bc9761d3": { - "balance": "362007990932000000000" - }, - "03e516db27b1abe008ffc57ced48f72f872d8b08": { - "balance": "3389116345657000000000" - }, - "03ef5ff863ee5f1167f38cdf316e4d52a242b750": { - "balance": "12395856876000000000" - }, - "03f27766760f2bd1cae1cb85ddf43ab59c871e47": { - "balance": "49000000000000000000" - }, - "03f4e1a8fb4eedc776f4835fcc85d0f236612f9c": { - "balance": "27210590272692000000000" - }, - "0404936ee04cc79cbb3aedfa33a53f94940f772c": { - "balance": "29919204637416000000000" - }, - "040501ffde9649be794b7d41643273ed6285ab39": { - "balance": "686000000000000000000" - }, - "040e449de680f69614120f0a2e894cde36e4adf1": { - "balance": "81993180085000000000" - }, - "041531e906dbdc70d89f5e255151d9865a059308": { - "balance": "2163418749315000000000" - }, - "041ad9f6bf970541e4ea8a14dde1e789d0fe4367": { - "balance": "44999979000000000000" - }, - "0446420c07cf73d2b3741b945c1cc8444b4ba6b6": { - "balance": "138749371512564000000000" - }, - "044c1a540b8ab286c218c2fa9d5bfbc2761e7626": { - "balance": "1" - }, - "04526b2c62911e78a939816aa4575fe30baa06c7": { - "balance": "2983093150081000000000" - }, - "04adf59f8a0ad3820a7972c6243202b3b0617fcf": { - "balance": "50000000000000000000" - }, - "04bbb42882a475eed58aae47fe530ed19c1cedaa": { - "balance": "278038763863000000000" - }, - "04cff7a7c2b9b0bf31c5ad4a5de8b0eade70aafc": { - "balance": "515406205244000000000" - }, - "04dcd325dc1fd37ff3c87da3b21c47ddfcc37cc2": { - "balance": "5831887315000000000" - }, - "04ec8d0b5157370f5a2671a2aa68ae486b7a7842": { - "balance": "10000000000000000000000" - }, - "04f50f2a6e89ee497a64c11baa90759a10a1247a": { - "balance": "25443071621949000000000" - }, - "0513a769ebef58ad3a4fd7011ddbe19799ff5600": { - "balance": "64369494797000000000" - }, - "0514c1151f356070ace281435f25c86b58280715": { - "balance": "38967380881301000000000" - }, - "052fda414fe1279c6276a237b07e1b4148a8cc77": { - "balance": "10000000000000000000000" - }, - "05431089cc62a987d0e99847e10a006233146f6d": { - "balance": "268977485219000000000" - }, - "054ed2f55028257212b996f9a3d34758d1d4ffd1": { - "balance": "100000000000000000000000" - }, - "05a68cc758560addde302baf814f2fdbe0ef2c2b": { - "balance": "10000000000000000000" - }, - "05c669d9ded79fe9e4e3718052bc7ca18a3205ab": { - "balance": "7347158140000000000" - }, - "05d77ce5c87477b05e90e829dafd8eb3a8c87823": { - "balance": "21191998933000000000" - }, - "05ef2894a2a1c6eb6c0a768d04ef5b573f357712": { - "balance": "20000000000000000000000" - }, - "0601011f80279190b96f641205c6a524a8ad5a28": { - "balance": "12025716447696000000000" - }, - "061a8acdb1a340ba7c550814831e27262708fc98": { - "balance": "234029764576000000000" - }, - "06219483e217c9ad479f76a95426f689ef4d5951": { - "balance": "1509408723551000000000" - }, - "062d0db8a650f2241f8a4295326a2570a7c771bb": { - "balance": "717459720227000000000" - }, - "0633ba746235d8fc8243751b1aa31646c299f262": { - "balance": "49000000000000000000" - }, - "06b6a5cadfe1fdc88015512e835d840e58ae4123": { - "balance": "1000000000000000000" - }, - "06d08fcbe96791514d900d2cb6c0f029d8d791d0": { - "balance": "19196168602258000000000" - }, - "06e5c0bad43a7011878b12a682abf01ccdfaa151": { - "balance": "30000000000000000000" - }, - "070656bb11ec36074d47c791c0b306394b703401": { - "balance": "1245216075291000000000" - }, - "070d84c938217163b60ed38e4937eea7158c03d9": { - "balance": "27507979787000000000" - }, - "07428c95ef3862026e54d3a963911cdc673dbcd9": { - "balance": "13792309994528000000000" - }, - "0781cb21df142ec5f67b956bf995f02f6f24985f": { - "balance": "224940990659000000000" - }, - "078c38c153b414cc4c12818fce2ea7ba09a34e51": { - "balance": "1410646136000000000" - }, - "07bfd0de7a9a1c927446aaf2d7ede55b471daa87": { - "balance": "77778844734000000000" - }, - "07d1ac83140188b8d7f4c8c607d0da22c5ba523f": { - "balance": "7713686418107000000000" - }, - "07d8ef8fc6dcde319a5af5b6cea18983bdc4c8fe": { - "balance": "3801361173000000000" - }, - "07dfab72dd3e44fcbb1ced625899bf20e0c52ffc": { - "balance": "154177778806000000000" - }, - "0817ce33d943e84c7b3261cc3e37b86b5d6d76ae": { - "balance": "90753785862000000000" - }, - "081be00a2ff62cbcb95a8eb020ac0efa33f93a42": { - "balance": "1027889807304000000000" - }, - "085ffdc6043b04653e51b1a34af20b609d158607": { - "balance": "3314058000000000" - }, - "0882c2228f5df24064bc37e8b7199199de308bb8": { - "balance": "98420617420000000000" - }, - "08918776e9a7136cedad5d0cee52f5d9dd833ece": { - "balance": "1263170315026000000000" - }, - "08bdbcff16919abc5e15fa68ece56eceef33f48d": { - "balance": "2552990000000000" - }, - "08fc8c7bd03fe1249266b233edfcf830693d0e10": { - "balance": "283490111768000000000" - }, - "090f79a4178b5180150444805f62c26cd21be897": { - "balance": "884195010282000000000" - }, - "0914a9dfc9d6ecc063a55e5320050112f305fe17": { - "balance": "15373898854941000000000" - }, - "091791ab5f8ab86f1d8f566ed221b268cbc55347": { - "balance": "2207516004000000000" - }, - "09529f8b1633ce4375451bb44b1025f6e5f9facd": { - "balance": "151697652792000000000" - }, - "09600bbb9d9b23661d269dbe1ed066d8e573b5e1": { - "balance": "802935104935000000000" - }, - "0964d2af1d5883fc0e0a77459f6a141824de7356": { - "balance": "9610980935058000000000" - }, - "097c731d1fc6792ac0f0ff92be4403c3749cc1dd": { - "balance": "165134479709000000000" - }, - "097f152b3f837d38ab1e8c0683d62f5a01d67902": { - "balance": "20000000000000000000000" - }, - "09a6772629ef0bf402ae6d27cd32e6eefb220a12": { - "balance": "20000000000000000000000" - }, - "09addb954d4e4b4e95e0c66d324115d609df5a99": { - "balance": "8435321515000000000" - }, - "09b2eb03e0fa321102196578eb40dcba3a46ec9c": { - "balance": "12723517962933000000000" - }, - "09ba0ed4dce470ba0bcb4d46b507c3b024b83070": { - "balance": "99999979000000000000" - }, - "09efbd6dfea375065be1b3a8f4541f024da21a34": { - "balance": "5870833623000000000" - }, - "0a24d4ae66edc7723bbb314e9b96dc7b9a31e813": { - "balance": "70000000000000000000" - }, - "0a3ee710909382f762648deff8ac7c8b30e2ce10": { - "balance": "407656462445000000000" - }, - "0a42b3145257154e76a97db8147c93be4cffd97b": { - "balance": "10000000000000000000000" - }, - "0a7cb6037f1eba5d19fe781335ecd37b7229c5f7": { - "balance": "74113322448000000000" - }, - "0a85d1bec4d44e309068b115abd517d3733fc56e": { - "balance": "14836218750000000000000" - }, - "0a891ba9ca7b99ecd815b1dcec9243dd4deff866": { - "balance": "178004857988000000000" - }, - "0ab69370b537d4ff5b45704fed293e46e3464f87": { - "balance": "1258876668246000000000" - }, - "0ab77a2e8ab9a3b659d1f1d37956c3607a0f9a60": { - "balance": "6283300817712000000000" - }, - "0abc7e8d52f5b0dcf1d4713e5fa4909102251dfb": { - "balance": "39307290577000000000" - }, - "0af2c0471c802d2e2b20aadf9dd4ec842d313ab0": { - "balance": "1529468143183000000000" - }, - "0b08c717bb3982fc8b92d5b3d30e5b41265a0d0f": { - "balance": "1184600154874000000000" - }, - "0b3f2aa9dc5b57b0469398d62f60a13774ec0e87": { - "balance": "132187640280004000000000" - }, - "0b3ffe85aa89e71a6e51e938c7265d2a7173061b": { - "balance": "2106793086824000000000" - }, - "0b468562e712d22b37e1a65f54b1fa825beebd1b": { - "balance": "15130906006000000000" - }, - "0b5333eb668dee29ebc0e335d74f33ffeaae9ac5": { - "balance": "125953133109000000000" - }, - "0b59a20107495e951b509187307782ca9dfa441f": { - "balance": "25000000000000000000" - }, - "0b8b7fb066601ea7744b81f6e1a21b8e489359cf": { - "balance": "101782000000000000000" - }, - "0bd7791097f79066d71ac0a2c94bce6628a63373": { - "balance": "44389955028000000000" - }, - "0be541af06e167206b5d1cbe08e8fb2b5ebc82cb": { - "balance": "9000000000000000000" - }, - "0bf178bba463f4f6c33e3d81b1a78d220f7b5d4b": { - "balance": "111784804790646000000000" - }, - "0c1f000249b1f1ac9e43c4f10e2da1cc2adf886f": { - "balance": "91251997635000000000" - }, - "0c74e46b115e19726997dd559d2b6ff1bfb79af6": { - "balance": "879229287149000000000" - }, - "0c7c1ec152c920a068c25626c22c4fae7f435536": { - "balance": "39849464104000000000" - }, - "0c85fbd7492d1ae87bf3d286c4750a34f1fd3121": { - "balance": "20000000000000000000000" - }, - "0c9fd6123e313f7d1f0cb25d99839102da08b2c5": { - "balance": "10000000000000000000000" - }, - "0cb051e3bdd9d96e667fbcc00a766d4f149f89e4": { - "balance": "1000000000000000000000" - }, - "0ce32bf6c433cbd26c6f09a1214db0374002784e": { - "balance": "3293279842000000000" - }, - "0ce6374ff04430e34edec8b6323feab2bccab92d": { - "balance": "93983447000000000" - }, - "0ce646412a1524c3f73edfd753c0ba3ee7338275": { - "balance": "10000000000000000000000" - }, - "0ced803e56eac3c99269ff7409d2d200d62d7c25": { - "balance": "49539379000000000" - }, - "0d1dc2be9f78ce2b2591e7f5b8af9dc778499bd5": { - "balance": "2235348003595000000000" - }, - "0d235583458a168e810275f907b5f87bebb2d1cf": { - "balance": "83106439283110000000000" - }, - "0d28fe6e8b7d4b8c90ef7c52b9656511ce5867f1": { - "balance": "1347248794799000000000" - }, - "0d5cbe0da660cbca831787efc45fecb20e06e02b": { - "balance": "297528508941000000000" - }, - "0d7a24f324176f6d793c3a2eb6c54d6ee47eca79": { - "balance": "25637813467000000000" - }, - "0da26a24e3650e84c52fedb36ef76225a8d9d259": { - "balance": "15467820321000000000" - }, - "0db7eaceaf3df21ebb49c56fa2d2e2c8e85dec52": { - "balance": "196000000000000000000" - }, - "0dde52823bd8fb2cb179e6d417c07ff285c31775": { - "balance": "347321514878000000000" - }, - "0df9585f1aa83189e0a813f5eac6e6e0b2bbb8d8": { - "balance": "2891430551000000000" - }, - "0e09af9368f05b476164953b7b9db60ac95248f0": { - "balance": "573644391203000000000" - }, - "0e18315dd2b663ce4859b5bed854403191452c2f": { - "balance": "24174325261000000000" - }, - "0e29bef5f4f66c38a0f05cca1e4938d57ff09c70": { - "balance": "10000000000000000000000" - }, - "0e443353b42e042ff5168e9b3c6de37070368223": { - "balance": "20000000000000000000000" - }, - "0e8cb6e439516b312158f169b546937b715db3f2": { - "balance": "8049136367000000000" - }, - "0e980fab23be601f3abec7b9a24e1335a5e765c8": { - "balance": "8301885845897000000000" - }, - "0ea63fef218ebf570a4ee62ef6ed712dbe623c44": { - "balance": "10000000000000000000000" - }, - "0eb60e3512336e4447ceeb8664ce0ecaa3eb0bdc": { - "balance": "41401696400000000000" - }, - "0edafc1058879a9568e711445b18ec4da31d2480": { - "balance": "10000000000000000000000" - }, - "0efce4565062b23b43dbc1e261463e363e4a5b4c": { - "balance": "10000000000000000000000" - }, - "0f08782c04bf7249ab08f4e251abc60aee792a96": { - "balance": "1380257622493000000000" - }, - "0f19bfe1eb24def828bf1be69791c63ba1de1263": { - "balance": "2223687184885000000000" - }, - "0f2171161eb9674218add261be61d18d86b846a6": { - "balance": "121000000000000000000" - }, - "0f42ef6c5690b6c95f8b8c9dbdc16f717c04852e": { - "balance": "81000000000000000000" - }, - "0f47f5063d321b34a0d800951bcdc3f53c07e32c": { - "balance": "5288516165000000000" - }, - "0f529a9beedb2c2a087a220f0013cea4f8454bfc": { - "balance": "114585457979000000000" - }, - "0f6751d10aaf855454a6e9e4241cfcae3b0ed732": { - "balance": "94160300063000000000" - }, - "0f6ed5a4c3ec100afcd59e9066ba7fcb63cfa6dc": { - "balance": "1000000000000000000" - }, - "0f77025519cc76c38e1cf0bd8721f4a5b9c814d4": { - "balance": "834620571043000000000" - }, - "0f773db2a1a96b775e4481575704f5f087b067e0": { - "balance": "554268361745000000000" - }, - "0fa0f73adbe82f8e09f8adbce15b051971e289c3": { - "balance": "11329911975000000000" - }, - "0fa6397d747d88a25d0c755b3be4eee0e3f68912": { - "balance": "31394936138000000000" - }, - "0fac8635a61bf7652d86725cc75c307949bd4f2a": { - "balance": "49000000000000000000" - }, - "0fb0ce787306ce13dcd614ab3d0e15d9772106ac": { - "balance": "50000000000000000000000" - }, - "0fb1d306d240360056f60f197dc7f68f732ac515": { - "balance": "20000000000000000000000" - }, - "0fe3571f498a6d945e123ac8ff6e3fed348d9432": { - "balance": "20000000000000000000000" - }, - "0ffd6b01ea9a7bd2576fe4a5838fe09e44c1639e": { - "balance": "100000000000000000000" - }, - "100bde3d73fda700369e78229127b58d2ade9177": { - "balance": "10000000000000000000000" - }, - "102028c7626970a28677bbdc7733484c8b14c2d2": { - "balance": "500000000000000000000000" - }, - "10245044be6a46ad41d4559129cb59e843379cf8": { - "balance": "857437279765000000000" - }, - "10417d0ff25c115b25915dd10ca57b16be497bf6": { - "balance": "10000000000000000000000" - }, - "10579870e6685ed7e97dd2c79a6dc3528bae968e": { - "balance": "5187866041491000000000" - }, - "109736465b4bbe31ea65ad01fc98f04498271e6c": { - "balance": "20000000000000000000000" - }, - "109c0535a4a86244c5094e99167d312a77657dd5": { - "balance": "138277702073000000000" - }, - "10aa08064689ee97d5f030a537f3cd4d8bbdaf74": { - "balance": "10000000000000000000000" - }, - "10d8bc8c3d3e2010e83009290586ad85b73321d1": { - "balance": "25000000000000000000" - }, - "10f22b82460252345753875555de2cebebe63a93": { - "balance": "765947730644000000000" - }, - "11111c3a2cfa55e52d6aacf533e1d412f8c8c01c": { - "balance": "4827254128275000000000" - }, - "11386103a0bf199db9504b617ccb3bbd780eb9fe": { - "balance": "10000000000000" - }, - "1156a129183e5bdfdf2bf7a70963285a979363a0": { - "balance": "10000000000000000000000" - }, - "11589cf70a6a4fbaac25224e2ddab222333f78e6": { - "balance": "49000000000000000000" - }, - "1162fabeb3eb1e4124179b00c4a1e01503023f54": { - "balance": "817145350625000000000" - }, - "116a7d140f4b7f9b4689063a8417ac07a32bae00": { - "balance": "106088220142108000000000" - }, - "116dc38ddb4b138b19ce6a51e5922c287da5c86b": { - "balance": "100000000000000000000" - }, - "1175f84f835a5ae40d49b8ca17e3e474c1eceef7": { - "balance": "1698584794716000000000" - }, - "119f822a796fee9c41a488949fcb14b589ffa628": { - "balance": "20000000000000000000000" - }, - "11a99f6019b6a53f5dc8cbd0c34f1ee75ced33b8": { - "balance": "102126982156000000000" - }, - "11b9324406068e8bf598d3a9ea59ef31c52f51fa": { - "balance": "6525925895203000000000" - }, - "11cb7be6869a10f5f9e8a47c6c92f729b083084b": { - "balance": "182959434323344000000000" - }, - "11d96a76166ec579e2b6cfa903f66da4af669351": { - "balance": "1000000000000000000000000" - }, - "11fcee55f78278df60f50096d45da1aafe72722d": { - "balance": "222859488179000000000" - }, - "120a1fc914718acd85bf92d9492330165d78075a": { - "balance": "3736627235906000000000" - }, - "12366136d83c77befdc30e04d4f5d808419f504f": { - "balance": "88008649003000000000" - }, - "12435af3f2f92ec43e8f2894be9c72fa932880fe": { - "balance": "1590548436852000000000" - }, - "124ff67125a00aed24e58b6d64ffa887a59b48a4": { - "balance": "20613022349070000000000" - }, - "1296f04910ebc89556ec7ab1b178fdbf14d0295c": { - "balance": "36000000000000000000" - }, - "1299f180e42bfaa1162d36110d29ab062e43e1c8": { - "balance": "321570118362000000000" - }, - "12abac62150c526866ec958cd0e3721b2c78d550": { - "balance": "51898545633262000000000" - }, - "12b345087cee385b9adccaaaa6741b767c82d7ea": { - "balance": "36000000000000000000" - }, - "12cd5e8c0c93f8e34b589b95954b719f54d1515b": { - "balance": "1000000000000000000" - }, - "12d262cdd25edc39b6fd9ae78184eb548e513927": { - "balance": "500976168000000000" - }, - "12d933448218629702c48547b3446b629ec65883": { - "balance": "2168010577395000000000" - }, - "13054aa42d3e119220ac359641c15f8b54bfffef": { - "balance": "24986834005530000000000" - }, - "130bda09f463a982199849ae617062a1d68f3a85": { - "balance": "154504844790000000000" - }, - "131a5da679863c05dc627d53634f2925ba0ce731": { - "balance": "10000000000000000000000" - }, - "1334f2752b5c21f681ba9e23a9fe95a85f8e05f1": { - "balance": "121000000000000000000" - }, - "13634512e2ae79fe3febb9e55e03b47bc350d7ba": { - "balance": "338331304738000000000" - }, - "136fae842aab625768bef9079ee1711e8c007d8f": { - "balance": "2759741687626000000000" - }, - "139fa969e8b74bee1f6113a362f15060ea998b15": { - "balance": "10000000000000000000000" - }, - "13c7e1d694bde6f8f6a31eb6c99f38dc739d61fe": { - "balance": "10901074773586000000000" - }, - "13c849944ad6ad12a46c46973d562bee8284f46d": { - "balance": "35114615504000000000" - }, - "13ec3aa8f4a427ecdecc7901060ccac9bea7a61e": { - "balance": "10000000000000000000000" - }, - "13f478c74acfd6897d13e602a8d362893f4fd038": { - "balance": "3521111850000000000" - }, - "14403970d0784a6458a7bf2584a53d14234e8860": { - "balance": "25000000000000000000" - }, - "14440bb7410337e34a064a92206075575f5362ee": { - "balance": "14918844868393000000000" - }, - "144a88e7a8af70b8bef5c4b70ee0cff771d0c252": { - "balance": "67961927542000000000" - }, - "146b79f474176a4b0069199b03669ab6467a4787": { - "balance": "122518123211000000000" - }, - "148893e7811c36c6bd1ada367681ab8327b3b2fa": { - "balance": "1313118418375000000000" - }, - "14900a17784e3b4d89d98b6cb31c74c685418b89": { - "balance": "131112181597000000000" - }, - "149a483758a98ffe28f7f25cfa17d7433f852ebe": { - "balance": "10000000000000000000000" - }, - "14a03c8e84f07c5596687a98d1e0b1859e9b34ac": { - "balance": "55000000000000000000000000" - }, - "14c7899cb34b5447d6363d4e8355113ebf4bcc66": { - "balance": "197554844582000000000" - }, - "14efa63ee285277c0f8e0d5cc22193e17984e11b": { - "balance": "106221254735000000000" - }, - "151c6099b3fb5b18e0e36a3335dff186dcd2904d": { - "balance": "4304311254087000000000" - }, - "1525dce233a971eb1387f130fdf0e5bf3455723b": { - "balance": "45004174531000000000" - }, - "15271904676f2bc2511294e500152d05ea9acc85": { - "balance": "9300898622566000000000" - }, - "1556ba42ea69d72c1d0faf802906645268e36aac": { - "balance": "171939212653000000000" - }, - "156558fb71ff986953d899c9916a121fd047675c": { - "balance": "290926338537000000000" - }, - "156fbf32614aac2cf462952ec1a3f141f797316e": { - "balance": "6084388860000000000" - }, - "15b9497d6bde8017baf3c29e12430e05a47efbf4": { - "balance": "206126229839000000000" - }, - "15d532e828bdcaf1246696d679a2eb66a154db5d": { - "balance": "69656571015000000000" - }, - "15e26a60cfaf23dfd9bbb999a30904d11b6ddd05": { - "balance": "9839303178835000000000" - }, - "15f3be2f11ee3b19472cc3d171931f050d8629a2": { - "balance": "13572825921000000000" - }, - "16254bed335420e5f793de2295b0081ac41a08d1": { - "balance": "144000000000000000000" - }, - "163aa91bc2ad588116141d48fcbd943985455cac": { - "balance": "618250979557000000000" - }, - "164cff4b9341d536b8aaf2d1dd0e3ed35ecb1db7": { - "balance": "671554639913000000000" - }, - "164d2a9a63868ac25bfe26ecba446d7ce256c351": { - "balance": "7233638188261000000000" - }, - "164e759b64d3ee0a23ec3030f50a1b454a6ec15b": { - "balance": "12281161499000000000" - }, - "165d4a0f23c016b8064adf0dcf7e31bc06350777": { - "balance": "256757922324741000000000" - }, - "166b862954dacddc3333aba4edbe523d693df858": { - "balance": "123677971414000000000" - }, - "16858eb1a6f0e7ff01b91aa9c92d0a433a5f767c": { - "balance": "500000000000000000000000" - }, - "168909a1c2a43cff1fe4faeac32a609c25fbd1e8": { - "balance": "62258808044224000000000" - }, - "16987ad8e10dda7f9e5d95c0f0ee36f46b10e168": { - "balance": "10000000000000000000000" - }, - "16b5dffce79573300a6514ace5f2e844d26fc64e": { - "balance": "5576805697087000000000" - }, - "16e01370a93befe24f6ae6076cd04c84cd3515b1": { - "balance": "1922179181578000000000" - }, - "16fbafd4fc871c7589e63062133793ab244c2019": { - "balance": "2865030627000000000" - }, - "16fdf76180796c6e4335eaa2842775b2e4a22e0b": { - "balance": "20000000000000000000000" - }, - "17081d4d6ebb9f4b163e181a59c2102c99fce6bd": { - "balance": "490625378000000000000" - }, - "17218ff455aa87b29ad4c4f7ba21e9c6f74fc97a": { - "balance": "1607392037652000000000" - }, - "1725bce47f3700f4646efb343f950e2e8ba66607": { - "balance": "58472967071000000000" - }, - "172c5f71aabf072507664471ebaa435779d74a32": { - "balance": "16000000000000000000" - }, - "173a065f351ee0513cfebfe9b950fd2c641fc8cc": { - "balance": "25000000000000000000" - }, - "174e1793c96cefb584ae0a67fff85c65065dafc5": { - "balance": "50221000010000000000" - }, - "1794bc4d622d514f95da5404358ed404b3f59aa3": { - "balance": "36000000000000000000" - }, - "179839d61e7c7a0382fe08e0573bcfbe42a108ca": { - "balance": "203299791419000000000" - }, - "179eb30b5b28a961eac70a919d26ca96e6472166": { - "balance": "55000000000000000000000000" - }, - "17be72168606fb5d27761157e48fc14789f84634": { - "balance": "311205588354000000000" - }, - "17cefb6611033759b8755197b983de2d7e98315e": { - "balance": "10000000000000000000000" - }, - "17e07cc7d89bcd1708b1f05ab6e1252c629d71cc": { - "balance": "903234908997000000000" - }, - "1811be559b657685c2f163122479101c404325b0": { - "balance": "10060694170000000000" - }, - "181417a4883c429ef26a4baeb48e70d4f00278b4": { - "balance": "4621446218088000000000" - }, - "181d345cd6b5f518bdab8d40f5d4896a725b3f3d": { - "balance": "114349561983000000000" - }, - "184625e544aa31552d2911023a892f739df84be7": { - "balance": "5303698708000000000" - }, - "185e4f6eee203ca3c089baa1e643ff1aab7cc8f4": { - "balance": "33969718257699000000000" - }, - "188e4a1a7b23ff35ec90b7bf7561db9e3c0f53bb": { - "balance": "394325508701000000000" - }, - "18a4dbf513be132f9ecfd69e3eb683d710e28c4b": { - "balance": "5997985132329000000000" - }, - "18c9298f62635ef47d0ef215b8a693af60829c27": { - "balance": "100000000000000000000" - }, - "18e7e2ee0c86bc1ba3595fee3d40257776fe8172": { - "balance": "185584626033000000000" - }, - "196575e74499b741877793f8c8facf2f3b1ddb8f": { - "balance": "30318381929000000000" - }, - "196df33f2d3ed473e6e07650419969f4a39fd03b": { - "balance": "15442864665000000000" - }, - "1975c5293ec9c72a28e6cc74173cdfd8de682fea": { - "balance": "103624886552134000000000" - }, - "19832cd1b2fc4138c8d9291a0f404d3c4326b48f": { - "balance": "4732362673000000000" - }, - "198705f46f31c7ca22f5b88fab210bc5b0c7647c": { - "balance": "548940869737000000000" - }, - "19a5a213e6abfee29f17e871222cbe9ac45322c8": { - "balance": "10000000000000000000000" - }, - "19ab9a7a4e9f9c08c9b4295c406b78389a864ba7": { - "balance": "369299839157000000000" - }, - "19f19f5f01b3f6a1c4f645dc7e3992b1196ccb7a": { - "balance": "97759406000000000000" - }, - "1a11a0b0081522e60e16f154e093ac2e005d24ee": { - "balance": "88024675252000000000" - }, - "1a27309b0c09be2234fd64afdbcfb099f8e2e7cd": { - "balance": "10000000000000000000000" - }, - "1a3d61754974bea23503a61ef0fe584b7b6e6cf3": { - "balance": "326950210355000000000" - }, - "1a49bbde1457a8d4c247606b206ac8d4d389da5a": { - "balance": "402438941516000000000" - }, - "1a7a4b41be64fff3a31eb6166db59741e073d0f7": { - "balance": "250000000000000000000" - }, - "1a8d282e82c606e992f69ce618ba634d98bf2683": { - "balance": "20000000000000000000000" - }, - "1aa0ba27662816e5e3d79e223cc18f5dfef089cf": { - "balance": "187581622694000000000" - }, - "1acab416a1d3e8caa65faca378c79aaf2065b851": { - "balance": "1000000000000000000" - }, - "1acd37af3f87da1dff743dfcb97038d178b1dc4f": { - "balance": "708034481300000000000" - }, - "1ad8f036022c3e5258455d6aa05fb4be5dd121b1": { - "balance": "42957064709000000000" - }, - "1aee811e06c579c21fbcc3b53d2dcf9d5f24808e": { - "balance": "52480060284048000000000" - }, - "1b03b7a4e9908c3531618f49f8d050ba6afb4de6": { - "balance": "28410489187000000000" - }, - "1b073d026e93de51db34d5a8e19047784c277ea1": { - "balance": "20579129628026000000000" - }, - "1b0b87e414bc8fe4920fe104b6de7d17db3a1a19": { - "balance": "10720000000000000000" - }, - "1b411c692c80948e59cd805a0f8574dd67519288": { - "balance": "5416615538000000000" - }, - "1b8d57e995749618c7bb3e60194ac6fc57e9b3eb": { - "balance": "10000000000000000000000" - }, - "1b913efde1255516346b40ae2a48ebf62251682d": { - "balance": "100000000000000000000" - }, - "1ba7276c133f93d43db2f2caddec08e0167eaf15": { - "balance": "82559173174000000000" - }, - "1ba919f7742160cabf2756eb6eae67b92530f3f3": { - "balance": "1102304139883000000000" - }, - "1bb20857de494694fe15bd11f8cac1218435fbc0": { - "balance": "10221322567000000000" - }, - "1bb5c5e81d451f03e899852edc8556a9f7aac5df": { - "balance": "18781017696028000000000" - }, - "1be3507349ed07d3e7902951d490f560a75e96be": { - "balance": "660691718918000000000" - }, - "1bf1c0b2e6f64b612f35f2bf98d894b13dda9bf7": { - "balance": "3050161851140000000000" - }, - "1bfd3c2ba6a537e97cedd542cd554a5050963d54": { - "balance": "20000000000000000000000" - }, - "1c4af5003f9e7223f4141107d21640e4a85a4827": { - "balance": "612390629874000000000" - }, - "1c6a94810bd0afcf79ceea11afe86c34f6813211": { - "balance": "10000000000000000000000" - }, - "1c7e277460191c886cb1647173d27122c2146252": { - "balance": "209062806527000000000" - }, - "1c818ffa9caa61d512fa5d7d6e566f3ae37d5434": { - "balance": "454897845316000000000" - }, - "1c9599d5f8e5eaf8f68d35d52132e15a153f6d3c": { - "balance": "36000000000000000000" - }, - "1c95ab5229fd08c638a1728c022f09291b8dc55d": { - "balance": "20000000000000000000000" - }, - "1c962808c175ee5e5e365483d066c8ea95993700": { - "balance": "1362779746855000000000" - }, - "1cafad295b2188f10192c8a32440931f7e3554e4": { - "balance": "36000000000000000000" - }, - "1cdc2899ec563d79569d1ba776bc03cff331e786": { - "balance": "572163587827000000000" - }, - "1ce0042e7b4f13589f5f8490836dc63e0ca60c3c": { - "balance": "25000000000000000000" - }, - "1ce62051fd7801d294bf31a7b44cd87510e8b545": { - "balance": "2008112411284000000000" - }, - "1cf20f30cd901b2e5fef3f948289dafaaabaa77d": { - "balance": "1444000000000000000000" - }, - "1d449764d38b7a4ac848f49e2dc99df02dfd8a53": { - "balance": "48215693645000000000" - }, - "1d635125c494b1137ca5f15ac95dd6d93c3a9546": { - "balance": "10000000000000000000000" - }, - "1d85a61353c3e0b6d34e105e35c8c7833b6a1e35": { - "balance": "16000000000000000000" - }, - "1d969134ee156c41c98c3721c5dbb092c0b581a6": { - "balance": "64000000000000000000" - }, - "1da12434596a9c318dab854f06d404fe61f0a69d": { - "balance": "16675185416000000000" - }, - "1db0d23fb63681958a66e716e99df3e0b848fd12": { - "balance": "1103581911968000000000" - }, - "1dc628820da657f07ab5eb887d5f512378b5b61f": { - "balance": "6272287019755000000000" - }, - "1e05cba75b0dd379037940352e0073564957b7d9": { - "balance": "12453446342664000000000" - }, - "1e13f037a92ab6f19c4484ae3301b3ac6f48575d": { - "balance": "106244918916000000000" - }, - "1e167bc07f094915c00e7aa4c43b607ed2c998b9": { - "balance": "1000000000000000000" - }, - "1e1f9409bf92c3ef59aa2fd82dce55cd90e23f19": { - "balance": "99139000000000000" - }, - "1e4dfea7871d941e72a161022b62fdb01818c86d": { - "balance": "81000000000000000000" - }, - "1e5d0b525228167334e94314a201388bba08153b": { - "balance": "1138044078759000000000" - }, - "1e6633290c9898abf5fcac54396de770164edc5a": { - "balance": "25052055674000000000" - }, - "1e76296584058670ea80fe9a39d8f457c03747c5": { - "balance": "10000000000000000000000" - }, - "1e88b2c8dcd289929e51a15c636d0b0f3b035569": { - "balance": "87357600832000000000" - }, - "1eb59a1732a159a91a9371650943840e0eb61174": { - "balance": "20542821429000000000" - }, - "1ee077bdef6d45d491602342cee008cd1e2912e3": { - "balance": "10000000000000000000000" - }, - "1f1ebf2f80afced68424cb7b0b966fdf42d508a4": { - "balance": "1460082126494000000000" - }, - "1f3d4a903bd32a537efae19592f5516698c95a20": { - "balance": "10000000000000000000000" - }, - "1f6431696efc6f1ab98dcc2ef0e8553da697e6f1": { - "balance": "20000000000000000000000" - }, - "1f657552b745acbdf731f2ad107d6362480abc88": { - "balance": "162042599568000000000" - }, - "1f699a7682c1266291a3f49e19cac0846470abf5": { - "balance": "712268213248000000000" - }, - "1f7a332dabb00851705274c59187817d859cb9a4": { - "balance": "199999999160000000000000" - }, - "1f7c333047e168f5d3408c42a4919bd44b8f7961": { - "balance": "3918096658000000000" - }, - "1f8226f7a4525b9f3cd4da3acc1bb34529f8d28a": { - "balance": "3530829464000000000" - }, - "1f8b6fcea9e0991ad0b0b25dc65748518a28713f": { - "balance": "142069368416000000000" - }, - "1fa3de6913e4de78cc4828e246554785950c3c8e": { - "balance": "178437291360000000000" - }, - "1faa75d57fd597d2b58d2ac6f65bc2bd5946911f": { - "balance": "13092024644362000000000" - }, - "1faf1721dba3266cde1e04a7e9c789bdabdd930d": { - "balance": "862698523071976000000000" - }, - "1fb861559361701fca1df6ab4ef4d2fb9d2d7e13": { - "balance": "100000000000000000000" - }, - "20154d678cdde9ca1c0acb94726f26617a4da0d8": { - "balance": "2288800561677000000000" - }, - "202484a46ca9d54d0d456bc38e2a74ec5f469349": { - "balance": "50178714107336000000000" - }, - "20324278018b4d8e0c49e0fd1be35d3494079165": { - "balance": "484082383314000000000" - }, - "2033ef68ef6297e9229bb73e6486330543aa3eb7": { - "balance": "51260669473000000000" - }, - "20b1e0ab7b9d62a314946b55a5775f24ae3cfa00": { - "balance": "1540424185584000000000" - }, - "20b61f2eb5e18b1e8568d18235918f9e2f596c32": { - "balance": "10000000000000000000000" - }, - "20ed8ca39dd148edf22e03b8021af32cecadd42a": { - "balance": "20000000000000000000000" - }, - "20fd5feb799fbb021ba262d28332b4dda8f44a2c": { - "balance": "7607475714434000000000" - }, - "215ab8aad1c8960838225294d086f0786c2dd796": { - "balance": "19929201327000000000" - }, - "21681cda53aa1a4cfb3e3ea645c8eeaecfc3ba4f": { - "balance": "10000000000000000000000" - }, - "217b75eaf2c0be12108120ba56ddb709e1885324": { - "balance": "36000000000000000000" - }, - "21be1d75b93e96017f088f1ca64ba7076c8edf07": { - "balance": "150798073752000000000" - }, - "21ccdbe0216b486cb39c94ed13767aa061c75ce9": { - "balance": "11070639373000000000" - }, - "21f2289f2d274bddd7928622fffdf3850d42d383": { - "balance": "268859368544000000000" - }, - "21f54f92a7d9a91915e1751ceb02cb8e3ed3d622": { - "balance": "10000000000000000000000" - }, - "2202c70ec23f4605394d69944edd9f90e488eb61": { - "balance": "9000000000000000000" - }, - "220e2253e1ab9ec348cc28d38bae4cb2d5d9cf8f": { - "balance": "116100821631000000000" - }, - "22328e434957107884854999e666ad0710187e3b": { - "balance": "233364805270000000000" - }, - "22851c0487d119ee3f150010515358d6ff14807a": { - "balance": "104464221701684000000000" - }, - "22a38000f5eca29001e387b52c18fb6030683fac": { - "balance": "55000000000000000000000000" - }, - "22b655a19810307750ed1b6b093da10a863d4fe2": { - "balance": "11840799203605000000000" - }, - "22cc48cf48e8ee207bc08411240f913a4e594529": { - "balance": "10000000000000000000000" - }, - "22d6ea6cb8a9206285ccddd3b6d0d1471ba66f17": { - "balance": "64000000000000000000" - }, - "22e2f41b31a0c69472a1a02d419886539b7b6197": { - "balance": "39885451304000000000" - }, - "22e962f91d01480d027ee0060030f529a7a64c8f": { - "balance": "93285203531000000000" - }, - "22f169328fb1104b386ad7fa69f0c7bf3e9a7d3b": { - "balance": "63366769386000000000" - }, - "22f35f5e0e7a8405714de66a5875c7ef84ec4891": { - "balance": "60944382032000000000" - }, - "23041bdc8d371dc29ffc890f19317dabeef12634": { - "balance": "402327389857000000000" - }, - "230eff5e8595f418686737ae671f1f1d225080a5": { - "balance": "114574598112000000000" - }, - "2331e1756d9800800fc9b54ee6e43e1150b6e58b": { - "balance": "44594796226000000000" - }, - "233a72b132e4ab1d3884274d4402d1a2a6399f0b": { - "balance": "1372148909093000000000" - }, - "2369d9dbbfd0f8aa8a3d84d8f2aea840a0cdf760": { - "balance": "500000000000000000000000" - }, - "23754e5cef31ab60aa97a0c8f9ccb4f2969f2d6c": { - "balance": "24764775861000000000" - }, - "2387973589fb07a8c1ec92492c0b8ba9ab5e52a2": { - "balance": "11642113696681000000000" - }, - "23950cd6f23912758ebe9d412166e27994fe6ec2": { - "balance": "100000000000000000000" - }, - "23b383e11573f3ca9be84e1e11694f58a432324b": { - "balance": "206558238838000000000" - }, - "23c329bb641fa51122ea476e3bc614f5d4f9cf00": { - "balance": "35908627324000000000" - }, - "23cb9f997c39853486adfc1a8b029874d1a6af15": { - "balance": "1400984459856000000000" - }, - "23ee14215c531f6ff1baef2c74b1754306f4532d": { - "balance": "10000000000000000000000" - }, - "23f641f765cf15665b6c28d77229d3b2a58fd857": { - "balance": "266570948120000000000" - }, - "23febb49d9541360b9d099377df16b5630dfbb52": { - "balance": "228513797641000000000" - }, - "24082040652a09cbed6504f3dd6491e0ee9d2bff": { - "balance": "91160839809000000000" - }, - "240d3edf4aaf42e99d366ca36d82c370271b8e8d": { - "balance": "65535355843947000000000" - }, - "242b63ebf47678f17c176d5d4a670e46e66a823c": { - "balance": "469668185647000000000" - }, - "2433612fb939236a87a97261ff7b3bc7b754afb1": { - "balance": "20000000000000000000000" - }, - "246bb03a3fab572b3c64fc23b03dfda42b7ea34c": { - "balance": "936364046000000000" - }, - "246c510dfaf5b49bc0fe01c8256d3879c1b5f89a": { - "balance": "100000000000000000000000" - }, - "24bf4d255bd3db4e33bff1effd73b5aa61ae1ac2": { - "balance": "302436106595000000000" - }, - "24c0378e1a02113c6f0c9f0f2f68167051735111": { - "balance": "36000000000000000000" - }, - "24cf04b7450a0fac4283fa6fcfef6215274b273e": { - "balance": "83714002622000000000" - }, - "24f5f8e7d6a23b55c95fcdc1300de05f9d2abd83": { - "balance": "20000000000000000000000" - }, - "25204bfb27a08dbdee826ad6d9c3398ec6d14fe1": { - "balance": "5929256591480000000000" - }, - "253d95911b4174805d13706b449879413b1672be": { - "balance": "37012901440000000000" - }, - "256065f7e919c508b68957b1d2c9120d29181e12": { - "balance": "25000000000000000000" - }, - "25624542c14c2ecb9a0fe7daec9ac5af16868ee7": { - "balance": "16000000000000000000" - }, - "256d05b6de445179e504a6c94ce1253ae159e19a": { - "balance": "12048598744001000000000" - }, - "256d37fc8980a969063b1f7e7fda8b87d4210da6": { - "balance": "107293553721000000000" - }, - "2588af91a0e8f3ba3ab636781bb84e263acd1f52": { - "balance": "8910000000000000000" - }, - "259774584d4fcae1d84f5997c00beee8a380e46c": { - "balance": "1140713354605000000000" - }, - "25bda1418853a22eb6a5380e8a2862d2a74949bc": { - "balance": "10000000000000000000000" - }, - "25cafdab7f79f7b95d55b4c2dda1f4080aa74d64": { - "balance": "2525573681000000000" - }, - "25cca69b41bb51c51b387c47ece83f30b9a78daa": { - "balance": "163449631440000000000" - }, - "25ce9dabd0a72b02e0056931155ba99c94cbc837": { - "balance": "230073284349000000000" - }, - "25d9d1785c96acddd926b3ed52987ff74f9083f6": { - "balance": "780460361789000000000" - }, - "25e56bd3e1461f27db4eb0cce8bb5ca1574401f8": { - "balance": "1001937531200000000000" - }, - "25fa2162d5c86cda10e4be42c14a24329e455ad8": { - "balance": "50000000000000000000000" - }, - "260a932a23b344056acb8e676714ffac0a13ad2b": { - "balance": "2000000000000000" - }, - "2622efe8836095fcf48d9c8019f48c8320d6e0f2": { - "balance": "5451866545636000000000" - }, - "262447c4d8826ed23ea25e9703a11b4ad3ae9388": { - "balance": "33992454005000000000" - }, - "263eee3badb9b0dd13579c09361806503705a1de": { - "balance": "1134831344000000000" - }, - "266f4c232ebc946c46979cd90d70868380e186d8": { - "balance": "20000000000000000000000" - }, - "267dfe6fa918686942f5e1d19d5fa615f6f2086d": { - "balance": "3569373363935000000000" - }, - "268ad2272c2b71243a7391020a600fd8dfa42d45": { - "balance": "122768017414906000000000" - }, - "269e4f43be9865f05a277933c2fbb466659ada7f": { - "balance": "22064992930948000000000" - }, - "26ae161c20acb26a320fbfbd60c97335cda28bca": { - "balance": "170710653621000000000" - }, - "26b4da905780fb0c5c3e7e5315989fed3aeef135": { - "balance": "20000000000000000000000" - }, - "2704312aa5a4202f14fa3b08e587e4f0ef13accf": { - "balance": "124259630994000000000" - }, - "2704e4b0e8df0c1f298843109ae3bb26c29a22c4": { - "balance": "3155521256785000000000" - }, - "2709347d12251c01aac6455108c6bebe72f0af2d": { - "balance": "220898650215000000000" - }, - "270a32b41dde877463d2106ea4f4529557a5e1d3": { - "balance": "10000000000000000000000" - }, - "2738b3746d6bda9bd72858eaa76f8b5ce7a88c8c": { - "balance": "10000000000000000000000" - }, - "27593d2271aced83e81034e8dd603d098238320c": { - "balance": "20000000000000000000000" - }, - "2771ba4b5944bb12d74b1888255c60e0db215fd2": { - "balance": "412946979808000000000" - }, - "27780086136ea3e97d264584d819dcb2176d7544": { - "balance": "292224348060000000000" - }, - "278936fff8afb553043f038c39fe93906bdb1f4f": { - "balance": "1448466441752000000000" - }, - "27aa0d45d3506f8446816e0e2e9675d46285f6e0": { - "balance": "20000000000000000000000" - }, - "27e655dcc5728b97b3b03fb2796c561090dced1a": { - "balance": "9841344000000000" - }, - "27eb0529279f7a71e50efb70bb1767cbe1ffa4ce": { - "balance": "10000000000000000000000" - }, - "27f564956c837d7949739f419d6ac99deb33d790": { - "balance": "1505247707018000000000" - }, - "280f5618a23c41ac8c60d8bef585aa1cc628a67d": { - "balance": "1316618646306000000000" - }, - "28167a591d66ae52ab22a990954a46e1555c8098": { - "balance": "1000000000000000000000000" - }, - "28257eeb8d20f2fe5f73b0ff2eca3214e30ece4f": { - "balance": "95924728584000000000" - }, - "2827abfc49828db0370b0e3f79de448d46af534e": { - "balance": "769862008499000000000" - }, - "2832b92434e3c922206c2408442bc8274606cbd9": { - "balance": "103421320914027000000000" - }, - "2854f190a38e9b9c04cf499259c6577a68b0b5ed": { - "balance": "144000000000000000000" - }, - "288923bd91be164496e5378ee484f0e4c6c16ed6": { - "balance": "10137243270703000000000" - }, - "2897ff80794153edb721801fb91c6d8373c965f4": { - "balance": "10000000000000000000000" - }, - "28aa06e2290010374097aa2f87a67556d8d68083": { - "balance": "84783245638916000000000" - }, - "28b04ec8eb18b0c6a384f9d92cfb44d1d43ecb51": { - "balance": "14364248730194000000000" - }, - "28db0c000cad3a524bb68dfdd74ffd47b42fb13a": { - "balance": "43586590410000000000" - }, - "28ecd4c5fe98cff66a5b8423f4a27cba9634e2d0": { - "balance": "56106658052000000000" - }, - "2930822031420731f09dce572554a8b8c1eaa09b": { - "balance": "1170839742000000000" - }, - "295154c4522d7bcb2e24b7de9c543dcd1c5f51d9": { - "balance": "179028680906000000000" - }, - "296be4ef7402b00d7af673c1770a50162d7ab602": { - "balance": "8206640005889000000000" - }, - "297b84150756fa89101dd59750a7beb36fb8785c": { - "balance": "1168894124400000000000" - }, - "297cfb72cd1b8b2808fd1b25cdcf7d8de279ad96": { - "balance": "500000000000000000000000" - }, - "29cec0eca9f8508a1ba192a90bb6dee18c40745a": { - "balance": "260217025084000000000" - }, - "29d8f7e72bfa297f17fdce9cf8f4a398f547e200": { - "balance": "307787433251000000000" - }, - "29e14b01c59ba894dd090382fb193ea441164b90": { - "balance": "229028661439000000000" - }, - "29ed634e165084b720e446d28893dbeecd6a7018": { - "balance": "226530464200000000000" - }, - "2a0f8136d43248233f652fe579ef3bd2281dde24": { - "balance": "4007544428000000000" - }, - "2a10204a0c7c9f7701e33c1b71c9427ea16e2e45": { - "balance": "50000000000000000000000" - }, - "2a319ee7a9dbe5b832beae324290f7df6d66f516": { - "balance": "28127560161000000000" - }, - "2a50bfda2b06a9fb28c73f14aaff4f7ef865db65": { - "balance": "10483823413828000000000" - }, - "2a7b7feb145c331cb385b9fcb9555859c16820f6": { - "balance": "1017182951264000000000" - }, - "2ae076c36b18a60f1e3c05d434276a1e16f3f838": { - "balance": "10000000000000000000000" - }, - "2ae2e51ea2ee6a848acde342db2bf6eac927e5af": { - "balance": "494279795271000000000" - }, - "2afd69fac54c167e7ca9d8198a8de386f3acee50": { - "balance": "227162683047000000000" - }, - "2b08018d6e65a7b74ddb5ce1af99976a484b9f50": { - "balance": "16000000000000000000" - }, - "2b0c1d629ad2958ab91e31f351a91219fdbca39e": { - "balance": "113239399820000000000" - }, - "2b2bb67fe9e44165d2108676579a9437c760da30": { - "balance": "20000000000000000000000" - }, - "2b2c99e88e938d1f1416a408a7d0041a605bce16": { - "balance": "6118539729000000000" - }, - "2b5c97b6402ac189e14bbca3e7759319ca8a9222": { - "balance": "10000000000000000000000" - }, - "2b813339c7f818f578b45f17c41c7e931c7828e2": { - "balance": "842834712955000000000" - }, - "2ba6fc21f743968d51f80113aadfc0fdfe8499ed": { - "balance": "309973507270000000000" - }, - "2bb75b272b279cb54498f12b6805261af643c8b1": { - "balance": "1426727673809000000000" - }, - "2bdac062364abd9cf67ba7de214a2cceb0511033": { - "balance": "1090525272063000000000" - }, - "2bea658caa805241aa921f48c8f10cb49e16ffae": { - "balance": "1295499213027000000000" - }, - "2befe7e34299a7c1ad53fc9988ce77e2d9fab20b": { - "balance": "4326342236300000000000" - }, - "2bf466a83cd44aaf0f627606a1c954fd31deb782": { - "balance": "1388986370166000000000" - }, - "2c016a23890e9633fc17b0a8d328ec1ec7ee0113": { - "balance": "92483174342000000000" - }, - "2c45a87a63cc5c8c102d12b83bd9a3501ee41995": { - "balance": "394657687589000000000" - }, - "2c600a596368405e584f3b869f7fabef4ce54aa4": { - "balance": "9879984853585000000000" - }, - "2c7032da8b7816e16095735aee43d1c3f1c43acb": { - "balance": "10000000000000000000" - }, - "2c7275511fe06ee86663b3a618497168b35b0cdf": { - "balance": "10000000000000000000000" - }, - "2ca4074843e9519265447c0dd9ac84ddc2033c1a": { - "balance": "179612279567000000000" - }, - "2cac03ba2c45a6c8186bdceb095b7c5feced3114": { - "balance": "2022060470376000000000" - }, - "2cb8c2cd506b2d7b4cac88ce63230022d412c62d": { - "balance": "211378154058000000000" - }, - "2cd27561cf37ec229982dd592c71d1aab9c2d7d8": { - "balance": "42189968284000000000" - }, - "2cd2e85310a4fbb7f296c3d0d1cee07b191239eb": { - "balance": "1940327317417000000000" - }, - "2ceca4501c5f2194518b411def28985e84d42913": { - "balance": "25000000000000000000" - }, - "2cf7abd42394634689aa2a36d263a6345116b7df": { - "balance": "3553167226295000000000" - }, - "2cf88f29356c166df8383d3312cea10397e25150": { - "balance": "76961677759000000000" - }, - "2d0b62fe49592752cfebaa19003a60b8b39b1cb9": { - "balance": "10277397502735000000000" - }, - "2d2051887107bbd8ed45b405b9be6974a13172d9": { - "balance": "1928781992000000000" - }, - "2d2c9525e2811f4d1016c042f476faf23274aa31": { - "balance": "1000000000000000000000000" - }, - "2d2ef9e1c7a6b66d9a2994adb3ac4a9921408e69": { - "balance": "10000000000000000000" - }, - "2d3bcd18e5c97ddbf1cd28ab37eabe070e9a04d1": { - "balance": "323879852538000000000" - }, - "2d3e60496d0092a4efc665389a916be1a9f8b378": { - "balance": "161958437779000000000" - }, - "2d3fb0ae9b17d3a57d23549ae5500fbb163de25d": { - "balance": "25000000000000000000" - }, - "2d8106dbee6f728c0ff11887690a6370a7d9f5a5": { - "balance": "3102418708000000000" - }, - "2da48eeb788686811ac8270ef3baf0159fc47446": { - "balance": "252187695395000000000" - }, - "2da9d2a6f0b92651a36b05c5e9d2a717c6e166de": { - "balance": "500000000000000000000000" - }, - "2dad81b23d8447190259119019c04a4ef61ab91f": { - "balance": "53428719965000000000" - }, - "2db1faf35901e272aee74a2469a278fdaa6e6e18": { - "balance": "100000000000000000000000" - }, - "2dbae8e1ad37384ca5ff0b4470d3dbc73559841c": { - "balance": "10000000000000000000000" - }, - "2ddf9e23945c181b8592d7965e782068b4c38b37": { - "balance": "100000000000000000" - }, - "2def05d1f2abbaa193a219b87e5319c7ecd48dea": { - "balance": "51359946957000000000" - }, - "2dfd221f96a21e41ffe4dca67b15cd352fe9637e": { - "balance": "36000000000000000000" - }, - "2e1371fcfea9d8dc8e692897a91753400caa9c3a": { - "balance": "5199902650733000000000" - }, - "2e2e04945adbfaeec698ea0f5275f1ad5ffd3d5b": { - "balance": "42034514567000000000" - }, - "2e41f865cfbcf8b89f848405e04de9114087f4ff": { - "balance": "44875730962000000000" - }, - "2e530254768ce94db0ef1204ede0e12b3558e7eb": { - "balance": "14319506377747000000000" - }, - "2e5c43868f45de268967fb22f3f4107da401510d": { - "balance": "20000000000000000000000" - }, - "2e5d2e117d2ba9af9697ec023a4d10b5a2436902": { - "balance": "16000000000000000000" - }, - "2e6000778fb225ddb3e1a2f297d56774e85d9c9d": { - "balance": "10000000000000000000000" - }, - "2eb64b8ab13f0d7823158217d15ba310ed3d0e58": { - "balance": "58724606000000000" - }, - "2ec3973ff33a06d355ad4e8f73b657af8a5ed8e9": { - "balance": "1165606294808000000000" - }, - "2ed4362ea5edf510e210af733089b294f87e8f67": { - "balance": "427561040806000000000" - }, - "2ed8788f1c31b508e37079098a7337bff77b49cc": { - "balance": "10000000000000000000000" - }, - "2edbbe1e2ea482920c76a4ff4c14602b4d37c955": { - "balance": "294409476945451000000000" - }, - "2edcba2bd76128750c8aa00f832c62db30aa7868": { - "balance": "25000000000000000000" - }, - "2ee5abcc0d0d51d4b18947b5aaaa95d037be4e2c": { - "balance": "20000000000000000000000" - }, - "2f058187ef141c06c7c87da86cc1953d2fcf70fa": { - "balance": "9000000000000000000" - }, - "2f16b101da9986a18f4b0d30a26557860338c4e0": { - "balance": "254907899725000000000" - }, - "2f4363df2c61273d230071286bb0157dfefee2cc": { - "balance": "64000000000000000000" - }, - "2f6099a8cb7bc3713b87dab20994d8dc09342003": { - "balance": "1902400000000000000000" - }, - "2f7b3902ce56f74adb0f83cc7d3a99df440cca1c": { - "balance": "825246221388000000000" - }, - "2f7d0298ff6a363375b7eecfe754fca0963c8a1b": { - "balance": "101000000000000000000" - }, - "2fb7c16232b3b1f2e3a676d6d5c93ae6fe5cb14e": { - "balance": "1000000000000000000" - }, - "2fbd5ccc716d2f510d10ec84def3fa69e49f46ca": { - "balance": "1000000000000000000" - }, - "2fd84376be11772e5d072cd74c96b0d9a49c27fb": { - "balance": "1000000000000000000" - }, - "2fdab070e20e2c8923a24c196bec72c33ff0f220": { - "balance": "64000000000000000000" - }, - "3003e6007f69902a0f5e4b4e6d0468277897fc70": { - "balance": "1501210602075000000000" - }, - "30095e6a4ccd1ac2014c3d1d98dce003d775708e": { - "balance": "500000000000000000000000" - }, - "300e47e0fa556371f6c882eb98423be44de7c239": { - "balance": "9108837665958000000000" - }, - "3011231224920b62bcfcbf0aed4fde35dd0a4bdb": { - "balance": "374689586073000000000" - }, - "304be24debce62e70943efddd20457d34e85ab40": { - "balance": "81000000000000000000" - }, - "30912555bb14023e9b7c90aa2314721918cdf1f9": { - "balance": "10000000000000000000000" - }, - "309a94ca7b44bc84a7909ee2b93ed1c94eaf75a1": { - "balance": "39000000000000" - }, - "30bcc93965fa36bbaabcd781326e42227c4e1a51": { - "balance": "10000000000000000000000" - }, - "30c71fed91d24bff69f286ff8f0c6c02a21736a8": { - "balance": "409782329653000000000" - }, - "30cbaf4103757013fd8fb71c44a985939e212b86": { - "balance": "7424807960947000000000" - }, - "30dd59e66093d0bfd87b09c5f6588b9857e9a6f7": { - "balance": "26123006239871345154" - }, - "30f692235f254b02f583d5b515f4701a35c7f692": { - "balance": "148184457997000000000" - }, - "310763019a24a927ce42b00604ee664ca53ff6d0": { - "balance": "393757908273000000000" - }, - "3118a5d4d06ca8b7c8835f4860e6973228000ee2": { - "balance": "56188713212579000000000" - }, - "311adec5bfcaed44680691cc644ee120a484aa05": { - "balance": "169000000000000000000" - }, - "3124e387aa7023995643344c782dac84b9d8c7d4": { - "balance": "1393596696367000000000" - }, - "31379702391cb5a737db3f3ffc336bd03aaa181f": { - "balance": "10000000000000000000000" - }, - "3145606c3ccbaf337610185ffac14ac4f0583c0b": { - "balance": "196454968572000000000" - }, - "315e11501d2c57a62af1631fc2662d4d8745401e": { - "balance": "225000000000000000000" - }, - "31a785ad3eea177c59fb575cad0b44f9a48a12e9": { - "balance": "38039017162416000000000" - }, - "31ae64035e95c1205bf957afb5e1636df00dea3d": { - "balance": "1718600907000000000" - }, - "31c0bb22fd2e9d22984f248a16ec3ed9ad834517": { - "balance": "5982762676000000000" - }, - "31e73a3b5451ebe1163571e9e0567c425bbbfb83": { - "balance": "10000000000000000000000" - }, - "322543c74039ef61fd051021b5e6f16b54bc7c1c": { - "balance": "101346282441000000000" - }, - "3233c7ed11c25bfc41d506c3ae0daf5a3c7c1278": { - "balance": "20000000000000000000" - }, - "325dae17b5225f6734a02c677d43fd126bea89b7": { - "balance": "365067246683000000000" - }, - "326ce8166a4094b93c15557f50f2b1d47811e72c": { - "balance": "16641460224765000000000" - }, - "32cf76046ae48b609524b1a6203eb6296d04853d": { - "balance": "1094839482061000000000" - }, - "33456a28f36aa240262cf95b78b4ac2cd8aa77f6": { - "balance": "3077123488326000000000" - }, - "3348bce2ef90ffd6a59ef5079e1af84b2dd604a7": { - "balance": "9000000000000000000" - }, - "334e5f0ae77dcd3d32dfc2c4ec6ab5e2826dc4b1": { - "balance": "3176777762079000000000" - }, - "335775e19200cd0305e529bc4cdf7295a47cb2d3": { - "balance": "2945631571804000000000" - }, - "336ba81ea6ec4f0da38c1a1761ed3d97fd3ca28c": { - "balance": "3587379203826000000000" - }, - "339191e03e9d5a08ae7b58f4c860235a0721b5a1": { - "balance": "2732237722000000000" - }, - "3399bf9f94c5488c89450257b39fdf3ec8c7f413": { - "balance": "477423805836000000000" - }, - "33cb8556a6c6c867e1be7de591cb22c1b7e9824e": { - "balance": "62293494164000000000" - }, - "33ed633804f39367078e830328dd223254be3366": { - "balance": "22842013797896000000000" - }, - "3409025dce86ad441a5a80f30ce03768d37e40bc": { - "balance": "1381667933000000000" - }, - "34153174cd4d3f1eaed7438638d302f6414d5965": { - "balance": "50000000000000000000000" - }, - "343c6b82b13f0dc82d4269e2c806d2d58e6dde35": { - "balance": "9546969736042000000000" - }, - "346089ea81f7dcb79caf2444df34bd6ee78be4bb": { - "balance": "4344080889000000000" - }, - "34984a8f96dbbfd1f977826a4c2187482559a2e4": { - "balance": "25000000000000000000" - }, - "34a5cce96d2211feb04472260c4cd368bda8432e": { - "balance": "1240050112677000000000" - }, - "34c026a39e44955d1051e8669f9cc58a027455c1": { - "balance": "20000000000000000000000" - }, - "34d730652f4aa002a9f39a47212ca3bc47506b8b": { - "balance": "418050617956000000000" - }, - "34e1d8c8a32ce0f6378abb9bd05ea1f9bfdc5782": { - "balance": "20000000000000000000000" - }, - "350b228870445141f4417ea5dba4f009d693b96c": { - "balance": "76995849736776000000000" - }, - "350eaec708d5d862831aa31be2c37b2fdcef97c6": { - "balance": "258753545822704000000000" - }, - "351fc1f25e88b4ccf090266ebb408593418d8fde": { - "balance": "10000000000000000000000" - }, - "3523ac7a6e79162bb8400bf161cb59389432aa51": { - "balance": "436606776923000000000" - }, - "354d490095e79a29bda2fa11823328450f14333b": { - "balance": "50000000000000000000" - }, - "355a555a36e319e76042e62875a15e1db3012b86": { - "balance": "20000000000000000000000" - }, - "3568840d0a26f39248ab088653ede831f150ce29": { - "balance": "16000000000000000000" - }, - "357096b9c1c7c8d51b682ed3c43d150f55629ff2": { - "balance": "900090781248000000000" - }, - "3588c47ba9204b672c456ee9b5c1ae70f3c738ac": { - "balance": "10000000000000000000000" - }, - "3591edeb9c036e871b4fc6fb3ae6d42e0c0d7203": { - "balance": "1000000000000000000" - }, - "359d92e3e8757a4a97187a96d408c0c11f5c7eb9": { - "balance": "22330509101591000000000" - }, - "35aac2a948f316ba93ed111ac127e29ee9a3adb0": { - "balance": "364387817746000000000" - }, - "35b20459a7daa5f44ae423fd4a1b451ea5090b09": { - "balance": "20000000000000000000000" - }, - "35cdaa84c1f3bc2673bc0c60222c133bae0d3db1": { - "balance": "15234182435000000000" - }, - "35d554233ca690130aaa43501e121a208c657226": { - "balance": "10000000000000000000000" - }, - "35ed399940ece44d01ac873b9c0d3212e659a97e": { - "balance": "55000000000000000000000000" - }, - "35f164612afc2d678bb770f317085ae68cce19bc": { - "balance": "693763596328000000000" - }, - "3601b36cb475101d0d0976a8de9d38e5f3483a08": { - "balance": "1000021000000000000" - }, - "361368bc42c8daf365bce9f9ff3b611373d7b690": { - "balance": "21658400518000000000" - }, - "361bc43be077a269e3e37c11e91479017c47f847": { - "balance": "268900383140000000000" - }, - "363c7a2203f6f93287de091bde3c87eb6800e7a7": { - "balance": "20874859005000000000" - }, - "365dc06856dc6ef35b75b1d4eabb00a7220f4fb5": { - "balance": "30000000000000000000" - }, - "3660e246bce68e2b6e4a802681f188587d2c1c99": { - "balance": "55000000000000000000000000" - }, - "366868ef8e193d7e649ee970d476e6774d5ff1ac": { - "balance": "2544456626840000000000" - }, - "366f7f762887cfb2d09cefa4a5108cf390bdeb41": { - "balance": "26837527714000000000" - }, - "36759f9c92a016b940424404de6548632c8721b1": { - "balance": "1033159825798000000000" - }, - "36a939be88508646709d36841110015bf7cedd90": { - "balance": "144000000000000000000" - }, - "36adca6635db6b00d28a250228532fe560127efb": { - "balance": "3370820618318000000000" - }, - "36bfaed8099ee9f216193ade26d21656c98ce4b5": { - "balance": "1353728563832000000000" - }, - "36df854d0123e271529a8767d1cded4e7b5f31d6": { - "balance": "10000000000000000000000" - }, - "36f59989a902cd10725ff7fe2cab1689aa4e9326": { - "balance": "20000000000000000000000" - }, - "370d6999ae70e781c81d12dc259ea304183b01eb": { - "balance": "45563989086590000000000" - }, - "370e8af59a64a3171b422913921a1e2f982dd512": { - "balance": "170263356254000000000" - }, - "372e01083072214134018f50bde3c8ac4f6e071d": { - "balance": "1400474252324000000000" - }, - "37410fda52f94185d824258ad5f3c9ad9a331257": { - "balance": "11830521097085000000000" - }, - "3752b7e1628275522cd693307787b9564501d959": { - "balance": "67839627078000000000" - }, - "3776f82701c384ce6cbf6a8fea40772cb882b66d": { - "balance": "50000000000000000000000" - }, - "379f63e538168925ba6313f9a6a3b6e7f0e8ed52": { - "balance": "292876625446000000000" - }, - "37a24c1a8080ab429a136c5582782b276eaa931f": { - "balance": "6099055841000000000" - }, - "37abbeaf24b5e6264c87633734852e243d377010": { - "balance": "1051360014489000000000" - }, - "37c50cecab8fe9dcd81aaede95050d27c53f4d45": { - "balance": "106051638566000000000" - }, - "37f82962c3097f0cd9ff605db66e792025a540cb": { - "balance": "10000000000000000000000" - }, - "382ba1e6c53cd7b9c360ef894962d281d557561f": { - "balance": "216789631461000000000" - }, - "38309b458993916efc1ac8b0b5d41302fec21095": { - "balance": "999139000000000000" - }, - "3847f25956a97a32caac059fd9e4cdc105756e25": { - "balance": "876497264905000000000" - }, - "384fe5f399638d277d4fb93f26d527497939287a": { - "balance": "280035151914000000000" - }, - "388335d8b92b445b1b19a3107547bb6ca7c0763c": { - "balance": "167140942784000000000" - }, - "3894a1e65973a542101caa4dc01e9553a5521d63": { - "balance": "34262479791000000000" - }, - "38a0e019c6120a19acaf0e651dd8338982cdaab1": { - "balance": "153843170492000000000" - }, - "38d4bdb10819a7d4ae9a32f4abb82402dff319b5": { - "balance": "1471131830647000000000" - }, - "38e56a55e2ac8320a480562f4a7cea9220306ee3": { - "balance": "907464312139000000000" - }, - "38f18123f3643e03d24ad759afbefc90ed923a2a": { - "balance": "943729130798000000000" - }, - "38f764c861def6d5d65e5ec099536f4cfcc3af55": { - "balance": "20000000000000000000000" - }, - "391e12b51fc85fb879a72fa746ca06c7a5659e6c": { - "balance": "9000000000000000000" - }, - "392342dc7b475c3975877a41622be0fed8e386be": { - "balance": "218719857770000000000" - }, - "3944cc960b8f1993ad841629a79e53d0535a88c8": { - "balance": "210571656485000000000" - }, - "396219864b8cfb0ffb3c675690ccd7026424ad4b": { - "balance": "138984508746000000000" - }, - "396403f26b388150b4876485b124a49845101464": { - "balance": "10000000000000000000000" - }, - "396f1e0f9e7ee86d1b2159ab8f9353677d12d340": { - "balance": "121000000000000000000" - }, - "397cc9f6254d56c721c767e41628a9078bea878c": { - "balance": "225000000000000000000" - }, - "39878b0c7049fb179aba0015279eff6cc3136816": { - "balance": "33962071375000000000" - }, - "3a06b58d0cceee5b091fe6aeb0fc0db5774e9395": { - "balance": "272033811720000000000" - }, - "3a3330e0152d86c5aa1d9bdfe9e1697645d3377e": { - "balance": "2165107207206000000000" - }, - "3a3bb8ed3130e09fbdfc21db3571d4711fc92d60": { - "balance": "885484658836000000000" - }, - "3a4ac96c489c864765cb1997a0084ba745b67a87": { - "balance": "1257436384863000000000" - }, - "3a69e1c351978ced418cea6cee019f220bcb065f": { - "balance": "579242822216000000000" - }, - "3a76a23d81929bed05ef7e1982d32b456e62aa7c": { - "balance": "1027078338792000000000" - }, - "3a7beadd1e11d0e3326c0dcd0f670530612931a5": { - "balance": "20633069818937000000000" - }, - "3a867c44d0dd06517a82ad467d0aefd7f11ce729": { - "balance": "12323708574000000000" - }, - "3a969ae486215e24c7ab89e38929562e2f85d923": { - "balance": "18955477335000000000" - }, - "3ab81366d898a8b798afb08a4b722ab0eb883652": { - "balance": "1220090012596000000000" - }, - "3ac1e14ed5929d382f6488c5444e717373ed29ba": { - "balance": "2030543873000000000" - }, - "3accf4b8ef20e4fea983f13f99ab257a5f9e988d": { - "balance": "156030342415000000000" - }, - "3ad38fa6e3c078025794e213d9dcc5aa397050c2": { - "balance": "36561766773000000000" - }, - "3adef81b2c861ae39c418d55be99aee2306e29fc": { - "balance": "15752410974000000000" - }, - "3b21ff4d5801d3976643899f195fbfd1b72a50b3": { - "balance": "8971221745646000000000" - }, - "3b2f2635dd428ac0b5873088a9a81800f09d6e02": { - "balance": "56922872447000000000" - }, - "3b39919c7bc8d0afec792288c56ab7f4934dc7d2": { - "balance": "1678237240464000000000" - }, - "3b468d9d5546810aa837c29ccb8349548b0e8170": { - "balance": "1100000000000000000" - }, - "3b83d1b651f117f1559a19b04ef408619c2dc4a7": { - "balance": "53628552066000000000" - }, - "3b9a72201bb1e8e678e36129cb1570e3ac99270e": { - "balance": "25000000000000000000" - }, - "3bcab1535b04a0a3fbb673bc41fedaa80bf7901c": { - "balance": "1526488015042000000000" - }, - "3bed42c3d0c49ffac87b9d482f6338fdc9e3880e": { - "balance": "26189771073000000000" - }, - "3bf736b57f0ae47f3714a6bb852090a543b9d367": { - "balance": "652395174320000000000" - }, - "3bfd481651956105ed909eeb98be404ec5ae77e9": { - "balance": "177520143473000000000" - }, - "3c0a12a327545b5f8b7b5c1f7a1ec6a341ec9578": { - "balance": "4184342789398000000000" - }, - "3c132698d59927fe08cba433a41d08acc96c0edd": { - "balance": "151913899135971000000000" - }, - "3c27bd92c4be1a19974ec773bd20b13afe582c9f": { - "balance": "10000000000000000000000" - }, - "3c2ad171573a608286f1fa3f5ef9e6099823983e": { - "balance": "3240802189194000000000" - }, - "3c4b5e808b9fb8baab1144b981b6cd53e216fcdd": { - "balance": "61214114118619000000000" - }, - "3c4cfc6ead044819ceb41c1c64ceda1a228af801": { - "balance": "9000000000000000000" - }, - "3c553afd45535f7c2a70c701d00890e607b96ffe": { - "balance": "2678827200938000000000" - }, - "3c620d55268c55b6deea3b7dc7f59dbe93b6e141": { - "balance": "55494311990000000000" - }, - "3c9b204db23b902d4295e6aba3405917efd59449": { - "balance": "55543672571000000000" - }, - "3cf233b7730a175d05a861318b7bb917bb5bee06": { - "balance": "1867187351033000000000" - }, - "3d292272992397ed5f27d5202da693128d023d35": { - "balance": "79770828413000000000" - }, - "3d353cfe84e9a93aef90547fbeb6e4b4bef83069": { - "balance": "36000000000000000000" - }, - "3d54da4ddd0621822a114581ecd15572e6488be9": { - "balance": "1623867132383000000000" - }, - "3d62ddc67d366fb055eaf92c936a6e7df5085454": { - "balance": "124933526793000000000" - }, - "3d754df1151b9b62a6ed48b477225121c29af063": { - "balance": "50000000000000000000000" - }, - "3d79d1ebd5224ffdc13e27924ab7f9f8e3452ec9": { - "balance": "520163228474000000000" - }, - "3d84fd9785a6bd3148847038c6f1e135042a892e": { - "balance": "10000000000000000000000" - }, - "3d9574c3860f30bcb42523a0cbb08aa7dd83e733": { - "balance": "15259904884000000000" - }, - "3da809a5911ccc77f892034049a97a9022c35e7d": { - "balance": "1415009021101000000000" - }, - "3db9a6c6ab3d0cf6d3bd7e04bdad39b4d419ab13": { - "balance": "9999781764000000000" - }, - "3dc7367c3218f88de8867c425f89102d2f2056f4": { - "balance": "10000000000000000000000" - }, - "3dd273dedb28824d1309c7d60a0744a6b6353e79": { - "balance": "9000000000000000000" - }, - "3dd6b25eb91dd2f3468e0786e8beb465abe7f515": { - "balance": "275172962210000000000" - }, - "3e0d14f83b304136311a33bbac2720c0cd66f117": { - "balance": "3390479675000000000" - }, - "3e15e947ee76f52f0f2a7d84da7c4ab060eb5cbf": { - "balance": "6751398714759000000000" - }, - "3e1b5469e1da4ec27537513f4df3f1a338a7dc2d": { - "balance": "161899580000000000000" - }, - "3e3329bcc90e47e4dabb5c93572b18b5e0efa024": { - "balance": "10000000000000000000000" - }, - "3e5a585ad0f34d78899433edaed574af052616f0": { - "balance": "910225655353000000000" - }, - "3e6be9615713bb06198bf354ef434a9db649699b": { - "balance": "783525278181000000000" - }, - "3e7c7c082f2f99b1ad579400a2e93586a24ed992": { - "balance": "159035553843000000000" - }, - "3e86ea5713f90022c0914fcc25e97c39487eb957": { - "balance": "101867287023438000000000" - }, - "3e9dabab6e50a696edfba6bcd44230d087c8d04c": { - "balance": "3315882414579000000000" - }, - "3ed956f86fe78223c86e164e4f372c9a0bf4a279": { - "balance": "119959915220000000000" - }, - "3ee87e776fb12e9c894e36fd5a61daa984e8a5cb": { - "balance": "50000000000000000000" - }, - "3ef1c8f294443f776a794563ce7569a8fe4d5d20": { - "balance": "25000000000000000000" - }, - "3ef6a396d6611df6c79ec1e6ad6bbd253917fbe9": { - "balance": "10000000000000000000000" - }, - "3ef727346fc631ae6473e9a36e2e5e54df696195": { - "balance": "121000000000000000000" - }, - "3efdcf2c0998637cb82d2b5fc24f27162578d207": { - "balance": "1054861112990000000000" - }, - "3f2cb2335e2bc07744175c497e2f437e87c2a146": { - "balance": "48999979000000000000" - }, - "3f4d16663a4f76ade93eb8bd6ca8fe2158e24322": { - "balance": "237117597268000000000" - }, - "3f7c5e6aea7f3f74d764df50f0fc1aa758fc99a7": { - "balance": "63372222562060000000000" - }, - "3f92239fdb41c6ec228252248c2db3f23675e275": { - "balance": "28538064487000000000" - }, - "3f9610454b621c04f00f01f4d54046502edb21fb": { - "balance": "16000000000000000000" - }, - "3fcfb30cbfe53c0c43f58c28386d9a6e5b49f7cd": { - "balance": "79080579219000000000" - }, - "3fda0c9a3d3f0000635376f064481d05d1b930bb": { - "balance": "10599947385000000000" - }, - "3ffce0475430de0bd9b09a412e404bc63aa28eea": { - "balance": "10000000000000000000000" - }, - "3ffe7583b568448ded5183e1544bca0d283680d2": { - "balance": "1076944549283000000000" - }, - "4003a137e577351a4ad7e42d1fc2d2cf1f906b6f": { - "balance": "25000000000000000000" - }, - "40215fc4c6300d8d8179383d9028fd2d909c6cc4": { - "balance": "3941346079000000000" - }, - "4027d7bbfa5d12c1ab9d08933a1659ae8dd023ee": { - "balance": "1156537386462000000000" - }, - "4039439c960070394dbda457726d97121c7b3669": { - "balance": "4444061364102000000000" - }, - "405978c24a12d930ada6163a44fc4a70c16569e1": { - "balance": "707298643296000000000" - }, - "405d2c1b55ba3f67c8634456b99c19092b407a10": { - "balance": "1462185951849000000000" - }, - "405ddfcf45005cf5a0ee1bfa605a7346a0167945": { - "balance": "88775535985000000000" - }, - "405f72a6940acf5d36a29498075f2d0d7a75bc22": { - "balance": "402796678569000000000" - }, - "407253b005ae97857f812fc60d441e5367b4bac8": { - "balance": "1484147810895000000000" - }, - "4091e1fb1c7af51a64c201d6a0c8f0183dfb7ca5": { - "balance": "10000000000000000000000" - }, - "40950bad9580d4b111955da7d3f9ada26dd9f05a": { - "balance": "500000000000000000000000" - }, - "409a28106192cae7a76c6aa8add0f73dcd63d2c0": { - "balance": "214832616721000000000" - }, - "409d5b872b059aea9a773e854f9a17ed2d5c2ef3": { - "balance": "64000000000000000000" - }, - "40a6e3c753b04c42fcf89cc30df8f50418caecb8": { - "balance": "754228409494000000000" - }, - "40e5ce1e18c78d6c792f46ed6246bfb31bcdb6af": { - "balance": "500000000000000000000000" - }, - "4121692a14554ddca1ca662fb577d7152d4fa7d0": { - "balance": "49000000000000000000" - }, - "412acb10c8ca937ddd64cf0d413b1dd34760f72b": { - "balance": "6073360870000000000" - }, - "4166a5c94d5ae48ced410f950d40656182bf8990": { - "balance": "55000000000000000000000000" - }, - "41752b7d0d3ee58a6b69d8ba721c0894ff701237": { - "balance": "585556720807000000000" - }, - "417c86d6bf734e99892a15294230771bbfd7e1e1": { - "balance": "38233258264000000000" - }, - "418414498f7361b29428c54732e1f49fb394f813": { - "balance": "2063786326155000000000" - }, - "41a424dcbff6bf31686f5c936e00d21e8a4e0f78": { - "balance": "33554754580438000000000" - }, - "41a893429d5f8487c1866b87779155d4bfe33198": { - "balance": "20000000000000000000000" - }, - "41bbedd607fa576d130305486824cd2871bf6b05": { - "balance": "649728993301000000000" - }, - "41ee42c1fb1bcdc9c7a97a199fdcf9b63623521a": { - "balance": "7906012418597000000000" - }, - "41feffaf56d1712af6965fa6eee1b06bd624e7b8": { - "balance": "49000000000000000000" - }, - "42107e765e77ea76b3d6069d3775bc3aef7d692c": { - "balance": "25320783684183000000000" - }, - "421f4dab3240e15a1c78e3ce8642de9b578b8e4a": { - "balance": "832511242936000000000" - }, - "4246c52c3601541a873d4bbaafedf28b9bad5b73": { - "balance": "10000000000000000000" - }, - "424efe1ba28bb1aeedc38a3a5135547d0fe80751": { - "balance": "25622294162729000000000" - }, - "424fb0a3ec325bf42e7edbef7e450f2ffd1cf318": { - "balance": "20000000000000000000000" - }, - "42714c04d17f6c29029daf7f50d1cbad6590cfad": { - "balance": "271755674161000000000" - }, - "42b66e9123d304b70fef3dbcfe8587fd6189b5c4": { - "balance": "1030481609000000000" - }, - "42dacbc412b829cb304ffbc316b3f81b379bfc80": { - "balance": "304208485736000000000" - }, - "42e3d9832c8b6cdea39c97525570391803dee276": { - "balance": "2581020833000000000" - }, - "42f757898f95c1b46f64a4a6b7f86ab03022d672": { - "balance": "100000000000000000000" - }, - "42f7956fd659e00d3be2f3d1d4f3ed187aef04d6": { - "balance": "50000000000000000000000" - }, - "43160b2bc00f7f8f7fc806e2f6e2ffdc62b3a651": { - "balance": "1000000000000000000000000" - }, - "431b77cdd067003eeed26c1aee32f67fb94f7092": { - "balance": "902514849986000000000" - }, - "434e44583786e354731bca250d94ef0d8860a538": { - "balance": "1187789683866000000000" - }, - "434f1b9b193c88bf58685124aac0167fe69f9014": { - "balance": "500000000000000000000000" - }, - "43535982688844fa703cb9bd5723790cab364049": { - "balance": "100000000000000000000000" - }, - "43559f405590592c254e427fa25f03e774d8defd": { - "balance": "6913200000000000000" - }, - "435c08c481d59308a64afec0d6f936321bb120bf": { - "balance": "9005920819593000000000" - }, - "43629748a92b846f21f637aac5103412fbabb9a6": { - "balance": "1177513692845000000000" - }, - "43650b37552882d225ccc977aa2b7a86a4ca9bb1": { - "balance": "16000000000000000000" - }, - "4385de394371d26a45f18e8b3842effd015027bf": { - "balance": "187331693412000000000" - }, - "4386ff9648fe420503c9a36fe7b97c079de3b770": { - "balance": "2714401478778000000000" - }, - "43b370c4457cf39a3be86cc00c2b27614ca6e638": { - "balance": "8316429850934000000000" - }, - "43c464ea740172fe6f4f09974106fd24029837b9": { - "balance": "129643160399000000000" - }, - "43ddd2d33dcb7e578f4e59ad6b9c61a24c793aa8": { - "balance": "500000000000000000000000" - }, - "43e0f8065eb7faf3bbd13bc7c5d5d8f5ff1bdac3": { - "balance": "4454324716300000000000" - }, - "43e96cd065d7934b246d0fec8cd2dc6b36d56d7a": { - "balance": "81721481452000000000" - }, - "43e99acabfbdc6cafee3afb12fa7ed1345370b2d": { - "balance": "4595292398872000000000" - }, - "43fae764c7555b859b93d2126edfa59cfbf298b5": { - "balance": "105746805109558000000000" - }, - "44052eb938c02776b5240f38ec99f5ef51ef0d87": { - "balance": "38446396949881000000000" - }, - "440fc7621cc17f121f0bdf2a68c5be2c3af4fd3b": { - "balance": "1026958147051000000000" - }, - "4440ccbc77249a4d891d9ab5a5f2026b17aff7c7": { - "balance": "10000000000000000000000" - }, - "447f3f702c13a3fbdc8675c6285702b5aa2b66bc": { - "balance": "1089533398014000000000" - }, - "448f152be153fdb0497403f70e37d876946a5021": { - "balance": "614429461682000000000" - }, - "44a1e3a044f5d1fb00f4beb3772a3ee08d8b7093": { - "balance": "1000000000000000000" - }, - "4515edc7154bedd7143b69a04c4e738f8aa4ab18": { - "balance": "10000000000000000000000" - }, - "4572148fe5ea9d4795e1f1ed93097aac1d70991c": { - "balance": "2873782218000000000" - }, - "457581f223b8eacd757abb292613e317d6f59305": { - "balance": "3582446780073000000000" - }, - "45b450961882850f7038d5cdcd2a8fa2dc4b5469": { - "balance": "20000000000000000000000" - }, - "45bdfdf3840d4341503cd7fc87e4b66f6179e5fe": { - "balance": "10000000000000000000000" - }, - "45dd9baa87b3c94df66308d8ed4f3a5bb65c3dcb": { - "balance": "25000000000000000000" - }, - "45de332b8ee95d886cf11b99291b46f46c1ddd45": { - "balance": "36000000000000000000" - }, - "45e06afdbc70288a2cc55bccc4fb2d8195aea028": { - "balance": "790360485306000000000" - }, - "45fce5fd1acb2bc5507723c897cb340437e39735": { - "balance": "100000000000000000000" - }, - "46045cddd940d80596826ce5354489b3047663bb": { - "balance": "100000000000000000000000" - }, - "4610286f8a2649dcfbc6d91735745f418a6abc75": { - "balance": "10000000000000000000000" - }, - "4615905ecc6f7df0ccb7b86a3e1d3770adb2f874": { - "balance": "1000000000000000" - }, - "46256e00ff927d54b0ca139ddccac2148784273b": { - "balance": "10000000000000000000000" - }, - "465e40e7d129ad310fc60ff0f17c0f968611118f": { - "balance": "677971225649000000000" - }, - "4664a920f7fe9b0d78a665e1a4aeb95f287d6059": { - "balance": "20000000000000000000000" - }, - "46679de1c6143138fd9c44ff05853a52371915ff": { - "balance": "363627463229000000000" - }, - "467cdc210ae48ba99740d37ee79fa57c4216bc81": { - "balance": "10000000000000000000000" - }, - "468053d193debb88735571acb24b764f2676272e": { - "balance": "49000000000000000000" - }, - "46826d1f1418abbe4e7b9236d643e5b57a0f0208": { - "balance": "37752144164916000000000" - }, - "468df2ea57972ddeb88d470a5f3c2c0e2284ac17": { - "balance": "757320434551000000000" - }, - "4695ad5b686520ee8426d24b50ff7a5f0d703443": { - "balance": "2851082366000000000" - }, - "46a149bc8ec2b85fdf938f753a6c53777dcca2b1": { - "balance": "10123698633000000000" - }, - "46c081440f760a21b74c2499bdda13aef8245930": { - "balance": "180752319265000000000" - }, - "46e615324f6e4fb242f9bfecffc0c802ba7733c9": { - "balance": "10000000000000000000000" - }, - "46eb54f09dbdaaf3b97a1f79a3d82ee2e902b3b8": { - "balance": "3430510380318000000000" - }, - "46ebb24b04919ec0164f0bafcebca2309f2d3035": { - "balance": "129155832233000000000" - }, - "4701f9fe78111011f820fe28c47522e601655678": { - "balance": "9000000000000000000" - }, - "473f44e2c1d5d7aa53cf7041d7ad19a0d9eaf1d8": { - "balance": "162679637505000000000" - }, - "474f8bf4d03a7efa4d190905ce062eea7c75118c": { - "balance": "1259904506149000000000" - }, - "47598330e862a4f7cbda8be74ac10cd5d370a55e": { - "balance": "291763101699000000000" - }, - "476455d48fc858a06bd7854fcf1bd60bcfde9ed3": { - "balance": "10000000000000000000000" - }, - "476826d58192ad822f4686311d6c6d4d4f66ee5f": { - "balance": "453184657722000000000" - }, - "47a231eb3fdbc24f2d008f06228624b2a45ae5fa": { - "balance": "1000000000000000000" - }, - "4805f4c0eb1c83c436118ec9148019e5fc1962e3": { - "balance": "1311161626928000000000" - }, - "4809f373cdd56c8481ba3bce5a401d55a7e50a50": { - "balance": "2284845194349000000000" - }, - "4839bf9ad56873abd5695057bf71972806cde827": { - "balance": "42264923611000000000" - }, - "486dba2a47decabc9a85d1d64d74687983ab273b": { - "balance": "49000000000000000000" - }, - "4877993f5ecf02451f8d4591594cb2f30dcf9f26": { - "balance": "100000000000000000000" - }, - "489723e325f609e27be14528c4111fb3eec13f7c": { - "balance": "2489030141000000000" - }, - "48b710d16e9da736b773453089d69cc6ede116b5": { - "balance": "26651593216000000000" - }, - "491088e1e4b5c3d65870f2deef9be6ec3dc6c7c7": { - "balance": "1446809481953000000000" - }, - "49174451320ad2e14cb2b05ecdd251b75ace3038": { - "balance": "15533380764616000000000" - }, - "4956ead915594b621131b2fc2dbbb49ba43c5559": { - "balance": "1175638488000000000" - }, - "4973a0d32147ba89f525a18f989518dcfce93b0e": { - "balance": "522848489444000000000" - }, - "498c6f9063705054fae07260d4176c3d55a97650": { - "balance": "732941433000000000" - }, - "49991f68f2a76bd1cffa3e9721be36f3fd8351b8": { - "balance": "17742568700019000000000" - }, - "499a8af194e0040f349e893937fe3858f8267fca": { - "balance": "80704784160862000000000" - }, - "49bcbb7b263febf54f8ff498525bac8e7241f966": { - "balance": "603044032468000000000" - }, - "49bd72773656c4e1a4d16284aea2fb05546d2b31": { - "balance": "1896607093054000000000" - }, - "49bf80fcdefebe8cd4830ba09e46ccd7231c8e6f": { - "balance": "10000000000000000000" - }, - "49c9d82dea78f14b1c52efc0196b67f508f7859b": { - "balance": "2313040051399000000000" - }, - "4a2daeacf0468d137e3bc464d6d5fa3893a9136b": { - "balance": "10000000000000000000000" - }, - "4a6c428f245e8d9115b34764bab17eb86ac472be": { - "balance": "10000000000000000000000" - }, - "4a6e8d037acf1960dbbf14e7a02fec0ac656f9c1": { - "balance": "6516295825438000000000" - }, - "4a7e7fc3c72f2f9b92bf0dcd5297cfb19f077d7c": { - "balance": "99426213999999999" - }, - "4aaa6817a5000bb7596e000135b3051c5931e7c5": { - "balance": "102884105546478000000000" - }, - "4abcdc3d7d3d314a163da92aee53a56b87313a2e": { - "balance": "44402243657000000000" - }, - "4ac9385ade2377b061f4211b392ed6a6e7fb83cc": { - "balance": "1000000000000000000" - }, - "4ac96e1e26cb66ff788ed8c62db811d7b4fdbc74": { - "balance": "68476115774000000000" - }, - "4b10c247caf33fb872d9bf86572424410aa86752": { - "balance": "337915294240000000000" - }, - "4b23ffff1894df49005c7afc0828880924571299": { - "balance": "169848767272000000000" - }, - "4b486895caf3a0b5afa198df744de7082eec8666": { - "balance": "1672587376054000000000" - }, - "4b98fc960610573be456c0e1e319f4f863bf9095": { - "balance": "259382246718303000000000" - }, - "4bc0cc483be20223f40ed6deef63dd9645c216c4": { - "balance": "4322684620000000000" - }, - "4bf4a046afdd4ec9d0e50730ff6ded5ef2327442": { - "balance": "70601389160000000000" - }, - "4c0149058e2e74f7c900e6d6e5fa12eea882c5e0": { - "balance": "2017399852886000000000" - }, - "4c17a3997fb70599794d01a33a27a6d5b52b6f01": { - "balance": "469002093209000000000" - }, - "4c4559e7b32340dce112cf7a021ced1b113f6dd9": { - "balance": "25000000000000000000" - }, - "4c4f02b3f232b8ce8485d425639271510cd0486f": { - "balance": "68828038140000000000" - }, - "4c52ec56142bb6e8c8830e5c17b01b5165915f3c": { - "balance": "321766233041000000000" - }, - "4c58defa57875e709ca039a54a2be5aed6672f6d": { - "balance": "121000000000000000000" - }, - "4c5a886ab90b6bac68677a7eb92a06bf33ff2930": { - "balance": "236899852150000000000" - }, - "4c60539363edbd812334a54543c40ecab8af2ac8": { - "balance": "3281904094699000000000" - }, - "4c76897d0d5d39195354194710c5e7f99bef63d1": { - "balance": "10232271258305000000000" - }, - "4ca3c03780c20a64f3b5ebb75669982a71ee8a71": { - "balance": "377172198976000000000" - }, - "4caf77eefe062a6f053a464171bc75254b47f52b": { - "balance": "20000000000000000000000" - }, - "4cb7d7ce805e56f6e47e94cd755b6d97f8f996a0": { - "balance": "120998866000000000000" - }, - "4cd34f8f3299d3b7aaee180baa0b432369e1b3d6": { - "balance": "197088135242000000000" - }, - "4cd7aaa5415d809f405f520e4c0319a6029b981b": { - "balance": "686627368232000000000" - }, - "4d01067555f1ef63883f25c562b07168f79fa80d": { - "balance": "17547055698000000000" - }, - "4d2cb4c1da53e227b08c0a269402e9243a13f08d": { - "balance": "324000000000000000000" - }, - "4d38bb5f48ec37b751d16de32a4896fbda479ce1": { - "balance": "802530078718000000000" - }, - "4db3e76e2f68896cecc9826e10a5e09df0352c28": { - "balance": "555180306924000000000" - }, - "4dc8730d9f032d33dc493bcd3c6375b38f41afff": { - "balance": "5726933881000000000" - }, - "4ddde96556f5185a13617f01ebd9102800bc9e9c": { - "balance": "1181822708402000000000" - }, - "4df9359cb204bf649668ff8086a7f5e24709083c": { - "balance": "262998978400000000000" - }, - "4e0a1a3dff0d33c418758263664b490140da9e01": { - "balance": "100000000000000000000" - }, - "4e0dd6d8de5caa3a3bf9fdd6f2d7b30618623cc0": { - "balance": "10000000000000000000" - }, - "4e11af85d184b7f5e56d6b54a99198e4a5594b38": { - "balance": "76658631121000000000" - }, - "4e314349abc52c686d47dc771ebc8040966be386": { - "balance": "632341985941000000000" - }, - "4e3fb09c35375106bece137dbe0e5491e872871b": { - "balance": "153648535396000000000" - }, - "4e4f0d606f7065bfb1545e60b5e684ae1934e055": { - "balance": "48998635468000000000" - }, - "4e50957aa6c91c548075add8ec625b74c0973abd": { - "balance": "1000000000000000000" - }, - "4e5c6efa76493f0e9422582016aac50539ae60d9": { - "balance": "2078967343000000000" - }, - "4e70bbcb50c4e875fd573dcb694908abf3b30b37": { - "balance": "20000000000000000000000" - }, - "4e7f5670a7dd168a0803e53b8bf72f4db280e3ae": { - "balance": "1658463113665000000000" - }, - "4edaf859990a10977bf378df45b32f93422c84b4": { - "balance": "121000000000000000000" - }, - "4ef41923a1a426772832d3c267adbd84e5994edd": { - "balance": "5432615017384000000000" - }, - "4f11a70d80f36f46ed0c2a5fff1a39b711f3bae5": { - "balance": "8415785077000000000" - }, - "4f159095afcc75b8f5cfc90c9d07a0d77ac8ed69": { - "balance": "25000000000000000000" - }, - "4f2652322736cc18b24af582d4022fe329a9dfb7": { - "balance": "9000000000000000000" - }, - "4f328173f352f3dfdca0ff5e3185f26de77c6f75": { - "balance": "10722917874680000000000" - }, - "4f47a62aba6ea049fc0e92d8afbe1682472d98bf": { - "balance": "10000000000000000000000" - }, - "4f4c3e89f1474fe0f20125fae97db0054e9e14e0": { - "balance": "50203638983000000000" - }, - "4f5ac8dfe79c366010eb340c6135fbee56f781d8": { - "balance": "50000000000000000000000" - }, - "4f672cbd373183d77d8bd791096c6ebb82fa9a2a": { - "balance": "978111227765000000000" - }, - "4fb179c9c88decaa9b21d8fc165889b8b5c56706": { - "balance": "24750205150000000000" - }, - "4fbcf391c765b244b321875d6ab4381c44d0747a": { - "balance": "99999580000000000000" - }, - "4fc979b38b981fca67dfa96c6a38a17816d00013": { - "balance": "1088876196468000000000" - }, - "4fdfdd1832b114b4404aae23305c346beee14e1d": { - "balance": "278724179057000000000" - }, - "4feffb1836029cd0e9b8f4aa94b35ae3982fa770": { - "balance": "1674590934924000000000" - }, - "50045745a859f8fce8a2becf2c2b883b3723b2c8": { - "balance": "169000000000000000000" - }, - "5028bde29fe88e03e3de069b3907fa9df551c379": { - "balance": "196000000000000000000" - }, - "507096ed771fa8a1d004ee5377c01506df461b32": { - "balance": "2669205000000000" - }, - "50788574a0967580fdaddc4758f834d8978455f6": { - "balance": "1648581593000000000" - }, - "508d8e8f338ca98d3c09f0f15fd9e7baa80701e8": { - "balance": "16000000000000000000" - }, - "50a4dc916845172b83764a6c8b4b00d6d02d41d3": { - "balance": "3020744393592000000000" - }, - "50da06418780c220ced4898af0b1fca533f73cca": { - "balance": "36486700700823000000000" - }, - "50fb6fd8432a66219e754234e9eea1dabcc07676": { - "balance": "489500000000000000" - }, - "5104bb1b831902333732dd25209afee810dfb4fe": { - "balance": "1333614132000000000" - }, - "513963743ec6ec9dc91abf356b807ebad64df221": { - "balance": "1508002412172000000000" - }, - "51397ca69d36e515a58882a04266179843727304": { - "balance": "941648956414000000000" - }, - "514a58f2b36c2cf1b6293c36360cf658d8af30ed": { - "balance": "1233397704089000000000" - }, - "514fe0cdb3de692cab9f2ef2fd774244df71be66": { - "balance": "9670444445882000000000" - }, - "51583128081fd800d9550144afebdf3fe88149cb": { - "balance": "231190355520000000000" - }, - "517384fe92391187d0e65747a17bfaadf967c331": { - "balance": "1943121865489000000000" - }, - "51aebfaa26a54071cfe6c2d8f81157ec313984ad": { - "balance": "1422225031261000000000" - }, - "51d4f1205b272e491e94fe21f0341465f14141fc": { - "balance": "552384783614000000000" - }, - "51de598faa85276bb26a68b135028755304b6700": { - "balance": "2068484560002000000000" - }, - "51e08e0304f08ef768c80ca149da4721fcf482b0": { - "balance": "194629207228000000000" - }, - "51fa3da695e24f602952a71966f37ac3596a94a4": { - "balance": "17008166261720000000000" - }, - "520b22776b1befd3064636da0dd251afe569ef13": { - "balance": "18538137781909000000000" - }, - "52219a1e1aa82b78b971088c30583a3bbe675c8e": { - "balance": "411959222637000000000" - }, - "5252b8a0688096523498cb5c1f42bcd1f61923d7": { - "balance": "1863936864000000000" - }, - "5259154e1a5a809b2e3dab80372124cebbfd56e2": { - "balance": "110000000000000" - }, - "5264f2de516835e549710bfe34ef03b08b8557dd": { - "balance": "1216000000000000000000" - }, - "52b17fae7e9cac447f026db71dba4034a1d53174": { - "balance": "99001631977000000000" - }, - "52b3363ae882a99354faeb76733d0fa2cbb89787": { - "balance": "102517584327000000000" - }, - "52bee7fb24a7fc1f34cf0874ec2f06c5fe847cb1": { - "balance": "54443400591000000000" - }, - "52d1f12d391c7a2f3b52939a61a20da5f85eecc3": { - "balance": "2707175772061000000000" - }, - "52f27099483589e883e7eb789896de39c61e46da": { - "balance": "358944977251000000000" - }, - "52f3b715b678de95d1befb292de14c70f89f5e03": { - "balance": "2989868434000000000" - }, - "53259780569f6dd6753c1da1d53d0b155c5b30d2": { - "balance": "200489122590000000000" - }, - "532e4908e8297c90d75d2280b432b469aaafa2ac": { - "balance": "20000000000000000" - }, - "5334d1e399feacabc9648cebcd93172db95d43be": { - "balance": "25000000000000000000" - }, - "5341665addfb5e367f7a7d35de95b87a0cceb3a9": { - "balance": "60544291695000000000" - }, - "535a39a854ed1c2f0afbc5944f1ee0e2e68cf65a": { - "balance": "2141913781000000000" - }, - "536515c0c08988ee69da1d75f18c706f6b9bf7a3": { - "balance": "169000000000000000000" - }, - "5387a1ce4cd2ef4f90075c15dc3c0744948ec356": { - "balance": "50000000000000000000000" - }, - "539a30ee5724978010990718bb8b0dd25f89fd15": { - "balance": "1306896514000000000" - }, - "53a5f87dfb17149b8c2934a2a9d519ace4ac9724": { - "balance": "4569449510000000000" - }, - "53b24fb36e72c22eb830dc93857a8188b03397a9": { - "balance": "64000000000000000000" - }, - "53cc35b3daf4b8e1982e0e63d0bc68d7252e7fcc": { - "balance": "68213426853658000000000" - }, - "53e1f85147e000ae1ff6a5910407395e388c683c": { - "balance": "20000000000000000000000" - }, - "541f43ff66ed5eb1a1ea0ae3f86355ecff665274": { - "balance": "49562725831000000000" - }, - "5428a31f736c0d2b3c4e80baefb75a76ed44d3f7": { - "balance": "10000000000000000000000" - }, - "542f732aec0873bf531f6941828b6f0ed0611106": { - "balance": "8407722276000000000" - }, - "54300b6a77b95545373b2bba73e60f37c31eb1c6": { - "balance": "1581215621996000000000" - }, - "5434bd65a492a4d14d3b97eb49f6e491350ef73c": { - "balance": "484000000000000000000" - }, - "5444a1735913eeac177d947ef38de7cd6bdfc0a6": { - "balance": "1000000000000000000000000" - }, - "544ffeab53bdc59ef8edaff0042b03c2ea123615": { - "balance": "10000000000000000000000" - }, - "54613713df6c5b89c3012a7835651f25cdac8331": { - "balance": "98684037547000000000" - }, - "5471fb39b4e48c118f855492830ad9e2eaa68179": { - "balance": "91791250228000000000" - }, - "5472591efd048dd60a4d6afdb549e95a65578b0a": { - "balance": "50000000000000000000000" - }, - "547b4c1ae70567fd77a896dc05eb536f502ac8a4": { - "balance": "14037444012000000000" - }, - "547fa9f6f86a2939f9144aacb74e0af60d434535": { - "balance": "428416957729000000000" - }, - "54841d6a478cb9b6e717a9de35577a1a4a504b0d": { - "balance": "144000000000000000000" - }, - "549157e5b1c92a88a0eef335b1bcf4d162482017": { - "balance": "21019502942000000000" - }, - "5492757c55c72ac5946b21514ee16c5065ecde7b": { - "balance": "10446737491000000000" - }, - "54984a41eeaa8e710e4e5b8a7f68c96057b7df3a": { - "balance": "10000000000000000000000" - }, - "549a3717a1bca3f38d24655197c3ccef1e8c273e": { - "balance": "4416133255000000000" - }, - "54b047fbe004191cd02f31163d29bd61ccfaadf7": { - "balance": "52649445905000000000" - }, - "54b125d8b260386633b756056b7d7e78e7071715": { - "balance": "10000000000000000000000" - }, - "54ffad1ae76ab45c4218ced27e49bf2745b2a2e7": { - "balance": "1426474871178000000000" - }, - "550b28968bae36f4e99780c6d7deb54c158be6d8": { - "balance": "10000000000000000000" - }, - "55117923e8393dbf233c0f10819e7de75569962c": { - "balance": "470094520022000000000" - }, - "554a2471e6ecf2320da545d559c40b8b622465ab": { - "balance": "4052895973949000000000" - }, - "55607b39da9480ed8f54d74d0818ab8798136589": { - "balance": "13704276648975000000000" - }, - "5561cbe99fd775f5d0f05903fd62ba4877b3319d": { - "balance": "1007596371374000000000" - }, - "559ba7ab58670d4a0b118bbf6aed7f6fdb276594": { - "balance": "3127762973000000000" - }, - "55b0bc444f2a5952a98f216f61cf07382da1e156": { - "balance": "18683409750727000000000" - }, - "55c0a02dc68123aca7ee0c9cd073ead50b16406e": { - "balance": "99999999580000000000000" - }, - "55c47d593952afd637050c5758a921a204f23fc6": { - "balance": "1615608723958000000000" - }, - "55c6855b3970e5a550f0c75d5727329476406d91": { - "balance": "600705012673000000000" - }, - "55eadbe33899f53138d0fb204f42e272f447cfd6": { - "balance": "1671128311341000000000" - }, - "55fa59fa0fbba06b7184ea78868d438176eb96eb": { - "balance": "1553000000000000000000" - }, - "560a11493b5a0ec28589e80276fe975ee26c6a3e": { - "balance": "10000000000000000000000" - }, - "560fbb31d83bf6dc49e5fb15bd582d70c49fd273": { - "balance": "46015432815000000000" - }, - "5620e17ccf094b1be1a93f6f3388fb96e3a90165": { - "balance": "484000000000000000000" - }, - "5633512298cf74f4d2b8663e6f291e9e25436e7f": { - "balance": "10026444446000000000" - }, - "564423f92b8841b3b1f8bdba443067b580916e65": { - "balance": "465451550122000000000" - }, - "56730e1d11a84970355c43ac7659f2f4786dadcd": { - "balance": "20000000000000000000000" - }, - "5678851984add045f3d054623c198dfd4665d54e": { - "balance": "227651903234000000000" - }, - "569cf18b4bcb99e3f3d27235f2c4c0d8d160af03": { - "balance": "4124979731000000000" - }, - "56ac5f2c3486a9ce744a71599ab89a606e7464a7": { - "balance": "9000000000000000000" - }, - "56bc5936a6ea37c1d0839bf64bcec0d366840ace": { - "balance": "14741201469670000000000" - }, - "56bf62e0135e903525cc46b0a3cce33f4a16880a": { - "balance": "534970476270000000000" - }, - "56da0781a80a0abf5dcda4da35861e9de601bfbb": { - "balance": "166898390441000000000" - }, - "56db15729e52d615a744a04f8a59d63e3b9f735b": { - "balance": "10000000000000000000000" - }, - "56e32ed78e7f5be6b00c28847efe7b3589cdae1a": { - "balance": "1046236086484000000000" - }, - "570f7a08150e0088178276f8116bc4103f885903": { - "balance": "1124393518440000000000" - }, - "57147fdd9b52ef53b4ebd4b5712d29da83f99374": { - "balance": "39000000000000" - }, - "57395fb355fe51f1b32c1baa4e9ee0fc2b8fe05c": { - "balance": "7701013675397000000000" - }, - "5752f0f11ed12bb1d5041b0cee4ddd500cd8806f": { - "balance": "151337200533000000000" - }, - "575907d73ad5ad4980a2037efbd20860afc67ad9": { - "balance": "3568754158000000000000" - }, - "576acb4c0bccc89903ad285ac08c70fde514aaf2": { - "balance": "25000000000000000000" - }, - "5784cb8a17cfb5392c4aeec2edbd173849ca6ee3": { - "balance": "15804767597000000000" - }, - "579234645eb857a3ca51230b3a02b964f8efa2f6": { - "balance": "20576922380000000000" - }, - "57989f9fa52b4c0502e7d0c3caac0c37a0b20516": { - "balance": "462711082812000000000" - }, - "57a55c376ea03c22e21c797d83e2fb039508ad3c": { - "balance": "10000000000000000000" - }, - "57d1612ea1fddacf088b62f625ad8cd49d7517cd": { - "balance": "18001023230648000000000" - }, - "5811590907050746b897efe65fea7b65710e1a2c": { - "balance": "310984892882000000000" - }, - "582ffd8c43966aa8ad3c6cecdfc18eddc56fe5c0": { - "balance": "69136214255000000000" - }, - "583b90b3c4d00b9ddf101efbce75bb811d969fe2": { - "balance": "7839200298177000000000" - }, - "5841fee8b1965141e51b8c146b6af00f6a879a8c": { - "balance": "1210322907244000000000" - }, - "5847a576f7799ba1a35e36906b2c2a5aadeb99b1": { - "balance": "183765768447000000000" - }, - "586dea7ada0a54150f5afcf54198db473ed046a2": { - "balance": "7123598380000000000" - }, - "586f545062ec7dc0ffc213eacd59af80660df570": { - "balance": "10000000000000000000000" - }, - "587187488758f67912bd5bb8a5be787a73d97ee3": { - "balance": "702757402654000000000" - }, - "58be0a3482dc3411571f047f4128387049cb9798": { - "balance": "1000000000000000000" - }, - "58d546e2ae82efc4d8efc887ac6fd30f7eb5dac6": { - "balance": "1486717153455000000000" - }, - "58e7010e6b8d97a556c0e7f0d90151224ebf674e": { - "balance": "20000000000000000000000" - }, - "58f991b3b12d29f09ff4cc2c6e83d576e95b1f59": { - "balance": "25000000000000000000" - }, - "5923a65a796934e69081715657e8dfec8874e40d": { - "balance": "10000000000000000000000" - }, - "593b7c43073b8954355ed76020ff3780dd6ae783": { - "balance": "1403468567787000000000" - }, - "5947f1dbd79a622bcc3fa64b19f9b6eda164dcce": { - "balance": "50000000000000000000" - }, - "596311e2fc09ae1eaee57900f2ca188afd5e68a6": { - "balance": "448723397560091000000000" - }, - "597a3adac4607d457c90817220f67eb4abcf129f": { - "balance": "18000240000000000000" - }, - "598201a9bcff0a773e9323338a8a094e9d9b3999": { - "balance": "74904485722481000000000" - }, - "599e93031704c2ce36308f44d4ff8166e71ae516": { - "balance": "100000000000000000000" - }, - "59af0178699f9f3d8f0ea645dda75356119a6e2e": { - "balance": "152462578058000000000" - }, - "59b0c06e40475cd75728797add9c69c3fdb17b4e": { - "balance": "23147237210000000000" - }, - "59b79577f183b9d39c2b458646a26b2fd6ed806e": { - "balance": "4244859516807000000000" - }, - "5a03b51d67a9c660258ebc030120d5d1d4f687c5": { - "balance": "4451691855300000000000" - }, - "5a0d03dff6754963c757eb15a3339ac6c4ba6196": { - "balance": "215126489934000000000" - }, - "5a34ab3937854e407a8739fa14574d3d20e30d6f": { - "balance": "1375979293937000000000" - }, - "5a352fbeb2fd78bbe0268b0efd34f68d401e2769": { - "balance": "27929247671418000000000" - }, - "5a47c2ca4c0fad7e2fc7bbdf5f2356d68843c564": { - "balance": "3218227936000000000" - }, - "5a538adb2c7f6a80634b0ec20ec5152ff6bb4d5f": { - "balance": "10000000000000000000000" - }, - "5a8fe770c221072a7cba79ae7759cae0185adde7": { - "balance": "11913943233694000000000" - }, - "5aafe1efac688583d7facb09d3e569d58fb5a357": { - "balance": "4713219466825000000000" - }, - "5ab68d762750d5185138187db7751c9f71db5836": { - "balance": "500000000000000000000000" - }, - "5acab69851959dd5a6f0673ef757009ed36dfa3b": { - "balance": "974443209942000000000" - }, - "5ad9f2ab11b5e59b756404395f350aad6019d7a7": { - "balance": "54151179981663000000000" - }, - "5b1dc013ba1a28235cc70e785a00eff8808faef6": { - "balance": "516289257133000000000" - }, - "5b1eeb44ef61c7f35482503b7041162bec9b1e32": { - "balance": "125493885394000000000" - }, - "5b3db31996bca4625d22330686128ec234270206": { - "balance": "362316593128000000000" - }, - "5b401fc9ff3be7cdf5f0df870843bbef94f43285": { - "balance": "1373804724122000000000" - }, - "5b47ba296069041f25768e61be14437b8a469e81": { - "balance": "3152706392234000000000" - }, - "5b5030b5057c0457c190489c5d709d7dbdddee8f": { - "balance": "1154404278000000000" - }, - "5b5a4a782d37154a307868cd79bec9cb2a8f0161": { - "balance": "100277816425153000000000" - }, - "5b5e0b6b7cc27b06456ba4c7816ac4e89e1e26a3": { - "balance": "1023749119000000000" - }, - "5b638e4b6dfdb6928b07586e63d5879dce69a1f8": { - "balance": "1000000000000000000000000" - }, - "5b7be81d6ff5228a2b8c2913deea3f86823f1dee": { - "balance": "36000000000000000000" - }, - "5b7c4804bc2b8c72f3112b73d44b59c0711f83cf": { - "balance": "6803857604000000000" - }, - "5ba26d941544d07100744d8ffd6595a8eb7770bc": { - "balance": "583051897662000000000" - }, - "5bd58fc88733632b63d4f26893bc5c08fb60e2ad": { - "balance": "3480620567502000000000" - }, - "5bd85b5f0ecad08133fceb486c43998e537b3451": { - "balance": "484263880245000000000" - }, - "5c12639a5ab107f9e580cbd2278568dde10758d6": { - "balance": "101293252434000000000" - }, - "5c5522df05d6c6d960394c4762599e74247ab102": { - "balance": "149088856773000000000" - }, - "5c722f3ac94421f95389756af9cd97d0eaa6b696": { - "balance": "1435349483553000000000" - }, - "5c7b14ce51abf629bb0953ee4e2d9d87fc86eb4d": { - "balance": "10000000000000000000000" - }, - "5c8b215403da4e7912c1a1704a949087e091b111": { - "balance": "1440961256910000000000" - }, - "5cab313964f6730888e4158234bbd4806db0286e": { - "balance": "32284637230203000000000" - }, - "5cd736bf65c99469490d0523b10a658178cab10b": { - "balance": "99740204082000000000" - }, - "5ce91ef7ae254b2bd6d910cbf0d380814200811b": { - "balance": "50000000000000000000000" - }, - "5d15fc3a0ba8b3d87b80f9bbf972320112c644f9": { - "balance": "64000000000000000000" - }, - "5d2ccc795b19df400f21f24c0dca4d0e9e898093": { - "balance": "10000000000000000000000" - }, - "5d879b8b31af1e400cf53eb7170f82583190b96f": { - "balance": "93765337844000000000" - }, - "5d8dd54178b68bb36e1963d47d29c123864fd0ef": { - "balance": "20000000000000000000000" - }, - "5da1653bbe8353134edfff6158211ad7ee21dbef": { - "balance": "1491149937915000000000" - }, - "5da733ef41a7bdc0cf7975f83ed24604fbb4d40b": { - "balance": "10343699901151000000000" - }, - "5ddf5d7306f7c603b8d3ff993f03906dca14cd8b": { - "balance": "862558469755000000000" - }, - "5de87ec54e2160c7c2a8eff2d859414737501ae2": { - "balance": "21579321171000000000" - }, - "5df1b805b1361c1f39ca844aebe5ecee8a8d06b2": { - "balance": "411820472746000000000" - }, - "5df86b0a183b5e7f702e4da582ce9a8116a05f61": { - "balance": "256000000000000000000" - }, - "5e22359e20dc14be6930c6c1ce5a0c81c039cac7": { - "balance": "10000000000000000000" - }, - "5e2d38a06f33c784303abf2012f9af12622d9e5a": { - "balance": "10000000000000000000000" - }, - "5e479e616585e7fa84bd6f7465d394a1c0302be7": { - "balance": "10000000000000000000000" - }, - "5e4a55027a0d372f6da042b7f73720b143347d9c": { - "balance": "16175516772000000000" - }, - "5e52e86eda3e05f96e353d7e3f0ee90f08864f84": { - "balance": "21255916842000000000" - }, - "5e91c4d3a21c9dfac2c0994ed8890c78d58626d5": { - "balance": "325349462011000000000" - }, - "5ea797b18caba45d5504e57b80b12f5f5ae630aa": { - "balance": "7805696321000000000" - }, - "5eaec8815e859c34dba88cfe7b7fe28572c964ba": { - "balance": "145852682588000000000" - }, - "5eb974b5716fc4712d431bec7fbb2c49057a7b84": { - "balance": "4890681156035000000000" - }, - "5ee5f8407dedbac839f509419051106219458006": { - "balance": "3042761975468000000000" - }, - "5ef782abb28d1ca889ceb3039eef98713effbf32": { - "balance": "40915083108000000000" - }, - "5f23b88f06430c42570ac3fa33b1c7503b388a3c": { - "balance": "2376070180325000000000" - }, - "5f2b1641c0f2605b090039851aacf297e35632ef": { - "balance": "141615261000000000" - }, - "5f44cc8083340e644d19d3debc84dc14a0cbc53f": { - "balance": "291829106275000000000" - }, - "5f633f89adcc70e9da0b66611a5da108b4b221cd": { - "balance": "50835573000000000" - }, - "5f94ef8e9612b03a5c6ffcf423ada9a19a40818f": { - "balance": "102566595099430000000000" - }, - "5fae1977b76a5e899b384f572e4d94855f9cb52f": { - "balance": "773616125740000000000" - }, - "5fbd22cb3de462c794e523fd1ce36f230cc84b83": { - "balance": "1009995132839000000000" - }, - "5fd91676bc95bd6b5e69db8b9216dc83ed9dddaa": { - "balance": "1000000000000000000" - }, - "5fdda8f5271a08cf1b830faa497019d75fa9d231": { - "balance": "4149626365000000000" - }, - "5fdea351c5eccedf2394fb54437b149ae423ecf3": { - "balance": "100000000000000000000000" - }, - "5fe70ee123cb2e03c768138b2f71c1e1ea75ad17": { - "balance": "1074496282650000000000" - }, - "5fec9df797214459f85a040a559b186ee9161c88": { - "balance": "205282872821268000000000" - }, - "60037df7e4092466656a6b9571437fc4600c66e3": { - "balance": "1000000000000000000000000" - }, - "6009a0bcf531640a5a7f1664a69fe0f64b564ede": { - "balance": "50170000000000000000" - }, - "601668d8b678c95ec5ef98d9d2624decbdd52e9b": { - "balance": "23592727870000000000" - }, - "6027bafcd0ade24fda8c345dcbc812d59df74bf7": { - "balance": "10000000000000000000000" - }, - "6029514f24825c1fadc68cf8614951de5d53268f": { - "balance": "1389262963614000000000" - }, - "606de6db14272a314d778cf0e67913b7fabea45c": { - "balance": "144000000000000000000" - }, - "6074f20675f975ae2c081930cae8f299710f0bba": { - "balance": "10000000000000000000000" - }, - "60850fa9e09d414af3690e4b5daefb1b906b0d20": { - "balance": "10000000000000000000000" - }, - "60ad0b6239dda5df7ac0f0ca941684cf20ae0fd8": { - "balance": "81000000000000000000" - }, - "60d6136e6db631be45fefb9667c3dfa69e9d6054": { - "balance": "651902184266000000000" - }, - "60d733dedec6886908520ba57cab8c9d5c2d7f7a": { - "balance": "555461746642000000000" - }, - "61202238aea4010d115c5c64322ad790576cee43": { - "balance": "10465801848035000000000" - }, - "6142d92b61111657de4b2d65698a3621411e3adc": { - "balance": "100000000000000000000" - }, - "61879bc1a022d9cac8b7d57c8f528065beb10bb2": { - "balance": "72766025231000000000" - }, - "618b15c9a60ad89e7fc28afc79bbf7f28d4998cf": { - "balance": "444855210015000000000" - }, - "61c1169e8ba43ee6b919e5be2eac19542eb913b4": { - "balance": "500000000000000000000000" - }, - "61f1cd6efce17f5458325f022f363fd9772d8f20": { - "balance": "19704989598372000000000" - }, - "61f7d39211a0af2e226d8cbc95fb673168653b0a": { - "balance": "484884476279000000000" - }, - "621aa67f09e6506efb2fd141f080fb1d96693a57": { - "balance": "1694451603196000000000" - }, - "62332fa5127b98bd2a627a0ac22d3a1bdb418efd": { - "balance": "926882233406000000000" - }, - "624a465696ad409586a2e67d84750ba50a971fee": { - "balance": "25000000000000000000" - }, - "624d866f0d61bdefc3ec2210bfe36b6d51018f9c": { - "balance": "199592183194000000000" - }, - "6255d6d3b49443891661b209056d530ecd63bcca": { - "balance": "10000000000000000000000" - }, - "626c484055e6739d46e2ff25190c8b3a4af3fe0f": { - "balance": "1485276462321000000000" - }, - "62865e637d723393ab9654d6439db7fb5abf8803": { - "balance": "10000000000000000000000" - }, - "628a47761d5ce755de88444aaf6d7736b911672f": { - "balance": "18625552918216000000000" - }, - "62df6a38e8b15a1c4f4a7aa7c1736c612f54a0e4": { - "balance": "16468111299582000000000" - }, - "631d7916ddbb5f7c469f8ba07cd48e377560319d": { - "balance": "2493487426430000000000" - }, - "632754f5afcae7dc36d9286cfcd91c14abf0f7bd": { - "balance": "1424933496931000000000" - }, - "635788343997ea9f145c508b0cd2ed36e180f46d": { - "balance": "143040938538000000000" - }, - "636973e7dbda9e3042a8c03e25696d0faf27f025": { - "balance": "5491869128148000000000" - }, - "63707efa26d34d7ceadf4e6439324e7bde0ebc3f": { - "balance": "1000000000000000000" - }, - "637d92494f7872d397340c9b5183dce354c8c43b": { - "balance": "724687404033000000000" - }, - "63b9c2e6762a431752f7669b8bbedae9f37120b3": { - "balance": "1360967549741000000000" - }, - "63bd281d8c4d1279519237a2b68f2a73c228f7e1": { - "balance": "217457311664000000000" - }, - "63c0eb8c9a0019e36ec9a731b4bd947271a5bed0": { - "balance": "36693488147419103230" - }, - "63c6362eff56de328a29b7e9d32ced28f3602b6b": { - "balance": "148335309448000000000" - }, - "63c979c787a7b037693cadfeda738ae33178c009": { - "balance": "81000000000000000000" - }, - "63d4621d91906215d32f6fbcee1ac48bd773f630": { - "balance": "1006939236069000000000" - }, - "63ff99fec1cbd2f6e83c0e6de3c0ea4b7c7e1398": { - "balance": "1201300688980000000000" - }, - "640ffd856e48528b05d5ef1e60348048ce291960": { - "balance": "20000000000000000000000" - }, - "641c25f7c380e2745c81a268384a029b2e2be0cf": { - "balance": "635133477665000000000" - }, - "6427792a164bbeab45f6c3acf17c76f721b90e81": { - "balance": "10000000000000000000000" - }, - "6437986b4c545af9c4a5ee96371a5807275e9221": { - "balance": "2951152516627000000000" - }, - "64460d09d1bc5c425d62bef5969eb0c5916963c3": { - "balance": "1680000000000000000" - }, - "646381f92216b97abbd86ca100a773eebdf7545b": { - "balance": "211234535515000000000" - }, - "649f73d1cafeb3ab0631432f04c9d08b9f438c22": { - "balance": "248900746448000000000" - }, - "64a239be45a92df83bb85b25f8ed7de5d82313b9": { - "balance": "100000000000000000000000" - }, - "64a3d97f82e3d42eea78bbcee31a95d33767b055": { - "balance": "2511466286000000000" - }, - "64ad579975888f455217e0f801e371900d9814c9": { - "balance": "7118859416319000000000" - }, - "64af5edbfec8adea679951662c08a781175688bb": { - "balance": "822966999709000000000" - }, - "64b7f2c22c20a59c07cb0dd7f8f692153c68f3f8": { - "balance": "20000000000000000000000" - }, - "64bc17e28d468b7b8368ee8a8375710d21c3ac5d": { - "balance": "875002262415000000000" - }, - "64d17aa662e56061cebb3c2e2421e637163e8dd3": { - "balance": "363241251465000000000" - }, - "64d714ec3145308e8f939bab7591b0773038b886": { - "balance": "338231954012000000000" - }, - "65199fc9ba95434382c108b44ac553534a9a3670": { - "balance": "2537340957145000000000" - }, - "6527c67c29e47833dc2440570596023318a7bd99": { - "balance": "555434226832000000000" - }, - "654b9d299077c90768c5ca6635e5802e8099f51a": { - "balance": "119004827465000000000" - }, - "655908513607cc38de35351ff3738b201bbf39d4": { - "balance": "652902936029000000000" - }, - "656ad16063b2d397788c231e537384ece94eb0d2": { - "balance": "63116382606000000000" - }, - "656e622970b8829a7cfe24f5b82696c7777683ba": { - "balance": "20390269890405000000000" - }, - "6583a6ff4dfcf447e3b163a61b0d5cb84ceee375": { - "balance": "3858529344000000000" - }, - "658d2b7e8a6517256efafd74321757d5c384a2b9": { - "balance": "221114751567000000000" - }, - "65920758857ee5b27b0f31487ccc3c5d6986df3a": { - "balance": "16272975796000000000" - }, - "659d60d67a07774ecc5cfea9e56809bec024d639": { - "balance": "20000000000000000000000" - }, - "65a1a3f968bab5fc1f097b8e297099a3d34ef45a": { - "balance": "16000000000000000000" - }, - "65b5e3163d20b2a6fc75c0219b7f97d83479a26d": { - "balance": "1716459529041000000000" - }, - "65c9bc3b8b0ce7c4d16b35abe1a5c285a59f672e": { - "balance": "20000000000000000000000" - }, - "65d5b458d9b1a9659c1125d20d970d5e6c29dc3e": { - "balance": "20000000000000000000000" - }, - "65e75bb8ade25eb7975ea12b9afdb17ac21063b3": { - "balance": "2270407774714000000000" - }, - "65ed78d0c4ef1150e8765b24b210f056e079cd59": { - "balance": "500000000000000000000000" - }, - "664ee5e334b8378928becfbf5d5e51daaf001125": { - "balance": "860160259186000000000" - }, - "6679bdb26adc179d046607d49f4b10c65d8a40d1": { - "balance": "436794739763000000000" - }, - "6680fe9d6eda3ab9fc4ac1ac933339b533eb682b": { - "balance": "551296206326000000000" - }, - "66a1249501cc5076b040bbb165ce032ace216ea2": { - "balance": "36000000000000000000" - }, - "66a475d014c2f976704bfb93ce78dbabbfc5e072": { - "balance": "1140135640169000000000" - }, - "66ae43d92e8fb2231fee8c72d720ff90cdd267ff": { - "balance": "796696150339000000000" - }, - "66b7e0c810d6959afa8210f6ca67e3e40bd24eb9": { - "balance": "16000000000000000000" - }, - "66bf8be16f33b111b2a425743bb7ebcdfbb35034": { - "balance": "538590591000000000" - }, - "66d2eaf7fe10900d93eab17823ebfde5486aa2b7": { - "balance": "121000000000000000000" - }, - "66e525bb01b3ede1a4a105bb6087ec8a76200616": { - "balance": "1506610219207000000000" - }, - "67291e0df83d6e9f1386e87a1792d7d147341df9": { - "balance": "272330177662000000000" - }, - "6730b27b62e064b9d63df3bcbb8c4bbb0e500afe": { - "balance": "331282968154000000000" - }, - "67318617bfe19b739fac9a126fd129223db52498": { - "balance": "12699924981000000000" - }, - "674dd0b036c91f3a83288af44897b4ceb2e15a12": { - "balance": "4352791270187000000000" - }, - "6751bffd04be55c86692994fed06694cb78b62ff": { - "balance": "26049487516000000000" - }, - "6768d99a0cdcd7bb7c7d0aeee466d6bdc7208bbc": { - "balance": "309909685000000000000" - }, - "677ba2de3e5c68a4c354c9e3129ed1c41025312b": { - "balance": "127426274611000000000" - }, - "67b83745856551f1878027843be20e1473191944": { - "balance": "185757248875000000000" - }, - "68170edcfaf2c6df4e6542b2856ad33e9e2d6623": { - "balance": "4003453949471000000000" - }, - "684ae403d9a08e4f4f971cfedf81094074daa77f": { - "balance": "25139713925794000000000" - }, - "684f3b8a749c002aa434bad6af7a3e2579c69315": { - "balance": "16000000000000000000" - }, - "68538a9e8246be5a5c5ea315cb325344062cf8c4": { - "balance": "14009193210480000000000" - }, - "68935ff3a3a3b6ef16ae7df58cee50b157658dd2": { - "balance": "20000000000000000000000" - }, - "689f508256ea64f5dbd6bb77f1ce1bdaf36d7152": { - "balance": "10000000000000000000000" - }, - "68a3e6e7c191a8c1add988bfbbb9b51d4f36f521": { - "balance": "10000000000000000000000" - }, - "68a74ff2a5577321f854b56d3834a55d3c41bd94": { - "balance": "88873831171000000000" - }, - "68e6da521bde13cf4e4f423a78fda2f69b3d1c2a": { - "balance": "538392460838000000000" - }, - "68ecd5cf8cf8d9704fafc36d8da53930afeb0553": { - "balance": "1090923641219767000000000" - }, - "68fd0b8e000bd2788be6cb10fc0496fe2cbe155d": { - "balance": "32853847745000000000" - }, - "6904045feb5ef94e096894b863d314ff8a0f206b": { - "balance": "9892165615000000000" - }, - "690fbae5153849bb20797af7b8dea66a728a06c3": { - "balance": "6082107223716000000000" - }, - "693d909842877d017e0f102e37a55024517dd0ae": { - "balance": "20000000000000000000000" - }, - "694cd00fac9cded484ef2cfcd44faf161354f288": { - "balance": "3049716150137000000000" - }, - "6964c3c2c7bc719ec94a51bc4bf412e137d2b4e9": { - "balance": "1000000000000000000000000" - }, - "69a5c692516940bebad8efaa2243a8fbdf2ade62": { - "balance": "2803346939929000000000" - }, - "69f566c44802b0140f5e1c9234f46006773c03d4": { - "balance": "20000000000000000000000" - }, - "6a17eef3a6bd407260f52067592226448182cdc3": { - "balance": "1116509364305000000000" - }, - "6a200e99a0f50aab32fa7373c7880817c81f472a": { - "balance": "1836680122795000000000" - }, - "6a2a29f5f441876816dd17856051040787f48a64": { - "balance": "1131603204000000000" - }, - "6a3f855c7dceb75d0de7fa18fbc2f40c81b76756": { - "balance": "32267494586000000000" - }, - "6a46af653b938643e781cc4a0edcf5357852fd21": { - "balance": "1140718780752000000000" - }, - "6a4b2e5b45da0d70621ce71f165a11078a1745e2": { - "balance": "3768326643000000000" - }, - "6a530c813595a5b7776cced05a865dedcb110d94": { - "balance": "270559347097000000000" - }, - "6a6e3e82f98ce891f47721770301dbe2652a9e25": { - "balance": "10000000000000000000000" - }, - "6a828d6f2f7f68bde4a12608024020e593540010": { - "balance": "7531817000000000" - }, - "6aaddd1f4ff6b4d414c87271619b826ead27f09f": { - "balance": "64000000000000000000" - }, - "6ae6bce1e2865ade0d02eff9899ea3767b5511cd": { - "balance": "6893781798524000000000" - }, - "6b04e7c6a837d218fd3322b87a267fdd979358ef": { - "balance": "302679180175000000000" - }, - "6b2210b8536803b134e69c5046904acafef48cdd": { - "balance": "47823456459000000000" - }, - "6b2da6f36c2e7f61cabd7580480065360c995c93": { - "balance": "55000000000000000000000000" - }, - "6b3401986f2be7ae5a4ec160b8f96b2a651fce73": { - "balance": "16000000000000000000" - }, - "6b3847774e99dec307dcf5bf5adba49df4a9f145": { - "balance": "43276069579000000000" - }, - "6b57f2d9d95cac67fd2f70c0911d48c7f09de072": { - "balance": "1000000000000000000" - }, - "6b65d736a8ca89ec8508b52e4aca5166f9703732": { - "balance": "766421968820000000000" - }, - "6bcc55d897829e98fc3f3ac8beb331e59c33b942": { - "balance": "318115956882000000000" - }, - "6bd76e7af1775b88743d5f53ede0ce846d3d7ced": { - "balance": "139548017482371000000000" - }, - "6bd7cca99acf6eed5842417c2327c642df5473fd": { - "balance": "3321731000000000" - }, - "6bf72c4d39d6700181954a8d386c3df216634412": { - "balance": "12742769034078000000000" - }, - "6bfd3aedeac7c6ec086c0a4ec29d2d0f5bd69bc5": { - "balance": "50000000000000000000000" - }, - "6c025962810a6fb8374af5e07d7fcd631d10b1ce": { - "balance": "674126722005000000000" - }, - "6c1b72df836f410038af9e020fa2ff2ead398ef4": { - "balance": "1851293017364000000000" - }, - "6c1fddb4254ff46b3750de322ebb7d6238c0a606": { - "balance": "9977629348276000000000" - }, - "6c37069a361c5c72355bb5a56879dd0a9735a237": { - "balance": "1062230154063000000000" - }, - "6cb166eeca248a234c971b2a864a7b3fdbe5a737": { - "balance": "390222992865000000000" - }, - "6cb797289059cadcfa77eab0365e6bf1ae12df46": { - "balance": "100000000000000000000" - }, - "6cc787e6bb4f484828b080330667b93953e7a3c9": { - "balance": "16106440380234000000000" - }, - "6cdf7b334fb2ef8115198d475d431eeb7d88df77": { - "balance": "1940904395351000000000" - }, - "6ced85b035b787e9e427d0904aaf96e011417310": { - "balance": "103417697874000000000" - }, - "6d6e09acc07f388cbab99e53959f75e9ad8f07bc": { - "balance": "1305917678000000000" - }, - "6da91b02f512f412d374392247a9aaa853e9dd59": { - "balance": "2300525907893000000000" - }, - "6de5d70481cd40db468f64227228cdd362ad9980": { - "balance": "10447389944082000000000" - }, - "6dea87255c9ebfa63f017209046e894ecbbc03b7": { - "balance": "1527216854064000000000" - }, - "6df6f6b9953c2f2a8ce5985e19dd6835ae2c566c": { - "balance": "6539856530000000000" - }, - "6e013c83cac111a38fbbf8d47778fda0d3af25d5": { - "balance": "12139181929380000000000" - }, - "6e18a484f402fd433a5ac4dee5a4b8bf6f22db47": { - "balance": "23215906572368000000000" - }, - "6e4fd058e4dcd502c2015f83f3677f680ec58110": { - "balance": "480059342014000000000" - }, - "6e501ac7357fc758caf5dff6c29a995c806a1a7f": { - "balance": "1573491311733000000000" - }, - "6e6912f9fc21dfba736055e6ccef074dd62dcc59": { - "balance": "256000000000000000000" - }, - "6e869c68511c1458f4fbed9a4c5296fe961eb47e": { - "balance": "68488423994541000000000" - }, - "6ea6827b377b3d3ecf7c7628ed8daad7fd8eab1e": { - "balance": "188825714738000000000" - }, - "6eb9237738339fcaad3763466509f23efd0c5054": { - "balance": "48417242786000000000" - }, - "6eb92a61390f9d9ecdac80a8833aa801c3926b13": { - "balance": "1412936326723000000000" - }, - "6ecb93f18153ef2d2a552286ea3b7436f1f8168c": { - "balance": "20272577229669000000000" - }, - "6ee087c04cf16f4768c783a548686448fd125914": { - "balance": "1397039628538000000000" - }, - "6efbae7a34c71233329d0bb4cbec45274824ebf4": { - "balance": "8910000000000000000" - }, - "6efcd6776f287c25a6eb3cf71018adc282eeab6d": { - "balance": "1310659853178000000000" - }, - "6f9ca805ddaaea5205e85778dedb2eff4a5aaa75": { - "balance": "2585733757016000000000" - }, - "6fbbea927469f4d18942ce0aade164828fe23a2a": { - "balance": "4671857880000000000" - }, - "6fbe9df6c42151c453502960d99170445dd3ac0a": { - "balance": "20060296562115000000000" - }, - "6fed121fb310431f1659e637f35f4c878a7256c7": { - "balance": "55170085399000000000" - }, - "6ff2dd5373bd72966ef48d3183c60d74a6549cb9": { - "balance": "24103445361000000000" - }, - "703a490c4783776da244384c964897491aed3711": { - "balance": "2001677632732000000000" - }, - "704dcd2d9f75f0bbfb73f2fe58bcbf4508374381": { - "balance": "439603954369000000000" - }, - "70859a14f33b8ab873fa5781a4af1ce40dff65c0": { - "balance": "10000000000000000000000" - }, - "70b9cdfa5f6d41c60e1c0d3f544f569c9b340ea2": { - "balance": "198355566698000000000" - }, - "70d0ee793e28e320b34267ef2df69050fca0a9e0": { - "balance": "8010660534227000000000" - }, - "70dc7e5951752c22a0e3c50e8e7b1f7af4971d51": { - "balance": "3991137321749000000000" - }, - "71057f5afbed7d82c92d50790e3797fd7395d036": { - "balance": "49000000000000000000" - }, - "7109a3b3d5d6af49693549728691099d696ce016": { - "balance": "4119694297000000000" - }, - "712231a5161745fa1b33c7b0f6e8c767e1de4f81": { - "balance": "1353809351914000000000" - }, - "712aa38999c0be211654e5c84f59e3b2e018f597": { - "balance": "160199774000000000000" - }, - "713229fc94a86b71a5bd1ea6498b9373e3f3c549": { - "balance": "98289185940000000000" - }, - "715de29a0b6f467b94d4a90dc767ad52d0fb3b9e": { - "balance": "948824982990000000000" - }, - "71776853ac97ce04b008c9a7b64156a3cafc52a4": { - "balance": "608309596513759000000000" - }, - "7189f6dcfe64e1ddbfb5e51fd5f3174bc636dd0e": { - "balance": "5674608906899000000000" - }, - "718a4da87464caf6e83ca374d5ef9255b8f7cc3e": { - "balance": "761891873568000000000" - }, - "71bc447761cdb68915cc2288b4929fdc0adce02d": { - "balance": "10000000000000000000" - }, - "71d78531896642069b725bf82fc385789c63217c": { - "balance": "33103960195000000000" - }, - "71e328deeafbb1724051d1062609c43eef56ecdf": { - "balance": "493550967964000000000" - }, - "71ed0310fb51b86a61794aea17a3c792dd301e3c": { - "balance": "3234918634449000000000" - }, - "71fa264f58041e41cfe36e8f8d4e0cb22ab71925": { - "balance": "5558941960000000000" - }, - "72059c57d0fc05bc02ba54ebea6cefd1efbeadf1": { - "balance": "4458278271443000000000" - }, - "720847a28916a532bcab33e1fcbde5d1c4d820bc": { - "balance": "1392418942284000000000" - }, - "723cd2b5b836b0ee8481d37b9c51b5f3f1beddd2": { - "balance": "1856420455522000000000" - }, - "72430c6664d23c7051b0e99912fa54dfadcfdeff": { - "balance": "102078926010505000000000" - }, - "72652c4320dda25348f15c0ecfeb4b3b3ceeb7c8": { - "balance": "307639955659000000000" - }, - "7288bd1b9f4c068dd5df9bcd6fec1ccecd240195": { - "balance": "80161087899000000000" - }, - "7299cb8a288abe8e1a22c11b53a903acb7db5827": { - "balance": "752198565719000000000" - }, - "72f6bc0c3ae437756c099e02e9c084febedc5569": { - "balance": "696294297587000000000" - }, - "730e5907b344c80e0a6115723a90a23e3635192f": { - "balance": "6056082041729000000000" - }, - "732e97b992e4f8a53034cf29cf11aacba7452261": { - "balance": "100000000000000000000000" - }, - "7339df65ce293b3d501647a04c83819099f0bd38": { - "balance": "706500983417000000000" - }, - "73482f8135ca2231db5e0e034a235a9d244a8656": { - "balance": "1143989148865000000000" - }, - "73769e43058d30a530048e5a2bea7e9333534e93": { - "balance": "113542901996000000000" - }, - "73bb9e6f1709fbb7964df7b3cc0f9170c3152f38": { - "balance": "1639793026701000000000" - }, - "73e261da7978764044ee916f88bf66680952607f": { - "balance": "100000000000000000000" - }, - "740154120c4f41c50b0aaa0636a2000ff1e870ad": { - "balance": "10000000000000000000000" - }, - "741fe2a1537284b70e97e3ff659eedfd7fc5b1b6": { - "balance": "75911502037000000000" - }, - "7420bb277d834763e4429db9bf37f053f71ab769": { - "balance": "3100160195046000000000" - }, - "74281371c3b569c774da6bab686e7d7a45d4dc4c": { - "balance": "25666397941223000000000" - }, - "7428d261b5418652c5ab248d6abc3d2af25d904a": { - "balance": "56252809397000000000" - }, - "742c876433297f5a8fd4a25f75ee9a607726bd3c": { - "balance": "4132793019677000000000" - }, - "74302036cf52e11aa3f32a371bb4992e2bdc3f39": { - "balance": "19557661364000000000" - }, - "7445c657c24d014f3a9dddc3e446868bc2dbd13e": { - "balance": "10000000000000000000000" - }, - "744b8fa69d2542be3557267edaeaf2cfa8a9e991": { - "balance": "16000000000000000000" - }, - "74728999963524e7cc1736abcb4deac630142c44": { - "balance": "37000250991000000000" - }, - "74926cbdacd0e871cad0d926c8e17cb2c00475b9": { - "balance": "20000000000000000000000" - }, - "749e115a9e675bb15af5e1c04f81fede07c40120": { - "balance": "440913547154000000000" - }, - "74b7e01acf825898544d6c1b61e53356be759c56": { - "balance": "25000000000000000000" - }, - "74c5fcf875e2e9b726a7cf6e176dc2f7eb84c200": { - "balance": "59208835472000000000" - }, - "74f44579859e4a7944dda7bd810088e116ae9910": { - "balance": "1038454108527000000000" - }, - "750b1e2955ba05c1fc8a1f9dbb1624ed11587edd": { - "balance": "9545712605000000000" - }, - "75375129cff2a051f656b91f868325c3b35ee1ae": { - "balance": "25000000000000000000" - }, - "753ca28fbd89081382a996fe938da7e6c3ae6cfd": { - "balance": "156582454263000000000" - }, - "753d91c04e554680cc32a97c1abc96280e8263ee": { - "balance": "725101425969000000000" - }, - "754e5b5d64c267e83fd4804d112725531cf5abe9": { - "balance": "83276113115000000000" - }, - "7588a96a2bc65569a6c124c4a4acc55863a8ab78": { - "balance": "24062602342000000000" - }, - "759075dc3a6b9d2499a74bc57e346c9ed7ff834e": { - "balance": "225000000000000000000" - }, - "7591d6fa043801fe12462e11d9e33a53f438c073": { - "balance": "1863874274000000000" - }, - "75bda5bdf6aa749bbd62b6107941a7dd9ce3880a": { - "balance": "36000000000000000000" - }, - "75c2d3a99f144c4b9962b49be9d0a81b203906e8": { - "balance": "9000000000000000000" - }, - "75f587a69a97eb4d1c4c4078418d5fa85dff6f94": { - "balance": "10000000000000000000000" - }, - "75f67649605f49d98d866102ea2d6881ead9bea0": { - "balance": "814929108418000000000" - }, - "7602abce0f510b6ca471fd8d734e21a2591886f6": { - "balance": "50000000001006000000000" - }, - "7629b788160531b0be28bf445bf305fbe2c514d2": { - "balance": "23022256366212000000000" - }, - "762aed2e3aa2293e69dc2110b1fc6c806ae799a5": { - "balance": "10000000000000000000000" - }, - "7637b89130bc3f87e90c618fd02d6dd27179101d": { - "balance": "77765738300000000000" - }, - "765136022facade53e7a95c0c7aa510787e674d5": { - "balance": "1478178932688000000000" - }, - "765274015a308a9e6b1f264e5bac592d267f2f7b": { - "balance": "3058788819393000000000" - }, - "765cbc0a89fd727a2c1a6b055139faee53f11330": { - "balance": "500000000000000000000000" - }, - "768bb6d4b190c18a0946d92073ee446d68d98a6f": { - "balance": "144000000000000000000" - }, - "76ae8079894c760f2850c02cf5a0d7bb41e5864d": { - "balance": "156059816821000000000" - }, - "76af4103a231b1302d314c486a0ba524d0427899": { - "balance": "10000000000000000000000" - }, - "76b6394cd02ddf761e981b6a6ce1654c0e575443": { - "balance": "1078304803757000000000" - }, - "76db33eafeaf965dcf15d5460b64a48b37285259": { - "balance": "1000000000000000000" - }, - "76e5721c0a39d41274f84cb572039967a07e9beb": { - "balance": "156298167226000000000" - }, - "76e6ca6ef145d2711ab27f82376a065cc6f62a29": { - "balance": "100000000000000000" - }, - "7705d637cf9f6ceaa452deaca7ccc581beb5fa34": { - "balance": "36254762908065000000000" - }, - "7706c80af4eb372e168501eedfe7bda6dc942243": { - "balance": "50000000000000000000000" - }, - "771493da92c9fc6c6b39a4071ae70d99f6a588d3": { - "balance": "2000677471360000000000" - }, - "7719206286f26144c0f20b5e1c35cf4495271152": { - "balance": "1380480863056000000000" - }, - "771adcba1409fa2df6db19d9f784abc81a7bbf36": { - "balance": "15416381820915000000000" - }, - "772f7baa80a852e05b2fb3903a36061da132b2d8": { - "balance": "121000000000000000000" - }, - "7731a4175eee5077e2ede48878e6e2a18fce0f9e": { - "balance": "10000000000000000000000" - }, - "77385deeba01e3cd7a63e13d6048011020f56724": { - "balance": "57204247488000000000" - }, - "776808e7688432755b9e91a838410d29e532c624": { - "balance": "120318608715941000000000" - }, - "776d1b406f63082b80e250c4a0073fa0d83b9090": { - "balance": "243779839900000000000" - }, - "779848a59036ee3cd23b93ff6d53620d874f0bee": { - "balance": "82228810849000000000" - }, - "77d02a031274bd4ed2a16f3cc29d94e755142036": { - "balance": "408567696646000000000" - }, - "77d609a407aa0d126d58090b8d635f5ab7a02d6d": { - "balance": "776754055755000000000" - }, - "77dec41e116301dbd6e542f139816bfd9bf6d154": { - "balance": "16335989583000000000" - }, - "780398b42f81167731a8ef6a8bd1d14942b83267": { - "balance": "25000000000000000000" - }, - "780a645d59027e7b0670d9565898dc00704cbe5f": { - "balance": "20000000000000000000000" - }, - "78182a7711c773f306ec42ce6da3e983cd49b00b": { - "balance": "580861257254000000000" - }, - "7822622f07fec12995c4bb8eb32d62aa7f00be05": { - "balance": "5018461926846000000000" - }, - "786410c679101c0ebf06fb4f36102368121f3c8b": { - "balance": "16098386724761000000000" - }, - "787d5476038ab0a09b846645285ada23ffd7318c": { - "balance": "492047430907000000000" - }, - "788e9e27ed979d1e7aefadda798f69df1de1d1bd": { - "balance": "30965301214000000000" - }, - "78ab2d2dfaf5d2580ed89c970e771572bc91d3be": { - "balance": "36000000000000000000" - }, - "78ab7ac6f379ff084a7acf4a1a31fe2e5a6834c0": { - "balance": "107332516726000000000" - }, - "78aba95da37385c736ef93d0ca8318baf6c5ff3e": { - "balance": "9000000000000000000" - }, - "78cecbd82229dc91a530bd555c9e45125e2a6bc7": { - "balance": "28474069251604000000000" - }, - "78d4df90990248f3ac67e492a0a1e3f4ee455507": { - "balance": "10000000000000000000" - }, - "78f6de3768abc604c49b10d798e0656948cd334e": { - "balance": "9000000000000000000" - }, - "7909aca95ed899743de222e56c231f9bed1b518a": { - "balance": "5355599376491000000000" - }, - "79193e660b4431e8aca9c821b7daa88064e33750": { - "balance": "100000000000000000000000" - }, - "792487caa23b0d9b9998002810cf29439f7190bb": { - "balance": "4828579961131000000000" - }, - "793f56adea51063243a9633ecc1d1e620a91f327": { - "balance": "926742377449000000000" - }, - "796d187077c1d7591583436ae64d10a641490ca5": { - "balance": "242664407084091000000000" - }, - "79a6b7fad3b5a655679450ca82818ec2d6f58688": { - "balance": "1400472715109000000000" - }, - "79acf627e67cedf48297c26fd135973bff6c57da": { - "balance": "444598475759000000000" - }, - "79ae0dda1964ff0191b98d28c9b52a79dc9ab078": { - "balance": "325908985422000000000" - }, - "79e71dcc52fa1b28226c519f715faa3cf63cfb09": { - "balance": "497898493594000000000" - }, - "79e98193ff8770f26af824734bbb1c2ce8197b6f": { - "balance": "10000000000000000000000" - }, - "79ff3d790d52c58b7317a415278e9058915d5241": { - "balance": "48502649691864000000000" - }, - "7a0b02d16d26e8f31e57106bbdad308f513d436c": { - "balance": "841000000000000000000" - }, - "7a1d422352ec7e6ca46131728e4b71f20ed84e2f": { - "balance": "50496873413000000000" - }, - "7a2a3fbe27e33df867ba8800788995d7662c046b": { - "balance": "100000000000000000000000" - }, - "7a629c4783079cd55633661d2b02e6706b45cf8e": { - "balance": "50000000000000000000000" - }, - "7a62d8875f53e54b775ee2f67f7e2ec137bf724f": { - "balance": "25000000000000000000" - }, - "7a67285fd883d36ea3107aa3fe7727c68a99eb2d": { - "balance": "254787158217000000000" - }, - "7a90fbec48492473d54b0fad128ceda94ea66100": { - "balance": "313715004199000000000" - }, - "7a9e11463d84a08140d698972e32e66bacf7a7c9": { - "balance": "3602603216258000000000" - }, - "7ac4f33e1b93ef0f9c15014e06da24904ef4419e": { - "balance": "101000000000000000" - }, - "7ae082ad247275fd5a9e77b127cee5693784e9e1": { - "balance": "1921957343533000000000" - }, - "7b27e070ca4158d13f8333b34842d4c28b678c92": { - "balance": "10000000000000000000000" - }, - "7b2e34374921e4dc10fd9cfc670a40f5d092da1b": { - "balance": "2098457950503000000000" - }, - "7b54c6c8041c8b09240de1ff06e0d3d2d8d877e0": { - "balance": "944752036841000000000" - }, - "7b5aecb798d8f4f5a04bdaef909e09a35bde8d47": { - "balance": "21975115049000000000" - }, - "7b88a7ef9201966bd1ca634779c3b7f40c22f0d7": { - "balance": "64344833519732000000000" - }, - "7b8c22ddc5c7e59e571587d7c776fa50e65f4845": { - "balance": "225108110445000000000" - }, - "7bb4d8a169f72432494ac362eeab005ce1e02d81": { - "balance": "2098993419448000000000" - }, - "7bbaaa6690698e749d095447bdd27207c0caee43": { - "balance": "490069993631000000000" - }, - "7bbf27f92f9f726381d4f68b21ed86af8f792d04": { - "balance": "806346082666000000000" - }, - "7bc6f172fd78953c3456c571ac8394756715d5fd": { - "balance": "81000000000000000000" - }, - "7bcca29b477730ee8f219a5d1bca24415c7a4625": { - "balance": "36273885000000000000" - }, - "7bd296e1cb29ad87ed28b0ed18440ee686b157e0": { - "balance": "35964679698000000000" - }, - "7bde6d49a1af34a5a9dac0b9007e9a5583c65ebd": { - "balance": "1041474566346000000000" - }, - "7bea6240f245e649563253fa4c1da39b12625da7": { - "balance": "100000000000000000000" - }, - "7bf096396c56f27f9c39c4056ee6cfcb0db44bc6": { - "balance": "407261849111000000000" - }, - "7c3b58d3ba283bd9b1580832e9d014eff48bff7f": { - "balance": "7074518779349000000000" - }, - "7c5a56c45f23c353ff9f6f71ec86c9a6a1a0ca67": { - "balance": "11277879639596900000000" - }, - "7c783ac9b07bc6576835635f37e7e3c137055c8c": { - "balance": "16253676225000000000" - }, - "7ca2fbc0a0d1370e95048a21a300eac4d6056df3": { - "balance": "2772084065617000000000" - }, - "7cbe95802a20eb765f9fcff0a068859cc35d2660": { - "balance": "255153842674000000000" - }, - "7d004fb3a6a81c00fd2872e8079ad2912841b0e0": { - "balance": "642630220843000000000" - }, - "7d30c788d4ea18849ebae1173373c8915ffd7a35": { - "balance": "61062263242000000000" - }, - "7d39324f5ff62e849b0f0f46ab8ee396fbd85581": { - "balance": "100000000000000000000000" - }, - "7db0ce6c04537417dca1dd3415a5bf213edc2028": { - "balance": "30393443462000000000" - }, - "7dcfaa795586c92f1ce7d5c7b10608fe6a773fe4": { - "balance": "183173395920000000000" - }, - "7ddd111cfdc3133f59b82568e3deefc3cf10b0d0": { - "balance": "5622149283840000000000" - }, - "7de81daaa7ed5cbf4d379cdd26ae353cbd5a2489": { - "balance": "10000000000000000000000" - }, - "7e0a11af993a41626c5564f719442c0dfd608ec5": { - "balance": "1532083534600000000000" - }, - "7e34971b187047e7f7980650630b936eedc11023": { - "balance": "10000000000000000000000" - }, - "7e5214e16851b33c4a4d29e5a06929461d3d9555": { - "balance": "371790231197000000000" - }, - "7e52ae9c7e4b888015a3a5af7a91444510aa18e2": { - "balance": "109879329128000000000" - }, - "7e69b383671f96b7abc2d1fed8b61477b87a58dd": { - "balance": "10000000000000000000000" - }, - "7e733b1fcadc9a20dc038fba74e236af0b5a39b3": { - "balance": "43583614302000000000" - }, - "7eadcf955c90040668fb0f75a61f687e4e41f314": { - "balance": "332201682206000000000" - }, - "7eb51f3ead1dd0f5384c199ad5518ec55f77d35c": { - "balance": "38487884822000000000" - }, - "7ee73c0d64caf46f47f439969060092ecafdecd9": { - "balance": "15063618320000000000" - }, - "7ee8e4c6742a4c6d8efbfacc4d56119bc6c74ea4": { - "balance": "31882319329000000000" - }, - "7f16d981521c06347db8324da38b25eab3cee23c": { - "balance": "400000000000000" - }, - "7f6ff7db81a26fe78dd80636f0b178c669344393": { - "balance": "10000000000000000" - }, - "7f792b094c0b96d6819823cf21bc0c402fc27bf9": { - "balance": "50000000000000000000000" - }, - "7f84ae97c21cc45a7e56603ddf97449d803fb246": { - "balance": "81000000000000000000" - }, - "7f89c2b9daba034841f19ae843cfb6cd6f75b1d7": { - "balance": "20000000000000000000000" - }, - "7fb18f8b0e1fd1ed8c863a66226082bdc0429ee6": { - "balance": "11465417544634000000000" - }, - "7fb4e30579c64efe981d0057204e5bd8770a1f87": { - "balance": "249801873762000000000" - }, - "7fcc4de10e837d98691acc52732e1568c890304a": { - "balance": "1000000000000000000" - }, - "7fcc77798cd50345b2784a78b81a25dd4c1e64ab": { - "balance": "2676882485895000000000" - }, - "7fe33e773a02b995278ff595d55a0741813b19d4": { - "balance": "5788279057355000000000" - }, - "7ff32b13d531ceef500ca6c6806ffc0773639264": { - "balance": "1000000000000000" - }, - "801380158ef8f24316bdceaa00eb89c3d886707e": { - "balance": "35627521347898000000000" - }, - "804fdccdc8603858d15dec88666437505b2a106a": { - "balance": "14607090269617000000000" - }, - "807915567eed99bb9146354a32409812b9490d70": { - "balance": "1083142734057000000000" - }, - "8092ceeb2be5b271f4c156d85fe14977e919c7e0": { - "balance": "761607160308000000000" - }, - "80962bf961d0d713395dbe00379a6e207b425a76": { - "balance": "524215754483000000000" - }, - "80a9787124075c8cd44b9c8674967a54445e2354": { - "balance": "7600078997429000000000" - }, - "80aacd59dd76bf443c47ca02976178af8453f23a": { - "balance": "411856023767000000000" - }, - "80db788f7fbd7613f0fff66c21389eedbbd4bd35": { - "balance": "956888725645000000000" - }, - "80e449a70e3c7707d6441ae8863a44aee2d7f3f2": { - "balance": "16260784762856000000000" - }, - "811a2c3d0ba4e1c36a848495585da824ec3a7620": { - "balance": "36000000000000000000" - }, - "812a3c55234d5849a854ad76891c34ee90c8a0e3": { - "balance": "703378980438000000000" - }, - "814b4b5eb67afb8d1a60e3d240fe804bb752f632": { - "balance": "17578964576000000000" - }, - "817025619f37838470b90d0a25af2c02de80dae6": { - "balance": "96000000000000000000" - }, - "817233a104d87cac34d9c90243aebd7f68e0a9ea": { - "balance": "510051038684000000000" - }, - "818be95c0c13c3018b4084ea177556705e84c1f5": { - "balance": "332239667000000000" - }, - "819618c19a4a490b821f8156c5633749ea782ca2": { - "balance": "10000000000000000000000" - }, - "81a80d26b70626e07e8747bc1569dd2855834f7c": { - "balance": "521696417321000000000" - }, - "81b2fb0db882bf2538cf8788bae1ad850cef3bab": { - "balance": "102457067052000000000" - }, - "81d4c3bf72837b21203b2a4f90bf42fda10acf48": { - "balance": "10000000000000000000000" - }, - "81df59e5d7b9a2db5463b53be83b4d7c7673d163": { - "balance": "887372337013000000000" - }, - "81ef38d074e0aa9ad618deaab01bcd135301fb67": { - "balance": "24072930558567000000000" - }, - "81f3a4c5291f13f8f97a067a6ed744a686331eaf": { - "balance": "56612148225000000000" - }, - "820610d0ddd3e9f3893f7cc13f32b1ad0d169f81": { - "balance": "50000000000000000000" - }, - "822d6388145e96cdeb2900420a0e0436e940b670": { - "balance": "20000000000000000000000" - }, - "82323b748fdee9f18e34aefc4ddebd4993ac6293": { - "balance": "112752706047881000000000" - }, - "82324995b36f4ff15be3559ccee14742d5b4c75a": { - "balance": "1184047304377000000000" - }, - "8235bfba0bf0fb664271ebe534616456a78852ce": { - "balance": "6804584686000000000" - }, - "824df7b17a61392f88f7e3067f8c261abb48806b": { - "balance": "144857897574000000000" - }, - "82555a7aebfc95a01a3773aa5370394cadef0302": { - "balance": "40069354268401000000000" - }, - "82831d451b8f92fbf6a763adb708010a3e66bb60": { - "balance": "8750983992240000000000" - }, - "8294176178418f46bb18440cc87a07cf40c1669d": { - "balance": "4439783816461000000000" - }, - "82a1c733c3c937ba0a1a49481e4d1f6226157d2a": { - "balance": "50000000000000000000000" - }, - "82ad0b5dc23bc763da0352f5983efceeaee6ea08": { - "balance": "171723633433000000000" - }, - "82b4a3d16655fd71f4020e6a562592a621ff6e1c": { - "balance": "190211621484000000000" - }, - "8357d5a016a00aa5e3ef05d3ce210826adf4c501": { - "balance": "10000000000000000" - }, - "836c41d7f9e72131eff839b7d510fd0ed412f939": { - "balance": "15575572364757000000000" - }, - "8377fff2b0eb03393543ddf5ffae90b3311af5d3": { - "balance": "2058810049054000000000" - }, - "838859e6fd751539a88d00581b0e19bc98c37e47": { - "balance": "338264241636000000000" - }, - "838da0414211392b644e73541e51e9f0fba26615": { - "balance": "20000000000000000000000" - }, - "83958896a43d23ef4ba01bdf6757c36105985096": { - "balance": "9000000000000000000" - }, - "83b88314b606df40d5e716df488980bc64125b46": { - "balance": "10985538717083000000000" - }, - "83bf53fa162e1d85751be0bc6f46e8ec881392e2": { - "balance": "1497107276676000000000" - }, - "83d7c52608b445e18fb1e28dc6198908d66bb6d8": { - "balance": "265446362740000000000" - }, - "83ee8ebaed62092d2116de6b4e90778454e8dfc4": { - "balance": "1000000000000000000000000" - }, - "8402fe573658250f50fbe111596ce35ea9ec01ca": { - "balance": "3479737676000000000" - }, - "8412b877e708a7d5db2a38d9b0f4f23d12231f63": { - "balance": "9225027744855000000000" - }, - "8418dcc09fe052febf2946ee22bcc8c53d548eb6": { - "balance": "3000000000000000" - }, - "84199f54ef96bda5e14f60aa1723e811f755d3bb": { - "balance": "129197612052433000000000" - }, - "841b1400f97ecd2ca008e7b4f5a95274bc3e99dc": { - "balance": "2095180906854000000000" - }, - "844177191a120d2dc4be9169ddbc3b5430e9e238": { - "balance": "3620793599287000000000" - }, - "84578fcffc73be7d65bfa81b0cdafd26885bafbc": { - "balance": "37592478429000000000" - }, - "8460acb05c6c476ca26495aec7224c2bf90996fc": { - "balance": "8999580000000000000" - }, - "84696cdb9f018d3e7bf453efdc174e1a586e9c25": { - "balance": "118007806297016000000000" - }, - "846a8a91d2890000d1e995fc1663cf5b7c22211c": { - "balance": "27266838638307000000000" - }, - "846b5ef52d5f7ccc17d9c7e5f49db807908c63f3": { - "balance": "375423381758000000000" - }, - "847409e5d6ed2c4e54ff97f2ed58217ac5fc3d68": { - "balance": "23972870617025000000000" - }, - "84bf432c967540caafb8bf49cdc9983e8953a18a": { - "balance": "453476687224000000000" - }, - "84eba1bb76f7a3f6d2b9052d068cc6c48d449d76": { - "balance": "17655334922000000000" - }, - "851245ef1637a07578241b3c35acf215908e1898": { - "balance": "1269389304110000000000" - }, - "853708e974fd4810655d9cd19fc8dbfd3d5e1e36": { - "balance": "18000534000000000000" - }, - "8547989af8c99a3432038a03d3fb30a054d90413": { - "balance": "10000000000000000000000" - }, - "854ba39bac4c7bf619804b6773fe43bc71f3255d": { - "balance": "15999580000000000000" - }, - "85636f3e113cbe1d1bbd1b3a23e9e98edbcb94f2": { - "balance": "1199038399611000000000" - }, - "857167896b859394babf897c4c6fa57b3a057117": { - "balance": "921057404898000000000" - }, - "85799226a1474371ca76f05597a1e3835c17e7d7": { - "balance": "562141544946000000000" - }, - "85a2221cbbb47e8b74fc2617d6087a98f47e2738": { - "balance": "10000000000000000000000" - }, - "85be0bd55fb9143ff17387914a82d0a2650224c4": { - "balance": "4038654147145000000000" - }, - "85c5ff0e4956ef0fb662a2cbf6a86325a53dac8a": { - "balance": "28690160424000000000" - }, - "85caff4ec0e1719ad963e97c1c02828683070370": { - "balance": "2022427900763000000000" - }, - "8630cc2780fee566f172ed0437264c45421ce675": { - "balance": "669721278148000000000" - }, - "8633d245c5f1b63403e3d7828dc197ce1cfafc0f": { - "balance": "10000000000000000000000" - }, - "867ccceae3192a27751d870ae13b1d3d2c3584dc": { - "balance": "1491436265909000000000" - }, - "868bed241f77983ff4a7a8d0bf121299b6b2248b": { - "balance": "5600000000000000000" - }, - "868ddd283a76a26c8bbb9761df3ca647bea267e2": { - "balance": "9000000000000000000" - }, - "8696e546f96f6e51f405905e095902db8bb90118": { - "balance": "533558981421000000000" - }, - "86ac0eae4e4c20cb7019325f4dbebad053f92213": { - "balance": "697960117764000000000" - }, - "86bef47f9d2cd7526495454eb4d1737510696a5f": { - "balance": "2938307902381000000000" - }, - "86ddd4e3f444b395be8b2b2b75c35c78877fefb7": { - "balance": "15615434748526000000000" - }, - "86f115ed19a32aba4f98270b8ad45820abbc4653": { - "balance": "151868798605000000000" - }, - "870f19e7ee358de61ad0fd3c7710441156d68f66": { - "balance": "674715936435000000000" - }, - "87141a2d3857fb8a328ef8e7b503ed965294c85d": { - "balance": "1609607183158000000000" - }, - "87257783d866af25a7a71b46ea6c2bd1e9ab9596": { - "balance": "64000000000000000000" - }, - "87298979a9a0dbc272b0e15b7e5f2e42639c9912": { - "balance": "722087160930000000000" - }, - "8757b784015f88d072229176cabefa358a0e95a4": { - "balance": "204003337866000000000" - }, - "8760e60a56c5b8b61276634a571400023f08e3ac": { - "balance": "1000000000000000000" - }, - "877e54ea7e8ab03bb8e2b842dadab16bf4ae0a4c": { - "balance": "341020957932000000000" - }, - "87919285fc5d98169bbd073cebb1b3a564264dd8": { - "balance": "579080463078000000000" - }, - "87c39cfaa9c82d84119f306e6a233a3abfbb0ad1": { - "balance": "121753433796000000000" - }, - "87d479659a472af7c8ea78a3c658605f8c40bec6": { - "balance": "20000000000000000000000" - }, - "87d933ad6fba603950da9d245b9387880e6d9def": { - "balance": "1087642723520000000000" - }, - "87ec448309024bb1b756116b81652ea518cf353d": { - "balance": "344562808694000000000" - }, - "87fbbe010837f8907cc01a5bbd967f402a216488": { - "balance": "185411503628000000000" - }, - "8805a3c529bef4d19a6491f3b7d7b1b7232bb93d": { - "balance": "264150205918000000000" - }, - "880ec9548864fcd51f711ab731d847260ed0e3d5": { - "balance": "723225945994000000000" - }, - "8818d160b56b18e196871a6c7ccf02112dc13342": { - "balance": "2857439182291000000000" - }, - "8836e25baa08c19a9b0155c57072582b49f7dbef": { - "balance": "5468425690148000000000" - }, - "885b6303d06142accf2ddddbbdd4a9379d1cd124": { - "balance": "11853214736000000000" - }, - "88656958d9cd758d71546ba52c4ea646b658c84c": { - "balance": "10000000000000000000000" - }, - "88740acdf9ab5711d015391fe8cf4a7c70a0bc86": { - "balance": "510027156671000000000" - }, - "8874966976d776c3154261afa802692afedf3d3d": { - "balance": "305634301700000000000" - }, - "88aea53c727d7a5dd8a416e49faba1c4f741f01a": { - "balance": "15358334295959000000000" - }, - "88b67d05997ae3852259ca638a00ce9b9e7e4a61": { - "balance": "278125551806452000000000" - }, - "88d730e074a102048008de81d3adcba831335736": { - "balance": "5984576042159000000000" - }, - "88da27b1f0a604a87fdedd9ea51087a331179cb4": { - "balance": "10000000000000000000000" - }, - "88efaa91dab9671f5c903e69aa6ca4d9a04b5ddb": { - "balance": "1996126782729000000000" - }, - "89a9d702f64f14fae4d1a69717744dd700208d9a": { - "balance": "251686323241000000000" - }, - "89ac81571265bebbf9d3c09e9459fd1ba7fb1297": { - "balance": "162368080974000000000" - }, - "89c75c4f0ce41d283587beba1a3e3efab05ca6ad": { - "balance": "16000000000000000000" - }, - "89d44cb81cc5a1bdf4d573c4954ee641f3cb91d1": { - "balance": "97965629614355000000000" - }, - "89e2fef4f7b7c255b36afa81cf4033b22de3db25": { - "balance": "7278615226888000000000" - }, - "89fe5d3cb5283c7b87daf6103bb568f92a230631": { - "balance": "64000000000000000000" - }, - "8a07242231f4a654aeea65b857d1519385a18065": { - "balance": "20000000000000000000000" - }, - "8a5a415f0fe2a8329e14628493d11ca20d4e482a": { - "balance": "157274758238000000000" - }, - "8a6ce9f270fe3ec33a013be9e5b1ef823c0dab53": { - "balance": "20672772672000000000" - }, - "8a6fe4fa2f86f879ec9b2bf643beeb0876da46d4": { - "balance": "1041983771868000000000" - }, - "8a765ff2b429dcdf59b65a34c4bb41798dfb5886": { - "balance": "355487172996000000000" - }, - "8a9b9b65a3d443a6e4dcf696a64983f3b625774f": { - "balance": "3185351572575000000000" - }, - "8ab1f5443cf9149773b9ddb69de3e6ea047ae38f": { - "balance": "161619949415000000000" - }, - "8abeacee0078e07fb417277e8bf15dcc2cdb9fa7": { - "balance": "144000000000000000000" - }, - "8ac0d9e0e77aa4ada4080604f2118b3a5a0f8102": { - "balance": "100000000000000000" - }, - "8adae0dc99300f60d31bfa619ec83d45b48ea22b": { - "balance": "697262590215000000000" - }, - "8aef59e59a27a8662043f1a4abcaf945a5e3fafc": { - "balance": "26780431538000000000" - }, - "8b3386f32e2d77526c223ee8bb95b7dd111ced92": { - "balance": "2179932854210000000000" - }, - "8b34d5e457ef6451bb7f5ecc93c80678a30e3194": { - "balance": "31492358338840000000000" - }, - "8b47e07f192c33bd7d298bae717dfcd68a8097ae": { - "balance": "1000000000000000000000000" - }, - "8b55bff4b281f6a24ab428d66b91f9bab06f7b96": { - "balance": "1596248680941000000000" - }, - "8b576b1e2391f22193bb4f91bec5f2a8aec02af7": { - "balance": "29660301836269000000000" - }, - "8b9097b762c7bc38a487974f3551fea697087553": { - "balance": "260887123991000000000" - }, - "8b92c50e1c39466f900a578edb20a49356c4fe24": { - "balance": "35654824979000000000" - }, - "8ba3933337108841a997accf0b5735e005373f53": { - "balance": "574965182000000000" - }, - "8ba3eeb2d1b27e021ed6bf5827280807f32c7897": { - "balance": "64000000000000000000" - }, - "8bb23a5b8c48ec5bde84f39b463559b7c048c853": { - "balance": "16186405874000000000" - }, - "8be0b6ab14e15b46905335d07df03726fb1df0e8": { - "balance": "500000000000000000000000" - }, - "8bfc53af1ae6931f47ad7f7ed2f807f70fddb24e": { - "balance": "20000000000000000000" - }, - "8c0599df87df142d3aea37d50c975c1813ecb642": { - "balance": "871085782287000000000" - }, - "8c2deeeaf095be075a2646ed7b8764d3665acf14": { - "balance": "10000000000000000000000" - }, - "8c3e7381b0598356ff81e860faf25390ae7de9d9": { - "balance": "36000000000000000000" - }, - "8c5671a6f4610ddbd05a5139659c7190f54117b5": { - "balance": "50000000000000000000000" - }, - "8c60582c4e4e60da665b4a5a2d18f514ded6c49d": { - "balance": "16806447782991000000000" - }, - "8c8464ea6b17687eec36ef04966d59c7c91fa092": { - "balance": "1872124465602000000000" - }, - "8c85c5a318cc0227576adba3e91dce6adc73f6a2": { - "balance": "52479305517000000000" - }, - "8c8f3796a2942a2298d14ff1a9e3264e9f63f2bd": { - "balance": "10000000000000000000000" - }, - "8cec1886f2cc71b09ca32a1cf77a280ae3a6a9fe": { - "balance": "500000000000000000000000" - }, - "8d0b26d57eb52a62814d7876d64c8274f4371464": { - "balance": "20794037603000000000" - }, - "8d40b92e41f3cfec06e767d64b4dafc5612133b6": { - "balance": "25000000000000000000" - }, - "8d41ea1cfb70d0ef1f6572fd72a6b417739ac7dc": { - "balance": "738777348304000000000" - }, - "8d4eb54646f9d14882fc8ebb0ef15f6056d1afbb": { - "balance": "1003867239086000000000" - }, - "8d51ab29ccd190bfe12bcd94a651e9f49a003253": { - "balance": "442251355663000000000" - }, - "8d6c0c8e4ca47626115433b39feb939014b8738f": { - "balance": "119828137027000000000" - }, - "8d7acd92d664a485625bb9884e7cac9cc6077f41": { - "balance": "1381910232084000000000" - }, - "8d7ee7a9c1c263ba8061f54dcf62d9f8420e2008": { - "balance": "20000000000000000000000" - }, - "8d941c5d0c6e2b8e2934c9f80f8a63e2fb5868ef": { - "balance": "116443644149000000000" - }, - "8da0dc43ed3ccefb18f21aa13f3fa42c13e540a6": { - "balance": "516000000000000000000" - }, - "8dab4500316475e8fc3bb6494be09f549dedf026": { - "balance": "2736245677000000000" - }, - "8db39a95f4e63bde0bd8c02e386122ce2c57a30f": { - "balance": "12577347153000000000" - }, - "8dc718b49fb68584d9472490743f9be1b0ad683b": { - "balance": "50000000000000000000000" - }, - "8dd05e26224aa8a6deb0904b6d3bbb34d268e901": { - "balance": "613146658282863000000000" - }, - "8dda0e7ddde515480ef08cf90a1eb4e78f50a2c4": { - "balance": "19265526663314000000000" - }, - "8dedad1511c11798c338334dde7be967de96e9b2": { - "balance": "50000000000000000000000" - }, - "8df63c04f18a854d7bb397bca3e2ba19202e9da1": { - "balance": "1479940547081000000000" - }, - "8dfd7edb7d28e8b3df1faab70a8ef9e3b923d998": { - "balance": "10000000000000000000000" - }, - "8e2c3af057e931b5f82e83873b336a7f68e7eb03": { - "balance": "27138009123000000000" - }, - "8e2f4eaddd60468bdc09d47f65839b96f50596ef": { - "balance": "970529157231000000000" - }, - "8e750010c88ba99d75b0b5943c716d6fc0d01802": { - "balance": "42271114987000000000" - }, - "8e889d47f3307a18490e53f2108dc31b14d6300e": { - "balance": "115722965933000000000" - }, - "8e9e1953c82217ba56365e7a9c54b1ded73914bd": { - "balance": "6248835752208000000000" - }, - "8ec980d3066cb6afa793577cf88ccb46ce8d13f2": { - "balance": "100000000000000000000000" - }, - "8ef324c861de7e042c445776bcc8ac026533bc15": { - "balance": "1869634994148000000000" - }, - "8efd14464465e50af087a80a5fbe652445de373d": { - "balance": "1157403424927000000000" - }, - "8f1b57304406fd8b2eb5dabcbd322e326dd873f5": { - "balance": "194188733254000000000" - }, - "8f36ffd921e12083e374335d3cc43fcfeeadfa46": { - "balance": "100000000000000000000000" - }, - "8f813b88e6e125eab71a63455f326322ef505501": { - "balance": "19087691927734000000000" - }, - "8f83892d4d2892cd57828fde2318610a54b14498": { - "balance": "22833507983000000000" - }, - "8f89c1bcba85757cf1718d5b9eb007e27e5195ab": { - "balance": "2241600478705000000000" - }, - "8f927ab63df4c2ce46f1ea35bc875a0c006d2d4f": { - "balance": "327487123409000000000" - }, - "8fc3c231df0f93a84bbe348aff12ab576284d70f": { - "balance": "25000000000000000000" - }, - "8ffa089b07ed1388a5d1a428daf54d9591e734e6": { - "balance": "1347580402248000000000" - }, - "90040e00f585f8be44c82597037fde452472e741": { - "balance": "2746884591879000000000" - }, - "9034eb46aad2a76bdb812c981565d4701dc10718": { - "balance": "10000000000000000000" - }, - "904ca1ac2381702bd18472b175262a8928cde5f1": { - "balance": "304421909590000000000" - }, - "90502c1123692c3b86e99b328d07fae473d4a283": { - "balance": "227491252462000000000" - }, - "9052ca7e9623c1bbe3568668673d6d252b56a764": { - "balance": "35268091378000000000" - }, - "9093d12d8410193293e1fda0cca98a43b85b91a8": { - "balance": "6829489147119000000000" - }, - "909ba8cdc707c12ba577dcd8ed1df1c02a7ce2ef": { - "balance": "60524108169000000000" - }, - "90a2cc3aa73495531691e027a8c02783cea7941d": { - "balance": "65263780625000000000" - }, - "90d7c82615f151953a8d71a68096cee4d428619c": { - "balance": "298774379499000000000" - }, - "90e02deb31d98b9c85fcaa7876eb5ec51d721dd4": { - "balance": "2000000000000000000" - }, - "90e538746bbfc6181514338a608181a3c4286d1d": { - "balance": "6069511690189000000000" - }, - "9106dddc1b693e7dcb85f1dc13563d6c7c9d8a6e": { - "balance": "1977000091291000000000" - }, - "910d1e0d3f71054835ee0d4cd87054dd7add3e38": { - "balance": "40104690362000000000" - }, - "912e2349b791fe702692a6c1ccbf6f0f06b826db": { - "balance": "6305336897000000000" - }, - "9144cc61c01eb819e654b46730620c230da9e936": { - "balance": "144000000000000000000" - }, - "91478d4c15d9ba02816456030915be08fa3aa208": { - "balance": "200078339107000000000" - }, - "9160c466b5f9020b0ab1c0ff497bf0345598ec90": { - "balance": "17705350930000000000" - }, - "919025625787101c572d8340ead1444a96593424": { - "balance": "2418027749789000000000" - }, - "91926323868c65f91b6d74c85c07279610651ede": { - "balance": "538073886450000000000" - }, - "91950cd6e2dd99e024854b65c09c5a7476777a21": { - "balance": "11629505934425000000000" - }, - "91ae8d74c26d3dcc291db208fc0783347fcc197f": { - "balance": "7604593786920000000000" - }, - "91b9ac26869abc9eb3090f1d8140eabe97f41001": { - "balance": "25000000000000000000" - }, - "91c349651afb604f9b00a08e097e02c0964e148a": { - "balance": "117290771022000000000" - }, - "91ddc95cadeb6dcf6ebbdb3300a29699ac8ded39": { - "balance": "20000000000000000000000" - }, - "91ebbd36714cc069f8ce46f3e0eda5504fdd3aa2": { - "balance": "203944728497000000000" - }, - "91f2765125b84923bd506a719d72b0c1de030e32": { - "balance": "452269960816000000000" - }, - "91f2e54a9d61ef52a33d150da50d5a8f2ebcd6bf": { - "balance": "242321058694000000000" - }, - "920dc90d11e087a0d8912c1d43db102e9ba4f43e": { - "balance": "20000000000000000000000" - }, - "922ff522cf7f3ce0bab9312132df51704caa755b": { - "balance": "1414824682473000000000" - }, - "9251449b0f757ef62f63c2774eb63ba15bf3712b": { - "balance": "102688517037000000000" - }, - "926255c17386720fdc1701747a2f024475063d4a": { - "balance": "25000000000000000000" - }, - "92808a38ffc5a339b1ab6b0b472f9975718d4a07": { - "balance": "500000000000000000000000" - }, - "9286c4497e820845341e3b9127813c1b7c884830": { - "balance": "101241387488275000000000" - }, - "9298e1df6730e91e9892d19f7ce18a3db9b5d2a1": { - "balance": "169000000000000000000" - }, - "92d98aed335c29402a43ba96c610251bed97308b": { - "balance": "3032350763000000000" - }, - "9319153f24814a81d920c60cbee9b5f2f275fac0": { - "balance": "56619610984000000000" - }, - "9347532d6396bc0b86bcd34eb80facd4c3690684": { - "balance": "258912194626000000000" - }, - "93487691d71e6248d88f06b1fbaee58b6fe34615": { - "balance": "1593901704394000000000" - }, - "9375154a7f19783b26ae1c9e48f114e1cfd1307a": { - "balance": "9000000000000000000" - }, - "9377947e0db688bb09c9ca3838ca2197fb262a1e": { - "balance": "323993393587000000000" - }, - "939ca9030b28d356dc1b071169f98b0728a9aef3": { - "balance": "218900305967000000000" - }, - "93b71636b8332515c2af031aac7a8805de716a62": { - "balance": "1640174743698000000000" - }, - "93bca153afd427b0c3c1de4a5584610e4a6595b7": { - "balance": "654782426410000000000" - }, - "93cb3b73fee80cedacf5197f8b4ac8f18f0d0184": { - "balance": "100000000000000000000" - }, - "940fcd215bab373d1b736e354f2def501244885a": { - "balance": "13133641534585000000000" - }, - "943f4bc76f20580b6546b6aff2800448f82cfdc0": { - "balance": "1927982550280000000000" - }, - "946ddb5c46fb13010b9c7ec56e4055b4f3e24b4a": { - "balance": "1410000000000000000" - }, - "947961dc367226f78d722361d5821cced52db01b": { - "balance": "115598797369000000000" - }, - "948eab3ffe44d5f1f381de2c8cadcb311c25df2a": { - "balance": "870664355820000000000" - }, - "94bf674593378243fb6b811f331f77561efb4106": { - "balance": "226539311455000000000" - }, - "94ce082887dd6324d7dcfa6cae17b653be021b25": { - "balance": "420000000000000000000" - }, - "94e2aaa4b5e2b36a12f866c96e3382a1150a97b4": { - "balance": "7344059136611000000000" - }, - "94ea5b1cdceb3f1a9d5ecacb6ac8dd2db9a461d7": { - "balance": "1951787237292000000000" - }, - "95218633176c0fe2f32fb55ad3df9f387e63aed1": { - "balance": "99999999580000000000000" - }, - "9543cb22853a46cce3aadc60e46cbddbd3fcf593": { - "balance": "2806074281914000000000" - }, - "958842c5389656d156aab05ac1731a20656716ff": { - "balance": "391064461038000000000" - }, - "958fd9bbc96531a00adc5c484d06dc61ccd717b6": { - "balance": "8021794447667000000000" - }, - "9593ce72919cb0648ddacc58af233d942963e2e6": { - "balance": "32322940730755000000000" - }, - "95a8e371af9128c97c9d4d7c4d58f5f75f2d07d4": { - "balance": "49000000000000000000" - }, - "95b9a9ad563a4c1ff7b6ebcf5fabcf5dbdb4a6a3": { - "balance": "10000000000000000000000" - }, - "95ef5fac6aa3ab1b4a87246fa800cfceff43dec7": { - "balance": "119666779022000000000" - }, - "961a3aa8015cd520de43bd47d81f5194ee4dfdc2": { - "balance": "248589901007000000000" - }, - "962bad39df25d64ee1c6b4ae9c14a18d316bfc06": { - "balance": "2404608291000000000" - }, - "96392119198c4b644c64284c9a75f61210a6292d": { - "balance": "1000000000000000000" - }, - "963c82319380587eeba0bd7b07eb63ea7042984b": { - "balance": "1480123630618000000000" - }, - "963e05fb6245ec11d67ed80e9feba6e2c0a8b4ae": { - "balance": "276053287417000000000" - }, - "964452b86b0d1d4b34aa881509a99e7b631d4a85": { - "balance": "64000000000000000000" - }, - "9644a2af2ff70eb43584a4351bfbe027c42ba3f9": { - "balance": "500000000000000000000000" - }, - "96572a017489450f2dfc0e31928576acd3bc6808": { - "balance": "1140183097730000000000" - }, - "9686bfcc0dc3de20604eb77787d0dba818cc5016": { - "balance": "10593448987804000000000" - }, - "96879780764b4433589d26573fc221f5218f1877": { - "balance": "154136576560000000000" - }, - "96ac1e62c95e33dbbd4f6ed389007e16c00b205e": { - "balance": "4130528000000000" - }, - "96ba703df3a8a6dc3c5d6be02cbf6a4afa2d1650": { - "balance": "2885298549532000000000" - }, - "96d516ded110f1d7e0290716689fd1b7964d9d42": { - "balance": "40665675241000000000" - }, - "96d75950c9354cec6084ba11058dd52d00fdb1f2": { - "balance": "903158106646000000000" - }, - "96f362c59c72fa1d39ae3ec37a7b715d2dd23679": { - "balance": "110000000000000000" - }, - "97115f7544cb05009b3fad2f0c2817f3ee77dd4d": { - "balance": "10000000000000000000000" - }, - "971cbaeafd4b0fdbad24fab946051b8949efaebf": { - "balance": "8462381628000000000" - }, - "971e195e980b4fd4db8d279c80968ca1bd390edd": { - "balance": "10000000000000000000" - }, - "9722648970c455929d621546fddbff27c49acd3c": { - "balance": "70337427969000000000" - }, - "9772027a4ea991eb9eb5ae6b8f34d750a917538b": { - "balance": "148918416138000000000" - }, - "97797e3919aa35567b9eb1224be87f96c6c2e1b4": { - "balance": "973342196399000000000" - }, - "9780a9c86160e27f627179535c3d3f23b6b29917": { - "balance": "10000000000000000000000" - }, - "97a85f4e3f53aa066825de15f1d0e25d4189b037": { - "balance": "2435764858719000000000" - }, - "97f46465e99910539bd3593c16a572e159bac87d": { - "balance": "25000000000000000000" - }, - "9882505fcb54ca2d2f4f79b03f0a5ead61936979": { - "balance": "249999580000000000000" - }, - "9898e969629502a891b758efecc9fdc5ada7d32c": { - "balance": "20000000000000000000000" - }, - "98a52d325e28ca9b4474846c7e4c07a223440fab": { - "balance": "418260286015000000000" - }, - "98a9b2f7d1ba7838e3242b5e4cbf1f2897aa4bc5": { - "balance": "500000000000000000000000" - }, - "98b8308c37a2f6cc1bb382dba2ba95a3c5ca2834": { - "balance": "10000000000000000000000" - }, - "98bf0170a61f98ab0710a68810bf152b7f6c56fd": { - "balance": "2279761566089000000000" - }, - "98c8a323a0022bd147a466fa1ac867977e12eb92": { - "balance": "10000000000000000000000" - }, - "98cd102caf0866ba0a74604b01f54049503905d6": { - "balance": "34739921273310000000000" - }, - "98d7e89c2765aaac224d4015aa277fef208953c3": { - "balance": "1291811952000000000" - }, - "98fe96bfd1e10fb60b343e512b15e955aefc0778": { - "balance": "464922897623000000000" - }, - "99064a57d693e45559a1a910c9ef7d46cce0e703": { - "balance": "8969733492948000000000" - }, - "991ea5429b91a8bfc4352a1d93304dc463be5b90": { - "balance": "149367286734000000000" - }, - "9921d405fada890fee6bf76acc39141fd34e5d2b": { - "balance": "5021308706457000000000" - }, - "9938d357d3d5dcc6f6fc7fb47a98405c0ab6830e": { - "balance": "516293591974000000000" - }, - "994f4e6521a3a5752359308b9f6b2722922c60b1": { - "balance": "23993133615000000000" - }, - "995a6a1c38f037b3a9f0a2e915b8fc0efdea082a": { - "balance": "1403498530728000000000" - }, - "99709e57748a7da6556b1670ba4f15c45aef4689": { - "balance": "36000000000000000000" - }, - "99789f65655c6f917d575169f4ba8192440e659a": { - "balance": "393071814319000000000" - }, - "998f66cbde2693603fa109ad7aaa8bc42a8765a9": { - "balance": "49000000000000000000" - }, - "99afd42a58af31daa54ad9ba35b06954330107ba": { - "balance": "25000000000000000000" - }, - "99b6a9ff2b2ac9ac0361af007aba107695ff5fad": { - "balance": "12860157225353000000000" - }, - "99d16a5955d43723ed8e2b1a642f8f1195f38b64": { - "balance": "62907829047000000000" - }, - "99df609926ca536ed3be80e35dbaecc42ae67f2f": { - "balance": "316809833612000000000" - }, - "99f3faf97a36fabea7306979b30b08fa70110e29": { - "balance": "173292373556000000000" - }, - "9a26110067b473e3bdc0fc32951b39596c967a56": { - "balance": "78192198764000000000" - }, - "9a3a8eff6fb82377da6c17ba658dca87ca0dfe26": { - "balance": "50000000000000000000000" - }, - "9a3b06257088ef8c17410a8f2d63392edb9b55ce": { - "balance": "239567000000000" - }, - "9a426842301802866cca0ef89794d928d3e8f843": { - "balance": "776173297821000000000" - }, - "9a5f2c0a6d41131d9aacdb4f8c274958cbdd377e": { - "balance": "441954000000000000000" - }, - "9a6893023ac6f34b493d33e4dc63ef697169a58d": { - "balance": "439689418527000000000" - }, - "9a86eefd848acafcbd9960003e90b22162b15ef9": { - "balance": "294190908093575000000000" - }, - "9aa711f3e4eb67d2f6405b5ee6290a014d203a72": { - "balance": "9101556549634000000000" - }, - "9abf9ccf6abb8d55ede458d2d12a279d0a823944": { - "balance": "17609693072000000000" - }, - "9ac1909b983c754f0800559174025c0f0baa9d31": { - "balance": "80921948093000000000" - }, - "9ad62cd855d629e1ddab632874a6dc2b812f2348": { - "balance": "2068118534000000000" - }, - "9afc2c33aa2c9a42600abb18aedaefa433326122": { - "balance": "2485353229354000000000" - }, - "9b18d230b221a99c74877d4a1dbdee2214c7d60c": { - "balance": "4024172228743000000000" - }, - "9b18e27788c9d59053072032a480569e142595a0": { - "balance": "110789164888000000000" - }, - "9b4535b23af0b8e5f488a6f318ff6badf71d16c1": { - "balance": "84756740661000000000" - }, - "9b5e7cf43aece7b38ea2af6d08bebe2d3b926840": { - "balance": "262771268227000000000" - }, - "9b77dac92fedd0ad3eb4326d4fafe0f4315a8844": { - "balance": "3616321626000000000" - }, - "9b8f6f223641f9b1bab319dd1e88c49fd411a765": { - "balance": "2054417462086000000000" - }, - "9b9f94861d80365464912e5c7213403405a6cd8d": { - "balance": "2367093088000000000" - }, - "9ba24397002929e6239848596b67b18a8dea1eef": { - "balance": "5000000000000000000" - }, - "9ba99736c5ac468d6b644e39b8d515c39151f51d": { - "balance": "311900650761999999999" - }, - "9bf2d4ff366e1bb2313ae9a93ccca75d6bc0d232": { - "balance": "764870206925000000000" - }, - "9bfce7dbfc9ae62d450e862261d1e21e68bac92c": { - "balance": "1000000000000000000000" - }, - "9c003e74b62f192a864045d678639580c672fc22": { - "balance": "50000000000000000000000" - }, - "9c128bd2c0c96b896db6c0f398e908c98302809e": { - "balance": "3251059363800000000000" - }, - "9c255daa89ee16f32fc0ab1ed8e22db39342e6ca": { - "balance": "37695843594589000000000" - }, - "9c32e714bcb601a56a8a4e6b3f7bcd9e1c7a1b54": { - "balance": "50000000000000000000" - }, - "9c503e087b04a540ed87056c9371d591afa72df2": { - "balance": "64229084991000000000" - }, - "9c54297dd3527cbbb8ca8c305291b89bfb7ab39d": { - "balance": "61682466962052000000000" - }, - "9c55bb1db3b2bb06e605a66ced9ea2ac95718205": { - "balance": "16512365324000000000" - }, - "9c59dbc48b9cf53fe668784e89d30493da9995b3": { - "balance": "50000000000000000000000" - }, - "9c61b58aa760265f7fd1b9e749df70122ea81175": { - "balance": "50590272373000000000" - }, - "9c6c7eaf4bec0566a7bf8acd30e10311a963267c": { - "balance": "999999999580000000000000" - }, - "9c91dd4006f9d01d8caf5f5fb4f2c4f35ee63ffc": { - "balance": "175730980227000000000" - }, - "9c99275f5dee14b426302b1a47a8488c16432f2b": { - "balance": "2000000000000000000" - }, - "9ccf7b23528d062da63f6af3e26531b775c83c52": { - "balance": "928373869120000000000" - }, - "9cd21c30ccbc1087c9b351395fdea17ad669cc2e": { - "balance": "529762292313000000000" - }, - "9cfee47d6f24880af7b281cc00e1fc58e0a4a718": { - "balance": "198888257958000000000" - }, - "9d08251f7d4cfd66d15c17e1ea6bae5c795e290b": { - "balance": "813841349140000000000" - }, - "9d5411490ce89359bfbacf9f9957ebfbbc18debb": { - "balance": "22263187467000000000" - }, - "9d61e1dfaa7d0e0c5f5d733a24a1883c4e201f3d": { - "balance": "144000000000000000000" - }, - "9d754d94a15ab6d738e511fe4c775ee6d20a53ee": { - "balance": "20000000000000000000000" - }, - "9daccedf104fdcc3c39f2961ddfa1c64eb632476": { - "balance": "1237093270947000000000" - }, - "9dad4968c0e44aa729fc5732f3ee903c6799637b": { - "balance": "838788687517000000000" - }, - "9db73ca677bacbb622f44fe90b53ee1d9f0c2009": { - "balance": "472858335000000000" - }, - "9dbcb5026e0f444a33197da240856f108db14ff0": { - "balance": "10000000000000000000000" - }, - "9dc46cf729187ceed8001c4ab14fa4fc21c35f32": { - "balance": "3320792646995000000000" - }, - "9dd895c1bdac2ed9864134aaa8c543473ee5f19b": { - "balance": "1430620966869000000000" - }, - "9de2687242cbf9fb94fee0ad873acc7494ebd2bf": { - "balance": "20000000000000000000000" - }, - "9deec036282717aac93ad5cc1b6d4a5354e85c2e": { - "balance": "2048627955362000000000" - }, - "9df8dc66395aeae9b4c831b4d63bdf48db08811a": { - "balance": "215874670561486000000000" - }, - "9e1fe68a70abd8ab517878b03961da8564b43eb5": { - "balance": "67908329894526000000000" - }, - "9e33293006982abc668e199aab20260b9b754463": { - "balance": "49000000000000000000" - }, - "9e65616282a0baf89469a58915fd8fdbed210e3f": { - "balance": "829209872657000000000" - }, - "9e7b7b522834dd7e83ff2bb6b6e4cd2972330899": { - "balance": "500000000000000000000000" - }, - "9ed134b3a8feccb4056b2e511cea9a8ec58a3e77": { - "balance": "18787546978390000000000" - }, - "9edcf477687a9dee79341ed5d89d576c9a854c2d": { - "balance": "500449025554000000000" - }, - "9eeb06d4b532118afa013a01c9e89216fe0475ae": { - "balance": "1823939486758000000000" - }, - "9ef20a338e85044922f08f3648355e834874d551": { - "balance": "50000000000000000000000" - }, - "9f0855f9cc429fd3590c6ad05bb66a9e038efdca": { - "balance": "8017999878252000000000" - }, - "9f3befcc1884d16b65ae429228d26fffc146c8dc": { - "balance": "1016482445089000000000" - }, - "9f4571748463eee19e59ff9bd734a62a66613850": { - "balance": "20000000000000000000000" - }, - "9f51de282745f77b8e531e1de0b7c14e3369ba54": { - "balance": "1010657089383000000000" - }, - "9f6527175a2b581cc79f2a68c35202e0a7f2af20": { - "balance": "216495522463000000000" - }, - "9f70204d1194f539c042a8b0f9a88b0a03bbcd8b": { - "balance": "10000000000000000000000" - }, - "9f70e44704049633110ecd444f9540e241b50783": { - "balance": "9139000000000000" - }, - "9f73fea741e8506ba7acb477745dab1cfab8366e": { - "balance": "4461472359634000000000" - }, - "9f88d33d26c90e74c39c9676b8b580d21bbad124": { - "balance": "54437240781000000000" - }, - "9fa47455be14ad2eecce495281ed0eea926ec6a6": { - "balance": "10000000000000000000000" - }, - "9fbb15b595d154754a2ae77c77283db9d4e9f27b": { - "balance": "6195722646556000000000" - }, - "9fc480ab1823a59fd6130c3948980f95ac99f1d2": { - "balance": "24101151540000000000" - }, - "9fe5f054165fbf1943b1b02c01063f04e0c3890b": { - "balance": "1000000000000000000" - }, - "9fe7d3d5976e7b8b5ad6baa15ceae96c43c60fea": { - "balance": "55000000000000000000000000" - }, - "9ff116ea0e219814970cf0030932f5ce2cd9a56f": { - "balance": "36000000000000000000" - }, - "a01f6c36193839bc3a31e6d0792324771040fc05": { - "balance": "48298750000000000000" - }, - "a0264706d668522b737bbdbe949ce3e5a60fe314": { - "balance": "1423066922869000000000" - }, - "a02b13bb3b13027045ffb9b44bc7380a942e8ebb": { - "balance": "86845430807181000000000" - }, - "a03d246a931c3d422e5d2bf90f64975923a93643": { - "balance": "5834171660287000000000" - }, - "a046caaee59425ea1040867c62a6fcda11652a23": { - "balance": "83087966538000000000" - }, - "a04b57b2dd8b2082c53517d956f5909d25e14b69": { - "balance": "4518538234851000000000" - }, - "a074ef9e0ffe15619103e3de490f5813be53dcbb": { - "balance": "4568113810000000000" - }, - "a07bae42b44c085067de16e7d9846db529059acf": { - "balance": "4000000000000000000" - }, - "a08530e5fb7e569102b2c226aa5e53dc74483e4e": { - "balance": "2325665286793000000000" - }, - "a095a2c666f4f3203a2714fb04867c13c2add4be": { - "balance": "14768043990000000000" - }, - "a0a967418a3fcb3ee3827a08efa851347c528a60": { - "balance": "20000000000000000000000" - }, - "a0bb293071e07418ecb2fefc073136569ebd1736": { - "balance": "25871128320000000000" - }, - "a0c6c220a53b7dc790f7a5b462a106245c761f70": { - "balance": "1000000000000000000000000" - }, - "a0f06c86c49b248f4835bff405b620d12ec80d07": { - "balance": "484572382390000000000" - }, - "a10bc9f4d05678b26c4ffd2d92ab358163020b61": { - "balance": "10000000000000000000000" - }, - "a10c1197f7bc96639d01a652df73e49c669165dc": { - "balance": "1205859101575000000000" - }, - "a1221b2001f85f71e0655551e300ce115284b8dd": { - "balance": "1376698025177000000000" - }, - "a13fce836d65124fe5bcfa2d817ab2a043acbcf8": { - "balance": "55000000000000000000000000" - }, - "a15f1f609f7464906e0eb9d5e1d26468b90d9198": { - "balance": "16000000000000000000" - }, - "a1617dcf3acda60737e5ca9e4d0ecd82a98ef667": { - "balance": "500000000000000000000000" - }, - "a165c5f151d0daab905ba4a6d1fe5d5114fd7686": { - "balance": "41039049526000000000" - }, - "a17d5bed36c1059561e184a8a90a38ce955b92e4": { - "balance": "10000000000000000000000" - }, - "a18efb4e0950e7ac95970cd4591dacc286241246": { - "balance": "12403188476000000000" - }, - "a191fa6be64f2f6d2b4a7fb5a586416a605552c6": { - "balance": "60340281461000000000" - }, - "a194c15518cefbe94edbef3a2421586b51f7e1f6": { - "balance": "4153525550636000000000" - }, - "a1d0e41aacf83fc62fbecf35f8e873f8d734ecaf": { - "balance": "9000000000000000000" - }, - "a1ddd1f615ed483ef895e341f3266b6891f9b59c": { - "balance": "180411786335000000000" - }, - "a1f4d1e03114707a56ef9069bc20c6094e810d34": { - "balance": "51949145435222000000000" - }, - "a1fe101a65616cd03e3af03092be63434b7bf203": { - "balance": "1005401878265000000000" - }, - "a25a8225ce67c54048737601eac5e0d063c2fa17": { - "balance": "272038848571000000000" - }, - "a2714999233bcaff7294fa3e3b64c63ad45a928b": { - "balance": "14560781294000000000" - }, - "a28db3f7fb1771a3d77dfb19b54f88fd55b15c8c": { - "balance": "8000940572576000000000" - }, - "a290101bfe5fbc73146c4ec3ab5266c043eb701c": { - "balance": "1397563244603000000000" - }, - "a2924cfbcd37d0b321d6abbe57c645f9ce32340e": { - "balance": "200000000000000000" - }, - "a2a26c34f3d950c795fc965f6b1df3990e111403": { - "balance": "34525064429023000000000" - }, - "a2a2855851711bfc051c1f298821ae89e4c872c5": { - "balance": "491025000000000" - }, - "a2b956dd6f1934a4a44a026a18ac345ddabe42d5": { - "balance": "20096625821563000000000" - }, - "a2b9a118a79be81711d95485aa12e3efe78ca256": { - "balance": "10451051632647000000000" - }, - "a2bcf08ddd1778b30ea7882518148edfba2d9b20": { - "balance": "347033754668000000000" - }, - "a2bd489ec4790f4145f8a9a95c9c829c5c020146": { - "balance": "100311110878000000000" - }, - "a2ee35300ddf6a2491ec0e1848f8b56defafd7fe": { - "balance": "500000000000000000000000" - }, - "a31adf082ffd212df18d5a84b105a937e83b1b1a": { - "balance": "7124891785000000000" - }, - "a32c944e6c5fe186794b88d6bcbf51c47bea55ab": { - "balance": "732129357042000000000" - }, - "a33105d543f5d2b1220d4e1ecfdcf85699324dad": { - "balance": "74798779358000000000" - }, - "a3330c73e2d79355a14e570da1ec2e80f8048c69": { - "balance": "10000000000000000000000" - }, - "a3580034590e3052b9de5abd635e514ec5ba8694": { - "balance": "10000000000000000000000" - }, - "a360d8e2519dc6d7793cc371d91ad6add75e3314": { - "balance": "192622260840000000000" - }, - "a36b9b8b2adb20fb4a84d3025bf2e35baa8b7fef": { - "balance": "20000000000000000000000" - }, - "a3771b191237bef48339aa77ad5357f6227b358c": { - "balance": "512633055119000000000" - }, - "a3892bfd25705387cfb4eeb6d21089753c22e3e2": { - "balance": "258136912825000000000" - }, - "a38c793775ebfc7330b4331fe2dc848abb862b73": { - "balance": "1193250172232000000000" - }, - "a39417002ab94845541aded4a614a5a04af8187b": { - "balance": "1185722898000000000" - }, - "a3a79a9f929b54075de43689adb665ef914812ca": { - "balance": "100000000000000000000" - }, - "a3b59ea3d366f818ca09980846ac533d4685c121": { - "balance": "59734700360000000000" - }, - "a3c7b7c594a64225922e02039669e4d0b43fc458": { - "balance": "11779233750000000000" - }, - "a3cc39a68184e51f6445d3ba681a55f4157d4383": { - "balance": "10000000000000000000" - }, - "a3d414d9f210f7b77f90790ce09f6128abe50adc": { - "balance": "10000000000000000000000" - }, - "a3dfda16e5ae534ac100f56741b77b6f86786615": { - "balance": "9000000000000000000" - }, - "a3f79b9d1fc9d6dbaaef49d48fa9c9fb5a822536": { - "balance": "108910000000000000000" - }, - "a3f87414bc9e6f01c2fbde966fc8fb6edbf58c29": { - "balance": "441000000000000000000" - }, - "a3fa3f58c802d9a9690de760716275f14449045a": { - "balance": "437227558095000000000" - }, - "a417ec5a9749064a6521ca2bf9d05f208eeaed54": { - "balance": "959205202638000000000" - }, - "a484d5b883d2b99b81b7bef27e307957ecb64b15": { - "balance": "126491152120000000000" - }, - "a488cd48258e57d66f44e73a60c121f963cb29f5": { - "balance": "20000000000000000000000" - }, - "a488e3b5096e964b21cdeba12ab423f391765b6d": { - "balance": "1712050478592000000000" - }, - "a49dba65f28909e9bd2ce5675bd091f498c6c5db": { - "balance": "216802821062000000000" - }, - "a49eb6a791022c1324facc23d8813f9954d1c639": { - "balance": "287438914902000000000" - }, - "a4cc080a5c4649f511b5844a8e0b031927e13a87": { - "balance": "20333578449000000000" - }, - "a4d2624ac5e027f72edaa625ef22134217203b5d": { - "balance": "1000000000000000000" - }, - "a4d30e35c9617eafeda82866c96c3ce6bf14400e": { - "balance": "1223254927978000000000" - }, - "a4deae7355bd2e1d57eefa56600601b8b475a501": { - "balance": "36000000000000000000" - }, - "a4ff3b5abfe4e50adad16d01aaf62c3d4cdb5260": { - "balance": "20000000000000000000000" - }, - "a502b109869ef07451576bf0e13ab294e1f236b9": { - "balance": "94843398055000000000" - }, - "a517a3b5e4324197902e16f8a29e47335cf39c11": { - "balance": "100000000000000000000" - }, - "a51e101088da23c82907e3e2c65a058f0454b131": { - "balance": "196000000000000000000" - }, - "a52bcff6a7e2e70cd714058bc30a16138fe39899": { - "balance": "30429750204000000000" - }, - "a544e84c2bc4b17859d06f136b6e377e4e398b22": { - "balance": "143977568178000000000" - }, - "a54ddacbc17a98b9fb6292aab3d92f4c5753fd0a": { - "balance": "100583192014000000000" - }, - "a557754f6637a19c1a48cb9bf58c1fe897acf434": { - "balance": "2087038692036000000000" - }, - "a56649205d9ea247b49e03dacbed6c78c21beb4a": { - "balance": "5046177099585000000000" - }, - "a568136446ee6b3bf62a20238db3b11397a065f2": { - "balance": "11652249158033000000000" - }, - "a56a7865b526e315a9eb41f4847485c7e0c952fd": { - "balance": "50000000000000000000000" - }, - "a56bab2a9aac9d08a7bc9265864a80089b68570d": { - "balance": "37138466291329000000000" - }, - "a5965a601c5df7765cd70e5dad27dd23da67ac99": { - "balance": "10000000000000000" - }, - "a5a3161c44c34c441784b7df795067760b0ee569": { - "balance": "35053289069000000000" - }, - "a5c245cf843e691956007b94e259b437a4e6b7e3": { - "balance": "18749166170000000000" - }, - "a5d7de961c3b991dc78f2d6c0448fa6225116d3f": { - "balance": "1574510758868000000000" - }, - "a5f47d2081ef728808786128549a28a5662e92a8": { - "balance": "1750000000000000000" - }, - "a610c90f5b7e5f33044956ba431a3887de1c969f": { - "balance": "25000000000000000000" - }, - "a61c1919bc3f3181dc94e2230d35574cfc972d78": { - "balance": "8990565120000000000" - }, - "a62f1aabd91cbc0112e796d1ec3727fcd26fa293": { - "balance": "1311277302001000000000" - }, - "a64fff0bb32e32f81a541c393982bc59fa183b1e": { - "balance": "8291357610655000000000" - }, - "a673dae555d367b8d4a784274577a1884615b9d9": { - "balance": "27416452091330000000000" - }, - "a6c780b585355d84d9d3c13be5bd05374588e240": { - "balance": "913657165911000000000" - }, - "a6cc1f6f51862c2798adaa1d266988022005a71a": { - "balance": "284500645805000000000" - }, - "a6d9c82784fa20dcf28266d047db441cfeb8855b": { - "balance": "10000000000000000000000" - }, - "a6dae08f99e4fb57b066a645a259d8e4f7ac2bc8": { - "balance": "9044922773690000000000" - }, - "a6f49f36f8d10a796bc2afc9e069cb0c76004ddd": { - "balance": "128555691078000000000" - }, - "a721ce1c294a0f1957ebf9be20b0fffcf90111ad": { - "balance": "3392103457630000000000" - }, - "a72b82c33bd3d6060e8a04392d236775d48ec3ae": { - "balance": "1434465940701000000000" - }, - "a7344654f2a1a44b3774e236f130dff8a4721e82": { - "balance": "100000000000000000000000" - }, - "a748cced92a87066db8b29f931fb92e827488a9e": { - "balance": "5487679824758000000000" - }, - "a78dcb2bcbec2d0a60661e1715c9a95c9d573a68": { - "balance": "346798292989000000000" - }, - "a7a6c0505e7090e0b2c21394877f91c50be6b45f": { - "balance": "4125233658872000000000" - }, - "a7dcdd9b9785a44a2dd4c5eeeb863ac1feae0f66": { - "balance": "10000000000000000000000" - }, - "a8013e9dca1bd38975748de2fb6cb3af5cae74d9": { - "balance": "10000000000000000000000" - }, - "a807bf78b15c15cd9e8edcf586849db716fedbb1": { - "balance": "1458293606310000000000" - }, - "a83410ff00fb4b913dd0ea2003b38c5c3247350a": { - "balance": "2876442029807000000000" - }, - "a848f61298a409e77a03900712017572f35a3319": { - "balance": "2783106133600000000000" - }, - "a85bb81d0dc57f824a763814759fd93fe3020569": { - "balance": "4558027813744000000000" - }, - "a860611cd098ce98974313030d9f6f462bb274d4": { - "balance": "961594154368000000000" - }, - "a8799eeff72929ee6cbfb5b0c02985cd4841be3c": { - "balance": "500000000000000000000000" - }, - "a8c29b9b1349fac0be9a65873e1911b7439c9a63": { - "balance": "1264035560749000000000" - }, - "a8c321024a3c015d881efca33bd1b2c1788b379e": { - "balance": "528752788000000000" - }, - "a8d02e8925ed48f4274d8bee62253dc0d4f2989c": { - "balance": "209083880937000000000" - }, - "a8d2bde2ccd6bad67ee1b9550c9310accb37cd79": { - "balance": "49000000000000000000" - }, - "a8d61abc6a403adc183aeb74c83e4221fd28ee1e": { - "balance": "50000000000000000000" - }, - "a8eb6aa5a0c5b6d9260a202dc76ab674d9a5f3b9": { - "balance": "1041257515142000000000" - }, - "a8efc57efc776dcaaf4003a8cfa63f215ab0284d": { - "balance": "166144142685000000000" - }, - "a8faba86d87678294e311cfa7f8cbeb6f9d8a499": { - "balance": "124541781000000000" - }, - "a912e02f8eab0cb620316129875f919455201117": { - "balance": "6454482105955000000000" - }, - "a929ac95281d1a77a3eda3b5ac90a761ef03ff16": { - "balance": "1074305309650000000000" - }, - "a92a4e40519003813f5574397ce328d046f75802": { - "balance": "9188437500000000000" - }, - "a93850ba8fff3bd18ab259f87c58bbce84165fff": { - "balance": "39018890852058000000000" - }, - "a9843660a17c2d972246028cb8045472abdd346d": { - "balance": "1052681604185000000000" - }, - "a9866c6271733971e46df3c9bb27b3d3c513c166": { - "balance": "200000000000000000000" - }, - "a9b1299c0c064e766f9f29f4301a78c6e4931fcd": { - "balance": "267785134400000000000" - }, - "a9bc33b9c99dd5a3967387c1e99766f9bc74d591": { - "balance": "65356157048000000000" - }, - "a9ccf1cd2f816b15182997e3207d9a681bf21b06": { - "balance": "17521053440000000000" - }, - "a9e54bd9826f853f65e0be1ec0bb9c28f95e0eea": { - "balance": "6260000000000000000000" - }, - "a9ef563c872342f49817a903a5725b504d455ea9": { - "balance": "50134015139000000000000" - }, - "aa0d69c7e1382cd16c527a3fee48db19c38e1398": { - "balance": "142562301500000000000" - }, - "aa12abcc3ab373d07bf560fd200652c8580fd967": { - "balance": "5509242259903000000000" - }, - "aa1d6b968b3f8046a94f128864bfc612fc2e2700": { - "balance": "489179780895000000000" - }, - "aa20b8559d6dd1543e8c528775ae4b04c6242471": { - "balance": "169000000000000000000" - }, - "aa227e9d6074a60ecd43e1cc24092ee58560374c": { - "balance": "596190898010000000000" - }, - "aa7b660fec7b05968ba656eae9a8aaef4481720e": { - "balance": "674642002744000000000" - }, - "aa9e04077d44d288978a3a3ab0d7c251c0447a4c": { - "balance": "10000000000000000000000" - }, - "aaaac1e72955e9d67625cf8bed73fa643fb1cc1a": { - "balance": "9781187987000000000" - }, - "aab46c0c2db4e330834081f97678906252746f97": { - "balance": "16440184245000000000" - }, - "aade5358c52b8aa5ad8ff285c6b297e86f49fa0f": { - "balance": "982846000000000" - }, - "aaedb3fa2cf0ebca0ef4a121a28a406264ccc900": { - "balance": "100000000000000000000000" - }, - "aaf30bf76362a03450aefaf5bd68d28b84eb4962": { - "balance": "509106199370000000000" - }, - "aafbaaa6b6369e986ba72b196bd5f08cc458e344": { - "balance": "216372214000000000" - }, - "abb03c888d61c9102827a1dc0950145beb9d96b3": { - "balance": "144000000000000000000" - }, - "abc6dc937d7703a6b0c83659a328cde0d5008e32": { - "balance": "4052429106341000000000" - }, - "abd3910139a97cb92dc09a8a0352575bcc9ebed3": { - "balance": "24028359215749000000000" - }, - "abdc3953ef293c98989802063f8cb55e0e506432": { - "balance": "64000000000000000000" - }, - "abf1a47c582bc87d36e47cfce24e0ad249f42e73": { - "balance": "71947491720909000000000" - }, - "ac0b6e7aadfb5ffafd5cb3ef3620ebb0691cc3fe": { - "balance": "10000000000000000000000" - }, - "ac1a182607046b56e7a4bbab87cc1182874f79ef": { - "balance": "453499500178000000000" - }, - "ac251b311f781ad7a43d01b0b4b20fe891004e7e": { - "balance": "304621378298000000000" - }, - "ac258cec5ef49f96612d659f66dd4e6ea88e3c87": { - "balance": "255185373455000000000" - }, - "ac4000d9ad080740ef4a2ebe4a3075877bea277e": { - "balance": "10000000000000000000000" - }, - "ac7445c09372f15259fd852cc458783d6140c0db": { - "balance": "10000000000000000000000" - }, - "ac8d29dc05ea6c2f5409a76abe04321bf9381f32": { - "balance": "22464474197854000000000" - }, - "accd52b63822d8cb5117d9deb56596e072462614": { - "balance": "20000000000000000000000" - }, - "ace63a86a2ddfc79f677344e93dc0c4750b8fdcf": { - "balance": "1355066360964000000000" - }, - "ace83deb83fa8d319979658592b75ed13bdf97c7": { - "balance": "20000000000000000000000" - }, - "acf91515df16b21f1e5f5474dbefe596e4929b96": { - "balance": "1153047238967000000000" - }, - "ad04381f7ba89220e8fcd7e200f98a476683a904": { - "balance": "2000000000000000000" - }, - "ad22225bf225d8f705f93bdcda8d301180ea28dd": { - "balance": "1272512717188000000000" - }, - "ad3f74034ff5ca89f97b2585edf12376820307ab": { - "balance": "12303261515593000000000" - }, - "ad43a3527ad2b9445417cb73cbcb42965a5f469c": { - "balance": "67607364133000000000" - }, - "ad61cf9bf560bd5da75d55738477bd9aa25fb0b8": { - "balance": "4358939446693000000000" - }, - "ad649e8a3e1436e0604b0b8c9b1a5f1c09e06d7c": { - "balance": "344000000000000000000" - }, - "ad6b584813814db4c72c4c7eb31447d224074b46": { - "balance": "18445595367000000000" - }, - "ad7d404afc67c0e457fd3ce142cd30b506408683": { - "balance": "48218702840000000000" - }, - "adaf4d39b6806d132128ac438c2862c0a1650cff": { - "balance": "500000000000000000000000" - }, - "adda124baed2e1fdc1acc7b4a048eab0cd249212": { - "balance": "1074765673925000000000" - }, - "adef437c429d90a350b99750d4b72bc8538c5f98": { - "balance": "931901903135000000000" - }, - "adf826a0ea7dc4322d26e9d8c54c4180c1827216": { - "balance": "323567723315099000000000" - }, - "ae01d8b1668f8bfe6e225bd9bc746f7e839ac0d8": { - "balance": "321211880744000000000" - }, - "ae17de3ae6127022e53ebcf9e08457174cdee0e9": { - "balance": "3817903000000000" - }, - "ae243b0186793eddc6ebbb1a2c1f0b1cd574b07c": { - "balance": "9000000000000000000" - }, - "ae3ae1d41dfb16e19a1817b3639cd4300fd166c1": { - "balance": "55437674845679000000000" - }, - "ae506999882d4c6f05cc7979c342c0ce559a8df0": { - "balance": "1391755905401000000000" - }, - "ae524cee5aa23025d6ad185ccab75a6974335d53": { - "balance": "797132751509000000000" - }, - "ae5a55075d0541f179b085152bfc8c72c74abe23": { - "balance": "589408139567000000000" - }, - "ae63d02b18b464f0bbab4de943766bdc7ba2926d": { - "balance": "300261019201000000000" - }, - "aed8ffb86a49c09ae3a83e93d9045851434a9f0c": { - "balance": "1031991707237000000000" - }, - "aee18a9a2ccdf6025d61005827753ce4f510f7e8": { - "balance": "1818639022863000000000" - }, - "aee67910c514fa63a228769d5e15ca40bc4b26c2": { - "balance": "5688989238568000000000" - }, - "aef744eb2ec682dca128dc3149afcf881e367121": { - "balance": "818801643225000000000" - }, - "af04430b3e40e746127623532353a0f177a88fe3": { - "balance": "100000000000000000000000" - }, - "af181833edb15c9b2ee2329dcf1845b977361b7d": { - "balance": "93228805338000000000" - }, - "af30db29765b4fda6f075af96e8acd5046b099c4": { - "balance": "1000000000000000000" - }, - "af31fd30cfb10f1b0a12c2e7dd7ca56bdf517745": { - "balance": "36000000000000000000" - }, - "af70d6820e1d26194b0a9965b55254a287b162f3": { - "balance": "87593999609754000000000" - }, - "af96a573fa86c07389a71db797bea689419b23ca": { - "balance": "36000000000000000000" - }, - "afa4c5b674934e31a9aa5e3e723d85060d51c4d0": { - "balance": "10000000000000000000000" - }, - "afa6e4b4060c2e5969c2329d13cc42924412efde": { - "balance": "127502378589556000000000" - }, - "aff2308ac607f85392f4c8a6a043af67b7b849cd": { - "balance": "11130371831000000000" - }, - "b00ea9c459105b650def1e8569c85fa01837454d": { - "balance": "94928352162000000000" - }, - "b02a7d16ea8663c88416e6f64eaf57787d230be3": { - "balance": "17215604601000000000" - }, - "b03f4e9aa5c352cb1cec953d1123c2f22cd94b5b": { - "balance": "206022552274000000000" - }, - "b051459b91d253c5e8251a5a68282c291833466a": { - "balance": "297127749975000000000" - }, - "b055bdc874ca5a7d2f4bcbc51f1cfc3671b55f72": { - "balance": "1421913523478000000000" - }, - "b06156b99b891b756262c5b40db9bbe39fddc77f": { - "balance": "49000000000000000000" - }, - "b076893b9841d2775ec8883f05b74f1e5aec327c": { - "balance": "22591055478000000000" - }, - "b095de644af3c9f960f67502da6ac5eb050a158e": { - "balance": "4958067562725000000000" - }, - "b0a1f794cf70422395f74395abc9a7d0b271846c": { - "balance": "812057322000000000" - }, - "b0d36e0f426a99416425689c657fc6d64ad698ca": { - "balance": "1157727077158000000000" - }, - "b0f35fa554d6ed657bf3996cc027d045c3971fcc": { - "balance": "64000000000000000000" - }, - "b0f76b4c9afdfe35c41d588265642da60f1b97d1": { - "balance": "1000000000000000000000000" - }, - "b0f76b4c9afdfe35c41d588265b42da60f1b97d1": { - "balance": "2028311808491377000000000" - }, - "b1445842d56c56bc532d2f33ab9b93509c732a3b": { - "balance": "13522982470164000000000" - }, - "b156bafe05973bc839c4f115be847bbde8a67cb1": { - "balance": "10000000000000000000000" - }, - "b182e4d318893dc1c4c585195dbde52a84ed4ffd": { - "balance": "329498977335000000000" - }, - "b18f506e77df4db80ca57cefeaca4f1010f78f50": { - "balance": "956339304078000000000" - }, - "b1b6f617b110dd79c8fd77e729584d1fdfa9aa09": { - "balance": "16000000000000000000" - }, - "b1bba36e2d9e272e0131f4bae09bcfd92e0a63db": { - "balance": "64000000000000000000" - }, - "b2285651e57ae0ff27c619207cceacd20884d152": { - "balance": "1345938295122000000000" - }, - "b2419a93732d0d324daf7707fac3782a77b0dff8": { - "balance": "625000000000000000000" - }, - "b27206e9f2ac430841fb8da69b49d505f1558b8b": { - "balance": "29507819229000000000" - }, - "b2801fe902c7bbc987ba12ecae98765c99980fef": { - "balance": "240016083000000000" - }, - "b2843d5215ceb761e78f281402a1660c3abadf5b": { - "balance": "3335539720927000000000" - }, - "b2a22e6a04a2ce3287da3b8b6eed4ea1f18f05dd": { - "balance": "99999978999999999999" - }, - "b2d55a061fc6f90d2a05e0cbd26ffe0a1c3321c2": { - "balance": "1000000000000000000" - }, - "b326aec1cd523948ffec2fd1e8f21bd2b4308f40": { - "balance": "913000000000000000" - }, - "b32abc82b251e2d310ea7588cae4ad4acb657cd9": { - "balance": "26946233911000000000" - }, - "b36924d578973aec05ce7ab556d7ed00004949ca": { - "balance": "393041705867000000000" - }, - "b37482114c83e857c730588d7d959d300b8142da": { - "balance": "29429544454000000000" - }, - "b39998bade135ac6ccadff41cd709e161d01aa60": { - "balance": "26272579375000000000" - }, - "b3a995ee94f1d63d12f10cea5ab3d596c7c6f284": { - "balance": "64000000000000000000" - }, - "b3bf35e936fdbb7d0bbeeb1cf076f243855ed477": { - "balance": "754081187934000000000" - }, - "b3c2ac85b99abed4a2a52b5f96a2c98040d16022": { - "balance": "50000000000000000000000" - }, - "b3d1a2c0ab2d8987446d74f49e357adf5bf15986": { - "balance": "10000000000000000000000" - }, - "b3fbcd24c8394a5d2b7fe877f18681a109a404e5": { - "balance": "2558689648423000000000" - }, - "b4110f4e38405adfc054e55ff73c55842db8e2cd": { - "balance": "129000000000000000000" - }, - "b417f4681fdd4e53cfdf8550e3d326dbb0a557ec": { - "balance": "1000000000000000000" - }, - "b422970fb8799d83642b7ff715fc941d69e86053": { - "balance": "81000000000000000000" - }, - "b4237be71920497715826eae8d85c26cb3c111a8": { - "balance": "10499979000000000000" - }, - "b431839de4b21dfb44150cfc6ed00ea430a81687": { - "balance": "26839560174813000000000" - }, - "b43a0d6399c7d1be943c4b45838156a47c88f909": { - "balance": "10000000000000000000" - }, - "b44ec608b95d0d51105ce5f4b48de5dd72f346fd": { - "balance": "448125120000000000" - }, - "b47f63e14f6de6c3413b2be95a725e367ac18fb6": { - "balance": "500000000000000000000000" - }, - "b48071cd1b15f45028e9dec2237f14f10b7aedf9": { - "balance": "38042711385000000000" - }, - "b4b874b323b560aa0e4811ca574bd48b65b3fc72": { - "balance": "18063913676592000000000" - }, - "b4e4d4af0667f8158cf817bf1bc3eada08a551ca": { - "balance": "2149067370317000000000" - }, - "b4ecd625ffe470ee1fa1d97832e42ddf3f9ddf6a": { - "balance": "1181738860120000000000" - }, - "b53f380ce92787c1db461524290e8fcede552fe7": { - "balance": "12640674931821000000000" - }, - "b547e04ab8a44d3cae38704356f1f59408457b67": { - "balance": "286604155735000000000" - }, - "b562e4010a0a5fd0906a4cd9f47fc28f6f51e210": { - "balance": "1000000000000000000000000" - }, - "b584de7b38a2a2e3d9ff9c055b309ca56e5da5a9": { - "balance": "237896887904000000000" - }, - "b5c1129961c4a43673324aaedb8296f5ade82516": { - "balance": "4213058948283000000000" - }, - "b5da6711c72bf27c87923aed4a39349b4192e6b4": { - "balance": "55180742586465000000000" - }, - "b5eac5e7e03b9d31e40393e16e956cd588cb7566": { - "balance": "4508019435556000000000" - }, - "b5fd46ee4e02946dca3485439f98bdab290c82b7": { - "balance": "108321600045000000000" - }, - "b5ff2a3caef6ec30365f4f0ecbecbdeec1cacbba": { - "balance": "979696597242000000000" - }, - "b609d05242f7c13a4ae4036f6da9c0bae18dd70c": { - "balance": "229121731278000000000" - }, - "b611156a2f87fb45c431a5cf5740ded90c2dc542": { - "balance": "401783365700000000000" - }, - "b61c7623144afbd0f6cf44c951e4219ef8096119": { - "balance": "36000000000000000000" - }, - "b61cbe0e58ff6fa4c810ad03c759c79d9ff052a5": { - "balance": "1034495371371000000000" - }, - "b622bb67e95a03f58dc9aecf82c217e86f2cf7c3": { - "balance": "500000000000000000000000" - }, - "b62a50be3ce0e7cf8f61991daf8fa7e23775141e": { - "balance": "1000000000000000000" - }, - "b63cbff6b1747ad5cda101d5f919ce81dd67e363": { - "balance": "2570089937000000000000" - }, - "b65e80551a8687c9cef2d852949177c0e3b56e51": { - "balance": "100000000000000000000" - }, - "b68126ebbcb5ab9b0371b62597a38d5c1685b0df": { - "balance": "671140851028000000000" - }, - "b69f5830c371cad5a74ae823eb8892d153ef3c23": { - "balance": "18446744063709551616" - }, - "b6b4468c4db64e0b85cddc251d02f32fffcd1f7c": { - "balance": "10308006217291000000000" - }, - "b6c129312505e571148dbe69833d30550efc12c9": { - "balance": "5105834767567000000000" - }, - "b6cee8ef00b8674a9a96447e4511b30d6564ff67": { - "balance": "667754569888000000000" - }, - "b70f805aeba260d44f0730f0a9dec60f2b4f54a1": { - "balance": "2751303297000000000" - }, - "b71a901dc4b6c6463f7d221f868677bcadbcc680": { - "balance": "169000000000000000000" - }, - "b7385bd8f8257331f4c7a87c7a23724f615cff8e": { - "balance": "196000000000000000000" - }, - "b755692bc027e30730dc1d0e0b2a883830a84115": { - "balance": "30713083153428000000000" - }, - "b765305dda3c1e069a7a022ec127ff2140d0a820": { - "balance": "603122990932000000000" - }, - "b77403a4c56ffc7715b4bfdfe4b054336aeca466": { - "balance": "130840969728386000000000" - }, - "b78b2f6dc731d7d84b7eea151805f9208a1d0cf0": { - "balance": "142084687500000000000" - }, - "b792a0fd762c002a7585cfdefd36cf7ffb42fc05": { - "balance": "10000000000000000000000" - }, - "b7ccd7164aa7fb871726d9d043a8f8f890068c0f": { - "balance": "1170997140237000000000" - }, - "b801f49018317caf30f310dbe116f4e876184874": { - "balance": "50000000000000000000000" - }, - "b81ca2bc63cb4008cebdda3ce8f4eaba322efca6": { - "balance": "4678481047354000000000" - }, - "b82e3d50bf8c5b471c525ec8dd37b06688ed6178": { - "balance": "1202448975553000000000" - }, - "b841162a7a8876296f10794d8847d8095426aa54": { - "balance": "73500210754000000000" - }, - "b8421d375c3f954e22b6fd304235dd7c43b68bd0": { - "balance": "6499782706009000000000" - }, - "b859b76d77eb604728093c61fcabe6f9d22433b0": { - "balance": "196000000000000000000" - }, - "b86536268ace9be93a1db2012d6e3e59023ef2cb": { - "balance": "52878034904067000000000" - }, - "b87e1ac4fc423ab37e10ffd221df8056537b1d03": { - "balance": "119159824674000000000" - }, - "b8825a99806c5a968423e69d22f2b61a2f0ae9e4": { - "balance": "999999999580000000000000" - }, - "b8835acaf63e0e5d41fb743eb0f954040a38d381": { - "balance": "64000000000000000000" - }, - "b8844c74b227781d4b3fafd32e39ff6fa9857f77": { - "balance": "490694157000000000" - }, - "b8962e8bcbcf0f69144f8fcd2ec3ae8e54c05034": { - "balance": "1425313342735000000000" - }, - "b898b4ece8e0eea375f6eb85615652cc5c221593": { - "balance": "2284038029169000000000" - }, - "b8a949bfd9751c29c4cd547cca2e584d8dac4e12": { - "balance": "50000000000000000000000" - }, - "b8ad5ce2ae781e2d245919c15bbbc992185e5ada": { - "balance": "733786526623000000000" - }, - "b8cb6a9bc5a52b9cfce26869e627b2af0ff5ed4a": { - "balance": "98364826821577000000000" - }, - "b8cf6aac7b9028649f0d55a57b61640d70cef120": { - "balance": "104799890645000000000" - }, - "b8e827b5d1e10a3944039adb1a3dd7ff6949145c": { - "balance": "172413427060000000000" - }, - "b8f6d7f33ee5755ba56647ab8fc9ca27b8aba677": { - "balance": "1430769696978000000000" - }, - "b9221177e2b09725bc95f08c72c17c42887eea62": { - "balance": "1212779749827000000000" - }, - "b936e0d83cde9bb810b85ad58eb5ff0fa9c11654": { - "balance": "4999580000000000000" - }, - "b961d435c457e205fdbed5442c8614ecfd59616c": { - "balance": "27847452621284000000000" - }, - "b969e9d89f32002cd4f90ef5907bebbbdca6fe6a": { - "balance": "12455448454838000000000" - }, - "b981c9137cfca5389f0123927852278d2d7ff618": { - "balance": "92180707865000000000" - }, - "b98abf0fe91b0d3a16c6ed37aea446baea33fd23": { - "balance": "560454425563614000000000" - }, - "b99ab4e6ae277b9fb04537adbb781e8390b490ad": { - "balance": "32814665223319000000000" - }, - "b99d0a433d7994743dd675894c18ed03164436e1": { - "balance": "16000000000000000000" - }, - "b9d8b6f0a505d217709bb9327f3b9b3f84813e00": { - "balance": "81000000000000000000" - }, - "b9dbd64e3c8e6ad84c9c67c66e678c06ea7bcb91": { - "balance": "1161140466507000000000" - }, - "ba361f7a6dff16a96f957c63e08267dec8f9ecf7": { - "balance": "2170060167590000000000" - }, - "ba47f4136f74b566f62ba373651332b59e74e1db": { - "balance": "906249296535000000000" - }, - "ba5287cf15de91daeaea2465da4d4c1a14dea716": { - "balance": "98978398162000000000" - }, - "ba77d056d52f84e740579aa527792f826591c858": { - "balance": "50000000000000000000000" - }, - "ba895406774ced5fd2e759b58f9ffaed5e04fb14": { - "balance": "10000000000000000000000" - }, - "ba96fab21a4926fd1137558ae996b52ec14538a6": { - "balance": "10000000000000000000000" - }, - "baacc247801eddbf152fd6ec39d659f265935743": { - "balance": "2661902597584000000000" - }, - "bab2eb9fab8e699a958699b15ddc7ada5428d33a": { - "balance": "27006404153000000000" - }, - "babeacd7933c817472875c86bf126e6d11886f8c": { - "balance": "2461234517292000000000" - }, - "baf7021d4d754d4478d3c3624c2376e3f1d4ee5e": { - "balance": "1352066301857000000000" - }, - "bb0760bd1da973d8f70dd0caa6cadfcfd8199231": { - "balance": "177674700430000000000" - }, - "bb278c6a52eebd0b8950e9b78ba211453ccb1b6a": { - "balance": "25000000000000000000" - }, - "bb327e5f260b2dfe25fb180c2d3f4b63211c1dee": { - "balance": "7694972715000000000" - }, - "bb643e768ab20c135e7df3f400284cf04c40a6f7": { - "balance": "385756449779000000000" - }, - "bb73d1d1c289b4953d0033b52d9d2d0d92573d22": { - "balance": "11000000000000000000" - }, - "bb89936d562b19e4c599826ce7cd0c60cb02b512": { - "balance": "725910446589000000000" - }, - "bbc509b7999b0e94534477b98ec8927cba879677": { - "balance": "20000000000000000000000" - }, - "bbcfa9ab62f4eab14d6a1b09c1aa554dae113183": { - "balance": "589417352665000000000" - }, - "bbe78301134249b52b74d73ee3855e7e3d288a40": { - "balance": "4456159000000000" - }, - "bbe7bb4c4f1b506b58f7e3334e6c89011cf2d6a7": { - "balance": "3889127030000000000" - }, - "bc016690596e077273465d1728d18553b185654c": { - "balance": "185932953686000000000" - }, - "bc16b2ab9c7ab309249f93b496b75c6a7392cb10": { - "balance": "5000000000000000000" - }, - "bc254e5405b154b98abb5fe5508d3e7c98663f4e": { - "balance": "144000000000000000000" - }, - "bc258aeb0f18150d3ca253c6bb04f63d657d99ac": { - "balance": "6011905701701000000000" - }, - "bc2620b5ebac12a88b287b625fa5b336568e7869": { - "balance": "534886892259000000000" - }, - "bc318687cfaae2be4c5ece4a18bb9252486a19d0": { - "balance": "147226513970000000000" - }, - "bc32dd123fcc2ef0dc36484c3ab1bae5d9890761": { - "balance": "16000000000000000000" - }, - "bc5c5151be06aaf6180bc9c1058b181a5a30366e": { - "balance": "113865120384000000000" - }, - "bc66241ca430dc31a3e2f44dedba868e16b9a6a1": { - "balance": "50000000000000000000000" - }, - "bc7c371af0688b1c409f4b07662609a1c9efd120": { - "balance": "20000000000000000000000" - }, - "bc9454f7efc86e25d18a8e8b6e230de42a51d967": { - "balance": "148103676062000000000" - }, - "bc9d5456b975bf0b95c161c3355e4ceb28898fd9": { - "balance": "28083912047000000000" - }, - "bce0b47bf13e4517c53bbbe6e51544b99f3147f6": { - "balance": "919711480389000000000" - }, - "bce2d1ec7c41b426f72b352f5f2b7da3edac4157": { - "balance": "908085365725000000000" - }, - "bcf0756789a57f16206dd78bf6e1322ba9b9b85b": { - "balance": "110888224252000000000" - }, - "bd0bc4a0730f9f55a2f65f62662c7553db52238e": { - "balance": "8440290043000000000" - }, - "bd29fda37c2581a3f040c77eead3143cff24a346": { - "balance": "126022762542000000000" - }, - "bd4c1270322a26a1b825040b239008a447c31918": { - "balance": "727012140904000000000" - }, - "bd6a3da2db66dc9fa26fa2b63b14003d26ef91d0": { - "balance": "5492112771780000000000" - }, - "bd80fcccac60078fcf09f5bddd8a25a92fb9cfdf": { - "balance": "10000000000000000000" - }, - "bd92dc94b6e81a3da5dc3ae6bd80782622658196": { - "balance": "10000000000000000000000" - }, - "bdb35c2c595fe7a2864ebe20dd56d6ddaf9d447c": { - "balance": "4346566125000000000" - }, - "bded4718cbad2150c9b6df9ee7356e0f5c713cea": { - "balance": "311694803600000000000" - }, - "be1804630ecd95ac411b935566cecc5a24c6f18a": { - "balance": "85033246331000000000" - }, - "be2318ad50b0a85b95870a81dce5c31029636159": { - "balance": "5185298019030000000000" - }, - "be3de52fc1119f02f4707f353c040b7c4222d847": { - "balance": "25267399461000000000" - }, - "be4feae01d429c872601ae84dfae8fddc3372686": { - "balance": "20000000000000000000000" - }, - "be7c09d704d16e4b2c9e19cc8c07808bb335f926": { - "balance": "25000000000000000000" - }, - "be873a9525899bdad5e4376b0115950e534dea2f": { - "balance": "404116929377000000000" - }, - "be891b1680ad835aab1ac05a30c0813306cf20f2": { - "balance": "144000000000000000000" - }, - "be8ed2d85a5e3f83c6105db1a1f304e9f174bfce": { - "balance": "50000000000000000000" - }, - "beb1cd80c2f8fabc27ee3a3b2a15e35fa52e7879": { - "balance": "11539095431000000000" - }, - "beb67375e46950830906bf281209be133075452f": { - "balance": "1305262446956000000000" - }, - "bebe54437722c6000bc6a8843f159538a2abf613": { - "balance": "41042548942568000000000" - }, - "bef2a05e283ae948efa9b0e3a6ab5d26a57f1de0": { - "balance": "180614450853000000000" - }, - "bf03950f265a4182b4402703723a0311158eef4f": { - "balance": "158997402149000000000" - }, - "bf06393654baa1ad15c2e717e06dbaa61834c214": { - "balance": "34409427774000000000" - }, - "bf2b867313a44bd04aceaa644771d1e95317c881": { - "balance": "10000000000000000000000" - }, - "bf350ccad91a2a2aff4cf27a291323a297a78009": { - "balance": "124593326152000000000" - }, - "bf3d86edfcf52733e91a9c59be606a95bd921885": { - "balance": "20000000000000000000000" - }, - "bf5b21d5e339752b33b180064d0e6047338650a5": { - "balance": "1000000000000000000" - }, - "bf64c2715db8f353600a45b9264e1f22a40ef8c1": { - "balance": "2952972677360000000000" - }, - "bfaff32c8b04a61658ff94f94e4687232b8d2d7a": { - "balance": "1117691379350000000000" - }, - "bfb00182321502e0729d9a0862ec1df1b3e2208e": { - "balance": "500000000000000000000000" - }, - "bfcdfc9f60610f0ca279ca2c89b9af831332aece": { - "balance": "1431082635308000000000" - }, - "bfe14356e86f6b2ad470bc77d250517c8dc03d15": { - "balance": "310115085185000000000" - }, - "c008bd3fb881da9dca4cadcc56b1d99c56db9abd": { - "balance": "12899598792000000000" - }, - "c01efea456d30360a78ee10c790d46bcb889ee61": { - "balance": "103203021492000000000" - }, - "c03d622627bba7d5db1a9f699924e9d5ff5640f2": { - "balance": "95102233308870000000000" - }, - "c0465ed806ce7ee730e5b6eb7b86a754bfd196a9": { - "balance": "1654379359619000000000" - }, - "c061c5b0d0ce7af95ded1805abb23f743e13c455": { - "balance": "500000000000000000000000" - }, - "c074f2024f79cf8d7aab2d858dd110fc2ee89d41": { - "balance": "18382732686000000000" - }, - "c085147a76d0336b4bd6e7d5b60d394bfd3c6f42": { - "balance": "3236912707535000000000" - }, - "c089416d2d679cb2abf44251de227d0a08fa1206": { - "balance": "497124416350000000000" - }, - "c09d8cfd85989397dc723f2df821dbfb2c0c39b3": { - "balance": "833485701262000000000" - }, - "c0aaf130e3b67250d9775d62e7cd3963daf0a627": { - "balance": "1249947125780000000000" - }, - "c0aebdb5c2e8c5ff9870535c738bfe892c9365dd": { - "balance": "360097616959000000000" - }, - "c0db5680ba88052652bfd5a617c4e8a5be188077": { - "balance": "509051625766000000000" - }, - "c0ee350e5e09a2daeff332a66a6e117fad102112": { - "balance": "10000000000000000000000" - }, - "c12c0a3fd42501f8772e4ad5d262eef3f0bc4701": { - "balance": "120398848512531000000000" - }, - "c135b48c7fd11670bbfba923b28767d21d7923ea": { - "balance": "20000000000000000000" - }, - "c1397c66b7f150c0062b0e87c981c107d771b109": { - "balance": "87751498250000000000" - }, - "c1507ee435cf506fc5d8e4cb62515f2ea0f3a7ae": { - "balance": "4935384099000000000" - }, - "c150d185e2cf203054a6e328b72d8c35bfbbcc33": { - "balance": "21044148271000000000" - }, - "c163098f8b8f0736862274860b3842cf14bd2288": { - "balance": "119025568966000000000" - }, - "c1687fbbc7d504b73fe3e71af440b3dec0da88b2": { - "balance": "229520711528000000000" - }, - "c172bf224080d448261b3b66453074b28628daf7": { - "balance": "7903438287958000000000" - }, - "c18e9bc05dfee2a39fe2b6778a24a48d5bf0f141": { - "balance": "500000000000000000000000" - }, - "c198fec4069c95300d34b9c7109d7441b8e62745": { - "balance": "50000000000000000" - }, - "c1b4134f4757d19a687d05bd7087872b5625405f": { - "balance": "20000000000000000000000" - }, - "c1b43ca2af534ac6bcad8f23c30c07ba07e7e8fb": { - "balance": "194999622000000000000" - }, - "c1c2249507d2dcaf4a9103fcea2cfb47aa4957f7": { - "balance": "571416394325000000000" - }, - "c1e90af40fb64427aeb79a13607debbae9270b52": { - "balance": "50000000000000000000" - }, - "c1ffc8938f3412d19d428b8450f17fd394ae539a": { - "balance": "36000000000000000000" - }, - "c20013e25ae53d0d41bf365aa767822bbbe70936": { - "balance": "10000000000000000000000" - }, - "c20e9eadffa5529ce58a39f5898f39906dcd4b78": { - "balance": "757301065305000000000" - }, - "c211fc2623d51846d26952628d140643efa5156c": { - "balance": "865384323985000000000" - }, - "c2546c312570b30ad2ed05edb13b6469494c5b92": { - "balance": "5000000000000000000" - }, - "c25b2280ed0f835538f8ffd9dfc08a3b853f1ccf": { - "balance": "1000000000000000000" - }, - "c260e43b89a7a4e84bcc4c21dc43d4b5e6923f3a": { - "balance": "1000000000000000000" - }, - "c26aeef0e1f382c88bbdb1eb8c01afa7f58218ce": { - "balance": "79774757760000000000" - }, - "c27dd2645254bc30b6cf7bf418803b02ac808b5e": { - "balance": "4419594173874000000000" - }, - "c2b4f6cf92d6d63a20034e409a358df1803159b8": { - "balance": "1630820442000000000" - }, - "c2ba4a7ea6ca2d17231fb17ebd5dd2dfc0964de4": { - "balance": "221662324727000000000" - }, - "c2bc18f24b8097208a8b2418c444ea58beb94281": { - "balance": "1766754009521000000000" - }, - "c2c028dd17f8a89b9131b7daaeae9cb1dddf86e7": { - "balance": "10000000000000000000000" - }, - "c2ed78a0cb850c12ce8e6ff3873e8c18ffc9f4b9": { - "balance": "1017518755567000000000" - }, - "c2fd7296210b7013d476205d2517d51b21c9e76c": { - "balance": "500000000000000000000000" - }, - "c3041d3d650ff6ac3e35b60371b6798360727651": { - "balance": "1011071365226000000000" - }, - "c328ab9ce1fddd5623e0383828714a7e3ff12eff": { - "balance": "285042661579000000000" - }, - "c34ab008ddddf376dd866cccae4a4d6eb88403e2": { - "balance": "2798642711076000000000" - }, - "c3511391c4515cf8f27e9bc0f777a02a4125c8b1": { - "balance": "20000000000000000000000" - }, - "c36916a9fdf656bb1a8c2f7fb752a3489020f6ff": { - "balance": "689483152953000000000" - }, - "c37598a388d6f4e8e046923265ee9256456e40ab": { - "balance": "62865106394696000000000" - }, - "c38813db256eb221a7142d042b81ba2babab2c31": { - "balance": "98477603778000000000" - }, - "c3acd30f0bc3146fc2cab8d54904f98289021374": { - "balance": "17820000000000000000" - }, - "c3ede34dc1cd995fda1c5cb6e9ffd0c0da080587": { - "balance": "1080428143758000000000" - }, - "c3f04dffe2be55a1d6cdaa78e5c09a79d0477e7b": { - "balance": "59747493842929000000000" - }, - "c3f09f681cfb57d3cabc547dc32a71d2a6585c1a": { - "balance": "1757648436173000000000" - }, - "c3f3bb6444d853614f18c04a3c81f7d26e62e96a": { - "balance": "9022830778000000000" - }, - "c3fe4534327a2fc4144e2d3d3392f7b78d2aabc5": { - "balance": "1759225739027000000000" - }, - "c424f5be9490ec7f0f1e2debc3f72bd83e35f587": { - "balance": "1774372626989000000000" - }, - "c434f64eb937207f80e9a02d2f77ca34bfc63aa2": { - "balance": "960850858644000000000" - }, - "c438b6fa5801a4b8dea450530d975f174cdd47ef": { - "balance": "64000000000000000000" - }, - "c446effb984ff3e5ed92280e7b3dcdb1284230b3": { - "balance": "503490303680000000000" - }, - "c453ae9f94253ebdb871e9dac19056b13d1747a3": { - "balance": "1621494076559000000000" - }, - "c4a473b5e3a6bfb51f963d4dcf109bddedf4fb43": { - "balance": "104273242373000000000" - }, - "c4b8058e9e5416e526ea16e37f29dc221d28a003": { - "balance": "1833513486496000000000" - }, - "c4c09f4bbae0ee06f2a52ff0ef0de1978b5305e9": { - "balance": "20000000000000000000000" - }, - "c4c5981f5ac0a9a3701663b887c4aaac3a3a4d1d": { - "balance": "1411640000000000" - }, - "c4f7a493d16aab4d18e88e530e75e3095a3439ee": { - "balance": "191606419322000000000" - }, - "c5259c18bbd8b0485ca83d069d5ac235b28f24ea": { - "balance": "1276479076242000000000" - }, - "c526ef1124c7d0549b117e7b7463539a24209290": { - "balance": "9106523141000000000" - }, - "c5278b9eeff2221604f30f002c307ca2882fba97": { - "balance": "20875716591000000000" - }, - "c527ca73562846de9fca1649fe5144e5068a2f6e": { - "balance": "25000000000000000000" - }, - "c52a960c5df55169ed5d5cb0109a576321ab82fa": { - "balance": "1097338876493000000000" - }, - "c533ab799e5a04e0ba4e4780d632e0044262d216": { - "balance": "200529941482000000000" - }, - "c5389e3ee2f043ac2b6481f254440a97a9cf3bdb": { - "balance": "84047554571000000000" - }, - "c5594292b324c1d63f797c588a589c895c680ed0": { - "balance": "334298857161000000000" - }, - "c55d7ae4f29d857182d5f1ac2a78cbf35a694dc2": { - "balance": "500000000000000000000000" - }, - "c55ead0ece8fcfbecc573666c0170228e089aefb": { - "balance": "438775082956000000000" - }, - "c55f7d73491cdba391b631581029de32755a09b8": { - "balance": "1340000000000000000" - }, - "c56cb4e8308d6462eded0bbc74965ee135e23e11": { - "balance": "568187503785000000000" - }, - "c5b0c5f840f579536d5977a77262458d72ef1490": { - "balance": "5880686297881000000000" - }, - "c5b129c764daac8bfbf023646b9306d817a8ebdd": { - "balance": "10000000000000000000000" - }, - "c5bba43db949e2ed3de3036caf7a6e42558b1ef2": { - "balance": "763947031151000000000" - }, - "c5d57171e5b9cbafaba7d2c13cca3ec9d81bda49": { - "balance": "25000000000000000000" - }, - "c604e6c539c857ae9e60ca20d1906308ba431892": { - "balance": "100000000000000000000" - }, - "c607bdc5ad2f189e9356edb4d7975c7ba9300836": { - "balance": "55828814399000000000" - }, - "c60b0d2341ecada6c3faf1efcc9027125d99e17a": { - "balance": "121000000000000000000" - }, - "c61e1b993c3fd91a1023ba5b92d06a0aa539d92c": { - "balance": "23863993763643000000000" - }, - "c624656ee5298786cb3d0de045b0ac089c5341d6": { - "balance": "2210389938000000000" - }, - "c6573a023d6f4b5e151f266af4ec0045df0d1518": { - "balance": "52505006485983000000000" - }, - "c66b1d84c42018b16dbc4777409bf50a49febba9": { - "balance": "9078953000000000" - }, - "c69e4de93457f251b1e0879b5250b26e57839fec": { - "balance": "500000000000000000000000" - }, - "c6c51205c9f0bcaea05dce8e47e91d94a3f63c2a": { - "balance": "2720612321571000000000" - }, - "c6d237e0936c4714e701823aadb368fdc471451d": { - "balance": "541700595551000000000" - }, - "c6dcac15739872089cb3d23287e8cd546487ecf2": { - "balance": "1023857245227000000000" - }, - "c6f40b81a5860dece34305f53570be61cdf9a8fa": { - "balance": "20000000000000000000000" - }, - "c7147a95cc4f6bedce6292e8f95539caf550e9d6": { - "balance": "20000000000000000000000" - }, - "c7185b1a680d8b0893065d8213de54375d086420": { - "balance": "11564622085000000000" - }, - "c71b3876613c928197aadf3dd7888db3665f28f0": { - "balance": "112276274428000000000" - }, - "c72200bb380db62a3fd741713d332be77bc1a4ed": { - "balance": "6962060809000000000" - }, - "c7345cd5a7eafc9d7ebdc17d674f83e23336538c": { - "balance": "4425703195684000000000" - }, - "c734f9dc3ee2d857ac826b101129eb77a4a22256": { - "balance": "100000000000000000000" - }, - "c736fa9550b73f4a4ca0ac1cd94bf6f42ccbb11b": { - "balance": "449139000000000000" - }, - "c74128ea37f5d1ee016086a38e470bb332eb5270": { - "balance": "40479951869000000000" - }, - "c7647ec91e823cfe57e8a3433ddafd7b4f675b80": { - "balance": "307102062000000000000" - }, - "c76d49334ce25f5fc62841e5a87d4e03ab3edd9f": { - "balance": "109999979000000000000" - }, - "c771093ed5c4df518536b76e013e8142ecc3f9ed": { - "balance": "5247752820195000000000" - }, - "c780dfb4cdcba4dc89245a8be8a93de1a3e82d3c": { - "balance": "205580199482642000000000" - }, - "c79c6c3a0a46052f723a26b1f107a332474df3a1": { - "balance": "50370325181000000000" - }, - "c7a4e02d2c0f00fa56662cc9f323cabeff82759f": { - "balance": "1163435680762000000000" - }, - "c7c0632cff11812130c30163c83746839a625f95": { - "balance": "10000000000000000000000" - }, - "c82238664bedfa8ded51e91969a39f13a8262a37": { - "balance": "10000000000000000000000" - }, - "c877d228c350ec0d8d97802e7d874d3130171813": { - "balance": "199845203467946000000000" - }, - "c88b8a2e498fee366a1290a575a7f09da12ea8b2": { - "balance": "50895598476000000000" - }, - "c8bbd0e52b11ae6a20adc5f6bbe4d34d7440e8ca": { - "balance": "114566193776000000000" - }, - "c8ca2bd1bef02b505f0333996bcb6bf730648390": { - "balance": "1177250974576000000000" - }, - "c92c3358910418fdb3950e1a378af7246553ae38": { - "balance": "81000000000000000000" - }, - "c9325c9b6d2af226bc5ae1cc975e00cc11274cd1": { - "balance": "2927587698197000000000" - }, - "c95ae8dbc8bb075e7dcb2b2c6d9411bedf26244e": { - "balance": "931878010706000000000" - }, - "c98fc33c1d980052d75fee8b34d08796734b6a4d": { - "balance": "8671327034000000000" - }, - "c99fba8321d16cb19c55703b407c54ed106dcdc4": { - "balance": "20000000000000000000000" - }, - "c9a0da2a3be799e751738e61b9cc376eb06e2b00": { - "balance": "50000000000000000000000" - }, - "c9afc551058c32e89bc2d6704d0d00e92f5ef6d7": { - "balance": "11135553563900000000000" - }, - "c9bfa2ad4b3e9c624255c6ede116421b04487d65": { - "balance": "105514983171000000000" - }, - "c9e4b61d8ddeee339e31ba088efb5d608c3464a5": { - "balance": "20000000000000000000000" - }, - "c9e9090d9f95f401c87c7240f3bf88ca9b540f8b": { - "balance": "553735838243000000000" - }, - "c9fd40bb35284e3d7f0dd3b43a1d9e958f7c86e0": { - "balance": "50480449695128000000000" - }, - "ca038c7c9e66531ad79e4d67b42d7920b7f05c26": { - "balance": "64000000000000000000" - }, - "ca0d08f6019884f94f2b5b191ac9bb247150cd13": { - "balance": "25078089364984000000000" - }, - "ca2c6e6ed3d6a1d030807f91e1fd5c79d36af86f": { - "balance": "849454139892000000000" - }, - "ca7c7bbc24cac0f3aabfdccc77df21004672e634": { - "balance": "6952718700000000000" - }, - "ca998c74383b55c8dcddd46b49f95456fb056b7a": { - "balance": "2000000000000000000000" - }, - "caa989e6a1e934532aaae6cad282c18b1a0b9fd6": { - "balance": "2335540529729000000000" - }, - "cab32ee5cce74e0ee88bbd4b505aa587ef2e4bbf": { - "balance": "75914058971000000000" - }, - "cabe9f0d0a18de8d3495dd063b04c6a33584a8c1": { - "balance": "116083536145000000000" - }, - "cacde94daeafc06e46c86b1e20387a23d909ace8": { - "balance": "1521003430346000000000" - }, - "cafbad01b81ad6cc401883773994a9dd6e6ed913": { - "balance": "10000000000000000000" - }, - "cb343b882cfe866f73cd5f0f31fc68cebaddd882": { - "balance": "221801563082000000000" - }, - "cb3a7aa2e97517b6ea8d9ed0ac270a6a9cc6e079": { - "balance": "958830201738000000000" - }, - "cbd2c4916211ab2c234bc8a51e6f680b59aff782": { - "balance": "24279462419000000000" - }, - "cbea4ed5e8d2ffad442e482fa5f8d551ef2a58e6": { - "balance": "26730000000000000000" - }, - "cc001ce4f4417505116486bed9fdf04bf97ca246": { - "balance": "31740534557000000000" - }, - "cc0b53b26b6dee9f8226f25b834085bde13f5eb5": { - "balance": "132440104515963000000000" - }, - "cc174862456f02f349303d1b8328495de8ccd789": { - "balance": "155951512603000000000" - }, - "cc2af3921727d6d2de31d5f656f837a5475de6cf": { - "balance": "10000000000000000000000" - }, - "cc3201749f55f0d7b450110bc11f65b1ce165d2a": { - "balance": "123428947550000000000" - }, - "cc3f37ad6b449e39c544e26bbdf4d7be66b9dab0": { - "balance": "348574664284000000000" - }, - "cc5b36c9ecea12ebfd0721a58ac11b0c340a3f44": { - "balance": "384197170701000000000" - }, - "cc5b410c7797faa05ac4233eb31b468ee4bf279f": { - "balance": "10000000000000000" - }, - "cc60b223554cc6425374c5e2424df7007621368a": { - "balance": "1128118098000000000" - }, - "cc7027381d98c2e883c82bb9c2f85b985e1e7b4c": { - "balance": "1370000000000000000000" - }, - "cca378f16e07258b9c15921233110fb4729645d2": { - "balance": "151974946930000000000" - }, - "cca781d996c3ef985bf7d2b4d68d55f52efe1905": { - "balance": "2217463190039000000000" - }, - "ccd0b9f6ffb0383553c355c6a14be1200966d47d": { - "balance": "12917165349191000000000" - }, - "ccfa4594129bbb9d07cb4ae8dc2b1c8f3bf98508": { - "balance": "524845286088000000000" - }, - "cd19c879df458106d179bbb5b7f44609d68e6e5f": { - "balance": "8601633489844000000000" - }, - "cd1c55037a0570e8f9aaa95ef157ae81a1969250": { - "balance": "10000000000000000000" - }, - "cd1e47695b0fc93b82cffd0326852dc04d8441f0": { - "balance": "144000000000000000000" - }, - "cd1f90c388d76b3aeaf77850f2191f12a2311f51": { - "balance": "1728456799866000000000" - }, - "cd3aecd58de07f80b64044875fa6ad4f18f72789": { - "balance": "2648597880142000000000" - }, - "cd4f39123ece1e0ab52cfa2a5d059b49c4d63c3f": { - "balance": "1661718859439000000000" - }, - "cd6ed2f7ab49515f8fd70aeb4d72bfae8956b5f1": { - "balance": "183807926254000000000" - }, - "cd9d9d07fcf476a8ee7240324a602449606d75f4": { - "balance": "100000000000000000000000" - }, - "cda66d375a10a22f13dff8a9c40b63461daddab3": { - "balance": "1116940051064000000000" - }, - "cdb0832ee5b26da24b1775c4cf0dfd669b94ce00": { - "balance": "23919219542965000000000" - }, - "cdba5805f17df1f3e47647464de978944ed36b62": { - "balance": "4204539000000000" - }, - "cdd1df8bd54941e26ea26eebbd537e751f64f5f7": { - "balance": "5000000000000000000000" - }, - "cddf5b34342200c37ba96eb0dd662ca4c29f89f8": { - "balance": "10000000000000000000000" - }, - "cdf6c838980afd91a600e3fff755a4848d138568": { - "balance": "25000000000000000000" - }, - "cdf7f55a5a16572d2f2bbf7faeffe3c4d64f86ab": { - "balance": "3115969322502000000000" - }, - "ce0f1dbbfa3490a21ee4b28232db612f44bb7bf1": { - "balance": "9227310122000000000" - }, - "ce33184573c33dd859450304984fa63ea4f2b62d": { - "balance": "7055925237496000000000" - }, - "ce33a3db107f01c51d30b24a8db80faf05308bb7": { - "balance": "10996113113089000000000" - }, - "ce4922b3daef62914f0580a55c524e6a02e31d83": { - "balance": "5541295938315000000000" - }, - "ce4ce8a8540678dda16380c211482dd8c8b71092": { - "balance": "6224176337062000000000" - }, - "ce62cfd71abb9979a0acc398c17dbb5cb6da4721": { - "balance": "13448605175000000000" - }, - "ce724bb30c7821a9c847e0a3e9c12843c3471f9d": { - "balance": "252657175031000000000" - }, - "ce8af01494c2c5b4e74bb02dc6de982e7234fed2": { - "balance": "77349533545000000000" - }, - "ce8c774b7f92045faec43e9cc1711224a3b32435": { - "balance": "370287579971000000000" - }, - "ce8c9ed5018559f36ec72e5a9b0701724e498b51": { - "balance": "142866501748000000000" - }, - "ce995c13568a8b1521d4c9721cfc11da4891860b": { - "balance": "1000000000000000000" - }, - "ceab9dddc767a9651e98527fcf51f6e85c9ae402": { - "balance": "5251411770975000000000" - }, - "ceace25f8c7cf853500a461df007f9c9703ac4a5": { - "balance": "1428847332255000000000" - }, - "ceb0c49dad36f6169ec82a2f0d80da36c87e4209": { - "balance": "459821324064000000000" - }, - "cee8083233bcb4d50ddbf2121c90b5c2019ca58d": { - "balance": "557985245088000000000" - }, - "cf0c6bcc66eb75899bc7f8ed4b8d2b29437bfe85": { - "balance": "3252418478000000000" - }, - "cf32c5bf1d7ef0cb0f2f190f8468b01a4f2d93e2": { - "balance": "6593164924646000000000" - }, - "cf6e47463382153fcf0ec6738880925dbc08116a": { - "balance": "1091910654350000000000" - }, - "cf7539096fd0cd97cd316efcfe9d3c87a101a74c": { - "balance": "741847588809000000000" - }, - "cf9439bf2fbab65cecd783e135a37127f585f1e5": { - "balance": "50100000000000000000" - }, - "cf9bdc902604fab070c611ebf6a989ac4a785c82": { - "balance": "1501000000000000000000" - }, - "cfbbefc0e6013fa2caeabc54ac05f45dbf17ca13": { - "balance": "230809632301000000000" - }, - "cfd53f18ac7d94cadd032a0f4cdbdffaf4765d6e": { - "balance": "64000000000000000000" - }, - "cfe66dc4aa9ac9c9f87fdd05c1b2b95da5211703": { - "balance": "1656993051100000000000" - }, - "cff376eef4d69c4a47d6c7916583228fab3b5967": { - "balance": "5904462494391000000000" - }, - "cfffcb819302d05ed763026bdf84b48818938fb0": { - "balance": "289619807900000000000" - }, - "d000aa72a77d55911a5e66c2906da9206db86633": { - "balance": "3008989624945000000000" - }, - "d02d7b42213e873f91e789cbaffc734ffabd1087": { - "balance": "144960809826000000000" - }, - "d02db5279e918b3e93ff81d00d4025cc71dccaf6": { - "balance": "2386625717975000000000" - }, - "d0802cbcca2bb516f251b873eb20bb5e94af7f37": { - "balance": "9287997718210000000000" - }, - "d0c07380308972a36f57d1cd9081d7389d0421cb": { - "balance": "1280367167470000000000" - }, - "d0c131c1b60891b91e58fbed787ee4567e3f2038": { - "balance": "6360752089492000000000" - }, - "d0c71159d46c4d2af7699f682a055c79a1a68a0d": { - "balance": "1527974433762000000000" - }, - "d0d5d9f242f2613079b3b443c359c2e18ed5faab": { - "balance": "637334647476000000000" - }, - "d0dd208ce92da02eee3ee3de335e67f819581a33": { - "balance": "100000000000000000000" - }, - "d0e55ec0ad0f8986dd9fa9d738007c5bdc22f840": { - "balance": "53012893797000000000" - }, - "d0f222cec657ee444e284c07228d585155b82c0a": { - "balance": "7368748129592000000000" - }, - "d11efb07887d8b5b87a77d8fd388190614e8c077": { - "balance": "4703283503278000000000" - }, - "d129f1b89045ebfb4d1df1d9077e9359fd2990f7": { - "balance": "14496053137000000000" - }, - "d15a509424c4e04868bdcf59cbee09882ba04c8d": { - "balance": "65042393236903000000000" - }, - "d162416912b03fa65f3972a63e357ceaa3b621f7": { - "balance": "325650177224000000000" - }, - "d166183164b81bd049b2146a3ccfcc78cc6a0bdd": { - "balance": "1000000000000000000" - }, - "d173d759f0916e61400d56ca690cbf1743fe27b0": { - "balance": "53550838679000000000" - }, - "d18dc883e3881bf4c7db2afaa097bc2d33656724": { - "balance": "5000000000000000000" - }, - "d19dc9b5ae689dea1ccbfea8b44ec6034559e326": { - "balance": "135552499885000000000" - }, - "d1c79160d0b8c1a1546b86db5123e87645a45d13": { - "balance": "10000000000000000000000" - }, - "d1cccaa22259c547993df3c147d5b545f003adb8": { - "balance": "10000000000000000000000" - }, - "d209c9f32f3292ac4d15ef353fbe6f6efcd4e49d": { - "balance": "81000000000000000000" - }, - "d21ac89a20d67e309f96f64adf05fc48f55918a9": { - "balance": "500000000000000000000000" - }, - "d21f6e7adbf480600295af683091f9b9833f5330": { - "balance": "1229445878922000000000" - }, - "d22700a47a0edb137d2f0348aa0f8d4b6dbc5850": { - "balance": "21301422923000000000" - }, - "d258ddc9372e3b70ff53da171252239655ca9886": { - "balance": "16000000000000000000" - }, - "d274c69317dd836df48562455e8f5a7bd2e47d19": { - "balance": "156091832558000000000" - }, - "d286b68a358fcf8a6cec70b83467079664632ae9": { - "balance": "90377010699000000000" - }, - "d29284915d9b924ae5673e8a4a557478f68a7471": { - "balance": "324678197320000000000" - }, - "d297e64ac2bd8e98e6d276d6fe080679c398a26a": { - "balance": "3401930527000000000" - }, - "d2a1e7b51f6b5930a0d9e2ee55736f3d83a1b323": { - "balance": "44578900750000000000" - }, - "d2c9b0b0bbe61de504e4f210c168fa5999c9c23d": { - "balance": "76537483113000000000" - }, - "d2d49f650d222ec3e2cecba163ee92f0e934ca14": { - "balance": "3312486482635000000000" - }, - "d2d803bf10ba18adef5716b4056c1b1d61c45abf": { - "balance": "964679698000000000" - }, - "d2f673b589df7ef5cb32fdeef842d48d66130567": { - "balance": "1079010447581000000000" - }, - "d2ffaceef1af3f1c3e3f35e4062cd9f9abd1da59": { - "balance": "3041453068594000000000" - }, - "d30a74f5041ec6e73d066a375a105116699ce177": { - "balance": "21814020745000000000" - }, - "d30d849a2d8ff5041304014ecf6752dc769bf004": { - "balance": "1247532881540000000000" - }, - "d3113f558c6376321691931c9b21205e31f4a56e": { - "balance": "572224428451000000000" - }, - "d314bac1bf85eedeac0b359dd2106dbae8fc6947": { - "balance": "20000000000000000000000" - }, - "d3283e17112028b324327ef64a238183ba189207": { - "balance": "136000000000000000000" - }, - "d33ce3c3b64d1b3d399651432c15ecb943d16c70": { - "balance": "10000000000000000000000" - }, - "d33e1e4b10a98e82810f6d161df5d35e5677e35f": { - "balance": "10169656674000000000" - }, - "d34699fd152fe38caacd3c096f6abb1cd79e88b2": { - "balance": "25056644550000000000" - }, - "d369c0e01b9a9d519b3b099a98fead19867c019c": { - "balance": "100000000000000000000000" - }, - "d388dcfe55a9b710d05c686f033fdbdd7861ab71": { - "balance": "1439589263065000000000" - }, - "d391a7d45c7b454b743bd867f8f62f56894f9b65": { - "balance": "484904747488000000000" - }, - "d39a75b4831543e1bc99e7a5ca8875c4f69da45b": { - "balance": "10000000000000000000000" - }, - "d39ed6978b6a90fea29e735f8ea3f1d20e0fbd15": { - "balance": "144000000000000000000" - }, - "d3a0a1a00dcbd6bc44c9803ce351a4b36a69c929": { - "balance": "191222401916000000000" - }, - "d3bf1c0a6b0470c30fc49d995025af5e6b639e61": { - "balance": "10000000000000000000000" - }, - "d3cda762bafaf204469f85e6896ec64147a3452c": { - "balance": "468094119213000000000" - }, - "d3d04d78c1ab9e6887a9467b8b1e31b5c9910e5c": { - "balance": "81000000000000000000" - }, - "d3e1bfdd9396aba00d3e78646ddcdaf139a967c0": { - "balance": "833333174120000000000" - }, - "d3e502c42ff0274da12ba87ffd45fa593bba052a": { - "balance": "100409899947269000000000" - }, - "d3e76066c2e32d9a693161de07f2d3b7e6ea07eb": { - "balance": "10000000000000000000000" - }, - "d3e8d577323d97407246b198c4c61f7943c468cd": { - "balance": "10000000000000000000000" - }, - "d3fd4d1b0edbc314b103d350fff023ab75b7d7cd": { - "balance": "84129547428000000000" - }, - "d40087fca8feb72d130bbc9622575d4987f12895": { - "balance": "1000000000000000000" - }, - "d407d4126cbf3619a422c532ccf20c3da1495dbd": { - "balance": "99622000000000000" - }, - "d41a28761c8e5de8c803813667f1dc0918a105be": { - "balance": "157507410260000000000" - }, - "d46ed38228a3c3d78065b2d8b71b325bf0f0e685": { - "balance": "6787045850000000000" - }, - "d4a7463d202e804b39a93bccd77491d8791baf58": { - "balance": "171694163573000000000" - }, - "d4c20716ff7288d811d05fd6f0696a9f5627a11d": { - "balance": "100000000000000000000" - }, - "d4d95059c808cf41e64f7f353246ffae635419d4": { - "balance": "10000000000000000000000" - }, - "d4ef925157c6d0e2d649332f44416b85f8abe69e": { - "balance": "1392945162611000000000" - }, - "d4f0cb25801794f6d803306878763e08209d19f4": { - "balance": "64000000000000000000" - }, - "d55fbebc4dcf2de6341c2325448e9c198f0f06a3": { - "balance": "14206622892000000000" - }, - "d566968c40211fb25114105e36b5a7219cde9d5f": { - "balance": "4898442964000000000" - }, - "d5817b95c6b504a6d07f64faccc9aedf408b0ac4": { - "balance": "54387832478000000000" - }, - "d59679fc40a71897065bf1b3a73f331226cdae72": { - "balance": "20000000000000000000000" - }, - "d5a7deec4a5898f094e1600f9b15768d8aada258": { - "balance": "100000000000000000000000" - }, - "d5b91c29bf772ad3ba04033dfb86b672b245ad77": { - "balance": "100500000000000000000" - }, - "d5c1a9bcc5e68b7547354178fefb3d870572fd67": { - "balance": "2252066779089000000000" - }, - "d5da2a826f5909a221bfd8561dbd7dbf4aca4c35": { - "balance": "13839784966766000000000" - }, - "d5dcc82fa169b4677a3fc26d78f38e27dcc763f3": { - "balance": "10000000000000000000000" - }, - "d5f344ee8a1b954ae5fd8fc7ac702174749bc8a4": { - "balance": "1398836216771000000000" - }, - "d61cd03afbfc1bea186e5a3a51347c2c4ee3a2c3": { - "balance": "109879472702000000000" - }, - "d647fd7ca17203a0049c28ec6759612d767cfcce": { - "balance": "162681136487000000000" - }, - "d656d14acfb2f0fbde2ed2a137a52d852bb6288b": { - "balance": "20000000000000000000000" - }, - "d68130b421b19c193d03a9017b2dc687c7307d26": { - "balance": "128569735484000000000" - }, - "d69a41f7ca76b40ee94b0d04a3780a00c6c651ba": { - "balance": "2801054372864000000000" - }, - "d69af2a796a737a103f12d2f0bcc563a13900e6f": { - "balance": "7412286547000000000" - }, - "d6a5a7e149cbccb72a50b0a3ae00e6756b0a7eda": { - "balance": "1075352201657000000000" - }, - "d6aa9957f141f0dfed77e943c39aeed978834fdf": { - "balance": "20920740110000000000" - }, - "d6e99ccb72d24e8a60f24d47afd4074b1d1fd336": { - "balance": "15415994387186000000000" - }, - "d6ea4a9dda8d5bc832229c916fa45f05f99c093a": { - "balance": "27075799893190000000000" - }, - "d71de419d746ac277baa955761cced4b34c376ec": { - "balance": "1388473506822000000000" - }, - "d71ec6b5e5d4c604f741bafde0974eca49c56156": { - "balance": "61938809628000000000" - }, - "d72f90d9879f6d2d407b4fdf5d128b98d518f1a5": { - "balance": "10000000000000000000000" - }, - "d743d7925a0cfd08150814cce8cd5d3f7099e1c9": { - "balance": "25681376856000000000" - }, - "d7575a09e7498f21cda3e9e7266b7fde91dfe19b": { - "balance": "9841565066000000000" - }, - "d75c2eb5e0a2b2ee72ef4fa7249c1a1ce03f333d": { - "balance": "134491489751000000000" - }, - "d77088329ec1e280ea7a087ad20c5e965721ff4d": { - "balance": "3949070941222000000000" - }, - "d78d564bb79ea19e4a93975a38fe0882018f177c": { - "balance": "992717434142000000000" - }, - "d78efb176b252ce67b5648e04088d12c4668aad1": { - "balance": "10070463674000000000" - }, - "d7a25e43d7d4e23744f0b10e2b4f2911fd3b3bc1": { - "balance": "1000000000000000000" - }, - "d7a941cd82f8aa63c55baa81db44bcb347b8e529": { - "balance": "49000000000000000000" - }, - "d7b34387880daede6cbdad11bb3db67daf942975": { - "balance": "20000000000000000000000" - }, - "d7bca0770e2f890c1e93c3595641241454a31045": { - "balance": "2000000000000000000" - }, - "d7cb675cea1c0dafded44f611c9c344e2a5e053c": { - "balance": "25000000000000000000" - }, - "d7e53a2d8eaefd18e02bbadb7e64906ca8613151": { - "balance": "166599594268000000000" - }, - "d8076b9db0b7496efbd198b73c4bfcf51ac080fd": { - "balance": "210272077089000000000" - }, - "d81dcf5756da397ff1f783ffe5391d1ffd4ff227": { - "balance": "500000000000000000000000" - }, - "d833c6d08f5fff8f77628ab1e86584d052976d1f": { - "balance": "10000000000000000000000" - }, - "d835732e85953baf2af9e49f770bac1caa1dac23": { - "balance": "152211441541000000000" - }, - "d84005fea447e8c6aa0b5436ad79654a75348456": { - "balance": "22563694224690000000000" - }, - "d84d9c59a445911922e88c0f22cc6534f33ca3de": { - "balance": "3054115413381000000000" - }, - "d84e69926216065749e624d87783e90ce3015b82": { - "balance": "1420803164313000000000" - }, - "d884bdbdb7e13cc523e7f192310230c7bdbb4a07": { - "balance": "10000000000000000000000" - }, - "d88eedca1dd9249702f5ffc807c1e439eee1c5e5": { - "balance": "36000000000000000000" - }, - "d8a23fd234bada1c726622925ade62d3021e0037": { - "balance": "1567046607931000000000" - }, - "d8b1aee24264efebd1c677fcab6ada6e0f000cc5": { - "balance": "20000000000000000000000" - }, - "d8ba7afbb8bf2910b983a114aedec626eb7426c1": { - "balance": "275491152435000000000" - }, - "d8c8af55ebf116ba3c3904f8ac39d3a7d31aadc5": { - "balance": "1499999998278000000000000" - }, - "d8d97645f5f62aa89bf0046362dd0f45d40f821f": { - "balance": "25000000000000000000" - }, - "d8ea0e24a7e28285c4454f54181d581324da2583": { - "balance": "53039425000000000" - }, - "d8f5d258164747ccf790f5ed358162c756de49db": { - "balance": "323009990690000000000" - }, - "d9477bb62d3eb668a83a9679f3a7ef43f17c9e4d": { - "balance": "14045557127869000000000" - }, - "d9585e1b03fc86636dde1e64aed3cad77868549a": { - "balance": "1000000000000000000000" - }, - "d975f9ce3fe773fac3f8338a034a757c58f6e11f": { - "balance": "25000000000000000000" - }, - "d97e490faf19de612fb49c041d3f9e7877d3c0bb": { - "balance": "65766847746000000000" - }, - "d98117b74b2f2888d7078d3116d5758e2d09bfca": { - "balance": "1749157484422000000000" - }, - "d990b3f69ec700bdc095c184b3804551c832d612": { - "balance": "509385034698000000000" - }, - "d99b35298e709e5f54e6a5c612a326a83f4268c4": { - "balance": "71963571266000000000" - }, - "d99d9ec76005da26ccc721ec26be4ed9b3b1c586": { - "balance": "469607736824000000000" - }, - "d9bc61075c3201351584a026e5bdfb7cf9a7b6ab": { - "balance": "200000000000000000000" - }, - "d9d07b72f83491b6db26602f6b7039aeebfe6b61": { - "balance": "144000000000000000000" - }, - "d9f6f1ddf03e836b3744d008b62a6424544c67a5": { - "balance": "74347470143000000000" - }, - "d9fceff07ad69bf3b4aef54a7eee541368980cf6": { - "balance": "1143407707495000000000" - }, - "da0285fb7e37fd4be66fb862b248cea94ea8f6db": { - "balance": "80770216661309000000000" - }, - "da05c7aa330fcc5834e19deeb0a808e9ab7f3d99": { - "balance": "169000000000000000000" - }, - "da129e4481bd25450e6c7b42fe417c87ee2ce7a7": { - "balance": "256000000000000000000" - }, - "da32e3ec421993db088c71e256263158f7855b61": { - "balance": "18540215888567000000000" - }, - "da3c99669acd202ccbe6f80902c807588eca0880": { - "balance": "1000000000000000" - }, - "da72a7bec114d43aee6449db830d2d3f16e4d9b6": { - "balance": "744534872932000000000" - }, - "da72ec2cd7b8e3924f8baaea75d5ed23ef39394c": { - "balance": "38646377617204000000000" - }, - "da73078957f491827d62cb3ca0c484c2d1004ba7": { - "balance": "891774109242000000000" - }, - "da828e50c7c8580c6ce81718f11fbd43b2b0541f": { - "balance": "66094097819000000000" - }, - "da91483db6a6a034e068e69a6b46674838c5bc80": { - "balance": "4000000000000000000000" - }, - "da9551b635c3619f81641571e267755b89f7fe1e": { - "balance": "670841942250000000000" - }, - "da9b43a9c1c574580ec43da9f6acb687fc2f8c68": { - "balance": "761695404114000000000" - }, - "daa7f446923f7481115ad285ca468c865147e563": { - "balance": "10000000000000000000000" - }, - "dac6bfd15954efa4c9254e24e5831ab1884f8d67": { - "balance": "960042043423000000000" - }, - "dad85d0b8bb5ebf6ef811d0d35c89f9f343c833c": { - "balance": "37664599958479000000000" - }, - "dad9b01652de5d50bf30f9bcb0c6edc6315139e3": { - "balance": "21500996724000000000" - }, - "dae9c7d6bb0efe3f7ea20442b184f6d99b2a2c12": { - "balance": "937830189066000000000" - }, - "db0d6c28e9b913f611accaab15cc887f9b770f58": { - "balance": "20000000000000000000000" - }, - "db0e5341d64817885721c5abff04c30bd38df40f": { - "balance": "62600679700000000000" - }, - "db387dd404d14478babb60bad2391720d68b92ed": { - "balance": "115096708329000000000" - }, - "db3fb19e8a4a6ace4d8c6c02085d4cbba528b532": { - "balance": "1000000000000000000" - }, - "db4f05a66c0ccf0532ea1ecb931e05a400a6f4a7": { - "balance": "20000000000000000000000" - }, - "db571f1cdf8e83fbff6fb48cc0c81ef95ede12a0": { - "balance": "118317387393000000000" - }, - "db6a6a6db2aef3f43afbfe23027b670ebb3d33bf": { - "balance": "9960755220000000000" - }, - "db8bed34f8f34f45cb83ab19ed33fad76437d217": { - "balance": "21003651205000000000" - }, - "dbeba6a2a7f66c20c6db7b9270a5aee74de3f441": { - "balance": "4086905723945000000000" - }, - "dc04efeac13b2dab3d07833a7e7fa728fc23d18a": { - "balance": "1161834099120000000000" - }, - "dc092386c3a3e28b6b2d7d70db8f3d11e79ef5df": { - "balance": "124362293793000000000" - }, - "dc10be66aa11acbd42a2b1953714f09b5281681b": { - "balance": "20000000000000000000000" - }, - "dc2d58a383ce0bd40bed859ec2f25412b68eca0a": { - "balance": "104917823922000000000" - }, - "dc2e38183dceb2bc82b23e8ccf48dd96ea1c97b6": { - "balance": "2847787376064000000000" - }, - "dc5d9d94530d88451cf081fe7f2ac33667af9d8f": { - "balance": "65321904051000000000000" - }, - "dc993112a8d89136e0e73d67e2f26191583a50ec": { - "balance": "1000000000000000000" - }, - "dc9bb69b295945589a41feb794406558ce65dedc": { - "balance": "104077637254454000000000" - }, - "dcb0109d4fca2dace08ddca5d989a09d470161a0": { - "balance": "28897833222000000000" - }, - "dcce3a4ec516d833f5a9790c40ad0334b0d2dd01": { - "balance": "25000000000000000000" - }, - "dcdb21cc811ab733c2a80a2d5c8e5bb49cb2ddc4": { - "balance": "16000000000000000000" - }, - "dcdf8dd3ce03a2fe0d72835dbbd58725e1ed2c57": { - "balance": "113330414284000000000" - }, - "dd2165839ab95d6b24591307adcde9ee1819927a": { - "balance": "20260199589072000000000" - }, - "dd3015a5fdef66e749a000585d5574f975e3432d": { - "balance": "85465001652000000000" - }, - "dd37c478727f44943c5fd79ace30f21fae5a589a": { - "balance": "108577233510000000000" - }, - "dd3fb5810c31d37652bd17b92497ed479faf123d": { - "balance": "669996966072000000000" - }, - "ddc3bda30f7cf36bd535de4e20c9becb78d159f4": { - "balance": "99998278000000000000" - }, - "ddcce2d2431b67d4157c7ac4bd77f20c24831de6": { - "balance": "36160893899000000000" - }, - "dddcebe609f8b4354a1f27ab1915135e25800344": { - "balance": "1457846339959000000000" - }, - "dde223eb48f81748abde6cbc08cf1e6b0e8e4e5a": { - "balance": "1501921107087000000000" - }, - "ddf4ba402007060d9940a96f8e7c39f0a2c6108a": { - "balance": "377268151287000000000" - }, - "de05d9ada6626a8492acd137c7c7f7080a987cd1": { - "balance": "222144234923000000000" - }, - "de0fab89f79c4edf9766c3b7b1f508cb43c5495e": { - "balance": "8278000000000000" - }, - "de1070f3ff6c47237768fbdead88b2d5184fbe2f": { - "balance": "1000000000000000000" - }, - "de2b16d7f36f630329287822f550ec19415acb3a": { - "balance": "25000000000000000000" - }, - "de3faf6884337a99e54ac5d3f08b34be51b0755b": { - "balance": "51926806905184000000000" - }, - "de4614fd632ddac888d177de0858e62bbbf7dc11": { - "balance": "52506376589000000000" - }, - "de54cabb241dc5def530191f948f67db942a85b0": { - "balance": "9691177060000000000" - }, - "de81e488284acc4f8f6061d3a73bad112efa7a40": { - "balance": "14654060992000000000" - }, - "dea86ac3a661272691c877c1bad8355789382b69": { - "balance": "903877103000000000" - }, - "deadfc79f2a722dbf1c1a92f2824da8874189fea": { - "balance": "98905944986000000000" - }, - "decf1af47e153f6f3749a1b7abadefdcf1607a0f": { - "balance": "529000000000000000000" - }, - "dede5fa984f0def639d5b633f54c60fc5aaa272a": { - "balance": "8193771708654000000000" - }, - "df23607c63b3fd4b5fde6aab093c0c56d1188f95": { - "balance": "14687379916000000000" - }, - "df5b74bf02902e4c466821de798406b663d4d73e": { - "balance": "9000000000000000000" - }, - "df6402ee3f37389e7f65720561b54e26e5f1cbaf": { - "balance": "358266132937000000000" - }, - "df83ea5b770d5abeccac7f0cae803e8bd7b9831d": { - "balance": "25000000000000000000" - }, - "df92802ffe9892c7704875755bdec648914430e6": { - "balance": "20000000000000000000000" - }, - "dfa108bcd80e824a255679a38b2450d428e2f939": { - "balance": "489209553654000000000" - }, - "dfa9f18e859353796afe384d05353dc80b3ffc43": { - "balance": "121000000000000000000" - }, - "dfb0d6580f011e68a39d7727818b0890e70f3036": { - "balance": "537675412560000000000" - }, - "dfdf006abf2293aadc58feea6af6b35db428675e": { - "balance": "9000000000000000000" - }, - "dfdf2ba93bd47d7243b7419413458a947effcf67": { - "balance": "45080282196110000000000" - }, - "dff01277ac23a8cf93383595a80a7c070eafe5c6": { - "balance": "312778552103000000000" - }, - "e0450154c441e52c5e507e8316d4e9376c59c12b": { - "balance": "170163401434000000000" - }, - "e059374d6a7e6c63e609b65642272869fa3b2b3c": { - "balance": "300122497803000000000" - }, - "e0c0d8e739a2f274a43f019a07f7f61d7d8e11a7": { - "balance": "2630310240000000000" - }, - "e0e779e4e3573ea77096daec252ac2b3f1c0013a": { - "balance": "10000000000000000000000" - }, - "e1325eb586180a67873718a2016172afeb03c6a5": { - "balance": "531691399657000000000" - }, - "e13958af480da6443b9ec1067f0f33440634a282": { - "balance": "10000000000000000000000" - }, - "e142daac753b2c4d215372797999e9c88b65dfc9": { - "balance": "585813299366000000000" - }, - "e142ea343bc36ec49989fd43ad5c403c70a40dbe": { - "balance": "656734902975000000000" - }, - "e14d0a3d259db6bfec2fc4ef6e18729e4d93b007": { - "balance": "210234446279000000000" - }, - "e16a5316e3a113f27bafdf3d4fe44fe30ae9c210": { - "balance": "16000000000000000000" - }, - "e1770944aec145a96c9491497eacf7f3fb03c1b2": { - "balance": "335417250470000000000" - }, - "e199ac237661dcac0a4cfab404876abde72ee209": { - "balance": "340000000000000000000" - }, - "e1ad427471023f38cbdf07fdca3728ec343810c4": { - "balance": "343957267368000000000" - }, - "e1ae0223cecd738c8e530a0007ef05e8f3b33769": { - "balance": "950528515289000000000" - }, - "e1d2d4ef39f01a60c3bb5d671af91c5298d87711": { - "balance": "121000000000000000000" - }, - "e1d4a8888cbb383f3671ca96e7b55310b59a2541": { - "balance": "242387826125000000000" - }, - "e1da9039ddfe117e6a0b484fd3962426c112871c": { - "balance": "3710499693813000000000" - }, - "e1da9f16d57c601af8b6d102323c20408af8531a": { - "balance": "3135322588771000000000" - }, - "e1e1c163f391ffad2d0be68641253b0860485a95": { - "balance": "10000000000000000000000" - }, - "e1ec6361df67ad915df9e9661cd0932186db034a": { - "balance": "4279936304854000000000" - }, - "e224050bcd723e63f1fc0567a86942546aaf8d13": { - "balance": "12007628539000000000" - }, - "e2342c7f411d7ca3a86484af59a9c3f3180e2f0f": { - "balance": "16000000000000000000" - }, - "e26f2b026a258ce5801c90bb8fd6f7a152b8d267": { - "balance": "304593714834000000000" - }, - "e2717eb5fd0a1da51272b50ca8d12858009c7016": { - "balance": "506943817535000000000" - }, - "e27546d5620e6398829260e58e8cf4a3a03f4164": { - "balance": "3000000000000000000000" - }, - "e2762bb64e0606a5d635032e15164b01f612a74f": { - "balance": "884716158811000000000" - }, - "e2882066ed0a3c041d09c00c8532850fc42eac06": { - "balance": "42441412728970000000000" - }, - "e294c5d64daf7b7c0994aa9d03669c4b2658c9cf": { - "balance": "6996693830997000000000" - }, - "e2b179f0ed6870a6268aea64b0c7b39d98d97fcf": { - "balance": "334205318353000000000" - }, - "e2d1f6f7e3128340b789565b527bb91de96d54bf": { - "balance": "100000000000000000000" - }, - "e2f136d3693aa0b2346a968a22aca6707fc1d0e5": { - "balance": "10000000000000000000000" - }, - "e2f229054293e32cf3e83f9bb88d9cf1d6acd66b": { - "balance": "20000000000000000000000" - }, - "e33b8f4c9a49554c8b134861f88c8fffc399e456": { - "balance": "83552502198000000000" - }, - "e33cfc7727b1460324b34277dde14cc49bcb273d": { - "balance": "100000000000000000" - }, - "e36af9bfed4f912cae21f3d899f7354e1c902601": { - "balance": "31474316356000000000" - }, - "e36eff7c061dec48446d47675f176b4da3c2e950": { - "balance": "10000000000000000000000" - }, - "e383f3cf431f3cf645f26c7d5e5e2f77348ede6f": { - "balance": "776224304171000000000" - }, - "e398b9f004a4f891cf871a57d9124a97b56e89e9": { - "balance": "84846187740000000000" - }, - "e39ab2415144b46db522e92ed51b8089a5ec01fd": { - "balance": "4158925896363000000000" - }, - "e3aa7ac7e15e9a8a6f54565067234a9d4bf7b569": { - "balance": "1080385576951000000000" - }, - "e3ec5ebd3e822c972d802a0ee4e0ec080b8237ba": { - "balance": "2129139289000000000" - }, - "e3f1fbff8686af23ab95eeeee6a6a03782d72416": { - "balance": "401776848194000000000" - }, - "e4001b830fbd86df257ebab54aec0c66314ef9aa": { - "balance": "518220809325000000000" - }, - "e40790bff894f0b3e534942b5ad6f6592cd6e896": { - "balance": "25000000000000000000" - }, - "e409170a296e46fc96d85a2395e4324212a470ee": { - "balance": "1072528749756000000000" - }, - "e41546f68bbe1771febbdac2a4a5999eef50edf3": { - "balance": "1000000000000000000000000" - }, - "e425d63d711a9996c09d928ba8df94c88163aea9": { - "balance": "10000000000000000000000" - }, - "e4432ff1aee13f97f73a8407e4c7d6e768b8040b": { - "balance": "700508995102000000000" - }, - "e4690f5d024a395355a7cb5238fb7e0dc921b1e8": { - "balance": "1000000000000000000000000" - }, - "e4829684fb36f054766a61fb2a8f6ecdf27c9e87": { - "balance": "73885178137000000000" - }, - "e48a68e1ac007e14ac08c1b3b0df2b5602081ec2": { - "balance": "1389262869176000000000" - }, - "e4d699b3f4117eba7ed27b323048c9ffcb46ed42": { - "balance": "183131036697000000000" - }, - "e4db688c29fdf9a1c16114f99797d8409545955f": { - "balance": "16000000000000000000" - }, - "e535b94d370190d1e0955d3c0d12480e558f00dd": { - "balance": "20000000000000000000000" - }, - "e53966d4bb17fa9b50d29b44ddf3951c9ca67caa": { - "balance": "6400630678000000000" - }, - "e56f2656fdd1a5f7d3716e65dd89a37dd6e42dcc": { - "balance": "1000000000000000000" - }, - "e5a364113076273352e0c31bf505028e0b7edbaa": { - "balance": "10000000000000000000000" - }, - "e5a3c80518fab6a0a721ccbdc3e673680a65f6de": { - "balance": "171727917465000000000" - }, - "e5c71c7170e5c9b07e62cc307d81a4a3053ed64c": { - "balance": "10000000000000000000000" - }, - "e5fb6408db128c55cfb3e7fa1942d6347e34932c": { - "balance": "10000000000000000000" - }, - "e606883236f8b2045393c574153a100675cd4b90": { - "balance": "14005226900000000000" - }, - "e61869d1cf72f25e195898217f5bf5bcec9c9038": { - "balance": "50000000000000000000000" - }, - "e61e2e29c0719457ab1bf7d6d9fe442bd6107b07": { - "balance": "30943034333100000000000" - }, - "e61eb97093e9ee609647bd55f434a27bb30a9401": { - "balance": "200951434577471000000000" - }, - "e62812ad5834747f17c92435d863639e84d132fc": { - "balance": "3017271391299000000000" - }, - "e630b92aa8443eb077e1f6990a2e194d99cf53ec": { - "balance": "1000000000000000000000000" - }, - "e656fd1641c15e1a4b753be41bc4aa438b44b42c": { - "balance": "26972744083000000000" - }, - "e663f0257b98dfa80602a2af1bea1f901c4a7612": { - "balance": "97075813547000000000" - }, - "e66e411a8a9d019b53bf2e0a7e44703e1aa93ac1": { - "balance": "25000000000000000000" - }, - "e6712675d13fff27af43bb1cb3f2f283755bacf5": { - "balance": "227572496234000000000" - }, - "e68e8f04b2cff484da2d41dd639ae8880920f781": { - "balance": "20000000000000000000000" - }, - "e6972b5d7e0fe8c722dec9146b92f89291a0207a": { - "balance": "2115924954211000000000" - }, - "e698b491330cb55ecc4cc4b74015cd94eb927fc4": { - "balance": "1038111785278000000000" - }, - "e6c411e67b90109dbb0fa75f0f07ae8a504e9637": { - "balance": "123792105420000000000" - }, - "e6fb1dabc624edb45b040ad66f30dae010a6b634": { - "balance": "16076893670852000000000" - }, - "e71dac161206e7d3686d13b98fd922ab73587988": { - "balance": "500000000000000000000000" - }, - "e773f9be9b3f4b35ac149b4d759b9e47c8000bdb": { - "balance": "329623043336000000000" - }, - "e781cbbd2dccfdf68595d54fa44104a80d52dd22": { - "balance": "188679476509000000000" - }, - "e793666c7850a409b1d5494f576d122e85cfed9c": { - "balance": "1141845197779000000000" - }, - "e7a5527c6deb922e9f84309c502048f49f0c8f14": { - "balance": "81415566708000000000" - }, - "e7b0f75f9c69ae464b1b63cf295555d0815fc532": { - "balance": "10000000000000000000000" - }, - "e7b43cc673e321e607190a6fde996b71508f4d81": { - "balance": "103958781426000000000" - }, - "e7bfcf3125e37755e57804dfe4479657b212a8ca": { - "balance": "10000000000000000000000" - }, - "e7d33cbbd4eb38365c5be04ce32658a5ac741cfa": { - "balance": "1545192252109000000000" - }, - "e84cfbd7844f6aa3e830258a6b1069b6a7ff5b7e": { - "balance": "543989509107945000000000" - }, - "e8aa0cbc5c1f59fadf3ec122fa8a59ebfc60b5b6": { - "balance": "61271973066000000000" - }, - "e8adb5303c30a8ee044dc09c49818c02a16f4254": { - "balance": "737375689166000000000" - }, - "e8aeef5114e19d467c3064938c5965d04830f2ae": { - "balance": "51130466380000000000" - }, - "e8b5a83497198a513fb2e244bcf05f9d4cf09d62": { - "balance": "10000000000000000000000" - }, - "e8b6818cf0d24bd0e7ded854b3d368662a150dab": { - "balance": "63697741112000000000" - }, - "e8b68b9cb24169fd688db7a626d79d0363777c75": { - "balance": "427222669643000000000" - }, - "e8b8b57b23ea953943da3ef7efaefced9cdbb44c": { - "balance": "16000000000000000000" - }, - "e8f85dca364d26c2149b767904c6c06249c3d88a": { - "balance": "199342917246000000000" - }, - "e916c7801cdcf1b6cf640fcd9dcc1e3148c80105": { - "balance": "9000756000000000000" - }, - "e93cbef13277324caae7816c3d601e2f6bb42589": { - "balance": "121000000000000000000" - }, - "e9415fedcdf8939b551999900128530195a2a5f0": { - "balance": "85165078941891000000000" - }, - "e9a79ade714ce48a07fe88532a20d8f8ed27bac9": { - "balance": "30768493367842000000000" - }, - "e9b35c7ca775661bbd3a4844e2c6bc5effcdea58": { - "balance": "134719523000000000" - }, - "e9b819dffb600373bfd1b1608fc9744cc9167855": { - "balance": "1537634693002000000000" - }, - "e9c5ef50d4a194e53928659b4486a1c456df9e56": { - "balance": "50000000000000000000000" - }, - "e9e21f4523b11567516f6fc525e8967ac707f988": { - "balance": "2498740681000000000" - }, - "ea02821d6c730e061a9947b75188eb8bc0bbf9f1": { - "balance": "12822292582000000000" - }, - "ea3bca3a17c7e724ac0e15acab6442f222cd8688": { - "balance": "2789689549000000000" - }, - "ea4f7923d7045a148d50153f5f4620dbd31a74da": { - "balance": "113595858930000000000" - }, - "ea6d4cbae3cfe49ffd36653bb0d64c01b2bbc0b8": { - "balance": "49325017701000000000" - }, - "ea76cd4cff825301932a5c1d3a1de55a0ff00797": { - "balance": "1282028021000000000" - }, - "ea8e4c8c6500856777e2b41832ff00443db291ce": { - "balance": "553674550359000000000" - }, - "eab52191e5afc804b8685fe13d7ad6f5dc64fc12": { - "balance": "244412435341000000000" - }, - "eac1b0868b710e40d6d5c66a461dfc8f78abbaa9": { - "balance": "10000000000000000000000" - }, - "eacac2c75920b8f6e65f37ad81deb113d526d031": { - "balance": "53028042076000000000" - }, - "eacc9ef8b534143560f420031a8a7f030ff1a36e": { - "balance": "381111853842000000000" - }, - "eaf2cc9fdfe6272de269f32486b2d4c248a05afe": { - "balance": "2793234915237000000000" - }, - "eb0220406832a8a5d4f242538e82c80bd83d0ac6": { - "balance": "10000000000000000000000" - }, - "eb20efc0e0af48c8e6da4b21efa9c9f02d92d29f": { - "balance": "152958793764000000000" - }, - "eb41bce8e3aac2bcf662854a3151e3c83d98c6f3": { - "balance": "219455327737000000000" - }, - "eb44c591306972c29a7084079720d8ee5fb9b0a1": { - "balance": "49000000000000000000" - }, - "eb4b26ab55dc35df2e78d47a90fc43148a6de881": { - "balance": "12139574483030000000000" - }, - "eb4f53510db5edcaad6ea169e521bd094e8da4b1": { - "balance": "100000000000000000" - }, - "eb4fbfb7c0082aa0e7edaed934c5166fee955e5b": { - "balance": "299713748180000000000" - }, - "eb6067ab544af6289a73111e7693dc449d5c2134": { - "balance": "20000000000000000000" - }, - "eb86fea82d10d309b1365237e4855a48684e0e49": { - "balance": "81510415589000000000" - }, - "eb8abbcadeb6e19ab4392cded7a407c8d5df2d5c": { - "balance": "25000000000000000000" - }, - "eba44ca2d6f36df8221a2021bf0644cf6cb59452": { - "balance": "500000000000000000000000" - }, - "ebacbc0eace170f66415df48f74d98eb31828d15": { - "balance": "19046465915296000000000" - }, - "ebc72fb8a1029139d8abdc08da23dc559f87e1a8": { - "balance": "24177703742991000000000" - }, - "ebd561bb9001991cb6b02c8ff9e7ece8a3d73dde": { - "balance": "6684606759000000000" - }, - "ebe1dc3ee857ae4add6fa6636b678af8451d1701": { - "balance": "1485349608007000000000" - }, - "ebe68dc904c737be83aa2ee7f613dd51a6d436e4": { - "balance": "11206782120918000000000" - }, - "ebecf4db55a99f018bf136173ae823528f211380": { - "balance": "191817711082000000000" - }, - "ec15ad0aafe0c0f18089de50b2397509e15a20de": { - "balance": "20000000000000000000000" - }, - "ec2e56973a6cbd8b37d0294b16ef806ab5943ec7": { - "balance": "12031630315394000000000" - }, - "ec432a6a4685ebf6c1e872001d1de246140c8d98": { - "balance": "280056522277000000000" - }, - "ec866ba1bdadb91ca25f5ae035b0f69421ed4377": { - "balance": "431849961155000000000" - }, - "ec9be854224d3d371b79ffc1230fe704ba03be2b": { - "balance": "3692428502391000000000" - }, - "ecc2d6e129c7daa37a93f559c6d4f575171d8386": { - "balance": "20000000000000000000000" - }, - "ecc3aca2a21cb317c5b9debdcb2090f3931d5cd7": { - "balance": "100000000000000000000000" - }, - "eccc9a49ff40aa4b07aa0e1271cfb6713de683dd": { - "balance": "617207728367000000000" - }, - "ecccf24530629033fd6234ae32bde2052ebaa640": { - "balance": "16000000000000000000" - }, - "ed16770d5a56dced87224d4ff68a361a2285fef2": { - "balance": "10000000000000000000000" - }, - "ed23b8e782d5ddf203f9b80e5df83ec32e484fc6": { - "balance": "5000000000000000000" - }, - "ed3244e4168e669ae9d54175173c3f0f0e7c4c7a": { - "balance": "803397672115000000000" - }, - "ed48f39d3f022b321c0864d4955e1cdc8cf54834": { - "balance": "64000000000000000000" - }, - "ed4cb42fa6737cbbbf095f181e1425b3bc3ab4f6": { - "balance": "8974148344000000000" - }, - "ed560f7d83c27a26965f84dcface3930bc447fc5": { - "balance": "2092287996000000000" - }, - "ed6ace91369ec3b06cce474e67d1ce4aba6475a6": { - "balance": "1227081000000000000" - }, - "ed8249dd4a91f70176ffff310e5546e7e0c30b91": { - "balance": "813069034369000000000" - }, - "ed8987fa3d4d42bb8f009c99cda5868633d94f5a": { - "balance": "174952234860000000000" - }, - "ed99b72a58a519ca7aa8f46b8d254c3f1eeea0d6": { - "balance": "10000000000000000000000" - }, - "edb720c9bde4801e204e90282de2a6cf1c44c4ad": { - "balance": "10000000000000000000000" - }, - "edbea23cd0cfde3705d83aada88e78b9f4bb1a50": { - "balance": "4000000000000000000000" - }, - "edc1f174655205bb961ddf94a997cdfd24f1c2ed": { - "balance": "65211537189000000000" - }, - "edd1d2dcba881202bc546943194d64e59bf74bfd": { - "balance": "10000000000000000000000" - }, - "eded28fbd959f2351b4252abc71f0e809562fd4c": { - "balance": "1000000000000000000" - }, - "edfe4d4c83c7db76e5e8a9ccafa34d9841669dac": { - "balance": "2578239411258000000000" - }, - "ee1ef79de869b89334d883ba766e65150f3f6cf5": { - "balance": "779780646165000000000" - }, - "ee27b2da240e862f0848d31116a7b4ed91835c8d": { - "balance": "111637484977461000000000" - }, - "ee3195bdb69e97796911c63fdd3fcebad61ffe9b": { - "balance": "214483035823000000000" - }, - "ee43306530c21793c4fd6039b51cf54fbc912bf0": { - "balance": "374531713769000000000" - }, - "ee4515e30ee1b8dba4779ef213d89e8dfff26ea6": { - "balance": "1166743135013000000000" - }, - "ee591e9ca7948b8485eb210e2a3f706b97e6f9e2": { - "balance": "27793157052774000000000" - }, - "ee5ba6c854d633a04f7656d311817e5104c6de14": { - "balance": "289361919166000000000" - }, - "ee909db4ee48bff3adb9e43db940245a8e5e094d": { - "balance": "582143490064000000000" - }, - "ee94d1afa82de70eb65aad0662f48ef3170495cb": { - "balance": "242490158636000000000" - }, - "ee97e18e09bbb16137a7b4aaae464e97d70e6606": { - "balance": "442709862861000000000" - }, - "eebe957af00050c2841f3ef8768c6a77a5394012": { - "balance": "9000000000000000000" - }, - "eec052f4e2902f7cc496162ca6525997d2b3ede4": { - "balance": "69349303517000000000" - }, - "eed30e1a939d5f0b4a39598967a5f149a7b7cb8c": { - "balance": "1637195595000000000" - }, - "eed7bf1ba39bfdad0ce1b6b8d4c9bb31dc1a9843": { - "balance": "203331701702000000000" - }, - "eee276140ea24e36eccb4fd748f675df1acd3b73": { - "balance": "1000000000000000000000000" - }, - "eefb33b290741c4cded862cea777efe4b14a76da": { - "balance": "64000000000000000000" - }, - "ef17a60d15ecf68a62b4bfd5e3acd6201e1931af": { - "balance": "113292502078000000000" - }, - "ef3f4df42127d3e94b4b5883ca97ee63f90b68b5": { - "balance": "17819622000000000000" - }, - "ef4aa6833a69cf72fbf3eaac57da236970aa4241": { - "balance": "1638520372091000000000" - }, - "ef958a1db06e5b8e12547148f3b01da9a8841aad": { - "balance": "12847752197000000000" - }, - "ef9fa861eefe12a3b4c161a47db5d94b1fa873a9": { - "balance": "49000000000000000000" - }, - "efd9b1ce6bc3932961e41e875edaaa367d318b36": { - "balance": "1626378762077000000000" - }, - "efdce7f577c77f0dac6afc78dcbf5ebadc1c3a73": { - "balance": "627500067619000000000" - }, - "eff3f26bc45638d89f28b3ea7a5471af0b680b72": { - "balance": "1650959950189000000000" - }, - "eff6d78814ddae79d6d09d830dd44de55f3f919d": { - "balance": "44409266093000000000" - }, - "eff739e22b9aeb3781dc301da70761fdd178f08f": { - "balance": "574842224234000000000" - }, - "f0059b3c8a32d3d012b4fcb993431a484b67762f": { - "balance": "516933429840000000000" - }, - "f06747d8e2c76b8827bbd0bf4ea3a68d390ee8f3": { - "balance": "8124594790100000000000" - }, - "f0e29fc0aecc36d1bdd818148878ea7d01957476": { - "balance": "79821431871000000000" - }, - "f0e42acf4e027aa61ac2f56e3d2c171ec0fd6ebf": { - "balance": "672499252575000000000" - }, - "f14338307bc5e6ab71fa202447ce240947568b3c": { - "balance": "13990001528784000000000" - }, - "f14f9a1206eb436a3d2e4ba9b3976137f67a6596": { - "balance": "1086707451000000000" - }, - "f15fcf1772fa5b2a578ce4f9270996430d533000": { - "balance": "496026996898000000000" - }, - "f18c691a5827ff1fdc44b54bd9a64fabd53c1cf4": { - "balance": "3112912699000000000000" - }, - "f1960640b52af75fc71101aec2611499c17cd9c6": { - "balance": "195957678178000000000" - }, - "f1abf01ddd474949713bd7fa67ec81d6b56c87b7": { - "balance": "121000000000000000000" - }, - "f1b93a6cfd4b1c7e0e89ebed119c5fe55af2035e": { - "balance": "1000000000000000000000000" - }, - "f1d14c7659a10ff38f4ea74ff5b07ac035984b6a": { - "balance": "9986323720000000000" - }, - "f1dbf37470a2c4fef98b1023026870ae8f7df2c0": { - "balance": "132757602000000000000" - }, - "f220b958b619d5d848597dd00824ab8b1401ebd2": { - "balance": "1461699635849000000000" - }, - "f2484911e0aa707f88d9dd970db21e8f24b9de2f": { - "balance": "20000000000000000000000" - }, - "f264c15790fd7a36d9ce7a454f6bfbe878708a50": { - "balance": "64000000000000000000" - }, - "f2662356cb3ae7b82efd6c82c3591ee40854892b": { - "balance": "50000000000000000000000" - }, - "f27ae5783b96ef637bde4179080a8f5af63ae692": { - "balance": "784985848611000000000" - }, - "f2a62fc212717e411f72f9a694e30b8da21bb31b": { - "balance": "614971541702000000000" - }, - "f2d0a9594231efb87ac833c365b80944251f29d7": { - "balance": "478622654587000000000" - }, - "f2df99a3df0b9b448d0ea48b9fd5cb1ce9ce50cf": { - "balance": "851116673037000000000" - }, - "f2dff0ae1f5f74808624e4f26fa814e4e19c216a": { - "balance": "404457730686000000000" - }, - "f2ea1ac6282364ad5904c6f058827a4382111d94": { - "balance": "5502482915000000000" - }, - "f2fafdcdb2d887eb13b5362eb76be2a682868643": { - "balance": "6174264174000000000" - }, - "f314adfc2fbf632a6e5d8a261385b6054aca31b6": { - "balance": "1267558242119000000000" - }, - "f31a66a88394ed7dd6609aff07dd26a60a219bd8": { - "balance": "346102834465000000000" - }, - "f3535f2b42d8613363e6d9717cc21a8ec3a74fe0": { - "balance": "35723093185103000000000" - }, - "f36a149466982c030ce3b9717f34b593613804d5": { - "balance": "10000000000000000000000" - }, - "f3828b0eaba4acfbbcf3c58277ceb4616a34b630": { - "balance": "633998941064000000000" - }, - "f38f767eeb8002ef051b32fe2f40193bf0751d92": { - "balance": "50000000000000000000000" - }, - "f39bce177817a7338b1adaf713222e515c0d762b": { - "balance": "1128231726329000000000" - }, - "f3ac7ea27a1cefc7787e5ba54dacfd8385ee4afc": { - "balance": "11364602682758000000000" - }, - "f3d9ea511335ed418b1837766da11832aedf5578": { - "balance": "29188596603509000000000" - }, - "f3ef05ccd19df167e06797d962f6afe16037e134": { - "balance": "144000000000000000000" - }, - "f3f630148eccea0ad7bd67bb806bd5676a4ea4cb": { - "balance": "87187208643000000000" - }, - "f3ff31784e0b8c3cd2f7e18cfd07c682a42d1c8d": { - "balance": "10515373125000000000" - }, - "f40b976e8519a2c97f64783bca495ed3f2e4a7c0": { - "balance": "780184503985000000000" - }, - "f416a3af7f3181ad9c8a916989949d35b0b636ec": { - "balance": "16114504005275000000000" - }, - "f419759927eea6afe77701c4cf4a98791a709ad1": { - "balance": "1032589347112000000000" - }, - "f4368f9c9ad8236b56413f174562d6b6fef21d1c": { - "balance": "5447645343000000000" - }, - "f43c57f984b0e2b7ce4d703e82f41195585504a4": { - "balance": "1135809111749000000000" - }, - "f4449f52895de96a4638c927dc389f010bbd530c": { - "balance": "693196063498000000000" - }, - "f449bd417a674c8bfa1db3a3e09c2b03da0f0c04": { - "balance": "106343287319000000000" - }, - "f44dec8340986c06d64dc98d78772a8a9cdc41ec": { - "balance": "1379381904815000000000" - }, - "f4642be1a7685aea0dc7b362d36f58f15d806b72": { - "balance": "4717509847323000000000" - }, - "f4712925f57391043e0cc2e671f33124a0bc8613": { - "balance": "419736833200000000000" - }, - "f47317fba5927dd8dffc4049d4f3277fcef503d6": { - "balance": "149279442682000000000" - }, - "f47ce4c5aaef82692e47f7a810ba38d1faec0eea": { - "balance": "10000000000000000000000" - }, - "f491ffc412bf142788bb82d48bd4eccbe9e0a286": { - "balance": "77276422315000000000" - }, - "f4a1e27e669c29f15b9f89ac15f702340a135743": { - "balance": "324000000000000000000" - }, - "f4b5cbfa50a6c4f5f7db7a93fa565362cc7aceac": { - "balance": "195951823248000000000" - }, - "f4b949c6e10615b651675016f0d7d6ff64e31aee": { - "balance": "35516207325223000000000" - }, - "f4c5e2f043ef3548a2c1c27d968087bec65e2f7d": { - "balance": "100000000000000000000000" - }, - "f4c79ea9c6f7297e016c39296d86f0304070c31d": { - "balance": "71036374423000000000" - }, - "f4dde3733a72872a7efc095cb412672c50928f1b": { - "balance": "129914864759880000000000" - }, - "f4ed736a413464eb93f8a430e093a64f0bd4222d": { - "balance": "10000000000000000000000" - }, - "f4f07e45560fb63d5207ed7e8d7cf4fe29e06d18": { - "balance": "293103814503448000000000" - }, - "f50eac35eef0a1bfa23ba31020ef60e89bf8e9df": { - "balance": "10000000000000000000000" - }, - "f51236dfd888929ccb2fe1f1fc5554abc5df4ce2": { - "balance": "25000000000000000000" - }, - "f521eb42e9092350f2ad4391ddb42bfe7abb4db9": { - "balance": "217462745186000000000" - }, - "f54e7062b6a9a8b283acf00fcbad58aca0737676": { - "balance": "7327357122437000000000" - }, - "f553301efd81629d0856d9c95c70f4a962e602ed": { - "balance": "1500355826530000000000" - }, - "f55c555b0991b2413f2f2764d8ed6a0d77825965": { - "balance": "1174679810163000000000" - }, - "f56ff110d521ceaec29dbf2842f1e78b24463cea": { - "balance": "20000000000000000000000" - }, - "f573fec366236ab87ba041f7dc6a88d92b1fc9b7": { - "balance": "4659857040000000000" - }, - "f59987743b239379aac9353e17e0e4442aa2c684": { - "balance": "25000000000000000000" - }, - "f5a9ca298e88c5492dd44a66d815b649c2f01d39": { - "balance": "95879585325000000000" - }, - "f5b4933164c55b5ba99db906ecaa52bba4f95164": { - "balance": "25663623936000000000" - }, - "f5d20af68c6fed98144718b6beab82fde00dfedc": { - "balance": "16000000000000000000" - }, - "f5e49ce72be9b17ff39688860e5cf6fd500a886c": { - "balance": "106142276914000000000" - }, - "f5f472405a4530075805fbc11928544770fd61fe": { - "balance": "64000000000000000000" - }, - "f62096c7305eb97b221bb637f4269246fe59262b": { - "balance": "855993602798000000000" - }, - "f622bf9b8f7be2f75d5ed73d318a0e7fa62a587f": { - "balance": "20000000000000000000000" - }, - "f6231f31d524ccc444bd046123ba33bc224bdd52": { - "balance": "97550810879000000000" - }, - "f641b4a721dcefa497274fd06888eb998b9bc038": { - "balance": "39401014566340000000000" - }, - "f64f0c5172c99d74b2450a4685c3ec715b379922": { - "balance": "28337413668000000000" - }, - "f65841061cd55cbf20843d9594bce9ee133aa644": { - "balance": "9064540188290000000000" - }, - "f65f0106f3d148d0660547f0683ded4dffc12fe9": { - "balance": "87334071785367000000000" - }, - "f677961296ed933db9e1dd887711387540c0436d": { - "balance": "3982789899000000000" - }, - "f68ba7530f423b8df1625cee36f8df2363a57c49": { - "balance": "5000000000000000000000" - }, - "f69c6eaf077b795f19a9590ee8b578543558e4c4": { - "balance": "10000000000000000000000" - }, - "f69dfe3f0f76e50e2850e44e9e36b6966e277eaa": { - "balance": "288231750575462000000000" - }, - "f6a73c4b958b4d6044f3f4da7147d0fa80e2ea31": { - "balance": "50000000000000000000000" - }, - "f6b0864be5f7bbc4210a3420aa3ead614a8fe7e2": { - "balance": "880968828000000000" - }, - "f6f43a6d9517471436d2ce5047a2b707580e7149": { - "balance": "20000000000000000000000" - }, - "f6fb414d1ca7c29be35b5f97096c817bbf70b070": { - "balance": "15156317416682000000000" - }, - "f707b491ac27b2d2e5e1f9d4123635ee0af92c5c": { - "balance": "500000000000000000000000" - }, - "f71179583a471767a1b399842d7d29caefe57a5e": { - "balance": "429648186876000000000" - }, - "f71ed909eca6bfd574cd670389bc9250493d686d": { - "balance": "38189267531000000000" - }, - "f72ccdc70b7878cdb94f42ee72ca5b4b35a46238": { - "balance": "86065647347000000000" - }, - "f74035e85dbfdb961037bf689ee7dfdcfaf32d64": { - "balance": "398451682882000000000" - }, - "f77668db085a87b0a0405a275e1c2516d3e02b66": { - "balance": "10000000000000000000000" - }, - "f78990d9e50876b49f933e9d74bda44197e9aa7d": { - "balance": "51984216556000000000" - }, - "f79b9df28b7d94d1b4491fca1cbe50bd36aedb3a": { - "balance": "11546152485156000000000" - }, - "f7c773b89be413848dc4a96f064693a0c3a2eab0": { - "balance": "7084247258755000000000" - }, - "f7e29c20bb0023e9ae079da589346fdfd960dae3": { - "balance": "93132014782000000000" - }, - "f8124428ea619d30a335ecc4c2f64e36500abdcb": { - "balance": "8838170798391000000000" - }, - "f843c9d70226e6c2c8cd4cef78e2db66a8eac027": { - "balance": "498377670361000000000" - }, - "f84bb3c0d872dcdbe99d6abcc57c6b5c2b2e35ad": { - "balance": "1405105232436000000000" - }, - "f8679b915ae94e4668f2e27d1094cbb2d97cf428": { - "balance": "1000000000000000000" - }, - "f86dbb82c634cdfa818e4d0dbcfcc9a5c47a9ddb": { - "balance": "196000000000000000000" - }, - "f88bad7726aa66bc1d0ca5824044072f3551fd15": { - "balance": "37432374800000000000" - }, - "f8ab07d0751a2c283ebe2a7e28c5b6e57867e1d1": { - "balance": "25000000000000000000" - }, - "f8afb4f5684c56ff7ce71b4e4cf7e42062470e08": { - "balance": "10000000000000000000000" - }, - "f8c28df0d1a0982289ddfa2a6d562e5c75a5dd01": { - "balance": "1447386977682000000000" - }, - "f8cca137f9c12b48eafd43f038e55e2d3c481919": { - "balance": "35370515421000000000" - }, - "f8e50d1816a5e5c649756ae208209b03b1ece0c3": { - "balance": "48449640035000000000" - }, - "f8fb33ba1d93112d9c3672806e0939083f09a88e": { - "balance": "419743187776000000000" - }, - "f903bebfcc6a7050fc2c5bd14248af9b300f1600": { - "balance": "473363252199000000000" - }, - "f90ab9078f26dd881fb054b4b6e3b3e17fa94718": { - "balance": "156449634345000000000" - }, - "f93e3f392efc057f0af3a91416858a515c1ed996": { - "balance": "1147663044625000000000" - }, - "f94eac538ca66931869c312acb67721c4337842f": { - "balance": "368103335377000000000" - }, - "f94fda503c3f792491fa77b3702fd465f028810d": { - "balance": "317241487661000000000" - }, - "f95dcedbefee8ed01086c91d91a4c115ad8fc947": { - "balance": "147059838786000000000" - }, - "f961a293bbce366a6fcc98d2ba0342e2ef3c5519": { - "balance": "10000000000000000000000" - }, - "f966fdbc4a42f055f8f52d31c23ad7b6a07a5e22": { - "balance": "10000000000000000000000" - }, - "f9a3a61a2f1469835240bb0641eae40c07451e30": { - "balance": "218000000000000" - }, - "f9adcf232180378b08a46d6c8d9d97f01802e01b": { - "balance": "15658216517944000000000" - }, - "f9c68991ff7ac307e41ea1c673f8ebb1a6afbd99": { - "balance": "10000000000000000000000" - }, - "f9cc0c60431d7bdb0c7581a9ae7f011b0abefeb1": { - "balance": "16000000000000000000" - }, - "f9d43c329b61ca2169600e45c8fad3c94226adb8": { - "balance": "120128558137000000000" - }, - "f9ef5d4e2ca8888216b939d3d938438a34dd9da2": { - "balance": "144000000000000000000" - }, - "f9f3d14cd3bd09e2c4c89035b4f50e93f6175cef": { - "balance": "725000000000000000000" - }, - "fa0f5a03601bd1fc76865cdd69d9671ba6073592": { - "balance": "225298289139000000000" - }, - "fa12f10db0eb552b719194becef20af9f45de8db": { - "balance": "1012484659496000000000" - }, - "fa146c58a0709951bc2e9bccddcd002c5a0bb7dd": { - "balance": "199563276701000000000" - }, - "fa159185c156f35fa450b77c48846c2dab6349b7": { - "balance": "100660066567000000000" - }, - "fa193312655f79c7b0ee7d7ef904486836180026": { - "balance": "48141690266000000000" - }, - "fa2484de744918bd8c91350fbabc0dab8b8a44f0": { - "balance": "36000000000000000000" - }, - "fa36dc463b026d8edfeb8ac4acac43a51d643457": { - "balance": "9608761064478000000000" - }, - "fa84199010be2bf53e803c23771e0d15fd025386": { - "balance": "1474902394742000000000" - }, - "fa958bbfa367a745bcd0904db2c4e30445edaefb": { - "balance": "175679888121000000000" - }, - "fa98bcaeb55285ad7ead12ccaa15cf488f567ede": { - "balance": "136105143781000000000" - }, - "faa1be631da42b41a026774f4166c1b831ef41e9": { - "balance": "86358861589000000000" - }, - "faaa857e7f149968434f313ab8db596e1b0ae75d": { - "balance": "36000000000000000000" - }, - "fac2b85ab274055cf1415d57394e8aca4541857d": { - "balance": "289000000000000000000" - }, - "fb23a508ccdb4e91b252f5c06c465c55ed59b1db": { - "balance": "14698710175236000000000" - }, - "fb24d4e47ba70aa4b984372b4852ad3d082daa24": { - "balance": "4526648424830000000000" - }, - "fb27a7e8b8b4ae43c69ce025b46187e538608769": { - "balance": "121000000000000000000" - }, - "fb2cdb5e85872f52c99985f219b8fb4125c6a8b7": { - "balance": "8568367153000000000" - }, - "fb3d76c8165bcb3c93fd3b2b10c20588d0fa97aa": { - "balance": "500000000000000000000000" - }, - "fb5161b2cc9d48a53f47d66002905f0458e3cd9e": { - "balance": "225000000000000000000" - }, - "fb72756c4845f18ab35d29f632b662c0c0d4b94f": { - "balance": "883095068524000000000" - }, - "fb8b7efb02ea5292304c0f0abc8c555684653587": { - "balance": "10000000000000000000000" - }, - "fb9ee61e337a5c7b57c5140e84919101570e2cb7": { - "balance": "16000000000000000000" - }, - "fbae69f44b116c186a86cb0de79323ca3d6b99eb": { - "balance": "1359504686067000000000" - }, - "fbbd399eb9e5d3dd67efc48927973601dcd84321": { - "balance": "2049018637367000000000" - }, - "fbc9a3c3c429990cc306710b3dd44174dcc72ad4": { - "balance": "55507457947000000000" - }, - "fbce66a6898ecd70893db6b4b8c3d00afef8e20b": { - "balance": "20857164902458000000000" - }, - "fbe8fe04084fc93dff8228861fe100bfeeb057b6": { - "balance": "10000000000000000000000" - }, - "fbfb717f902ad79ef63565f9ab57f041ff5f7626": { - "balance": "16000000000000000000" - }, - "fc0b6c8c6be79bf0c9554f7855dc8c4a617d02c9": { - "balance": "17347593956000000000" - }, - "fc17518d05e605807847bbf6f407da89037bca00": { - "balance": "1796383702108000000000" - }, - "fc2793424c809cc80938a1be1292813adbc8ac8c": { - "balance": "10000000000000000000" - }, - "fc35930abb108ae6cae33fd065dfb799808ea326": { - "balance": "912737460000000000000" - }, - "fc5a9209799e563ae8d958774dc86345a3bc7ed2": { - "balance": "29049176573000000000" - }, - "fc8011850c09c9288e737ea58ca5c15cded6dc8d": { - "balance": "10000000000000000000000" - }, - "fc9183ed137be071ad183d025395a0ebe2674654": { - "balance": "500000000000000000000000" - }, - "fc98c9d88b1fbbb68dbdd6448aa6a32e8282800d": { - "balance": "900000000000000000000" - }, - "fc9f4b9da7a46c2bfcd50cafe1f892b9984be0ee": { - "balance": "21577116424370000000000" - }, - "fca525b732a673b953f1c23083c276cc8cbcb86c": { - "balance": "77653618624000000000" - }, - "fca57b6a4798f33478b6e23622173cda3fe1b9a0": { - "balance": "793368066098000000000" - }, - "fca79b446c513a7bed643603c42f35ff0fa89f49": { - "balance": "998082799053000000000" - }, - "fcab42f7f07735a7b09074c1f1769287069c88c8": { - "balance": "94824830574000000000" - }, - "fcacbbc6810c586522012ad32c3dfac80eb563b4": { - "balance": "10000000000000000000000" - }, - "fcb38809b63810b6673dcb4c947e01f7b49fb1b3": { - "balance": "725937240372000000000" - }, - "fcc0e531d9f6265672aa885af361534464a11015": { - "balance": "22121462657000000000" - }, - "fcc49c62d7738fa1b92aa6a69a12b671e4c7c8d9": { - "balance": "50000000000000000000000" - }, - "fcc95394fd796ca5bd8f3814883b1150d74dd9a5": { - "balance": "144000000000000000000" - }, - "fccdb068dfd599d7d5c290a6ae65eba9151d5b29": { - "balance": "5369426564000000000" - }, - "fcde41ae28bdf9084a28f47a9348d8aac5b3dd43": { - "balance": "409599263197000000000" - }, - "fce5816f066ca32d1fa02e9e8b5eb8a7fa3e4dea": { - "balance": "1193272309645000000000" - }, - "fcf9fb8996d6d9175ade6d6063be0742de20ea1f": { - "balance": "16852526239339000000000" - }, - "fd10488d55e6861cb67f7f50950d78892e7032ad": { - "balance": "165069902909000000000" - }, - "fd23e8263d89256add0dfe93da153d305ad917c7": { - "balance": "26633825496000000000" - }, - "fd3a98cc3b3f1439af35f806de2fb05fef98f279": { - "balance": "1043321187464000000000" - }, - "fd3d79185a91984a117ee6f9fd304725875094e2": { - "balance": "2349991833898000000000" - }, - "fd5e6ac22634f04ec4ace5da8996c2b7b70b22f4": { - "balance": "10000000000000000" - }, - "fd62ed1cf7a535c989fbd742b1660205a2f69dd0": { - "balance": "49000000000000000000" - }, - "fd645043bd4d7b71e63e30409b91e9fdda3a86c0": { - "balance": "362957768837969000000000" - }, - "fd7014fc1c70af482115247ff94ff6bdbd3d364d": { - "balance": "743383172317000000000" - }, - "fda0cfe95df9021497752b04863c3ec44d13e853": { - "balance": "15586809617955000000000" - }, - "fdb5b964808bcb974d3e888cbb45bcd57e57c907": { - "balance": "5549247772273000000000" - }, - "fdbaaa865ec38da13e80554b6d0abc437f60d8a5": { - "balance": "3736861227131000000000" - }, - "fdbb8693b3c20c0eac5fb585e2347d41debbffce": { - "balance": "100000000000000000" - }, - "fdbdaec57829f25ad48e18d94e0b8533f2801818": { - "balance": "6934630922926000000000" - }, - "fdc318ba5b1f8ad33e00528828b93a840592e2fb": { - "balance": "10000000000000000000000" - }, - "fdcf6a997bb10806e4d87eb4222e9f93b4202179": { - "balance": "1000000000000000000" - }, - "fde5a9911a10770d733db4d32ca9a5493478399c": { - "balance": "20000000000000000000000" - }, - "fe39185a6b84378820ee215f630533e658731ca9": { - "balance": "17022202932000000000" - }, - "fe3b1032e524674cba5f329f940c837850fa53ed": { - "balance": "50000000000000000000000" - }, - "fe3bc4ff2c3b66bc582558314b80030407e7de96": { - "balance": "1669870860988000000000" - }, - "fe668dbb1f3de744d16e13e0ed6f5708c2c15d1f": { - "balance": "39974355655263000000000" - }, - "fe95bfb97fa60341f8af2ad621e606b85e3c2e57": { - "balance": "528601649597478000000000" - }, - "fe99cf2a1fbbe7c46e4235b2d135a3a093fcf16c": { - "balance": "7271022106877000000000" - }, - "fec1f6ed4b3ff01e7ebe13fb53f60ee5a3b9e191": { - "balance": "1316316072034000000000" - }, - "fed9bec1b2145452ed5535e4ba29fafac6c35fbb": { - "balance": "10799354586000000000" - }, - "fedced7aa1cf3f3a7eec321cc0274759b154ea8e": { - "balance": "11740927210323000000000" - }, - "fef5063701a93ad02676fe0b99d0f4d2da0ccd67": { - "balance": "10178531012000000000" - }, - "fefd5627a408ca099587892ee2a46fa8cc89be19": { - "balance": "458504035686000000000" - }, - "ff1fc0f6f26188cbe18cf65d8a344d3775aecc6d": { - "balance": "81000000000000000000" - }, - "ff4fe483b3c04ebc8d6705c699ecee3e92071715": { - "balance": "1000000000000000000" - }, - "ff51bfe823394b2bce05947a6068bd5158d4af0e": { - "balance": "692533626783000000000" - }, - "ff6652e4e45f6b0f95ad4c9ec2bc80476e3f7fc6": { - "balance": "46457898024000000000" - }, - "ff68246ac7640091e5e58345736b249e036364fc": { - "balance": "2626125272000000000" - }, - "ff6d4b8a8393a503047ff829dbf2bf8e9172dc6d": { - "balance": "2865001878255000000000" - }, - "ff6fe19e056a7211b7e484c2c540d5aa5f1d83e5": { - "balance": "36000000000000000000" - }, - "ff7fa33529e1781c1b2951e57581780b229e3fda": { - "balance": "10000000000000000000" - }, - "ff82d1052538539d07cf3955476cc9a5027d8e4e": { - "balance": "83572023121000000000" - }, - "ff8acfe75afcc1efb1bc44be9f9bb242a94f73f7": { - "balance": "7556034521000000000" - }, - "ffa2b5f1685de9fcf1af4653cd3a584db1beed64": { - "balance": "114892199805000000000" - }, - "ffb1e9be68ae8be8d7d066c473589921e68825a2": { - "balance": "484660652980000000000" - }, - "ffbf91a9d1a6377b7435e3e734132e7b34188dac": { - "balance": "20000000000000000000000" - }, - "ffbff1fab9f2bc2f387d0cc9cc28f6aac533c813": { - "balance": "10000000000000000000000" - }, - "ffc4ff6433ea35544e7a07fda170e62c451301df": { - "balance": "29238210920000000000" - }, - "ffc7534b64a8fe8760e931a710883119d28ae106": { - "balance": "500000000000000000000000" - }, - "ffda6b8e3de72d7f7c18b892e6a8b80b886d5fa5": { - "balance": "214366938289000000000" - }, - "ffddb1fb7521c9772ea4886aaf022c4375ef904d": { - "balance": "554864446437000000000" - } - } + "name": "Ethereum Social", + "dataDir": "social", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x2B5E3AF16B1880000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "ecip1017EraRounds": 5000000 + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x0000000000000000000000000000000000000000", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x1C", + "chainID": "0x1C", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x0400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x3230313820457468657265756d20536f6369616c2050726f6a656374", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://54d0824a268747046b6cabc7ee3afda48edba319f0d175e9e505aa9d425a1872b8b6f9ebf8f3b0a10dc7611a4c44ddec0fc691e5a5cde23e06fc4e4b3ff9dbef@13.125.185.147:30303", + "enode://7e150d47637177f675e20d663fc2500987f2149332caf23da522d92363be8a7880ef9150a6183e9031288a441e0457239474967a111eafce17e19a4288076ea9@18.219.40.235:30303", + "enode://6244c9d9cd288015d7ff165e90f3bb5649e34467e095a47c6d3c56e8fb8c849b3b4db683ff3c7ae8a654bbdc07ef12ee2fd7d72831ac213723281c1b0cc90599@13.250.220.98:30303", + "enode://e39f162b9f4b6ed6f098550f7867c2fb068fc66f362b3db0f45124c43ea18508f5ceef4e0e4de53d301e14a6f1683226aeb931d7401b4e83b5a583153ffdd7fd@52.57.98.157:30303", + "enode://54b4a117d66dc3aa93358dec1b31d4f38e72e4381b3e28a65ac6f1aaac3b304ebbe41d32cc864fa69a9a6815c34cf9b8965690dc174a5f72af14547b601b7924@222.239.255.71:30303", + "enode://851f14c5cc86cbc0a81acfcbe5dd99ad5c823435357219df736932c5f89ad4318f6973a553857a32d97a71793f5a35c062d46320be282aa0a80b06b9c6b624e4@13.125.232.71:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "ceed1c8254abaf069669fc6045e90482543d1f2e": { + "balance": "38000000000000000000000000" + }, + "6f22d7f8c38e0135e36be87e77fc8d4ae4b3d965": { + "balance": "38000000000000000000000000" + }, + "d016e982b7886302428d7c741392c658337513d2": { + "balance": "38000000000000000000000000" + }, + "defa96db5c8a41772bc56f68f95e307ff71a2c60": { + "balance": "38000000000000000000000000" + }, + "951ffd4253ffcf31b2895dd3f7f2a8a9bb2933e5": { + "balance": "38000000000000000000000000" + }, + "b7071dba21cfbe1b70abd7ddfd2f0f83d5d19a61": { + "balance": "38000000000000000000000000" + }, + "6ca420cd8d5407c61a9b14adcb38bee0f26e2848": { + "balance": "38000000000000000000000000" + }, + "b50d185b6cd04499a38afc0fcfcb59eaa74d0956": { + "balance": "38000000000000000000000000" + }, + "7ba8c49a444c117f2d2a50650b3f700d4ee659fe": { + "balance": "38000000000000000000000000" + }, + "83f9959ecc532dce071fcd0c62dc23cd571b689b": { + "balance": "38000000000000000000000000" + }, + "001327afce7ebb623a7d0f17b2ffc358fb863b5a": { + "balance": "9844198127334000000000" + }, + "0015ac7f8bb2a2c7d954fc2dbd4e20c0db5942a5": { + "balance": "1000000000000000000000000" + }, + "0021e69c041be2d28744b69361105ff51295da59": { + "balance": "1379639894000000000" + }, + "002cfd27bbb8164681b8762e71b2891beb127fdd": { + "balance": "25105286685000000000" + }, + "0033cf217bc765ccfc338869451588ce448fde65": { + "balance": "23425485280069000000000" + }, + "0048f1d1735979cd8ac9c0886088336b2d4a43a6": { + "balance": "10000000000000000000" + }, + "006a79cc154917cf204d8097728f290e29716d43": { + "balance": "20000000000000000000000" + }, + "007c8db36e4f649b14516dd78202670b671ba753": { + "balance": "1000000000000000000" + }, + "007d131b58388f251075a3c61020ce301106c5cf": { + "balance": "381079535880476000000000" + }, + "008e8fbffc2fdbefaa7e3be4f4a9160db826d05f": { + "balance": "10000000000000000000000" + }, + "0126d86b9814b0e78c4e01a3916bee6a7778145b": { + "balance": "10000000000000000000000" + }, + "012cb961297c837630251a173b7861e77724856d": { + "balance": "494562376059000000000" + }, + "0145886dfab5ef4f2def50a56b4a074cf5b18acf": { + "balance": "680585022951000000000" + }, + "0167918bab62aa2118cfa4d3eb80da0e71c71d8b": { + "balance": "122395119468000000000" + }, + "0182f7286ae9d4d6bc514d5175d14685d520bde7": { + "balance": "10000000000000000000000" + }, + "0184e9c8fe99d85100fe28a0e8877b14768b372a": { + "balance": "193295614762000000000" + }, + "019eff7dce7f31c2d4f7318da71d212cbf89d36e": { + "balance": "64004138198000000000" + }, + "01f3351ea66c352346244dbb79189066bed62fc5": { + "balance": "937056266523000000000" + }, + "0202ddd7f4f32bc575f7df24612f8aa9f9a7ae42": { + "balance": "106905151080000000000" + }, + "022b8c65e959cab71f56688b7073257b58bbef4a": { + "balance": "9682681149566000000000" + }, + "0245ff6382eb93ab1e8ed2e3c0bce7a1b9a9713d": { + "balance": "289000000000000000000" + }, + "025e117a69ca9244ed430732c11e550e3ee67577": { + "balance": "1861905310567000000000" + }, + "026e7457eeaeaec7898fdee1ad39be89e92733b3": { + "balance": "7529030978000000000" + }, + "028d2def8c54fcc77bf0191b183c0bc4570ec1c5": { + "balance": "9056720934000000000" + }, + "0291a087605b516e465134797b5459436d320e6a": { + "balance": "481100929805000000000" + }, + "02a4b18b3e13ec79307e712fba1867cbf7fb6155": { + "balance": "9000000000000000000" + }, + "02a812d4cebcac1a92ae470ade92fde7bead127d": { + "balance": "66793603497000000000" + }, + "02f718c94b2c8e8d62752f8632443504c1e4b6e2": { + "balance": "1000000000000000000000000" + }, + "030dab52b47b37505b72e5ca0985f65ead590816": { + "balance": "1376851176362000000000" + }, + "031c59846f75de1aefb0e8a95e0fb822fd06555b": { + "balance": "140978338628000000000" + }, + "031ee87c672d83ec73059c86a312a9e972142054": { + "balance": "96406273341000000000" + }, + "033182e860564cf695cb403c8c0f078053368d7d": { + "balance": "1504349255824000000000" + }, + "03788dc6528fa33a90e90e03295ae4b792d56644": { + "balance": "24356250426000000000" + }, + "037aae119047028157c5b3bc9d3d202b02cbce42": { + "balance": "105627739575000000000" + }, + "037d45b323cbc5cbac999c5001169646e690b94c": { + "balance": "2000000000000000000" + }, + "0390ba35c454a24519d845405a7e24df71250748": { + "balance": "1872501898509000000000" + }, + "03ab8c1e7f904db62437b16d28aeb539b2dee55e": { + "balance": "55000000000000000000000000" + }, + "03af4c69728a888fa26b1aefa439005989771fdf": { + "balance": "27704588237757000000000" + }, + "03b33fb19d165e5e33bcfbbfc009f418d71f30fb": { + "balance": "1999139000000000000" + }, + "03b34c79f8167a4e8be0f6133254d2b50cbd878d": { + "balance": "111065050160000000000" + }, + "03d7e8638b74ae44a2770287285489a95fa1ea11": { + "balance": "20000000000000000000000" + }, + "03d870bf719f03250c0dc5156a36751b3aa21f18": { + "balance": "981119649953000000000" + }, + "03de52c12b05fb8bcba3a1cfe02a0ad1bc9761d3": { + "balance": "362007990932000000000" + }, + "03e516db27b1abe008ffc57ced48f72f872d8b08": { + "balance": "3389116345657000000000" + }, + "03ef5ff863ee5f1167f38cdf316e4d52a242b750": { + "balance": "12395856876000000000" + }, + "03f27766760f2bd1cae1cb85ddf43ab59c871e47": { + "balance": "49000000000000000000" + }, + "03f4e1a8fb4eedc776f4835fcc85d0f236612f9c": { + "balance": "27210590272692000000000" + }, + "0404936ee04cc79cbb3aedfa33a53f94940f772c": { + "balance": "29919204637416000000000" + }, + "040501ffde9649be794b7d41643273ed6285ab39": { + "balance": "686000000000000000000" + }, + "040e449de680f69614120f0a2e894cde36e4adf1": { + "balance": "81993180085000000000" + }, + "041531e906dbdc70d89f5e255151d9865a059308": { + "balance": "2163418749315000000000" + }, + "041ad9f6bf970541e4ea8a14dde1e789d0fe4367": { + "balance": "44999979000000000000" + }, + "0446420c07cf73d2b3741b945c1cc8444b4ba6b6": { + "balance": "138749371512564000000000" + }, + "044c1a540b8ab286c218c2fa9d5bfbc2761e7626": { + "balance": "1" + }, + "04526b2c62911e78a939816aa4575fe30baa06c7": { + "balance": "2983093150081000000000" + }, + "04adf59f8a0ad3820a7972c6243202b3b0617fcf": { + "balance": "50000000000000000000" + }, + "04bbb42882a475eed58aae47fe530ed19c1cedaa": { + "balance": "278038763863000000000" + }, + "04cff7a7c2b9b0bf31c5ad4a5de8b0eade70aafc": { + "balance": "515406205244000000000" + }, + "04dcd325dc1fd37ff3c87da3b21c47ddfcc37cc2": { + "balance": "5831887315000000000" + }, + "04ec8d0b5157370f5a2671a2aa68ae486b7a7842": { + "balance": "10000000000000000000000" + }, + "04f50f2a6e89ee497a64c11baa90759a10a1247a": { + "balance": "25443071621949000000000" + }, + "0513a769ebef58ad3a4fd7011ddbe19799ff5600": { + "balance": "64369494797000000000" + }, + "0514c1151f356070ace281435f25c86b58280715": { + "balance": "38967380881301000000000" + }, + "052fda414fe1279c6276a237b07e1b4148a8cc77": { + "balance": "10000000000000000000000" + }, + "05431089cc62a987d0e99847e10a006233146f6d": { + "balance": "268977485219000000000" + }, + "054ed2f55028257212b996f9a3d34758d1d4ffd1": { + "balance": "100000000000000000000000" + }, + "05a68cc758560addde302baf814f2fdbe0ef2c2b": { + "balance": "10000000000000000000" + }, + "05c669d9ded79fe9e4e3718052bc7ca18a3205ab": { + "balance": "7347158140000000000" + }, + "05d77ce5c87477b05e90e829dafd8eb3a8c87823": { + "balance": "21191998933000000000" + }, + "05ef2894a2a1c6eb6c0a768d04ef5b573f357712": { + "balance": "20000000000000000000000" + }, + "0601011f80279190b96f641205c6a524a8ad5a28": { + "balance": "12025716447696000000000" + }, + "061a8acdb1a340ba7c550814831e27262708fc98": { + "balance": "234029764576000000000" + }, + "06219483e217c9ad479f76a95426f689ef4d5951": { + "balance": "1509408723551000000000" + }, + "062d0db8a650f2241f8a4295326a2570a7c771bb": { + "balance": "717459720227000000000" + }, + "0633ba746235d8fc8243751b1aa31646c299f262": { + "balance": "49000000000000000000" + }, + "06b6a5cadfe1fdc88015512e835d840e58ae4123": { + "balance": "1000000000000000000" + }, + "06d08fcbe96791514d900d2cb6c0f029d8d791d0": { + "balance": "19196168602258000000000" + }, + "06e5c0bad43a7011878b12a682abf01ccdfaa151": { + "balance": "30000000000000000000" + }, + "070656bb11ec36074d47c791c0b306394b703401": { + "balance": "1245216075291000000000" + }, + "070d84c938217163b60ed38e4937eea7158c03d9": { + "balance": "27507979787000000000" + }, + "07428c95ef3862026e54d3a963911cdc673dbcd9": { + "balance": "13792309994528000000000" + }, + "0781cb21df142ec5f67b956bf995f02f6f24985f": { + "balance": "224940990659000000000" + }, + "078c38c153b414cc4c12818fce2ea7ba09a34e51": { + "balance": "1410646136000000000" + }, + "07bfd0de7a9a1c927446aaf2d7ede55b471daa87": { + "balance": "77778844734000000000" + }, + "07d1ac83140188b8d7f4c8c607d0da22c5ba523f": { + "balance": "7713686418107000000000" + }, + "07d8ef8fc6dcde319a5af5b6cea18983bdc4c8fe": { + "balance": "3801361173000000000" + }, + "07dfab72dd3e44fcbb1ced625899bf20e0c52ffc": { + "balance": "154177778806000000000" + }, + "0817ce33d943e84c7b3261cc3e37b86b5d6d76ae": { + "balance": "90753785862000000000" + }, + "081be00a2ff62cbcb95a8eb020ac0efa33f93a42": { + "balance": "1027889807304000000000" + }, + "085ffdc6043b04653e51b1a34af20b609d158607": { + "balance": "3314058000000000" + }, + "0882c2228f5df24064bc37e8b7199199de308bb8": { + "balance": "98420617420000000000" + }, + "08918776e9a7136cedad5d0cee52f5d9dd833ece": { + "balance": "1263170315026000000000" + }, + "08bdbcff16919abc5e15fa68ece56eceef33f48d": { + "balance": "2552990000000000" + }, + "08fc8c7bd03fe1249266b233edfcf830693d0e10": { + "balance": "283490111768000000000" + }, + "090f79a4178b5180150444805f62c26cd21be897": { + "balance": "884195010282000000000" + }, + "0914a9dfc9d6ecc063a55e5320050112f305fe17": { + "balance": "15373898854941000000000" + }, + "091791ab5f8ab86f1d8f566ed221b268cbc55347": { + "balance": "2207516004000000000" + }, + "09529f8b1633ce4375451bb44b1025f6e5f9facd": { + "balance": "151697652792000000000" + }, + "09600bbb9d9b23661d269dbe1ed066d8e573b5e1": { + "balance": "802935104935000000000" + }, + "0964d2af1d5883fc0e0a77459f6a141824de7356": { + "balance": "9610980935058000000000" + }, + "097c731d1fc6792ac0f0ff92be4403c3749cc1dd": { + "balance": "165134479709000000000" + }, + "097f152b3f837d38ab1e8c0683d62f5a01d67902": { + "balance": "20000000000000000000000" + }, + "09a6772629ef0bf402ae6d27cd32e6eefb220a12": { + "balance": "20000000000000000000000" + }, + "09addb954d4e4b4e95e0c66d324115d609df5a99": { + "balance": "8435321515000000000" + }, + "09b2eb03e0fa321102196578eb40dcba3a46ec9c": { + "balance": "12723517962933000000000" + }, + "09ba0ed4dce470ba0bcb4d46b507c3b024b83070": { + "balance": "99999979000000000000" + }, + "09efbd6dfea375065be1b3a8f4541f024da21a34": { + "balance": "5870833623000000000" + }, + "0a24d4ae66edc7723bbb314e9b96dc7b9a31e813": { + "balance": "70000000000000000000" + }, + "0a3ee710909382f762648deff8ac7c8b30e2ce10": { + "balance": "407656462445000000000" + }, + "0a42b3145257154e76a97db8147c93be4cffd97b": { + "balance": "10000000000000000000000" + }, + "0a7cb6037f1eba5d19fe781335ecd37b7229c5f7": { + "balance": "74113322448000000000" + }, + "0a85d1bec4d44e309068b115abd517d3733fc56e": { + "balance": "14836218750000000000000" + }, + "0a891ba9ca7b99ecd815b1dcec9243dd4deff866": { + "balance": "178004857988000000000" + }, + "0ab69370b537d4ff5b45704fed293e46e3464f87": { + "balance": "1258876668246000000000" + }, + "0ab77a2e8ab9a3b659d1f1d37956c3607a0f9a60": { + "balance": "6283300817712000000000" + }, + "0abc7e8d52f5b0dcf1d4713e5fa4909102251dfb": { + "balance": "39307290577000000000" + }, + "0af2c0471c802d2e2b20aadf9dd4ec842d313ab0": { + "balance": "1529468143183000000000" + }, + "0b08c717bb3982fc8b92d5b3d30e5b41265a0d0f": { + "balance": "1184600154874000000000" + }, + "0b3f2aa9dc5b57b0469398d62f60a13774ec0e87": { + "balance": "132187640280004000000000" + }, + "0b3ffe85aa89e71a6e51e938c7265d2a7173061b": { + "balance": "2106793086824000000000" + }, + "0b468562e712d22b37e1a65f54b1fa825beebd1b": { + "balance": "15130906006000000000" + }, + "0b5333eb668dee29ebc0e335d74f33ffeaae9ac5": { + "balance": "125953133109000000000" + }, + "0b59a20107495e951b509187307782ca9dfa441f": { + "balance": "25000000000000000000" + }, + "0b8b7fb066601ea7744b81f6e1a21b8e489359cf": { + "balance": "101782000000000000000" + }, + "0bd7791097f79066d71ac0a2c94bce6628a63373": { + "balance": "44389955028000000000" + }, + "0be541af06e167206b5d1cbe08e8fb2b5ebc82cb": { + "balance": "9000000000000000000" + }, + "0bf178bba463f4f6c33e3d81b1a78d220f7b5d4b": { + "balance": "111784804790646000000000" + }, + "0c1f000249b1f1ac9e43c4f10e2da1cc2adf886f": { + "balance": "91251997635000000000" + }, + "0c74e46b115e19726997dd559d2b6ff1bfb79af6": { + "balance": "879229287149000000000" + }, + "0c7c1ec152c920a068c25626c22c4fae7f435536": { + "balance": "39849464104000000000" + }, + "0c85fbd7492d1ae87bf3d286c4750a34f1fd3121": { + "balance": "20000000000000000000000" + }, + "0c9fd6123e313f7d1f0cb25d99839102da08b2c5": { + "balance": "10000000000000000000000" + }, + "0cb051e3bdd9d96e667fbcc00a766d4f149f89e4": { + "balance": "1000000000000000000000" + }, + "0ce32bf6c433cbd26c6f09a1214db0374002784e": { + "balance": "3293279842000000000" + }, + "0ce6374ff04430e34edec8b6323feab2bccab92d": { + "balance": "93983447000000000" + }, + "0ce646412a1524c3f73edfd753c0ba3ee7338275": { + "balance": "10000000000000000000000" + }, + "0ced803e56eac3c99269ff7409d2d200d62d7c25": { + "balance": "49539379000000000" + }, + "0d1dc2be9f78ce2b2591e7f5b8af9dc778499bd5": { + "balance": "2235348003595000000000" + }, + "0d235583458a168e810275f907b5f87bebb2d1cf": { + "balance": "83106439283110000000000" + }, + "0d28fe6e8b7d4b8c90ef7c52b9656511ce5867f1": { + "balance": "1347248794799000000000" + }, + "0d5cbe0da660cbca831787efc45fecb20e06e02b": { + "balance": "297528508941000000000" + }, + "0d7a24f324176f6d793c3a2eb6c54d6ee47eca79": { + "balance": "25637813467000000000" + }, + "0da26a24e3650e84c52fedb36ef76225a8d9d259": { + "balance": "15467820321000000000" + }, + "0db7eaceaf3df21ebb49c56fa2d2e2c8e85dec52": { + "balance": "196000000000000000000" + }, + "0dde52823bd8fb2cb179e6d417c07ff285c31775": { + "balance": "347321514878000000000" + }, + "0df9585f1aa83189e0a813f5eac6e6e0b2bbb8d8": { + "balance": "2891430551000000000" + }, + "0e09af9368f05b476164953b7b9db60ac95248f0": { + "balance": "573644391203000000000" + }, + "0e18315dd2b663ce4859b5bed854403191452c2f": { + "balance": "24174325261000000000" + }, + "0e29bef5f4f66c38a0f05cca1e4938d57ff09c70": { + "balance": "10000000000000000000000" + }, + "0e443353b42e042ff5168e9b3c6de37070368223": { + "balance": "20000000000000000000000" + }, + "0e8cb6e439516b312158f169b546937b715db3f2": { + "balance": "8049136367000000000" + }, + "0e980fab23be601f3abec7b9a24e1335a5e765c8": { + "balance": "8301885845897000000000" + }, + "0ea63fef218ebf570a4ee62ef6ed712dbe623c44": { + "balance": "10000000000000000000000" + }, + "0eb60e3512336e4447ceeb8664ce0ecaa3eb0bdc": { + "balance": "41401696400000000000" + }, + "0edafc1058879a9568e711445b18ec4da31d2480": { + "balance": "10000000000000000000000" + }, + "0efce4565062b23b43dbc1e261463e363e4a5b4c": { + "balance": "10000000000000000000000" + }, + "0f08782c04bf7249ab08f4e251abc60aee792a96": { + "balance": "1380257622493000000000" + }, + "0f19bfe1eb24def828bf1be69791c63ba1de1263": { + "balance": "2223687184885000000000" + }, + "0f2171161eb9674218add261be61d18d86b846a6": { + "balance": "121000000000000000000" + }, + "0f42ef6c5690b6c95f8b8c9dbdc16f717c04852e": { + "balance": "81000000000000000000" + }, + "0f47f5063d321b34a0d800951bcdc3f53c07e32c": { + "balance": "5288516165000000000" + }, + "0f529a9beedb2c2a087a220f0013cea4f8454bfc": { + "balance": "114585457979000000000" + }, + "0f6751d10aaf855454a6e9e4241cfcae3b0ed732": { + "balance": "94160300063000000000" + }, + "0f6ed5a4c3ec100afcd59e9066ba7fcb63cfa6dc": { + "balance": "1000000000000000000" + }, + "0f77025519cc76c38e1cf0bd8721f4a5b9c814d4": { + "balance": "834620571043000000000" + }, + "0f773db2a1a96b775e4481575704f5f087b067e0": { + "balance": "554268361745000000000" + }, + "0fa0f73adbe82f8e09f8adbce15b051971e289c3": { + "balance": "11329911975000000000" + }, + "0fa6397d747d88a25d0c755b3be4eee0e3f68912": { + "balance": "31394936138000000000" + }, + "0fac8635a61bf7652d86725cc75c307949bd4f2a": { + "balance": "49000000000000000000" + }, + "0fb0ce787306ce13dcd614ab3d0e15d9772106ac": { + "balance": "50000000000000000000000" + }, + "0fb1d306d240360056f60f197dc7f68f732ac515": { + "balance": "20000000000000000000000" + }, + "0fe3571f498a6d945e123ac8ff6e3fed348d9432": { + "balance": "20000000000000000000000" + }, + "0ffd6b01ea9a7bd2576fe4a5838fe09e44c1639e": { + "balance": "100000000000000000000" + }, + "100bde3d73fda700369e78229127b58d2ade9177": { + "balance": "10000000000000000000000" + }, + "102028c7626970a28677bbdc7733484c8b14c2d2": { + "balance": "500000000000000000000000" + }, + "10245044be6a46ad41d4559129cb59e843379cf8": { + "balance": "857437279765000000000" + }, + "10417d0ff25c115b25915dd10ca57b16be497bf6": { + "balance": "10000000000000000000000" + }, + "10579870e6685ed7e97dd2c79a6dc3528bae968e": { + "balance": "5187866041491000000000" + }, + "109736465b4bbe31ea65ad01fc98f04498271e6c": { + "balance": "20000000000000000000000" + }, + "109c0535a4a86244c5094e99167d312a77657dd5": { + "balance": "138277702073000000000" + }, + "10aa08064689ee97d5f030a537f3cd4d8bbdaf74": { + "balance": "10000000000000000000000" + }, + "10d8bc8c3d3e2010e83009290586ad85b73321d1": { + "balance": "25000000000000000000" + }, + "10f22b82460252345753875555de2cebebe63a93": { + "balance": "765947730644000000000" + }, + "11111c3a2cfa55e52d6aacf533e1d412f8c8c01c": { + "balance": "4827254128275000000000" + }, + "11386103a0bf199db9504b617ccb3bbd780eb9fe": { + "balance": "10000000000000" + }, + "1156a129183e5bdfdf2bf7a70963285a979363a0": { + "balance": "10000000000000000000000" + }, + "11589cf70a6a4fbaac25224e2ddab222333f78e6": { + "balance": "49000000000000000000" + }, + "1162fabeb3eb1e4124179b00c4a1e01503023f54": { + "balance": "817145350625000000000" + }, + "116a7d140f4b7f9b4689063a8417ac07a32bae00": { + "balance": "106088220142108000000000" + }, + "116dc38ddb4b138b19ce6a51e5922c287da5c86b": { + "balance": "100000000000000000000" + }, + "1175f84f835a5ae40d49b8ca17e3e474c1eceef7": { + "balance": "1698584794716000000000" + }, + "119f822a796fee9c41a488949fcb14b589ffa628": { + "balance": "20000000000000000000000" + }, + "11a99f6019b6a53f5dc8cbd0c34f1ee75ced33b8": { + "balance": "102126982156000000000" + }, + "11b9324406068e8bf598d3a9ea59ef31c52f51fa": { + "balance": "6525925895203000000000" + }, + "11cb7be6869a10f5f9e8a47c6c92f729b083084b": { + "balance": "182959434323344000000000" + }, + "11d96a76166ec579e2b6cfa903f66da4af669351": { + "balance": "1000000000000000000000000" + }, + "11fcee55f78278df60f50096d45da1aafe72722d": { + "balance": "222859488179000000000" + }, + "120a1fc914718acd85bf92d9492330165d78075a": { + "balance": "3736627235906000000000" + }, + "12366136d83c77befdc30e04d4f5d808419f504f": { + "balance": "88008649003000000000" + }, + "12435af3f2f92ec43e8f2894be9c72fa932880fe": { + "balance": "1590548436852000000000" + }, + "124ff67125a00aed24e58b6d64ffa887a59b48a4": { + "balance": "20613022349070000000000" + }, + "1296f04910ebc89556ec7ab1b178fdbf14d0295c": { + "balance": "36000000000000000000" + }, + "1299f180e42bfaa1162d36110d29ab062e43e1c8": { + "balance": "321570118362000000000" + }, + "12abac62150c526866ec958cd0e3721b2c78d550": { + "balance": "51898545633262000000000" + }, + "12b345087cee385b9adccaaaa6741b767c82d7ea": { + "balance": "36000000000000000000" + }, + "12cd5e8c0c93f8e34b589b95954b719f54d1515b": { + "balance": "1000000000000000000" + }, + "12d262cdd25edc39b6fd9ae78184eb548e513927": { + "balance": "500976168000000000" + }, + "12d933448218629702c48547b3446b629ec65883": { + "balance": "2168010577395000000000" + }, + "13054aa42d3e119220ac359641c15f8b54bfffef": { + "balance": "24986834005530000000000" + }, + "130bda09f463a982199849ae617062a1d68f3a85": { + "balance": "154504844790000000000" + }, + "131a5da679863c05dc627d53634f2925ba0ce731": { + "balance": "10000000000000000000000" + }, + "1334f2752b5c21f681ba9e23a9fe95a85f8e05f1": { + "balance": "121000000000000000000" + }, + "13634512e2ae79fe3febb9e55e03b47bc350d7ba": { + "balance": "338331304738000000000" + }, + "136fae842aab625768bef9079ee1711e8c007d8f": { + "balance": "2759741687626000000000" + }, + "139fa969e8b74bee1f6113a362f15060ea998b15": { + "balance": "10000000000000000000000" + }, + "13c7e1d694bde6f8f6a31eb6c99f38dc739d61fe": { + "balance": "10901074773586000000000" + }, + "13c849944ad6ad12a46c46973d562bee8284f46d": { + "balance": "35114615504000000000" + }, + "13ec3aa8f4a427ecdecc7901060ccac9bea7a61e": { + "balance": "10000000000000000000000" + }, + "13f478c74acfd6897d13e602a8d362893f4fd038": { + "balance": "3521111850000000000" + }, + "14403970d0784a6458a7bf2584a53d14234e8860": { + "balance": "25000000000000000000" + }, + "14440bb7410337e34a064a92206075575f5362ee": { + "balance": "14918844868393000000000" + }, + "144a88e7a8af70b8bef5c4b70ee0cff771d0c252": { + "balance": "67961927542000000000" + }, + "146b79f474176a4b0069199b03669ab6467a4787": { + "balance": "122518123211000000000" + }, + "148893e7811c36c6bd1ada367681ab8327b3b2fa": { + "balance": "1313118418375000000000" + }, + "14900a17784e3b4d89d98b6cb31c74c685418b89": { + "balance": "131112181597000000000" + }, + "149a483758a98ffe28f7f25cfa17d7433f852ebe": { + "balance": "10000000000000000000000" + }, + "14a03c8e84f07c5596687a98d1e0b1859e9b34ac": { + "balance": "55000000000000000000000000" + }, + "14c7899cb34b5447d6363d4e8355113ebf4bcc66": { + "balance": "197554844582000000000" + }, + "14efa63ee285277c0f8e0d5cc22193e17984e11b": { + "balance": "106221254735000000000" + }, + "151c6099b3fb5b18e0e36a3335dff186dcd2904d": { + "balance": "4304311254087000000000" + }, + "1525dce233a971eb1387f130fdf0e5bf3455723b": { + "balance": "45004174531000000000" + }, + "15271904676f2bc2511294e500152d05ea9acc85": { + "balance": "9300898622566000000000" + }, + "1556ba42ea69d72c1d0faf802906645268e36aac": { + "balance": "171939212653000000000" + }, + "156558fb71ff986953d899c9916a121fd047675c": { + "balance": "290926338537000000000" + }, + "156fbf32614aac2cf462952ec1a3f141f797316e": { + "balance": "6084388860000000000" + }, + "15b9497d6bde8017baf3c29e12430e05a47efbf4": { + "balance": "206126229839000000000" + }, + "15d532e828bdcaf1246696d679a2eb66a154db5d": { + "balance": "69656571015000000000" + }, + "15e26a60cfaf23dfd9bbb999a30904d11b6ddd05": { + "balance": "9839303178835000000000" + }, + "15f3be2f11ee3b19472cc3d171931f050d8629a2": { + "balance": "13572825921000000000" + }, + "16254bed335420e5f793de2295b0081ac41a08d1": { + "balance": "144000000000000000000" + }, + "163aa91bc2ad588116141d48fcbd943985455cac": { + "balance": "618250979557000000000" + }, + "164cff4b9341d536b8aaf2d1dd0e3ed35ecb1db7": { + "balance": "671554639913000000000" + }, + "164d2a9a63868ac25bfe26ecba446d7ce256c351": { + "balance": "7233638188261000000000" + }, + "164e759b64d3ee0a23ec3030f50a1b454a6ec15b": { + "balance": "12281161499000000000" + }, + "165d4a0f23c016b8064adf0dcf7e31bc06350777": { + "balance": "256757922324741000000000" + }, + "166b862954dacddc3333aba4edbe523d693df858": { + "balance": "123677971414000000000" + }, + "16858eb1a6f0e7ff01b91aa9c92d0a433a5f767c": { + "balance": "500000000000000000000000" + }, + "168909a1c2a43cff1fe4faeac32a609c25fbd1e8": { + "balance": "62258808044224000000000" + }, + "16987ad8e10dda7f9e5d95c0f0ee36f46b10e168": { + "balance": "10000000000000000000000" + }, + "16b5dffce79573300a6514ace5f2e844d26fc64e": { + "balance": "5576805697087000000000" + }, + "16e01370a93befe24f6ae6076cd04c84cd3515b1": { + "balance": "1922179181578000000000" + }, + "16fbafd4fc871c7589e63062133793ab244c2019": { + "balance": "2865030627000000000" + }, + "16fdf76180796c6e4335eaa2842775b2e4a22e0b": { + "balance": "20000000000000000000000" + }, + "17081d4d6ebb9f4b163e181a59c2102c99fce6bd": { + "balance": "490625378000000000000" + }, + "17218ff455aa87b29ad4c4f7ba21e9c6f74fc97a": { + "balance": "1607392037652000000000" + }, + "1725bce47f3700f4646efb343f950e2e8ba66607": { + "balance": "58472967071000000000" + }, + "172c5f71aabf072507664471ebaa435779d74a32": { + "balance": "16000000000000000000" + }, + "173a065f351ee0513cfebfe9b950fd2c641fc8cc": { + "balance": "25000000000000000000" + }, + "174e1793c96cefb584ae0a67fff85c65065dafc5": { + "balance": "50221000010000000000" + }, + "1794bc4d622d514f95da5404358ed404b3f59aa3": { + "balance": "36000000000000000000" + }, + "179839d61e7c7a0382fe08e0573bcfbe42a108ca": { + "balance": "203299791419000000000" + }, + "179eb30b5b28a961eac70a919d26ca96e6472166": { + "balance": "55000000000000000000000000" + }, + "17be72168606fb5d27761157e48fc14789f84634": { + "balance": "311205588354000000000" + }, + "17cefb6611033759b8755197b983de2d7e98315e": { + "balance": "10000000000000000000000" + }, + "17e07cc7d89bcd1708b1f05ab6e1252c629d71cc": { + "balance": "903234908997000000000" + }, + "1811be559b657685c2f163122479101c404325b0": { + "balance": "10060694170000000000" + }, + "181417a4883c429ef26a4baeb48e70d4f00278b4": { + "balance": "4621446218088000000000" + }, + "181d345cd6b5f518bdab8d40f5d4896a725b3f3d": { + "balance": "114349561983000000000" + }, + "184625e544aa31552d2911023a892f739df84be7": { + "balance": "5303698708000000000" + }, + "185e4f6eee203ca3c089baa1e643ff1aab7cc8f4": { + "balance": "33969718257699000000000" + }, + "188e4a1a7b23ff35ec90b7bf7561db9e3c0f53bb": { + "balance": "394325508701000000000" + }, + "18a4dbf513be132f9ecfd69e3eb683d710e28c4b": { + "balance": "5997985132329000000000" + }, + "18c9298f62635ef47d0ef215b8a693af60829c27": { + "balance": "100000000000000000000" + }, + "18e7e2ee0c86bc1ba3595fee3d40257776fe8172": { + "balance": "185584626033000000000" + }, + "196575e74499b741877793f8c8facf2f3b1ddb8f": { + "balance": "30318381929000000000" + }, + "196df33f2d3ed473e6e07650419969f4a39fd03b": { + "balance": "15442864665000000000" + }, + "1975c5293ec9c72a28e6cc74173cdfd8de682fea": { + "balance": "103624886552134000000000" + }, + "19832cd1b2fc4138c8d9291a0f404d3c4326b48f": { + "balance": "4732362673000000000" + }, + "198705f46f31c7ca22f5b88fab210bc5b0c7647c": { + "balance": "548940869737000000000" + }, + "19a5a213e6abfee29f17e871222cbe9ac45322c8": { + "balance": "10000000000000000000000" + }, + "19ab9a7a4e9f9c08c9b4295c406b78389a864ba7": { + "balance": "369299839157000000000" + }, + "19f19f5f01b3f6a1c4f645dc7e3992b1196ccb7a": { + "balance": "97759406000000000000" + }, + "1a11a0b0081522e60e16f154e093ac2e005d24ee": { + "balance": "88024675252000000000" + }, + "1a27309b0c09be2234fd64afdbcfb099f8e2e7cd": { + "balance": "10000000000000000000000" + }, + "1a3d61754974bea23503a61ef0fe584b7b6e6cf3": { + "balance": "326950210355000000000" + }, + "1a49bbde1457a8d4c247606b206ac8d4d389da5a": { + "balance": "402438941516000000000" + }, + "1a7a4b41be64fff3a31eb6166db59741e073d0f7": { + "balance": "250000000000000000000" + }, + "1a8d282e82c606e992f69ce618ba634d98bf2683": { + "balance": "20000000000000000000000" + }, + "1aa0ba27662816e5e3d79e223cc18f5dfef089cf": { + "balance": "187581622694000000000" + }, + "1acab416a1d3e8caa65faca378c79aaf2065b851": { + "balance": "1000000000000000000" + }, + "1acd37af3f87da1dff743dfcb97038d178b1dc4f": { + "balance": "708034481300000000000" + }, + "1ad8f036022c3e5258455d6aa05fb4be5dd121b1": { + "balance": "42957064709000000000" + }, + "1aee811e06c579c21fbcc3b53d2dcf9d5f24808e": { + "balance": "52480060284048000000000" + }, + "1b03b7a4e9908c3531618f49f8d050ba6afb4de6": { + "balance": "28410489187000000000" + }, + "1b073d026e93de51db34d5a8e19047784c277ea1": { + "balance": "20579129628026000000000" + }, + "1b0b87e414bc8fe4920fe104b6de7d17db3a1a19": { + "balance": "10720000000000000000" + }, + "1b411c692c80948e59cd805a0f8574dd67519288": { + "balance": "5416615538000000000" + }, + "1b8d57e995749618c7bb3e60194ac6fc57e9b3eb": { + "balance": "10000000000000000000000" + }, + "1b913efde1255516346b40ae2a48ebf62251682d": { + "balance": "100000000000000000000" + }, + "1ba7276c133f93d43db2f2caddec08e0167eaf15": { + "balance": "82559173174000000000" + }, + "1ba919f7742160cabf2756eb6eae67b92530f3f3": { + "balance": "1102304139883000000000" + }, + "1bb20857de494694fe15bd11f8cac1218435fbc0": { + "balance": "10221322567000000000" + }, + "1bb5c5e81d451f03e899852edc8556a9f7aac5df": { + "balance": "18781017696028000000000" + }, + "1be3507349ed07d3e7902951d490f560a75e96be": { + "balance": "660691718918000000000" + }, + "1bf1c0b2e6f64b612f35f2bf98d894b13dda9bf7": { + "balance": "3050161851140000000000" + }, + "1bfd3c2ba6a537e97cedd542cd554a5050963d54": { + "balance": "20000000000000000000000" + }, + "1c4af5003f9e7223f4141107d21640e4a85a4827": { + "balance": "612390629874000000000" + }, + "1c6a94810bd0afcf79ceea11afe86c34f6813211": { + "balance": "10000000000000000000000" + }, + "1c7e277460191c886cb1647173d27122c2146252": { + "balance": "209062806527000000000" + }, + "1c818ffa9caa61d512fa5d7d6e566f3ae37d5434": { + "balance": "454897845316000000000" + }, + "1c9599d5f8e5eaf8f68d35d52132e15a153f6d3c": { + "balance": "36000000000000000000" + }, + "1c95ab5229fd08c638a1728c022f09291b8dc55d": { + "balance": "20000000000000000000000" + }, + "1c962808c175ee5e5e365483d066c8ea95993700": { + "balance": "1362779746855000000000" + }, + "1cafad295b2188f10192c8a32440931f7e3554e4": { + "balance": "36000000000000000000" + }, + "1cdc2899ec563d79569d1ba776bc03cff331e786": { + "balance": "572163587827000000000" + }, + "1ce0042e7b4f13589f5f8490836dc63e0ca60c3c": { + "balance": "25000000000000000000" + }, + "1ce62051fd7801d294bf31a7b44cd87510e8b545": { + "balance": "2008112411284000000000" + }, + "1cf20f30cd901b2e5fef3f948289dafaaabaa77d": { + "balance": "1444000000000000000000" + }, + "1d449764d38b7a4ac848f49e2dc99df02dfd8a53": { + "balance": "48215693645000000000" + }, + "1d635125c494b1137ca5f15ac95dd6d93c3a9546": { + "balance": "10000000000000000000000" + }, + "1d85a61353c3e0b6d34e105e35c8c7833b6a1e35": { + "balance": "16000000000000000000" + }, + "1d969134ee156c41c98c3721c5dbb092c0b581a6": { + "balance": "64000000000000000000" + }, + "1da12434596a9c318dab854f06d404fe61f0a69d": { + "balance": "16675185416000000000" + }, + "1db0d23fb63681958a66e716e99df3e0b848fd12": { + "balance": "1103581911968000000000" + }, + "1dc628820da657f07ab5eb887d5f512378b5b61f": { + "balance": "6272287019755000000000" + }, + "1e05cba75b0dd379037940352e0073564957b7d9": { + "balance": "12453446342664000000000" + }, + "1e13f037a92ab6f19c4484ae3301b3ac6f48575d": { + "balance": "106244918916000000000" + }, + "1e167bc07f094915c00e7aa4c43b607ed2c998b9": { + "balance": "1000000000000000000" + }, + "1e1f9409bf92c3ef59aa2fd82dce55cd90e23f19": { + "balance": "99139000000000000" + }, + "1e4dfea7871d941e72a161022b62fdb01818c86d": { + "balance": "81000000000000000000" + }, + "1e5d0b525228167334e94314a201388bba08153b": { + "balance": "1138044078759000000000" + }, + "1e6633290c9898abf5fcac54396de770164edc5a": { + "balance": "25052055674000000000" + }, + "1e76296584058670ea80fe9a39d8f457c03747c5": { + "balance": "10000000000000000000000" + }, + "1e88b2c8dcd289929e51a15c636d0b0f3b035569": { + "balance": "87357600832000000000" + }, + "1eb59a1732a159a91a9371650943840e0eb61174": { + "balance": "20542821429000000000" + }, + "1ee077bdef6d45d491602342cee008cd1e2912e3": { + "balance": "10000000000000000000000" + }, + "1f1ebf2f80afced68424cb7b0b966fdf42d508a4": { + "balance": "1460082126494000000000" + }, + "1f3d4a903bd32a537efae19592f5516698c95a20": { + "balance": "10000000000000000000000" + }, + "1f6431696efc6f1ab98dcc2ef0e8553da697e6f1": { + "balance": "20000000000000000000000" + }, + "1f657552b745acbdf731f2ad107d6362480abc88": { + "balance": "162042599568000000000" + }, + "1f699a7682c1266291a3f49e19cac0846470abf5": { + "balance": "712268213248000000000" + }, + "1f7a332dabb00851705274c59187817d859cb9a4": { + "balance": "199999999160000000000000" + }, + "1f7c333047e168f5d3408c42a4919bd44b8f7961": { + "balance": "3918096658000000000" + }, + "1f8226f7a4525b9f3cd4da3acc1bb34529f8d28a": { + "balance": "3530829464000000000" + }, + "1f8b6fcea9e0991ad0b0b25dc65748518a28713f": { + "balance": "142069368416000000000" + }, + "1fa3de6913e4de78cc4828e246554785950c3c8e": { + "balance": "178437291360000000000" + }, + "1faa75d57fd597d2b58d2ac6f65bc2bd5946911f": { + "balance": "13092024644362000000000" + }, + "1faf1721dba3266cde1e04a7e9c789bdabdd930d": { + "balance": "862698523071976000000000" + }, + "1fb861559361701fca1df6ab4ef4d2fb9d2d7e13": { + "balance": "100000000000000000000" + }, + "20154d678cdde9ca1c0acb94726f26617a4da0d8": { + "balance": "2288800561677000000000" + }, + "202484a46ca9d54d0d456bc38e2a74ec5f469349": { + "balance": "50178714107336000000000" + }, + "20324278018b4d8e0c49e0fd1be35d3494079165": { + "balance": "484082383314000000000" + }, + "2033ef68ef6297e9229bb73e6486330543aa3eb7": { + "balance": "51260669473000000000" + }, + "20b1e0ab7b9d62a314946b55a5775f24ae3cfa00": { + "balance": "1540424185584000000000" + }, + "20b61f2eb5e18b1e8568d18235918f9e2f596c32": { + "balance": "10000000000000000000000" + }, + "20ed8ca39dd148edf22e03b8021af32cecadd42a": { + "balance": "20000000000000000000000" + }, + "20fd5feb799fbb021ba262d28332b4dda8f44a2c": { + "balance": "7607475714434000000000" + }, + "215ab8aad1c8960838225294d086f0786c2dd796": { + "balance": "19929201327000000000" + }, + "21681cda53aa1a4cfb3e3ea645c8eeaecfc3ba4f": { + "balance": "10000000000000000000000" + }, + "217b75eaf2c0be12108120ba56ddb709e1885324": { + "balance": "36000000000000000000" + }, + "21be1d75b93e96017f088f1ca64ba7076c8edf07": { + "balance": "150798073752000000000" + }, + "21ccdbe0216b486cb39c94ed13767aa061c75ce9": { + "balance": "11070639373000000000" + }, + "21f2289f2d274bddd7928622fffdf3850d42d383": { + "balance": "268859368544000000000" + }, + "21f54f92a7d9a91915e1751ceb02cb8e3ed3d622": { + "balance": "10000000000000000000000" + }, + "2202c70ec23f4605394d69944edd9f90e488eb61": { + "balance": "9000000000000000000" + }, + "220e2253e1ab9ec348cc28d38bae4cb2d5d9cf8f": { + "balance": "116100821631000000000" + }, + "22328e434957107884854999e666ad0710187e3b": { + "balance": "233364805270000000000" + }, + "22851c0487d119ee3f150010515358d6ff14807a": { + "balance": "104464221701684000000000" + }, + "22a38000f5eca29001e387b52c18fb6030683fac": { + "balance": "55000000000000000000000000" + }, + "22b655a19810307750ed1b6b093da10a863d4fe2": { + "balance": "11840799203605000000000" + }, + "22cc48cf48e8ee207bc08411240f913a4e594529": { + "balance": "10000000000000000000000" + }, + "22d6ea6cb8a9206285ccddd3b6d0d1471ba66f17": { + "balance": "64000000000000000000" + }, + "22e2f41b31a0c69472a1a02d419886539b7b6197": { + "balance": "39885451304000000000" + }, + "22e962f91d01480d027ee0060030f529a7a64c8f": { + "balance": "93285203531000000000" + }, + "22f169328fb1104b386ad7fa69f0c7bf3e9a7d3b": { + "balance": "63366769386000000000" + }, + "22f35f5e0e7a8405714de66a5875c7ef84ec4891": { + "balance": "60944382032000000000" + }, + "23041bdc8d371dc29ffc890f19317dabeef12634": { + "balance": "402327389857000000000" + }, + "230eff5e8595f418686737ae671f1f1d225080a5": { + "balance": "114574598112000000000" + }, + "2331e1756d9800800fc9b54ee6e43e1150b6e58b": { + "balance": "44594796226000000000" + }, + "233a72b132e4ab1d3884274d4402d1a2a6399f0b": { + "balance": "1372148909093000000000" + }, + "2369d9dbbfd0f8aa8a3d84d8f2aea840a0cdf760": { + "balance": "500000000000000000000000" + }, + "23754e5cef31ab60aa97a0c8f9ccb4f2969f2d6c": { + "balance": "24764775861000000000" + }, + "2387973589fb07a8c1ec92492c0b8ba9ab5e52a2": { + "balance": "11642113696681000000000" + }, + "23950cd6f23912758ebe9d412166e27994fe6ec2": { + "balance": "100000000000000000000" + }, + "23b383e11573f3ca9be84e1e11694f58a432324b": { + "balance": "206558238838000000000" + }, + "23c329bb641fa51122ea476e3bc614f5d4f9cf00": { + "balance": "35908627324000000000" + }, + "23cb9f997c39853486adfc1a8b029874d1a6af15": { + "balance": "1400984459856000000000" + }, + "23ee14215c531f6ff1baef2c74b1754306f4532d": { + "balance": "10000000000000000000000" + }, + "23f641f765cf15665b6c28d77229d3b2a58fd857": { + "balance": "266570948120000000000" + }, + "23febb49d9541360b9d099377df16b5630dfbb52": { + "balance": "228513797641000000000" + }, + "24082040652a09cbed6504f3dd6491e0ee9d2bff": { + "balance": "91160839809000000000" + }, + "240d3edf4aaf42e99d366ca36d82c370271b8e8d": { + "balance": "65535355843947000000000" + }, + "242b63ebf47678f17c176d5d4a670e46e66a823c": { + "balance": "469668185647000000000" + }, + "2433612fb939236a87a97261ff7b3bc7b754afb1": { + "balance": "20000000000000000000000" + }, + "246bb03a3fab572b3c64fc23b03dfda42b7ea34c": { + "balance": "936364046000000000" + }, + "246c510dfaf5b49bc0fe01c8256d3879c1b5f89a": { + "balance": "100000000000000000000000" + }, + "24bf4d255bd3db4e33bff1effd73b5aa61ae1ac2": { + "balance": "302436106595000000000" + }, + "24c0378e1a02113c6f0c9f0f2f68167051735111": { + "balance": "36000000000000000000" + }, + "24cf04b7450a0fac4283fa6fcfef6215274b273e": { + "balance": "83714002622000000000" + }, + "24f5f8e7d6a23b55c95fcdc1300de05f9d2abd83": { + "balance": "20000000000000000000000" + }, + "25204bfb27a08dbdee826ad6d9c3398ec6d14fe1": { + "balance": "5929256591480000000000" + }, + "253d95911b4174805d13706b449879413b1672be": { + "balance": "37012901440000000000" + }, + "256065f7e919c508b68957b1d2c9120d29181e12": { + "balance": "25000000000000000000" + }, + "25624542c14c2ecb9a0fe7daec9ac5af16868ee7": { + "balance": "16000000000000000000" + }, + "256d05b6de445179e504a6c94ce1253ae159e19a": { + "balance": "12048598744001000000000" + }, + "256d37fc8980a969063b1f7e7fda8b87d4210da6": { + "balance": "107293553721000000000" + }, + "2588af91a0e8f3ba3ab636781bb84e263acd1f52": { + "balance": "8910000000000000000" + }, + "259774584d4fcae1d84f5997c00beee8a380e46c": { + "balance": "1140713354605000000000" + }, + "25bda1418853a22eb6a5380e8a2862d2a74949bc": { + "balance": "10000000000000000000000" + }, + "25cafdab7f79f7b95d55b4c2dda1f4080aa74d64": { + "balance": "2525573681000000000" + }, + "25cca69b41bb51c51b387c47ece83f30b9a78daa": { + "balance": "163449631440000000000" + }, + "25ce9dabd0a72b02e0056931155ba99c94cbc837": { + "balance": "230073284349000000000" + }, + "25d9d1785c96acddd926b3ed52987ff74f9083f6": { + "balance": "780460361789000000000" + }, + "25e56bd3e1461f27db4eb0cce8bb5ca1574401f8": { + "balance": "1001937531200000000000" + }, + "25fa2162d5c86cda10e4be42c14a24329e455ad8": { + "balance": "50000000000000000000000" + }, + "260a932a23b344056acb8e676714ffac0a13ad2b": { + "balance": "2000000000000000" + }, + "2622efe8836095fcf48d9c8019f48c8320d6e0f2": { + "balance": "5451866545636000000000" + }, + "262447c4d8826ed23ea25e9703a11b4ad3ae9388": { + "balance": "33992454005000000000" + }, + "263eee3badb9b0dd13579c09361806503705a1de": { + "balance": "1134831344000000000" + }, + "266f4c232ebc946c46979cd90d70868380e186d8": { + "balance": "20000000000000000000000" + }, + "267dfe6fa918686942f5e1d19d5fa615f6f2086d": { + "balance": "3569373363935000000000" + }, + "268ad2272c2b71243a7391020a600fd8dfa42d45": { + "balance": "122768017414906000000000" + }, + "269e4f43be9865f05a277933c2fbb466659ada7f": { + "balance": "22064992930948000000000" + }, + "26ae161c20acb26a320fbfbd60c97335cda28bca": { + "balance": "170710653621000000000" + }, + "26b4da905780fb0c5c3e7e5315989fed3aeef135": { + "balance": "20000000000000000000000" + }, + "2704312aa5a4202f14fa3b08e587e4f0ef13accf": { + "balance": "124259630994000000000" + }, + "2704e4b0e8df0c1f298843109ae3bb26c29a22c4": { + "balance": "3155521256785000000000" + }, + "2709347d12251c01aac6455108c6bebe72f0af2d": { + "balance": "220898650215000000000" + }, + "270a32b41dde877463d2106ea4f4529557a5e1d3": { + "balance": "10000000000000000000000" + }, + "2738b3746d6bda9bd72858eaa76f8b5ce7a88c8c": { + "balance": "10000000000000000000000" + }, + "27593d2271aced83e81034e8dd603d098238320c": { + "balance": "20000000000000000000000" + }, + "2771ba4b5944bb12d74b1888255c60e0db215fd2": { + "balance": "412946979808000000000" + }, + "27780086136ea3e97d264584d819dcb2176d7544": { + "balance": "292224348060000000000" + }, + "278936fff8afb553043f038c39fe93906bdb1f4f": { + "balance": "1448466441752000000000" + }, + "27aa0d45d3506f8446816e0e2e9675d46285f6e0": { + "balance": "20000000000000000000000" + }, + "27e655dcc5728b97b3b03fb2796c561090dced1a": { + "balance": "9841344000000000" + }, + "27eb0529279f7a71e50efb70bb1767cbe1ffa4ce": { + "balance": "10000000000000000000000" + }, + "27f564956c837d7949739f419d6ac99deb33d790": { + "balance": "1505247707018000000000" + }, + "280f5618a23c41ac8c60d8bef585aa1cc628a67d": { + "balance": "1316618646306000000000" + }, + "28167a591d66ae52ab22a990954a46e1555c8098": { + "balance": "1000000000000000000000000" + }, + "28257eeb8d20f2fe5f73b0ff2eca3214e30ece4f": { + "balance": "95924728584000000000" + }, + "2827abfc49828db0370b0e3f79de448d46af534e": { + "balance": "769862008499000000000" + }, + "2832b92434e3c922206c2408442bc8274606cbd9": { + "balance": "103421320914027000000000" + }, + "2854f190a38e9b9c04cf499259c6577a68b0b5ed": { + "balance": "144000000000000000000" + }, + "288923bd91be164496e5378ee484f0e4c6c16ed6": { + "balance": "10137243270703000000000" + }, + "2897ff80794153edb721801fb91c6d8373c965f4": { + "balance": "10000000000000000000000" + }, + "28aa06e2290010374097aa2f87a67556d8d68083": { + "balance": "84783245638916000000000" + }, + "28b04ec8eb18b0c6a384f9d92cfb44d1d43ecb51": { + "balance": "14364248730194000000000" + }, + "28db0c000cad3a524bb68dfdd74ffd47b42fb13a": { + "balance": "43586590410000000000" + }, + "28ecd4c5fe98cff66a5b8423f4a27cba9634e2d0": { + "balance": "56106658052000000000" + }, + "2930822031420731f09dce572554a8b8c1eaa09b": { + "balance": "1170839742000000000" + }, + "295154c4522d7bcb2e24b7de9c543dcd1c5f51d9": { + "balance": "179028680906000000000" + }, + "296be4ef7402b00d7af673c1770a50162d7ab602": { + "balance": "8206640005889000000000" + }, + "297b84150756fa89101dd59750a7beb36fb8785c": { + "balance": "1168894124400000000000" + }, + "297cfb72cd1b8b2808fd1b25cdcf7d8de279ad96": { + "balance": "500000000000000000000000" + }, + "29cec0eca9f8508a1ba192a90bb6dee18c40745a": { + "balance": "260217025084000000000" + }, + "29d8f7e72bfa297f17fdce9cf8f4a398f547e200": { + "balance": "307787433251000000000" + }, + "29e14b01c59ba894dd090382fb193ea441164b90": { + "balance": "229028661439000000000" + }, + "29ed634e165084b720e446d28893dbeecd6a7018": { + "balance": "226530464200000000000" + }, + "2a0f8136d43248233f652fe579ef3bd2281dde24": { + "balance": "4007544428000000000" + }, + "2a10204a0c7c9f7701e33c1b71c9427ea16e2e45": { + "balance": "50000000000000000000000" + }, + "2a319ee7a9dbe5b832beae324290f7df6d66f516": { + "balance": "28127560161000000000" + }, + "2a50bfda2b06a9fb28c73f14aaff4f7ef865db65": { + "balance": "10483823413828000000000" + }, + "2a7b7feb145c331cb385b9fcb9555859c16820f6": { + "balance": "1017182951264000000000" + }, + "2ae076c36b18a60f1e3c05d434276a1e16f3f838": { + "balance": "10000000000000000000000" + }, + "2ae2e51ea2ee6a848acde342db2bf6eac927e5af": { + "balance": "494279795271000000000" + }, + "2afd69fac54c167e7ca9d8198a8de386f3acee50": { + "balance": "227162683047000000000" + }, + "2b08018d6e65a7b74ddb5ce1af99976a484b9f50": { + "balance": "16000000000000000000" + }, + "2b0c1d629ad2958ab91e31f351a91219fdbca39e": { + "balance": "113239399820000000000" + }, + "2b2bb67fe9e44165d2108676579a9437c760da30": { + "balance": "20000000000000000000000" + }, + "2b2c99e88e938d1f1416a408a7d0041a605bce16": { + "balance": "6118539729000000000" + }, + "2b5c97b6402ac189e14bbca3e7759319ca8a9222": { + "balance": "10000000000000000000000" + }, + "2b813339c7f818f578b45f17c41c7e931c7828e2": { + "balance": "842834712955000000000" + }, + "2ba6fc21f743968d51f80113aadfc0fdfe8499ed": { + "balance": "309973507270000000000" + }, + "2bb75b272b279cb54498f12b6805261af643c8b1": { + "balance": "1426727673809000000000" + }, + "2bdac062364abd9cf67ba7de214a2cceb0511033": { + "balance": "1090525272063000000000" + }, + "2bea658caa805241aa921f48c8f10cb49e16ffae": { + "balance": "1295499213027000000000" + }, + "2befe7e34299a7c1ad53fc9988ce77e2d9fab20b": { + "balance": "4326342236300000000000" + }, + "2bf466a83cd44aaf0f627606a1c954fd31deb782": { + "balance": "1388986370166000000000" + }, + "2c016a23890e9633fc17b0a8d328ec1ec7ee0113": { + "balance": "92483174342000000000" + }, + "2c45a87a63cc5c8c102d12b83bd9a3501ee41995": { + "balance": "394657687589000000000" + }, + "2c600a596368405e584f3b869f7fabef4ce54aa4": { + "balance": "9879984853585000000000" + }, + "2c7032da8b7816e16095735aee43d1c3f1c43acb": { + "balance": "10000000000000000000" + }, + "2c7275511fe06ee86663b3a618497168b35b0cdf": { + "balance": "10000000000000000000000" + }, + "2ca4074843e9519265447c0dd9ac84ddc2033c1a": { + "balance": "179612279567000000000" + }, + "2cac03ba2c45a6c8186bdceb095b7c5feced3114": { + "balance": "2022060470376000000000" + }, + "2cb8c2cd506b2d7b4cac88ce63230022d412c62d": { + "balance": "211378154058000000000" + }, + "2cd27561cf37ec229982dd592c71d1aab9c2d7d8": { + "balance": "42189968284000000000" + }, + "2cd2e85310a4fbb7f296c3d0d1cee07b191239eb": { + "balance": "1940327317417000000000" + }, + "2ceca4501c5f2194518b411def28985e84d42913": { + "balance": "25000000000000000000" + }, + "2cf7abd42394634689aa2a36d263a6345116b7df": { + "balance": "3553167226295000000000" + }, + "2cf88f29356c166df8383d3312cea10397e25150": { + "balance": "76961677759000000000" + }, + "2d0b62fe49592752cfebaa19003a60b8b39b1cb9": { + "balance": "10277397502735000000000" + }, + "2d2051887107bbd8ed45b405b9be6974a13172d9": { + "balance": "1928781992000000000" + }, + "2d2c9525e2811f4d1016c042f476faf23274aa31": { + "balance": "1000000000000000000000000" + }, + "2d2ef9e1c7a6b66d9a2994adb3ac4a9921408e69": { + "balance": "10000000000000000000" + }, + "2d3bcd18e5c97ddbf1cd28ab37eabe070e9a04d1": { + "balance": "323879852538000000000" + }, + "2d3e60496d0092a4efc665389a916be1a9f8b378": { + "balance": "161958437779000000000" + }, + "2d3fb0ae9b17d3a57d23549ae5500fbb163de25d": { + "balance": "25000000000000000000" + }, + "2d8106dbee6f728c0ff11887690a6370a7d9f5a5": { + "balance": "3102418708000000000" + }, + "2da48eeb788686811ac8270ef3baf0159fc47446": { + "balance": "252187695395000000000" + }, + "2da9d2a6f0b92651a36b05c5e9d2a717c6e166de": { + "balance": "500000000000000000000000" + }, + "2dad81b23d8447190259119019c04a4ef61ab91f": { + "balance": "53428719965000000000" + }, + "2db1faf35901e272aee74a2469a278fdaa6e6e18": { + "balance": "100000000000000000000000" + }, + "2dbae8e1ad37384ca5ff0b4470d3dbc73559841c": { + "balance": "10000000000000000000000" + }, + "2ddf9e23945c181b8592d7965e782068b4c38b37": { + "balance": "100000000000000000" + }, + "2def05d1f2abbaa193a219b87e5319c7ecd48dea": { + "balance": "51359946957000000000" + }, + "2dfd221f96a21e41ffe4dca67b15cd352fe9637e": { + "balance": "36000000000000000000" + }, + "2e1371fcfea9d8dc8e692897a91753400caa9c3a": { + "balance": "5199902650733000000000" + }, + "2e2e04945adbfaeec698ea0f5275f1ad5ffd3d5b": { + "balance": "42034514567000000000" + }, + "2e41f865cfbcf8b89f848405e04de9114087f4ff": { + "balance": "44875730962000000000" + }, + "2e530254768ce94db0ef1204ede0e12b3558e7eb": { + "balance": "14319506377747000000000" + }, + "2e5c43868f45de268967fb22f3f4107da401510d": { + "balance": "20000000000000000000000" + }, + "2e5d2e117d2ba9af9697ec023a4d10b5a2436902": { + "balance": "16000000000000000000" + }, + "2e6000778fb225ddb3e1a2f297d56774e85d9c9d": { + "balance": "10000000000000000000000" + }, + "2eb64b8ab13f0d7823158217d15ba310ed3d0e58": { + "balance": "58724606000000000" + }, + "2ec3973ff33a06d355ad4e8f73b657af8a5ed8e9": { + "balance": "1165606294808000000000" + }, + "2ed4362ea5edf510e210af733089b294f87e8f67": { + "balance": "427561040806000000000" + }, + "2ed8788f1c31b508e37079098a7337bff77b49cc": { + "balance": "10000000000000000000000" + }, + "2edbbe1e2ea482920c76a4ff4c14602b4d37c955": { + "balance": "294409476945451000000000" + }, + "2edcba2bd76128750c8aa00f832c62db30aa7868": { + "balance": "25000000000000000000" + }, + "2ee5abcc0d0d51d4b18947b5aaaa95d037be4e2c": { + "balance": "20000000000000000000000" + }, + "2f058187ef141c06c7c87da86cc1953d2fcf70fa": { + "balance": "9000000000000000000" + }, + "2f16b101da9986a18f4b0d30a26557860338c4e0": { + "balance": "254907899725000000000" + }, + "2f4363df2c61273d230071286bb0157dfefee2cc": { + "balance": "64000000000000000000" + }, + "2f6099a8cb7bc3713b87dab20994d8dc09342003": { + "balance": "1902400000000000000000" + }, + "2f7b3902ce56f74adb0f83cc7d3a99df440cca1c": { + "balance": "825246221388000000000" + }, + "2f7d0298ff6a363375b7eecfe754fca0963c8a1b": { + "balance": "101000000000000000000" + }, + "2fb7c16232b3b1f2e3a676d6d5c93ae6fe5cb14e": { + "balance": "1000000000000000000" + }, + "2fbd5ccc716d2f510d10ec84def3fa69e49f46ca": { + "balance": "1000000000000000000" + }, + "2fd84376be11772e5d072cd74c96b0d9a49c27fb": { + "balance": "1000000000000000000" + }, + "2fdab070e20e2c8923a24c196bec72c33ff0f220": { + "balance": "64000000000000000000" + }, + "3003e6007f69902a0f5e4b4e6d0468277897fc70": { + "balance": "1501210602075000000000" + }, + "30095e6a4ccd1ac2014c3d1d98dce003d775708e": { + "balance": "500000000000000000000000" + }, + "300e47e0fa556371f6c882eb98423be44de7c239": { + "balance": "9108837665958000000000" + }, + "3011231224920b62bcfcbf0aed4fde35dd0a4bdb": { + "balance": "374689586073000000000" + }, + "304be24debce62e70943efddd20457d34e85ab40": { + "balance": "81000000000000000000" + }, + "30912555bb14023e9b7c90aa2314721918cdf1f9": { + "balance": "10000000000000000000000" + }, + "309a94ca7b44bc84a7909ee2b93ed1c94eaf75a1": { + "balance": "39000000000000" + }, + "30bcc93965fa36bbaabcd781326e42227c4e1a51": { + "balance": "10000000000000000000000" + }, + "30c71fed91d24bff69f286ff8f0c6c02a21736a8": { + "balance": "409782329653000000000" + }, + "30cbaf4103757013fd8fb71c44a985939e212b86": { + "balance": "7424807960947000000000" + }, + "30dd59e66093d0bfd87b09c5f6588b9857e9a6f7": { + "balance": "26123006239871345154" + }, + "30f692235f254b02f583d5b515f4701a35c7f692": { + "balance": "148184457997000000000" + }, + "310763019a24a927ce42b00604ee664ca53ff6d0": { + "balance": "393757908273000000000" + }, + "3118a5d4d06ca8b7c8835f4860e6973228000ee2": { + "balance": "56188713212579000000000" + }, + "311adec5bfcaed44680691cc644ee120a484aa05": { + "balance": "169000000000000000000" + }, + "3124e387aa7023995643344c782dac84b9d8c7d4": { + "balance": "1393596696367000000000" + }, + "31379702391cb5a737db3f3ffc336bd03aaa181f": { + "balance": "10000000000000000000000" + }, + "3145606c3ccbaf337610185ffac14ac4f0583c0b": { + "balance": "196454968572000000000" + }, + "315e11501d2c57a62af1631fc2662d4d8745401e": { + "balance": "225000000000000000000" + }, + "31a785ad3eea177c59fb575cad0b44f9a48a12e9": { + "balance": "38039017162416000000000" + }, + "31ae64035e95c1205bf957afb5e1636df00dea3d": { + "balance": "1718600907000000000" + }, + "31c0bb22fd2e9d22984f248a16ec3ed9ad834517": { + "balance": "5982762676000000000" + }, + "31e73a3b5451ebe1163571e9e0567c425bbbfb83": { + "balance": "10000000000000000000000" + }, + "322543c74039ef61fd051021b5e6f16b54bc7c1c": { + "balance": "101346282441000000000" + }, + "3233c7ed11c25bfc41d506c3ae0daf5a3c7c1278": { + "balance": "20000000000000000000" + }, + "325dae17b5225f6734a02c677d43fd126bea89b7": { + "balance": "365067246683000000000" + }, + "326ce8166a4094b93c15557f50f2b1d47811e72c": { + "balance": "16641460224765000000000" + }, + "32cf76046ae48b609524b1a6203eb6296d04853d": { + "balance": "1094839482061000000000" + }, + "33456a28f36aa240262cf95b78b4ac2cd8aa77f6": { + "balance": "3077123488326000000000" + }, + "3348bce2ef90ffd6a59ef5079e1af84b2dd604a7": { + "balance": "9000000000000000000" + }, + "334e5f0ae77dcd3d32dfc2c4ec6ab5e2826dc4b1": { + "balance": "3176777762079000000000" + }, + "335775e19200cd0305e529bc4cdf7295a47cb2d3": { + "balance": "2945631571804000000000" + }, + "336ba81ea6ec4f0da38c1a1761ed3d97fd3ca28c": { + "balance": "3587379203826000000000" + }, + "339191e03e9d5a08ae7b58f4c860235a0721b5a1": { + "balance": "2732237722000000000" + }, + "3399bf9f94c5488c89450257b39fdf3ec8c7f413": { + "balance": "477423805836000000000" + }, + "33cb8556a6c6c867e1be7de591cb22c1b7e9824e": { + "balance": "62293494164000000000" + }, + "33ed633804f39367078e830328dd223254be3366": { + "balance": "22842013797896000000000" + }, + "3409025dce86ad441a5a80f30ce03768d37e40bc": { + "balance": "1381667933000000000" + }, + "34153174cd4d3f1eaed7438638d302f6414d5965": { + "balance": "50000000000000000000000" + }, + "343c6b82b13f0dc82d4269e2c806d2d58e6dde35": { + "balance": "9546969736042000000000" + }, + "346089ea81f7dcb79caf2444df34bd6ee78be4bb": { + "balance": "4344080889000000000" + }, + "34984a8f96dbbfd1f977826a4c2187482559a2e4": { + "balance": "25000000000000000000" + }, + "34a5cce96d2211feb04472260c4cd368bda8432e": { + "balance": "1240050112677000000000" + }, + "34c026a39e44955d1051e8669f9cc58a027455c1": { + "balance": "20000000000000000000000" + }, + "34d730652f4aa002a9f39a47212ca3bc47506b8b": { + "balance": "418050617956000000000" + }, + "34e1d8c8a32ce0f6378abb9bd05ea1f9bfdc5782": { + "balance": "20000000000000000000000" + }, + "350b228870445141f4417ea5dba4f009d693b96c": { + "balance": "76995849736776000000000" + }, + "350eaec708d5d862831aa31be2c37b2fdcef97c6": { + "balance": "258753545822704000000000" + }, + "351fc1f25e88b4ccf090266ebb408593418d8fde": { + "balance": "10000000000000000000000" + }, + "3523ac7a6e79162bb8400bf161cb59389432aa51": { + "balance": "436606776923000000000" + }, + "354d490095e79a29bda2fa11823328450f14333b": { + "balance": "50000000000000000000" + }, + "355a555a36e319e76042e62875a15e1db3012b86": { + "balance": "20000000000000000000000" + }, + "3568840d0a26f39248ab088653ede831f150ce29": { + "balance": "16000000000000000000" + }, + "357096b9c1c7c8d51b682ed3c43d150f55629ff2": { + "balance": "900090781248000000000" + }, + "3588c47ba9204b672c456ee9b5c1ae70f3c738ac": { + "balance": "10000000000000000000000" + }, + "3591edeb9c036e871b4fc6fb3ae6d42e0c0d7203": { + "balance": "1000000000000000000" + }, + "359d92e3e8757a4a97187a96d408c0c11f5c7eb9": { + "balance": "22330509101591000000000" + }, + "35aac2a948f316ba93ed111ac127e29ee9a3adb0": { + "balance": "364387817746000000000" + }, + "35b20459a7daa5f44ae423fd4a1b451ea5090b09": { + "balance": "20000000000000000000000" + }, + "35cdaa84c1f3bc2673bc0c60222c133bae0d3db1": { + "balance": "15234182435000000000" + }, + "35d554233ca690130aaa43501e121a208c657226": { + "balance": "10000000000000000000000" + }, + "35ed399940ece44d01ac873b9c0d3212e659a97e": { + "balance": "55000000000000000000000000" + }, + "35f164612afc2d678bb770f317085ae68cce19bc": { + "balance": "693763596328000000000" + }, + "3601b36cb475101d0d0976a8de9d38e5f3483a08": { + "balance": "1000021000000000000" + }, + "361368bc42c8daf365bce9f9ff3b611373d7b690": { + "balance": "21658400518000000000" + }, + "361bc43be077a269e3e37c11e91479017c47f847": { + "balance": "268900383140000000000" + }, + "363c7a2203f6f93287de091bde3c87eb6800e7a7": { + "balance": "20874859005000000000" + }, + "365dc06856dc6ef35b75b1d4eabb00a7220f4fb5": { + "balance": "30000000000000000000" + }, + "3660e246bce68e2b6e4a802681f188587d2c1c99": { + "balance": "55000000000000000000000000" + }, + "366868ef8e193d7e649ee970d476e6774d5ff1ac": { + "balance": "2544456626840000000000" + }, + "366f7f762887cfb2d09cefa4a5108cf390bdeb41": { + "balance": "26837527714000000000" + }, + "36759f9c92a016b940424404de6548632c8721b1": { + "balance": "1033159825798000000000" + }, + "36a939be88508646709d36841110015bf7cedd90": { + "balance": "144000000000000000000" + }, + "36adca6635db6b00d28a250228532fe560127efb": { + "balance": "3370820618318000000000" + }, + "36bfaed8099ee9f216193ade26d21656c98ce4b5": { + "balance": "1353728563832000000000" + }, + "36df854d0123e271529a8767d1cded4e7b5f31d6": { + "balance": "10000000000000000000000" + }, + "36f59989a902cd10725ff7fe2cab1689aa4e9326": { + "balance": "20000000000000000000000" + }, + "370d6999ae70e781c81d12dc259ea304183b01eb": { + "balance": "45563989086590000000000" + }, + "370e8af59a64a3171b422913921a1e2f982dd512": { + "balance": "170263356254000000000" + }, + "372e01083072214134018f50bde3c8ac4f6e071d": { + "balance": "1400474252324000000000" + }, + "37410fda52f94185d824258ad5f3c9ad9a331257": { + "balance": "11830521097085000000000" + }, + "3752b7e1628275522cd693307787b9564501d959": { + "balance": "67839627078000000000" + }, + "3776f82701c384ce6cbf6a8fea40772cb882b66d": { + "balance": "50000000000000000000000" + }, + "379f63e538168925ba6313f9a6a3b6e7f0e8ed52": { + "balance": "292876625446000000000" + }, + "37a24c1a8080ab429a136c5582782b276eaa931f": { + "balance": "6099055841000000000" + }, + "37abbeaf24b5e6264c87633734852e243d377010": { + "balance": "1051360014489000000000" + }, + "37c50cecab8fe9dcd81aaede95050d27c53f4d45": { + "balance": "106051638566000000000" + }, + "37f82962c3097f0cd9ff605db66e792025a540cb": { + "balance": "10000000000000000000000" + }, + "382ba1e6c53cd7b9c360ef894962d281d557561f": { + "balance": "216789631461000000000" + }, + "38309b458993916efc1ac8b0b5d41302fec21095": { + "balance": "999139000000000000" + }, + "3847f25956a97a32caac059fd9e4cdc105756e25": { + "balance": "876497264905000000000" + }, + "384fe5f399638d277d4fb93f26d527497939287a": { + "balance": "280035151914000000000" + }, + "388335d8b92b445b1b19a3107547bb6ca7c0763c": { + "balance": "167140942784000000000" + }, + "3894a1e65973a542101caa4dc01e9553a5521d63": { + "balance": "34262479791000000000" + }, + "38a0e019c6120a19acaf0e651dd8338982cdaab1": { + "balance": "153843170492000000000" + }, + "38d4bdb10819a7d4ae9a32f4abb82402dff319b5": { + "balance": "1471131830647000000000" + }, + "38e56a55e2ac8320a480562f4a7cea9220306ee3": { + "balance": "907464312139000000000" + }, + "38f18123f3643e03d24ad759afbefc90ed923a2a": { + "balance": "943729130798000000000" + }, + "38f764c861def6d5d65e5ec099536f4cfcc3af55": { + "balance": "20000000000000000000000" + }, + "391e12b51fc85fb879a72fa746ca06c7a5659e6c": { + "balance": "9000000000000000000" + }, + "392342dc7b475c3975877a41622be0fed8e386be": { + "balance": "218719857770000000000" + }, + "3944cc960b8f1993ad841629a79e53d0535a88c8": { + "balance": "210571656485000000000" + }, + "396219864b8cfb0ffb3c675690ccd7026424ad4b": { + "balance": "138984508746000000000" + }, + "396403f26b388150b4876485b124a49845101464": { + "balance": "10000000000000000000000" + }, + "396f1e0f9e7ee86d1b2159ab8f9353677d12d340": { + "balance": "121000000000000000000" + }, + "397cc9f6254d56c721c767e41628a9078bea878c": { + "balance": "225000000000000000000" + }, + "39878b0c7049fb179aba0015279eff6cc3136816": { + "balance": "33962071375000000000" + }, + "3a06b58d0cceee5b091fe6aeb0fc0db5774e9395": { + "balance": "272033811720000000000" + }, + "3a3330e0152d86c5aa1d9bdfe9e1697645d3377e": { + "balance": "2165107207206000000000" + }, + "3a3bb8ed3130e09fbdfc21db3571d4711fc92d60": { + "balance": "885484658836000000000" + }, + "3a4ac96c489c864765cb1997a0084ba745b67a87": { + "balance": "1257436384863000000000" + }, + "3a69e1c351978ced418cea6cee019f220bcb065f": { + "balance": "579242822216000000000" + }, + "3a76a23d81929bed05ef7e1982d32b456e62aa7c": { + "balance": "1027078338792000000000" + }, + "3a7beadd1e11d0e3326c0dcd0f670530612931a5": { + "balance": "20633069818937000000000" + }, + "3a867c44d0dd06517a82ad467d0aefd7f11ce729": { + "balance": "12323708574000000000" + }, + "3a969ae486215e24c7ab89e38929562e2f85d923": { + "balance": "18955477335000000000" + }, + "3ab81366d898a8b798afb08a4b722ab0eb883652": { + "balance": "1220090012596000000000" + }, + "3ac1e14ed5929d382f6488c5444e717373ed29ba": { + "balance": "2030543873000000000" + }, + "3accf4b8ef20e4fea983f13f99ab257a5f9e988d": { + "balance": "156030342415000000000" + }, + "3ad38fa6e3c078025794e213d9dcc5aa397050c2": { + "balance": "36561766773000000000" + }, + "3adef81b2c861ae39c418d55be99aee2306e29fc": { + "balance": "15752410974000000000" + }, + "3b21ff4d5801d3976643899f195fbfd1b72a50b3": { + "balance": "8971221745646000000000" + }, + "3b2f2635dd428ac0b5873088a9a81800f09d6e02": { + "balance": "56922872447000000000" + }, + "3b39919c7bc8d0afec792288c56ab7f4934dc7d2": { + "balance": "1678237240464000000000" + }, + "3b468d9d5546810aa837c29ccb8349548b0e8170": { + "balance": "1100000000000000000" + }, + "3b83d1b651f117f1559a19b04ef408619c2dc4a7": { + "balance": "53628552066000000000" + }, + "3b9a72201bb1e8e678e36129cb1570e3ac99270e": { + "balance": "25000000000000000000" + }, + "3bcab1535b04a0a3fbb673bc41fedaa80bf7901c": { + "balance": "1526488015042000000000" + }, + "3bed42c3d0c49ffac87b9d482f6338fdc9e3880e": { + "balance": "26189771073000000000" + }, + "3bf736b57f0ae47f3714a6bb852090a543b9d367": { + "balance": "652395174320000000000" + }, + "3bfd481651956105ed909eeb98be404ec5ae77e9": { + "balance": "177520143473000000000" + }, + "3c0a12a327545b5f8b7b5c1f7a1ec6a341ec9578": { + "balance": "4184342789398000000000" + }, + "3c132698d59927fe08cba433a41d08acc96c0edd": { + "balance": "151913899135971000000000" + }, + "3c27bd92c4be1a19974ec773bd20b13afe582c9f": { + "balance": "10000000000000000000000" + }, + "3c2ad171573a608286f1fa3f5ef9e6099823983e": { + "balance": "3240802189194000000000" + }, + "3c4b5e808b9fb8baab1144b981b6cd53e216fcdd": { + "balance": "61214114118619000000000" + }, + "3c4cfc6ead044819ceb41c1c64ceda1a228af801": { + "balance": "9000000000000000000" + }, + "3c553afd45535f7c2a70c701d00890e607b96ffe": { + "balance": "2678827200938000000000" + }, + "3c620d55268c55b6deea3b7dc7f59dbe93b6e141": { + "balance": "55494311990000000000" + }, + "3c9b204db23b902d4295e6aba3405917efd59449": { + "balance": "55543672571000000000" + }, + "3cf233b7730a175d05a861318b7bb917bb5bee06": { + "balance": "1867187351033000000000" + }, + "3d292272992397ed5f27d5202da693128d023d35": { + "balance": "79770828413000000000" + }, + "3d353cfe84e9a93aef90547fbeb6e4b4bef83069": { + "balance": "36000000000000000000" + }, + "3d54da4ddd0621822a114581ecd15572e6488be9": { + "balance": "1623867132383000000000" + }, + "3d62ddc67d366fb055eaf92c936a6e7df5085454": { + "balance": "124933526793000000000" + }, + "3d754df1151b9b62a6ed48b477225121c29af063": { + "balance": "50000000000000000000000" + }, + "3d79d1ebd5224ffdc13e27924ab7f9f8e3452ec9": { + "balance": "520163228474000000000" + }, + "3d84fd9785a6bd3148847038c6f1e135042a892e": { + "balance": "10000000000000000000000" + }, + "3d9574c3860f30bcb42523a0cbb08aa7dd83e733": { + "balance": "15259904884000000000" + }, + "3da809a5911ccc77f892034049a97a9022c35e7d": { + "balance": "1415009021101000000000" + }, + "3db9a6c6ab3d0cf6d3bd7e04bdad39b4d419ab13": { + "balance": "9999781764000000000" + }, + "3dc7367c3218f88de8867c425f89102d2f2056f4": { + "balance": "10000000000000000000000" + }, + "3dd273dedb28824d1309c7d60a0744a6b6353e79": { + "balance": "9000000000000000000" + }, + "3dd6b25eb91dd2f3468e0786e8beb465abe7f515": { + "balance": "275172962210000000000" + }, + "3e0d14f83b304136311a33bbac2720c0cd66f117": { + "balance": "3390479675000000000" + }, + "3e15e947ee76f52f0f2a7d84da7c4ab060eb5cbf": { + "balance": "6751398714759000000000" + }, + "3e1b5469e1da4ec27537513f4df3f1a338a7dc2d": { + "balance": "161899580000000000000" + }, + "3e3329bcc90e47e4dabb5c93572b18b5e0efa024": { + "balance": "10000000000000000000000" + }, + "3e5a585ad0f34d78899433edaed574af052616f0": { + "balance": "910225655353000000000" + }, + "3e6be9615713bb06198bf354ef434a9db649699b": { + "balance": "783525278181000000000" + }, + "3e7c7c082f2f99b1ad579400a2e93586a24ed992": { + "balance": "159035553843000000000" + }, + "3e86ea5713f90022c0914fcc25e97c39487eb957": { + "balance": "101867287023438000000000" + }, + "3e9dabab6e50a696edfba6bcd44230d087c8d04c": { + "balance": "3315882414579000000000" + }, + "3ed956f86fe78223c86e164e4f372c9a0bf4a279": { + "balance": "119959915220000000000" + }, + "3ee87e776fb12e9c894e36fd5a61daa984e8a5cb": { + "balance": "50000000000000000000" + }, + "3ef1c8f294443f776a794563ce7569a8fe4d5d20": { + "balance": "25000000000000000000" + }, + "3ef6a396d6611df6c79ec1e6ad6bbd253917fbe9": { + "balance": "10000000000000000000000" + }, + "3ef727346fc631ae6473e9a36e2e5e54df696195": { + "balance": "121000000000000000000" + }, + "3efdcf2c0998637cb82d2b5fc24f27162578d207": { + "balance": "1054861112990000000000" + }, + "3f2cb2335e2bc07744175c497e2f437e87c2a146": { + "balance": "48999979000000000000" + }, + "3f4d16663a4f76ade93eb8bd6ca8fe2158e24322": { + "balance": "237117597268000000000" + }, + "3f7c5e6aea7f3f74d764df50f0fc1aa758fc99a7": { + "balance": "63372222562060000000000" + }, + "3f92239fdb41c6ec228252248c2db3f23675e275": { + "balance": "28538064487000000000" + }, + "3f9610454b621c04f00f01f4d54046502edb21fb": { + "balance": "16000000000000000000" + }, + "3fcfb30cbfe53c0c43f58c28386d9a6e5b49f7cd": { + "balance": "79080579219000000000" + }, + "3fda0c9a3d3f0000635376f064481d05d1b930bb": { + "balance": "10599947385000000000" + }, + "3ffce0475430de0bd9b09a412e404bc63aa28eea": { + "balance": "10000000000000000000000" + }, + "3ffe7583b568448ded5183e1544bca0d283680d2": { + "balance": "1076944549283000000000" + }, + "4003a137e577351a4ad7e42d1fc2d2cf1f906b6f": { + "balance": "25000000000000000000" + }, + "40215fc4c6300d8d8179383d9028fd2d909c6cc4": { + "balance": "3941346079000000000" + }, + "4027d7bbfa5d12c1ab9d08933a1659ae8dd023ee": { + "balance": "1156537386462000000000" + }, + "4039439c960070394dbda457726d97121c7b3669": { + "balance": "4444061364102000000000" + }, + "405978c24a12d930ada6163a44fc4a70c16569e1": { + "balance": "707298643296000000000" + }, + "405d2c1b55ba3f67c8634456b99c19092b407a10": { + "balance": "1462185951849000000000" + }, + "405ddfcf45005cf5a0ee1bfa605a7346a0167945": { + "balance": "88775535985000000000" + }, + "405f72a6940acf5d36a29498075f2d0d7a75bc22": { + "balance": "402796678569000000000" + }, + "407253b005ae97857f812fc60d441e5367b4bac8": { + "balance": "1484147810895000000000" + }, + "4091e1fb1c7af51a64c201d6a0c8f0183dfb7ca5": { + "balance": "10000000000000000000000" + }, + "40950bad9580d4b111955da7d3f9ada26dd9f05a": { + "balance": "500000000000000000000000" + }, + "409a28106192cae7a76c6aa8add0f73dcd63d2c0": { + "balance": "214832616721000000000" + }, + "409d5b872b059aea9a773e854f9a17ed2d5c2ef3": { + "balance": "64000000000000000000" + }, + "40a6e3c753b04c42fcf89cc30df8f50418caecb8": { + "balance": "754228409494000000000" + }, + "40e5ce1e18c78d6c792f46ed6246bfb31bcdb6af": { + "balance": "500000000000000000000000" + }, + "4121692a14554ddca1ca662fb577d7152d4fa7d0": { + "balance": "49000000000000000000" + }, + "412acb10c8ca937ddd64cf0d413b1dd34760f72b": { + "balance": "6073360870000000000" + }, + "4166a5c94d5ae48ced410f950d40656182bf8990": { + "balance": "55000000000000000000000000" + }, + "41752b7d0d3ee58a6b69d8ba721c0894ff701237": { + "balance": "585556720807000000000" + }, + "417c86d6bf734e99892a15294230771bbfd7e1e1": { + "balance": "38233258264000000000" + }, + "418414498f7361b29428c54732e1f49fb394f813": { + "balance": "2063786326155000000000" + }, + "41a424dcbff6bf31686f5c936e00d21e8a4e0f78": { + "balance": "33554754580438000000000" + }, + "41a893429d5f8487c1866b87779155d4bfe33198": { + "balance": "20000000000000000000000" + }, + "41bbedd607fa576d130305486824cd2871bf6b05": { + "balance": "649728993301000000000" + }, + "41ee42c1fb1bcdc9c7a97a199fdcf9b63623521a": { + "balance": "7906012418597000000000" + }, + "41feffaf56d1712af6965fa6eee1b06bd624e7b8": { + "balance": "49000000000000000000" + }, + "42107e765e77ea76b3d6069d3775bc3aef7d692c": { + "balance": "25320783684183000000000" + }, + "421f4dab3240e15a1c78e3ce8642de9b578b8e4a": { + "balance": "832511242936000000000" + }, + "4246c52c3601541a873d4bbaafedf28b9bad5b73": { + "balance": "10000000000000000000" + }, + "424efe1ba28bb1aeedc38a3a5135547d0fe80751": { + "balance": "25622294162729000000000" + }, + "424fb0a3ec325bf42e7edbef7e450f2ffd1cf318": { + "balance": "20000000000000000000000" + }, + "42714c04d17f6c29029daf7f50d1cbad6590cfad": { + "balance": "271755674161000000000" + }, + "42b66e9123d304b70fef3dbcfe8587fd6189b5c4": { + "balance": "1030481609000000000" + }, + "42dacbc412b829cb304ffbc316b3f81b379bfc80": { + "balance": "304208485736000000000" + }, + "42e3d9832c8b6cdea39c97525570391803dee276": { + "balance": "2581020833000000000" + }, + "42f757898f95c1b46f64a4a6b7f86ab03022d672": { + "balance": "100000000000000000000" + }, + "42f7956fd659e00d3be2f3d1d4f3ed187aef04d6": { + "balance": "50000000000000000000000" + }, + "43160b2bc00f7f8f7fc806e2f6e2ffdc62b3a651": { + "balance": "1000000000000000000000000" + }, + "431b77cdd067003eeed26c1aee32f67fb94f7092": { + "balance": "902514849986000000000" + }, + "434e44583786e354731bca250d94ef0d8860a538": { + "balance": "1187789683866000000000" + }, + "434f1b9b193c88bf58685124aac0167fe69f9014": { + "balance": "500000000000000000000000" + }, + "43535982688844fa703cb9bd5723790cab364049": { + "balance": "100000000000000000000000" + }, + "43559f405590592c254e427fa25f03e774d8defd": { + "balance": "6913200000000000000" + }, + "435c08c481d59308a64afec0d6f936321bb120bf": { + "balance": "9005920819593000000000" + }, + "43629748a92b846f21f637aac5103412fbabb9a6": { + "balance": "1177513692845000000000" + }, + "43650b37552882d225ccc977aa2b7a86a4ca9bb1": { + "balance": "16000000000000000000" + }, + "4385de394371d26a45f18e8b3842effd015027bf": { + "balance": "187331693412000000000" + }, + "4386ff9648fe420503c9a36fe7b97c079de3b770": { + "balance": "2714401478778000000000" + }, + "43b370c4457cf39a3be86cc00c2b27614ca6e638": { + "balance": "8316429850934000000000" + }, + "43c464ea740172fe6f4f09974106fd24029837b9": { + "balance": "129643160399000000000" + }, + "43ddd2d33dcb7e578f4e59ad6b9c61a24c793aa8": { + "balance": "500000000000000000000000" + }, + "43e0f8065eb7faf3bbd13bc7c5d5d8f5ff1bdac3": { + "balance": "4454324716300000000000" + }, + "43e96cd065d7934b246d0fec8cd2dc6b36d56d7a": { + "balance": "81721481452000000000" + }, + "43e99acabfbdc6cafee3afb12fa7ed1345370b2d": { + "balance": "4595292398872000000000" + }, + "43fae764c7555b859b93d2126edfa59cfbf298b5": { + "balance": "105746805109558000000000" + }, + "44052eb938c02776b5240f38ec99f5ef51ef0d87": { + "balance": "38446396949881000000000" + }, + "440fc7621cc17f121f0bdf2a68c5be2c3af4fd3b": { + "balance": "1026958147051000000000" + }, + "4440ccbc77249a4d891d9ab5a5f2026b17aff7c7": { + "balance": "10000000000000000000000" + }, + "447f3f702c13a3fbdc8675c6285702b5aa2b66bc": { + "balance": "1089533398014000000000" + }, + "448f152be153fdb0497403f70e37d876946a5021": { + "balance": "614429461682000000000" + }, + "44a1e3a044f5d1fb00f4beb3772a3ee08d8b7093": { + "balance": "1000000000000000000" + }, + "4515edc7154bedd7143b69a04c4e738f8aa4ab18": { + "balance": "10000000000000000000000" + }, + "4572148fe5ea9d4795e1f1ed93097aac1d70991c": { + "balance": "2873782218000000000" + }, + "457581f223b8eacd757abb292613e317d6f59305": { + "balance": "3582446780073000000000" + }, + "45b450961882850f7038d5cdcd2a8fa2dc4b5469": { + "balance": "20000000000000000000000" + }, + "45bdfdf3840d4341503cd7fc87e4b66f6179e5fe": { + "balance": "10000000000000000000000" + }, + "45dd9baa87b3c94df66308d8ed4f3a5bb65c3dcb": { + "balance": "25000000000000000000" + }, + "45de332b8ee95d886cf11b99291b46f46c1ddd45": { + "balance": "36000000000000000000" + }, + "45e06afdbc70288a2cc55bccc4fb2d8195aea028": { + "balance": "790360485306000000000" + }, + "45fce5fd1acb2bc5507723c897cb340437e39735": { + "balance": "100000000000000000000" + }, + "46045cddd940d80596826ce5354489b3047663bb": { + "balance": "100000000000000000000000" + }, + "4610286f8a2649dcfbc6d91735745f418a6abc75": { + "balance": "10000000000000000000000" + }, + "4615905ecc6f7df0ccb7b86a3e1d3770adb2f874": { + "balance": "1000000000000000" + }, + "46256e00ff927d54b0ca139ddccac2148784273b": { + "balance": "10000000000000000000000" + }, + "465e40e7d129ad310fc60ff0f17c0f968611118f": { + "balance": "677971225649000000000" + }, + "4664a920f7fe9b0d78a665e1a4aeb95f287d6059": { + "balance": "20000000000000000000000" + }, + "46679de1c6143138fd9c44ff05853a52371915ff": { + "balance": "363627463229000000000" + }, + "467cdc210ae48ba99740d37ee79fa57c4216bc81": { + "balance": "10000000000000000000000" + }, + "468053d193debb88735571acb24b764f2676272e": { + "balance": "49000000000000000000" + }, + "46826d1f1418abbe4e7b9236d643e5b57a0f0208": { + "balance": "37752144164916000000000" + }, + "468df2ea57972ddeb88d470a5f3c2c0e2284ac17": { + "balance": "757320434551000000000" + }, + "4695ad5b686520ee8426d24b50ff7a5f0d703443": { + "balance": "2851082366000000000" + }, + "46a149bc8ec2b85fdf938f753a6c53777dcca2b1": { + "balance": "10123698633000000000" + }, + "46c081440f760a21b74c2499bdda13aef8245930": { + "balance": "180752319265000000000" + }, + "46e615324f6e4fb242f9bfecffc0c802ba7733c9": { + "balance": "10000000000000000000000" + }, + "46eb54f09dbdaaf3b97a1f79a3d82ee2e902b3b8": { + "balance": "3430510380318000000000" + }, + "46ebb24b04919ec0164f0bafcebca2309f2d3035": { + "balance": "129155832233000000000" + }, + "4701f9fe78111011f820fe28c47522e601655678": { + "balance": "9000000000000000000" + }, + "473f44e2c1d5d7aa53cf7041d7ad19a0d9eaf1d8": { + "balance": "162679637505000000000" + }, + "474f8bf4d03a7efa4d190905ce062eea7c75118c": { + "balance": "1259904506149000000000" + }, + "47598330e862a4f7cbda8be74ac10cd5d370a55e": { + "balance": "291763101699000000000" + }, + "476455d48fc858a06bd7854fcf1bd60bcfde9ed3": { + "balance": "10000000000000000000000" + }, + "476826d58192ad822f4686311d6c6d4d4f66ee5f": { + "balance": "453184657722000000000" + }, + "47a231eb3fdbc24f2d008f06228624b2a45ae5fa": { + "balance": "1000000000000000000" + }, + "4805f4c0eb1c83c436118ec9148019e5fc1962e3": { + "balance": "1311161626928000000000" + }, + "4809f373cdd56c8481ba3bce5a401d55a7e50a50": { + "balance": "2284845194349000000000" + }, + "4839bf9ad56873abd5695057bf71972806cde827": { + "balance": "42264923611000000000" + }, + "486dba2a47decabc9a85d1d64d74687983ab273b": { + "balance": "49000000000000000000" + }, + "4877993f5ecf02451f8d4591594cb2f30dcf9f26": { + "balance": "100000000000000000000" + }, + "489723e325f609e27be14528c4111fb3eec13f7c": { + "balance": "2489030141000000000" + }, + "48b710d16e9da736b773453089d69cc6ede116b5": { + "balance": "26651593216000000000" + }, + "491088e1e4b5c3d65870f2deef9be6ec3dc6c7c7": { + "balance": "1446809481953000000000" + }, + "49174451320ad2e14cb2b05ecdd251b75ace3038": { + "balance": "15533380764616000000000" + }, + "4956ead915594b621131b2fc2dbbb49ba43c5559": { + "balance": "1175638488000000000" + }, + "4973a0d32147ba89f525a18f989518dcfce93b0e": { + "balance": "522848489444000000000" + }, + "498c6f9063705054fae07260d4176c3d55a97650": { + "balance": "732941433000000000" + }, + "49991f68f2a76bd1cffa3e9721be36f3fd8351b8": { + "balance": "17742568700019000000000" + }, + "499a8af194e0040f349e893937fe3858f8267fca": { + "balance": "80704784160862000000000" + }, + "49bcbb7b263febf54f8ff498525bac8e7241f966": { + "balance": "603044032468000000000" + }, + "49bd72773656c4e1a4d16284aea2fb05546d2b31": { + "balance": "1896607093054000000000" + }, + "49bf80fcdefebe8cd4830ba09e46ccd7231c8e6f": { + "balance": "10000000000000000000" + }, + "49c9d82dea78f14b1c52efc0196b67f508f7859b": { + "balance": "2313040051399000000000" + }, + "4a2daeacf0468d137e3bc464d6d5fa3893a9136b": { + "balance": "10000000000000000000000" + }, + "4a6c428f245e8d9115b34764bab17eb86ac472be": { + "balance": "10000000000000000000000" + }, + "4a6e8d037acf1960dbbf14e7a02fec0ac656f9c1": { + "balance": "6516295825438000000000" + }, + "4a7e7fc3c72f2f9b92bf0dcd5297cfb19f077d7c": { + "balance": "99426213999999999" + }, + "4aaa6817a5000bb7596e000135b3051c5931e7c5": { + "balance": "102884105546478000000000" + }, + "4abcdc3d7d3d314a163da92aee53a56b87313a2e": { + "balance": "44402243657000000000" + }, + "4ac9385ade2377b061f4211b392ed6a6e7fb83cc": { + "balance": "1000000000000000000" + }, + "4ac96e1e26cb66ff788ed8c62db811d7b4fdbc74": { + "balance": "68476115774000000000" + }, + "4b10c247caf33fb872d9bf86572424410aa86752": { + "balance": "337915294240000000000" + }, + "4b23ffff1894df49005c7afc0828880924571299": { + "balance": "169848767272000000000" + }, + "4b486895caf3a0b5afa198df744de7082eec8666": { + "balance": "1672587376054000000000" + }, + "4b98fc960610573be456c0e1e319f4f863bf9095": { + "balance": "259382246718303000000000" + }, + "4bc0cc483be20223f40ed6deef63dd9645c216c4": { + "balance": "4322684620000000000" + }, + "4bf4a046afdd4ec9d0e50730ff6ded5ef2327442": { + "balance": "70601389160000000000" + }, + "4c0149058e2e74f7c900e6d6e5fa12eea882c5e0": { + "balance": "2017399852886000000000" + }, + "4c17a3997fb70599794d01a33a27a6d5b52b6f01": { + "balance": "469002093209000000000" + }, + "4c4559e7b32340dce112cf7a021ced1b113f6dd9": { + "balance": "25000000000000000000" + }, + "4c4f02b3f232b8ce8485d425639271510cd0486f": { + "balance": "68828038140000000000" + }, + "4c52ec56142bb6e8c8830e5c17b01b5165915f3c": { + "balance": "321766233041000000000" + }, + "4c58defa57875e709ca039a54a2be5aed6672f6d": { + "balance": "121000000000000000000" + }, + "4c5a886ab90b6bac68677a7eb92a06bf33ff2930": { + "balance": "236899852150000000000" + }, + "4c60539363edbd812334a54543c40ecab8af2ac8": { + "balance": "3281904094699000000000" + }, + "4c76897d0d5d39195354194710c5e7f99bef63d1": { + "balance": "10232271258305000000000" + }, + "4ca3c03780c20a64f3b5ebb75669982a71ee8a71": { + "balance": "377172198976000000000" + }, + "4caf77eefe062a6f053a464171bc75254b47f52b": { + "balance": "20000000000000000000000" + }, + "4cb7d7ce805e56f6e47e94cd755b6d97f8f996a0": { + "balance": "120998866000000000000" + }, + "4cd34f8f3299d3b7aaee180baa0b432369e1b3d6": { + "balance": "197088135242000000000" + }, + "4cd7aaa5415d809f405f520e4c0319a6029b981b": { + "balance": "686627368232000000000" + }, + "4d01067555f1ef63883f25c562b07168f79fa80d": { + "balance": "17547055698000000000" + }, + "4d2cb4c1da53e227b08c0a269402e9243a13f08d": { + "balance": "324000000000000000000" + }, + "4d38bb5f48ec37b751d16de32a4896fbda479ce1": { + "balance": "802530078718000000000" + }, + "4db3e76e2f68896cecc9826e10a5e09df0352c28": { + "balance": "555180306924000000000" + }, + "4dc8730d9f032d33dc493bcd3c6375b38f41afff": { + "balance": "5726933881000000000" + }, + "4ddde96556f5185a13617f01ebd9102800bc9e9c": { + "balance": "1181822708402000000000" + }, + "4df9359cb204bf649668ff8086a7f5e24709083c": { + "balance": "262998978400000000000" + }, + "4e0a1a3dff0d33c418758263664b490140da9e01": { + "balance": "100000000000000000000" + }, + "4e0dd6d8de5caa3a3bf9fdd6f2d7b30618623cc0": { + "balance": "10000000000000000000" + }, + "4e11af85d184b7f5e56d6b54a99198e4a5594b38": { + "balance": "76658631121000000000" + }, + "4e314349abc52c686d47dc771ebc8040966be386": { + "balance": "632341985941000000000" + }, + "4e3fb09c35375106bece137dbe0e5491e872871b": { + "balance": "153648535396000000000" + }, + "4e4f0d606f7065bfb1545e60b5e684ae1934e055": { + "balance": "48998635468000000000" + }, + "4e50957aa6c91c548075add8ec625b74c0973abd": { + "balance": "1000000000000000000" + }, + "4e5c6efa76493f0e9422582016aac50539ae60d9": { + "balance": "2078967343000000000" + }, + "4e70bbcb50c4e875fd573dcb694908abf3b30b37": { + "balance": "20000000000000000000000" + }, + "4e7f5670a7dd168a0803e53b8bf72f4db280e3ae": { + "balance": "1658463113665000000000" + }, + "4edaf859990a10977bf378df45b32f93422c84b4": { + "balance": "121000000000000000000" + }, + "4ef41923a1a426772832d3c267adbd84e5994edd": { + "balance": "5432615017384000000000" + }, + "4f11a70d80f36f46ed0c2a5fff1a39b711f3bae5": { + "balance": "8415785077000000000" + }, + "4f159095afcc75b8f5cfc90c9d07a0d77ac8ed69": { + "balance": "25000000000000000000" + }, + "4f2652322736cc18b24af582d4022fe329a9dfb7": { + "balance": "9000000000000000000" + }, + "4f328173f352f3dfdca0ff5e3185f26de77c6f75": { + "balance": "10722917874680000000000" + }, + "4f47a62aba6ea049fc0e92d8afbe1682472d98bf": { + "balance": "10000000000000000000000" + }, + "4f4c3e89f1474fe0f20125fae97db0054e9e14e0": { + "balance": "50203638983000000000" + }, + "4f5ac8dfe79c366010eb340c6135fbee56f781d8": { + "balance": "50000000000000000000000" + }, + "4f672cbd373183d77d8bd791096c6ebb82fa9a2a": { + "balance": "978111227765000000000" + }, + "4fb179c9c88decaa9b21d8fc165889b8b5c56706": { + "balance": "24750205150000000000" + }, + "4fbcf391c765b244b321875d6ab4381c44d0747a": { + "balance": "99999580000000000000" + }, + "4fc979b38b981fca67dfa96c6a38a17816d00013": { + "balance": "1088876196468000000000" + }, + "4fdfdd1832b114b4404aae23305c346beee14e1d": { + "balance": "278724179057000000000" + }, + "4feffb1836029cd0e9b8f4aa94b35ae3982fa770": { + "balance": "1674590934924000000000" + }, + "50045745a859f8fce8a2becf2c2b883b3723b2c8": { + "balance": "169000000000000000000" + }, + "5028bde29fe88e03e3de069b3907fa9df551c379": { + "balance": "196000000000000000000" + }, + "507096ed771fa8a1d004ee5377c01506df461b32": { + "balance": "2669205000000000" + }, + "50788574a0967580fdaddc4758f834d8978455f6": { + "balance": "1648581593000000000" + }, + "508d8e8f338ca98d3c09f0f15fd9e7baa80701e8": { + "balance": "16000000000000000000" + }, + "50a4dc916845172b83764a6c8b4b00d6d02d41d3": { + "balance": "3020744393592000000000" + }, + "50da06418780c220ced4898af0b1fca533f73cca": { + "balance": "36486700700823000000000" + }, + "50fb6fd8432a66219e754234e9eea1dabcc07676": { + "balance": "489500000000000000" + }, + "5104bb1b831902333732dd25209afee810dfb4fe": { + "balance": "1333614132000000000" + }, + "513963743ec6ec9dc91abf356b807ebad64df221": { + "balance": "1508002412172000000000" + }, + "51397ca69d36e515a58882a04266179843727304": { + "balance": "941648956414000000000" + }, + "514a58f2b36c2cf1b6293c36360cf658d8af30ed": { + "balance": "1233397704089000000000" + }, + "514fe0cdb3de692cab9f2ef2fd774244df71be66": { + "balance": "9670444445882000000000" + }, + "51583128081fd800d9550144afebdf3fe88149cb": { + "balance": "231190355520000000000" + }, + "517384fe92391187d0e65747a17bfaadf967c331": { + "balance": "1943121865489000000000" + }, + "51aebfaa26a54071cfe6c2d8f81157ec313984ad": { + "balance": "1422225031261000000000" + }, + "51d4f1205b272e491e94fe21f0341465f14141fc": { + "balance": "552384783614000000000" + }, + "51de598faa85276bb26a68b135028755304b6700": { + "balance": "2068484560002000000000" + }, + "51e08e0304f08ef768c80ca149da4721fcf482b0": { + "balance": "194629207228000000000" + }, + "51fa3da695e24f602952a71966f37ac3596a94a4": { + "balance": "17008166261720000000000" + }, + "520b22776b1befd3064636da0dd251afe569ef13": { + "balance": "18538137781909000000000" + }, + "52219a1e1aa82b78b971088c30583a3bbe675c8e": { + "balance": "411959222637000000000" + }, + "5252b8a0688096523498cb5c1f42bcd1f61923d7": { + "balance": "1863936864000000000" + }, + "5259154e1a5a809b2e3dab80372124cebbfd56e2": { + "balance": "110000000000000" + }, + "5264f2de516835e549710bfe34ef03b08b8557dd": { + "balance": "1216000000000000000000" + }, + "52b17fae7e9cac447f026db71dba4034a1d53174": { + "balance": "99001631977000000000" + }, + "52b3363ae882a99354faeb76733d0fa2cbb89787": { + "balance": "102517584327000000000" + }, + "52bee7fb24a7fc1f34cf0874ec2f06c5fe847cb1": { + "balance": "54443400591000000000" + }, + "52d1f12d391c7a2f3b52939a61a20da5f85eecc3": { + "balance": "2707175772061000000000" + }, + "52f27099483589e883e7eb789896de39c61e46da": { + "balance": "358944977251000000000" + }, + "52f3b715b678de95d1befb292de14c70f89f5e03": { + "balance": "2989868434000000000" + }, + "53259780569f6dd6753c1da1d53d0b155c5b30d2": { + "balance": "200489122590000000000" + }, + "532e4908e8297c90d75d2280b432b469aaafa2ac": { + "balance": "20000000000000000" + }, + "5334d1e399feacabc9648cebcd93172db95d43be": { + "balance": "25000000000000000000" + }, + "5341665addfb5e367f7a7d35de95b87a0cceb3a9": { + "balance": "60544291695000000000" + }, + "535a39a854ed1c2f0afbc5944f1ee0e2e68cf65a": { + "balance": "2141913781000000000" + }, + "536515c0c08988ee69da1d75f18c706f6b9bf7a3": { + "balance": "169000000000000000000" + }, + "5387a1ce4cd2ef4f90075c15dc3c0744948ec356": { + "balance": "50000000000000000000000" + }, + "539a30ee5724978010990718bb8b0dd25f89fd15": { + "balance": "1306896514000000000" + }, + "53a5f87dfb17149b8c2934a2a9d519ace4ac9724": { + "balance": "4569449510000000000" + }, + "53b24fb36e72c22eb830dc93857a8188b03397a9": { + "balance": "64000000000000000000" + }, + "53cc35b3daf4b8e1982e0e63d0bc68d7252e7fcc": { + "balance": "68213426853658000000000" + }, + "53e1f85147e000ae1ff6a5910407395e388c683c": { + "balance": "20000000000000000000000" + }, + "541f43ff66ed5eb1a1ea0ae3f86355ecff665274": { + "balance": "49562725831000000000" + }, + "5428a31f736c0d2b3c4e80baefb75a76ed44d3f7": { + "balance": "10000000000000000000000" + }, + "542f732aec0873bf531f6941828b6f0ed0611106": { + "balance": "8407722276000000000" + }, + "54300b6a77b95545373b2bba73e60f37c31eb1c6": { + "balance": "1581215621996000000000" + }, + "5434bd65a492a4d14d3b97eb49f6e491350ef73c": { + "balance": "484000000000000000000" + }, + "5444a1735913eeac177d947ef38de7cd6bdfc0a6": { + "balance": "1000000000000000000000000" + }, + "544ffeab53bdc59ef8edaff0042b03c2ea123615": { + "balance": "10000000000000000000000" + }, + "54613713df6c5b89c3012a7835651f25cdac8331": { + "balance": "98684037547000000000" + }, + "5471fb39b4e48c118f855492830ad9e2eaa68179": { + "balance": "91791250228000000000" + }, + "5472591efd048dd60a4d6afdb549e95a65578b0a": { + "balance": "50000000000000000000000" + }, + "547b4c1ae70567fd77a896dc05eb536f502ac8a4": { + "balance": "14037444012000000000" + }, + "547fa9f6f86a2939f9144aacb74e0af60d434535": { + "balance": "428416957729000000000" + }, + "54841d6a478cb9b6e717a9de35577a1a4a504b0d": { + "balance": "144000000000000000000" + }, + "549157e5b1c92a88a0eef335b1bcf4d162482017": { + "balance": "21019502942000000000" + }, + "5492757c55c72ac5946b21514ee16c5065ecde7b": { + "balance": "10446737491000000000" + }, + "54984a41eeaa8e710e4e5b8a7f68c96057b7df3a": { + "balance": "10000000000000000000000" + }, + "549a3717a1bca3f38d24655197c3ccef1e8c273e": { + "balance": "4416133255000000000" + }, + "54b047fbe004191cd02f31163d29bd61ccfaadf7": { + "balance": "52649445905000000000" + }, + "54b125d8b260386633b756056b7d7e78e7071715": { + "balance": "10000000000000000000000" + }, + "54ffad1ae76ab45c4218ced27e49bf2745b2a2e7": { + "balance": "1426474871178000000000" + }, + "550b28968bae36f4e99780c6d7deb54c158be6d8": { + "balance": "10000000000000000000" + }, + "55117923e8393dbf233c0f10819e7de75569962c": { + "balance": "470094520022000000000" + }, + "554a2471e6ecf2320da545d559c40b8b622465ab": { + "balance": "4052895973949000000000" + }, + "55607b39da9480ed8f54d74d0818ab8798136589": { + "balance": "13704276648975000000000" + }, + "5561cbe99fd775f5d0f05903fd62ba4877b3319d": { + "balance": "1007596371374000000000" + }, + "559ba7ab58670d4a0b118bbf6aed7f6fdb276594": { + "balance": "3127762973000000000" + }, + "55b0bc444f2a5952a98f216f61cf07382da1e156": { + "balance": "18683409750727000000000" + }, + "55c0a02dc68123aca7ee0c9cd073ead50b16406e": { + "balance": "99999999580000000000000" + }, + "55c47d593952afd637050c5758a921a204f23fc6": { + "balance": "1615608723958000000000" + }, + "55c6855b3970e5a550f0c75d5727329476406d91": { + "balance": "600705012673000000000" + }, + "55eadbe33899f53138d0fb204f42e272f447cfd6": { + "balance": "1671128311341000000000" + }, + "55fa59fa0fbba06b7184ea78868d438176eb96eb": { + "balance": "1553000000000000000000" + }, + "560a11493b5a0ec28589e80276fe975ee26c6a3e": { + "balance": "10000000000000000000000" + }, + "560fbb31d83bf6dc49e5fb15bd582d70c49fd273": { + "balance": "46015432815000000000" + }, + "5620e17ccf094b1be1a93f6f3388fb96e3a90165": { + "balance": "484000000000000000000" + }, + "5633512298cf74f4d2b8663e6f291e9e25436e7f": { + "balance": "10026444446000000000" + }, + "564423f92b8841b3b1f8bdba443067b580916e65": { + "balance": "465451550122000000000" + }, + "56730e1d11a84970355c43ac7659f2f4786dadcd": { + "balance": "20000000000000000000000" + }, + "5678851984add045f3d054623c198dfd4665d54e": { + "balance": "227651903234000000000" + }, + "569cf18b4bcb99e3f3d27235f2c4c0d8d160af03": { + "balance": "4124979731000000000" + }, + "56ac5f2c3486a9ce744a71599ab89a606e7464a7": { + "balance": "9000000000000000000" + }, + "56bc5936a6ea37c1d0839bf64bcec0d366840ace": { + "balance": "14741201469670000000000" + }, + "56bf62e0135e903525cc46b0a3cce33f4a16880a": { + "balance": "534970476270000000000" + }, + "56da0781a80a0abf5dcda4da35861e9de601bfbb": { + "balance": "166898390441000000000" + }, + "56db15729e52d615a744a04f8a59d63e3b9f735b": { + "balance": "10000000000000000000000" + }, + "56e32ed78e7f5be6b00c28847efe7b3589cdae1a": { + "balance": "1046236086484000000000" + }, + "570f7a08150e0088178276f8116bc4103f885903": { + "balance": "1124393518440000000000" + }, + "57147fdd9b52ef53b4ebd4b5712d29da83f99374": { + "balance": "39000000000000" + }, + "57395fb355fe51f1b32c1baa4e9ee0fc2b8fe05c": { + "balance": "7701013675397000000000" + }, + "5752f0f11ed12bb1d5041b0cee4ddd500cd8806f": { + "balance": "151337200533000000000" + }, + "575907d73ad5ad4980a2037efbd20860afc67ad9": { + "balance": "3568754158000000000000" + }, + "576acb4c0bccc89903ad285ac08c70fde514aaf2": { + "balance": "25000000000000000000" + }, + "5784cb8a17cfb5392c4aeec2edbd173849ca6ee3": { + "balance": "15804767597000000000" + }, + "579234645eb857a3ca51230b3a02b964f8efa2f6": { + "balance": "20576922380000000000" + }, + "57989f9fa52b4c0502e7d0c3caac0c37a0b20516": { + "balance": "462711082812000000000" + }, + "57a55c376ea03c22e21c797d83e2fb039508ad3c": { + "balance": "10000000000000000000" + }, + "57d1612ea1fddacf088b62f625ad8cd49d7517cd": { + "balance": "18001023230648000000000" + }, + "5811590907050746b897efe65fea7b65710e1a2c": { + "balance": "310984892882000000000" + }, + "582ffd8c43966aa8ad3c6cecdfc18eddc56fe5c0": { + "balance": "69136214255000000000" + }, + "583b90b3c4d00b9ddf101efbce75bb811d969fe2": { + "balance": "7839200298177000000000" + }, + "5841fee8b1965141e51b8c146b6af00f6a879a8c": { + "balance": "1210322907244000000000" + }, + "5847a576f7799ba1a35e36906b2c2a5aadeb99b1": { + "balance": "183765768447000000000" + }, + "586dea7ada0a54150f5afcf54198db473ed046a2": { + "balance": "7123598380000000000" + }, + "586f545062ec7dc0ffc213eacd59af80660df570": { + "balance": "10000000000000000000000" + }, + "587187488758f67912bd5bb8a5be787a73d97ee3": { + "balance": "702757402654000000000" + }, + "58be0a3482dc3411571f047f4128387049cb9798": { + "balance": "1000000000000000000" + }, + "58d546e2ae82efc4d8efc887ac6fd30f7eb5dac6": { + "balance": "1486717153455000000000" + }, + "58e7010e6b8d97a556c0e7f0d90151224ebf674e": { + "balance": "20000000000000000000000" + }, + "58f991b3b12d29f09ff4cc2c6e83d576e95b1f59": { + "balance": "25000000000000000000" + }, + "5923a65a796934e69081715657e8dfec8874e40d": { + "balance": "10000000000000000000000" + }, + "593b7c43073b8954355ed76020ff3780dd6ae783": { + "balance": "1403468567787000000000" + }, + "5947f1dbd79a622bcc3fa64b19f9b6eda164dcce": { + "balance": "50000000000000000000" + }, + "596311e2fc09ae1eaee57900f2ca188afd5e68a6": { + "balance": "448723397560091000000000" + }, + "597a3adac4607d457c90817220f67eb4abcf129f": { + "balance": "18000240000000000000" + }, + "598201a9bcff0a773e9323338a8a094e9d9b3999": { + "balance": "74904485722481000000000" + }, + "599e93031704c2ce36308f44d4ff8166e71ae516": { + "balance": "100000000000000000000" + }, + "59af0178699f9f3d8f0ea645dda75356119a6e2e": { + "balance": "152462578058000000000" + }, + "59b0c06e40475cd75728797add9c69c3fdb17b4e": { + "balance": "23147237210000000000" + }, + "59b79577f183b9d39c2b458646a26b2fd6ed806e": { + "balance": "4244859516807000000000" + }, + "5a03b51d67a9c660258ebc030120d5d1d4f687c5": { + "balance": "4451691855300000000000" + }, + "5a0d03dff6754963c757eb15a3339ac6c4ba6196": { + "balance": "215126489934000000000" + }, + "5a34ab3937854e407a8739fa14574d3d20e30d6f": { + "balance": "1375979293937000000000" + }, + "5a352fbeb2fd78bbe0268b0efd34f68d401e2769": { + "balance": "27929247671418000000000" + }, + "5a47c2ca4c0fad7e2fc7bbdf5f2356d68843c564": { + "balance": "3218227936000000000" + }, + "5a538adb2c7f6a80634b0ec20ec5152ff6bb4d5f": { + "balance": "10000000000000000000000" + }, + "5a8fe770c221072a7cba79ae7759cae0185adde7": { + "balance": "11913943233694000000000" + }, + "5aafe1efac688583d7facb09d3e569d58fb5a357": { + "balance": "4713219466825000000000" + }, + "5ab68d762750d5185138187db7751c9f71db5836": { + "balance": "500000000000000000000000" + }, + "5acab69851959dd5a6f0673ef757009ed36dfa3b": { + "balance": "974443209942000000000" + }, + "5ad9f2ab11b5e59b756404395f350aad6019d7a7": { + "balance": "54151179981663000000000" + }, + "5b1dc013ba1a28235cc70e785a00eff8808faef6": { + "balance": "516289257133000000000" + }, + "5b1eeb44ef61c7f35482503b7041162bec9b1e32": { + "balance": "125493885394000000000" + }, + "5b3db31996bca4625d22330686128ec234270206": { + "balance": "362316593128000000000" + }, + "5b401fc9ff3be7cdf5f0df870843bbef94f43285": { + "balance": "1373804724122000000000" + }, + "5b47ba296069041f25768e61be14437b8a469e81": { + "balance": "3152706392234000000000" + }, + "5b5030b5057c0457c190489c5d709d7dbdddee8f": { + "balance": "1154404278000000000" + }, + "5b5a4a782d37154a307868cd79bec9cb2a8f0161": { + "balance": "100277816425153000000000" + }, + "5b5e0b6b7cc27b06456ba4c7816ac4e89e1e26a3": { + "balance": "1023749119000000000" + }, + "5b638e4b6dfdb6928b07586e63d5879dce69a1f8": { + "balance": "1000000000000000000000000" + }, + "5b7be81d6ff5228a2b8c2913deea3f86823f1dee": { + "balance": "36000000000000000000" + }, + "5b7c4804bc2b8c72f3112b73d44b59c0711f83cf": { + "balance": "6803857604000000000" + }, + "5ba26d941544d07100744d8ffd6595a8eb7770bc": { + "balance": "583051897662000000000" + }, + "5bd58fc88733632b63d4f26893bc5c08fb60e2ad": { + "balance": "3480620567502000000000" + }, + "5bd85b5f0ecad08133fceb486c43998e537b3451": { + "balance": "484263880245000000000" + }, + "5c12639a5ab107f9e580cbd2278568dde10758d6": { + "balance": "101293252434000000000" + }, + "5c5522df05d6c6d960394c4762599e74247ab102": { + "balance": "149088856773000000000" + }, + "5c722f3ac94421f95389756af9cd97d0eaa6b696": { + "balance": "1435349483553000000000" + }, + "5c7b14ce51abf629bb0953ee4e2d9d87fc86eb4d": { + "balance": "10000000000000000000000" + }, + "5c8b215403da4e7912c1a1704a949087e091b111": { + "balance": "1440961256910000000000" + }, + "5cab313964f6730888e4158234bbd4806db0286e": { + "balance": "32284637230203000000000" + }, + "5cd736bf65c99469490d0523b10a658178cab10b": { + "balance": "99740204082000000000" + }, + "5ce91ef7ae254b2bd6d910cbf0d380814200811b": { + "balance": "50000000000000000000000" + }, + "5d15fc3a0ba8b3d87b80f9bbf972320112c644f9": { + "balance": "64000000000000000000" + }, + "5d2ccc795b19df400f21f24c0dca4d0e9e898093": { + "balance": "10000000000000000000000" + }, + "5d879b8b31af1e400cf53eb7170f82583190b96f": { + "balance": "93765337844000000000" + }, + "5d8dd54178b68bb36e1963d47d29c123864fd0ef": { + "balance": "20000000000000000000000" + }, + "5da1653bbe8353134edfff6158211ad7ee21dbef": { + "balance": "1491149937915000000000" + }, + "5da733ef41a7bdc0cf7975f83ed24604fbb4d40b": { + "balance": "10343699901151000000000" + }, + "5ddf5d7306f7c603b8d3ff993f03906dca14cd8b": { + "balance": "862558469755000000000" + }, + "5de87ec54e2160c7c2a8eff2d859414737501ae2": { + "balance": "21579321171000000000" + }, + "5df1b805b1361c1f39ca844aebe5ecee8a8d06b2": { + "balance": "411820472746000000000" + }, + "5df86b0a183b5e7f702e4da582ce9a8116a05f61": { + "balance": "256000000000000000000" + }, + "5e22359e20dc14be6930c6c1ce5a0c81c039cac7": { + "balance": "10000000000000000000" + }, + "5e2d38a06f33c784303abf2012f9af12622d9e5a": { + "balance": "10000000000000000000000" + }, + "5e479e616585e7fa84bd6f7465d394a1c0302be7": { + "balance": "10000000000000000000000" + }, + "5e4a55027a0d372f6da042b7f73720b143347d9c": { + "balance": "16175516772000000000" + }, + "5e52e86eda3e05f96e353d7e3f0ee90f08864f84": { + "balance": "21255916842000000000" + }, + "5e91c4d3a21c9dfac2c0994ed8890c78d58626d5": { + "balance": "325349462011000000000" + }, + "5ea797b18caba45d5504e57b80b12f5f5ae630aa": { + "balance": "7805696321000000000" + }, + "5eaec8815e859c34dba88cfe7b7fe28572c964ba": { + "balance": "145852682588000000000" + }, + "5eb974b5716fc4712d431bec7fbb2c49057a7b84": { + "balance": "4890681156035000000000" + }, + "5ee5f8407dedbac839f509419051106219458006": { + "balance": "3042761975468000000000" + }, + "5ef782abb28d1ca889ceb3039eef98713effbf32": { + "balance": "40915083108000000000" + }, + "5f23b88f06430c42570ac3fa33b1c7503b388a3c": { + "balance": "2376070180325000000000" + }, + "5f2b1641c0f2605b090039851aacf297e35632ef": { + "balance": "141615261000000000" + }, + "5f44cc8083340e644d19d3debc84dc14a0cbc53f": { + "balance": "291829106275000000000" + }, + "5f633f89adcc70e9da0b66611a5da108b4b221cd": { + "balance": "50835573000000000" + }, + "5f94ef8e9612b03a5c6ffcf423ada9a19a40818f": { + "balance": "102566595099430000000000" + }, + "5fae1977b76a5e899b384f572e4d94855f9cb52f": { + "balance": "773616125740000000000" + }, + "5fbd22cb3de462c794e523fd1ce36f230cc84b83": { + "balance": "1009995132839000000000" + }, + "5fd91676bc95bd6b5e69db8b9216dc83ed9dddaa": { + "balance": "1000000000000000000" + }, + "5fdda8f5271a08cf1b830faa497019d75fa9d231": { + "balance": "4149626365000000000" + }, + "5fdea351c5eccedf2394fb54437b149ae423ecf3": { + "balance": "100000000000000000000000" + }, + "5fe70ee123cb2e03c768138b2f71c1e1ea75ad17": { + "balance": "1074496282650000000000" + }, + "5fec9df797214459f85a040a559b186ee9161c88": { + "balance": "205282872821268000000000" + }, + "60037df7e4092466656a6b9571437fc4600c66e3": { + "balance": "1000000000000000000000000" + }, + "6009a0bcf531640a5a7f1664a69fe0f64b564ede": { + "balance": "50170000000000000000" + }, + "601668d8b678c95ec5ef98d9d2624decbdd52e9b": { + "balance": "23592727870000000000" + }, + "6027bafcd0ade24fda8c345dcbc812d59df74bf7": { + "balance": "10000000000000000000000" + }, + "6029514f24825c1fadc68cf8614951de5d53268f": { + "balance": "1389262963614000000000" + }, + "606de6db14272a314d778cf0e67913b7fabea45c": { + "balance": "144000000000000000000" + }, + "6074f20675f975ae2c081930cae8f299710f0bba": { + "balance": "10000000000000000000000" + }, + "60850fa9e09d414af3690e4b5daefb1b906b0d20": { + "balance": "10000000000000000000000" + }, + "60ad0b6239dda5df7ac0f0ca941684cf20ae0fd8": { + "balance": "81000000000000000000" + }, + "60d6136e6db631be45fefb9667c3dfa69e9d6054": { + "balance": "651902184266000000000" + }, + "60d733dedec6886908520ba57cab8c9d5c2d7f7a": { + "balance": "555461746642000000000" + }, + "61202238aea4010d115c5c64322ad790576cee43": { + "balance": "10465801848035000000000" + }, + "6142d92b61111657de4b2d65698a3621411e3adc": { + "balance": "100000000000000000000" + }, + "61879bc1a022d9cac8b7d57c8f528065beb10bb2": { + "balance": "72766025231000000000" + }, + "618b15c9a60ad89e7fc28afc79bbf7f28d4998cf": { + "balance": "444855210015000000000" + }, + "61c1169e8ba43ee6b919e5be2eac19542eb913b4": { + "balance": "500000000000000000000000" + }, + "61f1cd6efce17f5458325f022f363fd9772d8f20": { + "balance": "19704989598372000000000" + }, + "61f7d39211a0af2e226d8cbc95fb673168653b0a": { + "balance": "484884476279000000000" + }, + "621aa67f09e6506efb2fd141f080fb1d96693a57": { + "balance": "1694451603196000000000" + }, + "62332fa5127b98bd2a627a0ac22d3a1bdb418efd": { + "balance": "926882233406000000000" + }, + "624a465696ad409586a2e67d84750ba50a971fee": { + "balance": "25000000000000000000" + }, + "624d866f0d61bdefc3ec2210bfe36b6d51018f9c": { + "balance": "199592183194000000000" + }, + "6255d6d3b49443891661b209056d530ecd63bcca": { + "balance": "10000000000000000000000" + }, + "626c484055e6739d46e2ff25190c8b3a4af3fe0f": { + "balance": "1485276462321000000000" + }, + "62865e637d723393ab9654d6439db7fb5abf8803": { + "balance": "10000000000000000000000" + }, + "628a47761d5ce755de88444aaf6d7736b911672f": { + "balance": "18625552918216000000000" + }, + "62df6a38e8b15a1c4f4a7aa7c1736c612f54a0e4": { + "balance": "16468111299582000000000" + }, + "631d7916ddbb5f7c469f8ba07cd48e377560319d": { + "balance": "2493487426430000000000" + }, + "632754f5afcae7dc36d9286cfcd91c14abf0f7bd": { + "balance": "1424933496931000000000" + }, + "635788343997ea9f145c508b0cd2ed36e180f46d": { + "balance": "143040938538000000000" + }, + "636973e7dbda9e3042a8c03e25696d0faf27f025": { + "balance": "5491869128148000000000" + }, + "63707efa26d34d7ceadf4e6439324e7bde0ebc3f": { + "balance": "1000000000000000000" + }, + "637d92494f7872d397340c9b5183dce354c8c43b": { + "balance": "724687404033000000000" + }, + "63b9c2e6762a431752f7669b8bbedae9f37120b3": { + "balance": "1360967549741000000000" + }, + "63bd281d8c4d1279519237a2b68f2a73c228f7e1": { + "balance": "217457311664000000000" + }, + "63c0eb8c9a0019e36ec9a731b4bd947271a5bed0": { + "balance": "36693488147419103230" + }, + "63c6362eff56de328a29b7e9d32ced28f3602b6b": { + "balance": "148335309448000000000" + }, + "63c979c787a7b037693cadfeda738ae33178c009": { + "balance": "81000000000000000000" + }, + "63d4621d91906215d32f6fbcee1ac48bd773f630": { + "balance": "1006939236069000000000" + }, + "63ff99fec1cbd2f6e83c0e6de3c0ea4b7c7e1398": { + "balance": "1201300688980000000000" + }, + "640ffd856e48528b05d5ef1e60348048ce291960": { + "balance": "20000000000000000000000" + }, + "641c25f7c380e2745c81a268384a029b2e2be0cf": { + "balance": "635133477665000000000" + }, + "6427792a164bbeab45f6c3acf17c76f721b90e81": { + "balance": "10000000000000000000000" + }, + "6437986b4c545af9c4a5ee96371a5807275e9221": { + "balance": "2951152516627000000000" + }, + "64460d09d1bc5c425d62bef5969eb0c5916963c3": { + "balance": "1680000000000000000" + }, + "646381f92216b97abbd86ca100a773eebdf7545b": { + "balance": "211234535515000000000" + }, + "649f73d1cafeb3ab0631432f04c9d08b9f438c22": { + "balance": "248900746448000000000" + }, + "64a239be45a92df83bb85b25f8ed7de5d82313b9": { + "balance": "100000000000000000000000" + }, + "64a3d97f82e3d42eea78bbcee31a95d33767b055": { + "balance": "2511466286000000000" + }, + "64ad579975888f455217e0f801e371900d9814c9": { + "balance": "7118859416319000000000" + }, + "64af5edbfec8adea679951662c08a781175688bb": { + "balance": "822966999709000000000" + }, + "64b7f2c22c20a59c07cb0dd7f8f692153c68f3f8": { + "balance": "20000000000000000000000" + }, + "64bc17e28d468b7b8368ee8a8375710d21c3ac5d": { + "balance": "875002262415000000000" + }, + "64d17aa662e56061cebb3c2e2421e637163e8dd3": { + "balance": "363241251465000000000" + }, + "64d714ec3145308e8f939bab7591b0773038b886": { + "balance": "338231954012000000000" + }, + "65199fc9ba95434382c108b44ac553534a9a3670": { + "balance": "2537340957145000000000" + }, + "6527c67c29e47833dc2440570596023318a7bd99": { + "balance": "555434226832000000000" + }, + "654b9d299077c90768c5ca6635e5802e8099f51a": { + "balance": "119004827465000000000" + }, + "655908513607cc38de35351ff3738b201bbf39d4": { + "balance": "652902936029000000000" + }, + "656ad16063b2d397788c231e537384ece94eb0d2": { + "balance": "63116382606000000000" + }, + "656e622970b8829a7cfe24f5b82696c7777683ba": { + "balance": "20390269890405000000000" + }, + "6583a6ff4dfcf447e3b163a61b0d5cb84ceee375": { + "balance": "3858529344000000000" + }, + "658d2b7e8a6517256efafd74321757d5c384a2b9": { + "balance": "221114751567000000000" + }, + "65920758857ee5b27b0f31487ccc3c5d6986df3a": { + "balance": "16272975796000000000" + }, + "659d60d67a07774ecc5cfea9e56809bec024d639": { + "balance": "20000000000000000000000" + }, + "65a1a3f968bab5fc1f097b8e297099a3d34ef45a": { + "balance": "16000000000000000000" + }, + "65b5e3163d20b2a6fc75c0219b7f97d83479a26d": { + "balance": "1716459529041000000000" + }, + "65c9bc3b8b0ce7c4d16b35abe1a5c285a59f672e": { + "balance": "20000000000000000000000" + }, + "65d5b458d9b1a9659c1125d20d970d5e6c29dc3e": { + "balance": "20000000000000000000000" + }, + "65e75bb8ade25eb7975ea12b9afdb17ac21063b3": { + "balance": "2270407774714000000000" + }, + "65ed78d0c4ef1150e8765b24b210f056e079cd59": { + "balance": "500000000000000000000000" + }, + "664ee5e334b8378928becfbf5d5e51daaf001125": { + "balance": "860160259186000000000" + }, + "6679bdb26adc179d046607d49f4b10c65d8a40d1": { + "balance": "436794739763000000000" + }, + "6680fe9d6eda3ab9fc4ac1ac933339b533eb682b": { + "balance": "551296206326000000000" + }, + "66a1249501cc5076b040bbb165ce032ace216ea2": { + "balance": "36000000000000000000" + }, + "66a475d014c2f976704bfb93ce78dbabbfc5e072": { + "balance": "1140135640169000000000" + }, + "66ae43d92e8fb2231fee8c72d720ff90cdd267ff": { + "balance": "796696150339000000000" + }, + "66b7e0c810d6959afa8210f6ca67e3e40bd24eb9": { + "balance": "16000000000000000000" + }, + "66bf8be16f33b111b2a425743bb7ebcdfbb35034": { + "balance": "538590591000000000" + }, + "66d2eaf7fe10900d93eab17823ebfde5486aa2b7": { + "balance": "121000000000000000000" + }, + "66e525bb01b3ede1a4a105bb6087ec8a76200616": { + "balance": "1506610219207000000000" + }, + "67291e0df83d6e9f1386e87a1792d7d147341df9": { + "balance": "272330177662000000000" + }, + "6730b27b62e064b9d63df3bcbb8c4bbb0e500afe": { + "balance": "331282968154000000000" + }, + "67318617bfe19b739fac9a126fd129223db52498": { + "balance": "12699924981000000000" + }, + "674dd0b036c91f3a83288af44897b4ceb2e15a12": { + "balance": "4352791270187000000000" + }, + "6751bffd04be55c86692994fed06694cb78b62ff": { + "balance": "26049487516000000000" + }, + "6768d99a0cdcd7bb7c7d0aeee466d6bdc7208bbc": { + "balance": "309909685000000000000" + }, + "677ba2de3e5c68a4c354c9e3129ed1c41025312b": { + "balance": "127426274611000000000" + }, + "67b83745856551f1878027843be20e1473191944": { + "balance": "185757248875000000000" + }, + "68170edcfaf2c6df4e6542b2856ad33e9e2d6623": { + "balance": "4003453949471000000000" + }, + "684ae403d9a08e4f4f971cfedf81094074daa77f": { + "balance": "25139713925794000000000" + }, + "684f3b8a749c002aa434bad6af7a3e2579c69315": { + "balance": "16000000000000000000" + }, + "68538a9e8246be5a5c5ea315cb325344062cf8c4": { + "balance": "14009193210480000000000" + }, + "68935ff3a3a3b6ef16ae7df58cee50b157658dd2": { + "balance": "20000000000000000000000" + }, + "689f508256ea64f5dbd6bb77f1ce1bdaf36d7152": { + "balance": "10000000000000000000000" + }, + "68a3e6e7c191a8c1add988bfbbb9b51d4f36f521": { + "balance": "10000000000000000000000" + }, + "68a74ff2a5577321f854b56d3834a55d3c41bd94": { + "balance": "88873831171000000000" + }, + "68e6da521bde13cf4e4f423a78fda2f69b3d1c2a": { + "balance": "538392460838000000000" + }, + "68ecd5cf8cf8d9704fafc36d8da53930afeb0553": { + "balance": "1090923641219767000000000" + }, + "68fd0b8e000bd2788be6cb10fc0496fe2cbe155d": { + "balance": "32853847745000000000" + }, + "6904045feb5ef94e096894b863d314ff8a0f206b": { + "balance": "9892165615000000000" + }, + "690fbae5153849bb20797af7b8dea66a728a06c3": { + "balance": "6082107223716000000000" + }, + "693d909842877d017e0f102e37a55024517dd0ae": { + "balance": "20000000000000000000000" + }, + "694cd00fac9cded484ef2cfcd44faf161354f288": { + "balance": "3049716150137000000000" + }, + "6964c3c2c7bc719ec94a51bc4bf412e137d2b4e9": { + "balance": "1000000000000000000000000" + }, + "69a5c692516940bebad8efaa2243a8fbdf2ade62": { + "balance": "2803346939929000000000" + }, + "69f566c44802b0140f5e1c9234f46006773c03d4": { + "balance": "20000000000000000000000" + }, + "6a17eef3a6bd407260f52067592226448182cdc3": { + "balance": "1116509364305000000000" + }, + "6a200e99a0f50aab32fa7373c7880817c81f472a": { + "balance": "1836680122795000000000" + }, + "6a2a29f5f441876816dd17856051040787f48a64": { + "balance": "1131603204000000000" + }, + "6a3f855c7dceb75d0de7fa18fbc2f40c81b76756": { + "balance": "32267494586000000000" + }, + "6a46af653b938643e781cc4a0edcf5357852fd21": { + "balance": "1140718780752000000000" + }, + "6a4b2e5b45da0d70621ce71f165a11078a1745e2": { + "balance": "3768326643000000000" + }, + "6a530c813595a5b7776cced05a865dedcb110d94": { + "balance": "270559347097000000000" + }, + "6a6e3e82f98ce891f47721770301dbe2652a9e25": { + "balance": "10000000000000000000000" + }, + "6a828d6f2f7f68bde4a12608024020e593540010": { + "balance": "7531817000000000" + }, + "6aaddd1f4ff6b4d414c87271619b826ead27f09f": { + "balance": "64000000000000000000" + }, + "6ae6bce1e2865ade0d02eff9899ea3767b5511cd": { + "balance": "6893781798524000000000" + }, + "6b04e7c6a837d218fd3322b87a267fdd979358ef": { + "balance": "302679180175000000000" + }, + "6b2210b8536803b134e69c5046904acafef48cdd": { + "balance": "47823456459000000000" + }, + "6b2da6f36c2e7f61cabd7580480065360c995c93": { + "balance": "55000000000000000000000000" + }, + "6b3401986f2be7ae5a4ec160b8f96b2a651fce73": { + "balance": "16000000000000000000" + }, + "6b3847774e99dec307dcf5bf5adba49df4a9f145": { + "balance": "43276069579000000000" + }, + "6b57f2d9d95cac67fd2f70c0911d48c7f09de072": { + "balance": "1000000000000000000" + }, + "6b65d736a8ca89ec8508b52e4aca5166f9703732": { + "balance": "766421968820000000000" + }, + "6bcc55d897829e98fc3f3ac8beb331e59c33b942": { + "balance": "318115956882000000000" + }, + "6bd76e7af1775b88743d5f53ede0ce846d3d7ced": { + "balance": "139548017482371000000000" + }, + "6bd7cca99acf6eed5842417c2327c642df5473fd": { + "balance": "3321731000000000" + }, + "6bf72c4d39d6700181954a8d386c3df216634412": { + "balance": "12742769034078000000000" + }, + "6bfd3aedeac7c6ec086c0a4ec29d2d0f5bd69bc5": { + "balance": "50000000000000000000000" + }, + "6c025962810a6fb8374af5e07d7fcd631d10b1ce": { + "balance": "674126722005000000000" + }, + "6c1b72df836f410038af9e020fa2ff2ead398ef4": { + "balance": "1851293017364000000000" + }, + "6c1fddb4254ff46b3750de322ebb7d6238c0a606": { + "balance": "9977629348276000000000" + }, + "6c37069a361c5c72355bb5a56879dd0a9735a237": { + "balance": "1062230154063000000000" + }, + "6cb166eeca248a234c971b2a864a7b3fdbe5a737": { + "balance": "390222992865000000000" + }, + "6cb797289059cadcfa77eab0365e6bf1ae12df46": { + "balance": "100000000000000000000" + }, + "6cc787e6bb4f484828b080330667b93953e7a3c9": { + "balance": "16106440380234000000000" + }, + "6cdf7b334fb2ef8115198d475d431eeb7d88df77": { + "balance": "1940904395351000000000" + }, + "6ced85b035b787e9e427d0904aaf96e011417310": { + "balance": "103417697874000000000" + }, + "6d6e09acc07f388cbab99e53959f75e9ad8f07bc": { + "balance": "1305917678000000000" + }, + "6da91b02f512f412d374392247a9aaa853e9dd59": { + "balance": "2300525907893000000000" + }, + "6de5d70481cd40db468f64227228cdd362ad9980": { + "balance": "10447389944082000000000" + }, + "6dea87255c9ebfa63f017209046e894ecbbc03b7": { + "balance": "1527216854064000000000" + }, + "6df6f6b9953c2f2a8ce5985e19dd6835ae2c566c": { + "balance": "6539856530000000000" + }, + "6e013c83cac111a38fbbf8d47778fda0d3af25d5": { + "balance": "12139181929380000000000" + }, + "6e18a484f402fd433a5ac4dee5a4b8bf6f22db47": { + "balance": "23215906572368000000000" + }, + "6e4fd058e4dcd502c2015f83f3677f680ec58110": { + "balance": "480059342014000000000" + }, + "6e501ac7357fc758caf5dff6c29a995c806a1a7f": { + "balance": "1573491311733000000000" + }, + "6e6912f9fc21dfba736055e6ccef074dd62dcc59": { + "balance": "256000000000000000000" + }, + "6e869c68511c1458f4fbed9a4c5296fe961eb47e": { + "balance": "68488423994541000000000" + }, + "6ea6827b377b3d3ecf7c7628ed8daad7fd8eab1e": { + "balance": "188825714738000000000" + }, + "6eb9237738339fcaad3763466509f23efd0c5054": { + "balance": "48417242786000000000" + }, + "6eb92a61390f9d9ecdac80a8833aa801c3926b13": { + "balance": "1412936326723000000000" + }, + "6ecb93f18153ef2d2a552286ea3b7436f1f8168c": { + "balance": "20272577229669000000000" + }, + "6ee087c04cf16f4768c783a548686448fd125914": { + "balance": "1397039628538000000000" + }, + "6efbae7a34c71233329d0bb4cbec45274824ebf4": { + "balance": "8910000000000000000" + }, + "6efcd6776f287c25a6eb3cf71018adc282eeab6d": { + "balance": "1310659853178000000000" + }, + "6f9ca805ddaaea5205e85778dedb2eff4a5aaa75": { + "balance": "2585733757016000000000" + }, + "6fbbea927469f4d18942ce0aade164828fe23a2a": { + "balance": "4671857880000000000" + }, + "6fbe9df6c42151c453502960d99170445dd3ac0a": { + "balance": "20060296562115000000000" + }, + "6fed121fb310431f1659e637f35f4c878a7256c7": { + "balance": "55170085399000000000" + }, + "6ff2dd5373bd72966ef48d3183c60d74a6549cb9": { + "balance": "24103445361000000000" + }, + "703a490c4783776da244384c964897491aed3711": { + "balance": "2001677632732000000000" + }, + "704dcd2d9f75f0bbfb73f2fe58bcbf4508374381": { + "balance": "439603954369000000000" + }, + "70859a14f33b8ab873fa5781a4af1ce40dff65c0": { + "balance": "10000000000000000000000" + }, + "70b9cdfa5f6d41c60e1c0d3f544f569c9b340ea2": { + "balance": "198355566698000000000" + }, + "70d0ee793e28e320b34267ef2df69050fca0a9e0": { + "balance": "8010660534227000000000" + }, + "70dc7e5951752c22a0e3c50e8e7b1f7af4971d51": { + "balance": "3991137321749000000000" + }, + "71057f5afbed7d82c92d50790e3797fd7395d036": { + "balance": "49000000000000000000" + }, + "7109a3b3d5d6af49693549728691099d696ce016": { + "balance": "4119694297000000000" + }, + "712231a5161745fa1b33c7b0f6e8c767e1de4f81": { + "balance": "1353809351914000000000" + }, + "712aa38999c0be211654e5c84f59e3b2e018f597": { + "balance": "160199774000000000000" + }, + "713229fc94a86b71a5bd1ea6498b9373e3f3c549": { + "balance": "98289185940000000000" + }, + "715de29a0b6f467b94d4a90dc767ad52d0fb3b9e": { + "balance": "948824982990000000000" + }, + "71776853ac97ce04b008c9a7b64156a3cafc52a4": { + "balance": "608309596513759000000000" + }, + "7189f6dcfe64e1ddbfb5e51fd5f3174bc636dd0e": { + "balance": "5674608906899000000000" + }, + "718a4da87464caf6e83ca374d5ef9255b8f7cc3e": { + "balance": "761891873568000000000" + }, + "71bc447761cdb68915cc2288b4929fdc0adce02d": { + "balance": "10000000000000000000" + }, + "71d78531896642069b725bf82fc385789c63217c": { + "balance": "33103960195000000000" + }, + "71e328deeafbb1724051d1062609c43eef56ecdf": { + "balance": "493550967964000000000" + }, + "71ed0310fb51b86a61794aea17a3c792dd301e3c": { + "balance": "3234918634449000000000" + }, + "71fa264f58041e41cfe36e8f8d4e0cb22ab71925": { + "balance": "5558941960000000000" + }, + "72059c57d0fc05bc02ba54ebea6cefd1efbeadf1": { + "balance": "4458278271443000000000" + }, + "720847a28916a532bcab33e1fcbde5d1c4d820bc": { + "balance": "1392418942284000000000" + }, + "723cd2b5b836b0ee8481d37b9c51b5f3f1beddd2": { + "balance": "1856420455522000000000" + }, + "72430c6664d23c7051b0e99912fa54dfadcfdeff": { + "balance": "102078926010505000000000" + }, + "72652c4320dda25348f15c0ecfeb4b3b3ceeb7c8": { + "balance": "307639955659000000000" + }, + "7288bd1b9f4c068dd5df9bcd6fec1ccecd240195": { + "balance": "80161087899000000000" + }, + "7299cb8a288abe8e1a22c11b53a903acb7db5827": { + "balance": "752198565719000000000" + }, + "72f6bc0c3ae437756c099e02e9c084febedc5569": { + "balance": "696294297587000000000" + }, + "730e5907b344c80e0a6115723a90a23e3635192f": { + "balance": "6056082041729000000000" + }, + "732e97b992e4f8a53034cf29cf11aacba7452261": { + "balance": "100000000000000000000000" + }, + "7339df65ce293b3d501647a04c83819099f0bd38": { + "balance": "706500983417000000000" + }, + "73482f8135ca2231db5e0e034a235a9d244a8656": { + "balance": "1143989148865000000000" + }, + "73769e43058d30a530048e5a2bea7e9333534e93": { + "balance": "113542901996000000000" + }, + "73bb9e6f1709fbb7964df7b3cc0f9170c3152f38": { + "balance": "1639793026701000000000" + }, + "73e261da7978764044ee916f88bf66680952607f": { + "balance": "100000000000000000000" + }, + "740154120c4f41c50b0aaa0636a2000ff1e870ad": { + "balance": "10000000000000000000000" + }, + "741fe2a1537284b70e97e3ff659eedfd7fc5b1b6": { + "balance": "75911502037000000000" + }, + "7420bb277d834763e4429db9bf37f053f71ab769": { + "balance": "3100160195046000000000" + }, + "74281371c3b569c774da6bab686e7d7a45d4dc4c": { + "balance": "25666397941223000000000" + }, + "7428d261b5418652c5ab248d6abc3d2af25d904a": { + "balance": "56252809397000000000" + }, + "742c876433297f5a8fd4a25f75ee9a607726bd3c": { + "balance": "4132793019677000000000" + }, + "74302036cf52e11aa3f32a371bb4992e2bdc3f39": { + "balance": "19557661364000000000" + }, + "7445c657c24d014f3a9dddc3e446868bc2dbd13e": { + "balance": "10000000000000000000000" + }, + "744b8fa69d2542be3557267edaeaf2cfa8a9e991": { + "balance": "16000000000000000000" + }, + "74728999963524e7cc1736abcb4deac630142c44": { + "balance": "37000250991000000000" + }, + "74926cbdacd0e871cad0d926c8e17cb2c00475b9": { + "balance": "20000000000000000000000" + }, + "749e115a9e675bb15af5e1c04f81fede07c40120": { + "balance": "440913547154000000000" + }, + "74b7e01acf825898544d6c1b61e53356be759c56": { + "balance": "25000000000000000000" + }, + "74c5fcf875e2e9b726a7cf6e176dc2f7eb84c200": { + "balance": "59208835472000000000" + }, + "74f44579859e4a7944dda7bd810088e116ae9910": { + "balance": "1038454108527000000000" + }, + "750b1e2955ba05c1fc8a1f9dbb1624ed11587edd": { + "balance": "9545712605000000000" + }, + "75375129cff2a051f656b91f868325c3b35ee1ae": { + "balance": "25000000000000000000" + }, + "753ca28fbd89081382a996fe938da7e6c3ae6cfd": { + "balance": "156582454263000000000" + }, + "753d91c04e554680cc32a97c1abc96280e8263ee": { + "balance": "725101425969000000000" + }, + "754e5b5d64c267e83fd4804d112725531cf5abe9": { + "balance": "83276113115000000000" + }, + "7588a96a2bc65569a6c124c4a4acc55863a8ab78": { + "balance": "24062602342000000000" + }, + "759075dc3a6b9d2499a74bc57e346c9ed7ff834e": { + "balance": "225000000000000000000" + }, + "7591d6fa043801fe12462e11d9e33a53f438c073": { + "balance": "1863874274000000000" + }, + "75bda5bdf6aa749bbd62b6107941a7dd9ce3880a": { + "balance": "36000000000000000000" + }, + "75c2d3a99f144c4b9962b49be9d0a81b203906e8": { + "balance": "9000000000000000000" + }, + "75f587a69a97eb4d1c4c4078418d5fa85dff6f94": { + "balance": "10000000000000000000000" + }, + "75f67649605f49d98d866102ea2d6881ead9bea0": { + "balance": "814929108418000000000" + }, + "7602abce0f510b6ca471fd8d734e21a2591886f6": { + "balance": "50000000001006000000000" + }, + "7629b788160531b0be28bf445bf305fbe2c514d2": { + "balance": "23022256366212000000000" + }, + "762aed2e3aa2293e69dc2110b1fc6c806ae799a5": { + "balance": "10000000000000000000000" + }, + "7637b89130bc3f87e90c618fd02d6dd27179101d": { + "balance": "77765738300000000000" + }, + "765136022facade53e7a95c0c7aa510787e674d5": { + "balance": "1478178932688000000000" + }, + "765274015a308a9e6b1f264e5bac592d267f2f7b": { + "balance": "3058788819393000000000" + }, + "765cbc0a89fd727a2c1a6b055139faee53f11330": { + "balance": "500000000000000000000000" + }, + "768bb6d4b190c18a0946d92073ee446d68d98a6f": { + "balance": "144000000000000000000" + }, + "76ae8079894c760f2850c02cf5a0d7bb41e5864d": { + "balance": "156059816821000000000" + }, + "76af4103a231b1302d314c486a0ba524d0427899": { + "balance": "10000000000000000000000" + }, + "76b6394cd02ddf761e981b6a6ce1654c0e575443": { + "balance": "1078304803757000000000" + }, + "76db33eafeaf965dcf15d5460b64a48b37285259": { + "balance": "1000000000000000000" + }, + "76e5721c0a39d41274f84cb572039967a07e9beb": { + "balance": "156298167226000000000" + }, + "76e6ca6ef145d2711ab27f82376a065cc6f62a29": { + "balance": "100000000000000000" + }, + "7705d637cf9f6ceaa452deaca7ccc581beb5fa34": { + "balance": "36254762908065000000000" + }, + "7706c80af4eb372e168501eedfe7bda6dc942243": { + "balance": "50000000000000000000000" + }, + "771493da92c9fc6c6b39a4071ae70d99f6a588d3": { + "balance": "2000677471360000000000" + }, + "7719206286f26144c0f20b5e1c35cf4495271152": { + "balance": "1380480863056000000000" + }, + "771adcba1409fa2df6db19d9f784abc81a7bbf36": { + "balance": "15416381820915000000000" + }, + "772f7baa80a852e05b2fb3903a36061da132b2d8": { + "balance": "121000000000000000000" + }, + "7731a4175eee5077e2ede48878e6e2a18fce0f9e": { + "balance": "10000000000000000000000" + }, + "77385deeba01e3cd7a63e13d6048011020f56724": { + "balance": "57204247488000000000" + }, + "776808e7688432755b9e91a838410d29e532c624": { + "balance": "120318608715941000000000" + }, + "776d1b406f63082b80e250c4a0073fa0d83b9090": { + "balance": "243779839900000000000" + }, + "779848a59036ee3cd23b93ff6d53620d874f0bee": { + "balance": "82228810849000000000" + }, + "77d02a031274bd4ed2a16f3cc29d94e755142036": { + "balance": "408567696646000000000" + }, + "77d609a407aa0d126d58090b8d635f5ab7a02d6d": { + "balance": "776754055755000000000" + }, + "77dec41e116301dbd6e542f139816bfd9bf6d154": { + "balance": "16335989583000000000" + }, + "780398b42f81167731a8ef6a8bd1d14942b83267": { + "balance": "25000000000000000000" + }, + "780a645d59027e7b0670d9565898dc00704cbe5f": { + "balance": "20000000000000000000000" + }, + "78182a7711c773f306ec42ce6da3e983cd49b00b": { + "balance": "580861257254000000000" + }, + "7822622f07fec12995c4bb8eb32d62aa7f00be05": { + "balance": "5018461926846000000000" + }, + "786410c679101c0ebf06fb4f36102368121f3c8b": { + "balance": "16098386724761000000000" + }, + "787d5476038ab0a09b846645285ada23ffd7318c": { + "balance": "492047430907000000000" + }, + "788e9e27ed979d1e7aefadda798f69df1de1d1bd": { + "balance": "30965301214000000000" + }, + "78ab2d2dfaf5d2580ed89c970e771572bc91d3be": { + "balance": "36000000000000000000" + }, + "78ab7ac6f379ff084a7acf4a1a31fe2e5a6834c0": { + "balance": "107332516726000000000" + }, + "78aba95da37385c736ef93d0ca8318baf6c5ff3e": { + "balance": "9000000000000000000" + }, + "78cecbd82229dc91a530bd555c9e45125e2a6bc7": { + "balance": "28474069251604000000000" + }, + "78d4df90990248f3ac67e492a0a1e3f4ee455507": { + "balance": "10000000000000000000" + }, + "78f6de3768abc604c49b10d798e0656948cd334e": { + "balance": "9000000000000000000" + }, + "7909aca95ed899743de222e56c231f9bed1b518a": { + "balance": "5355599376491000000000" + }, + "79193e660b4431e8aca9c821b7daa88064e33750": { + "balance": "100000000000000000000000" + }, + "792487caa23b0d9b9998002810cf29439f7190bb": { + "balance": "4828579961131000000000" + }, + "793f56adea51063243a9633ecc1d1e620a91f327": { + "balance": "926742377449000000000" + }, + "796d187077c1d7591583436ae64d10a641490ca5": { + "balance": "242664407084091000000000" + }, + "79a6b7fad3b5a655679450ca82818ec2d6f58688": { + "balance": "1400472715109000000000" + }, + "79acf627e67cedf48297c26fd135973bff6c57da": { + "balance": "444598475759000000000" + }, + "79ae0dda1964ff0191b98d28c9b52a79dc9ab078": { + "balance": "325908985422000000000" + }, + "79e71dcc52fa1b28226c519f715faa3cf63cfb09": { + "balance": "497898493594000000000" + }, + "79e98193ff8770f26af824734bbb1c2ce8197b6f": { + "balance": "10000000000000000000000" + }, + "79ff3d790d52c58b7317a415278e9058915d5241": { + "balance": "48502649691864000000000" + }, + "7a0b02d16d26e8f31e57106bbdad308f513d436c": { + "balance": "841000000000000000000" + }, + "7a1d422352ec7e6ca46131728e4b71f20ed84e2f": { + "balance": "50496873413000000000" + }, + "7a2a3fbe27e33df867ba8800788995d7662c046b": { + "balance": "100000000000000000000000" + }, + "7a629c4783079cd55633661d2b02e6706b45cf8e": { + "balance": "50000000000000000000000" + }, + "7a62d8875f53e54b775ee2f67f7e2ec137bf724f": { + "balance": "25000000000000000000" + }, + "7a67285fd883d36ea3107aa3fe7727c68a99eb2d": { + "balance": "254787158217000000000" + }, + "7a90fbec48492473d54b0fad128ceda94ea66100": { + "balance": "313715004199000000000" + }, + "7a9e11463d84a08140d698972e32e66bacf7a7c9": { + "balance": "3602603216258000000000" + }, + "7ac4f33e1b93ef0f9c15014e06da24904ef4419e": { + "balance": "101000000000000000" + }, + "7ae082ad247275fd5a9e77b127cee5693784e9e1": { + "balance": "1921957343533000000000" + }, + "7b27e070ca4158d13f8333b34842d4c28b678c92": { + "balance": "10000000000000000000000" + }, + "7b2e34374921e4dc10fd9cfc670a40f5d092da1b": { + "balance": "2098457950503000000000" + }, + "7b54c6c8041c8b09240de1ff06e0d3d2d8d877e0": { + "balance": "944752036841000000000" + }, + "7b5aecb798d8f4f5a04bdaef909e09a35bde8d47": { + "balance": "21975115049000000000" + }, + "7b88a7ef9201966bd1ca634779c3b7f40c22f0d7": { + "balance": "64344833519732000000000" + }, + "7b8c22ddc5c7e59e571587d7c776fa50e65f4845": { + "balance": "225108110445000000000" + }, + "7bb4d8a169f72432494ac362eeab005ce1e02d81": { + "balance": "2098993419448000000000" + }, + "7bbaaa6690698e749d095447bdd27207c0caee43": { + "balance": "490069993631000000000" + }, + "7bbf27f92f9f726381d4f68b21ed86af8f792d04": { + "balance": "806346082666000000000" + }, + "7bc6f172fd78953c3456c571ac8394756715d5fd": { + "balance": "81000000000000000000" + }, + "7bcca29b477730ee8f219a5d1bca24415c7a4625": { + "balance": "36273885000000000000" + }, + "7bd296e1cb29ad87ed28b0ed18440ee686b157e0": { + "balance": "35964679698000000000" + }, + "7bde6d49a1af34a5a9dac0b9007e9a5583c65ebd": { + "balance": "1041474566346000000000" + }, + "7bea6240f245e649563253fa4c1da39b12625da7": { + "balance": "100000000000000000000" + }, + "7bf096396c56f27f9c39c4056ee6cfcb0db44bc6": { + "balance": "407261849111000000000" + }, + "7c3b58d3ba283bd9b1580832e9d014eff48bff7f": { + "balance": "7074518779349000000000" + }, + "7c5a56c45f23c353ff9f6f71ec86c9a6a1a0ca67": { + "balance": "11277879639596900000000" + }, + "7c783ac9b07bc6576835635f37e7e3c137055c8c": { + "balance": "16253676225000000000" + }, + "7ca2fbc0a0d1370e95048a21a300eac4d6056df3": { + "balance": "2772084065617000000000" + }, + "7cbe95802a20eb765f9fcff0a068859cc35d2660": { + "balance": "255153842674000000000" + }, + "7d004fb3a6a81c00fd2872e8079ad2912841b0e0": { + "balance": "642630220843000000000" + }, + "7d30c788d4ea18849ebae1173373c8915ffd7a35": { + "balance": "61062263242000000000" + }, + "7d39324f5ff62e849b0f0f46ab8ee396fbd85581": { + "balance": "100000000000000000000000" + }, + "7db0ce6c04537417dca1dd3415a5bf213edc2028": { + "balance": "30393443462000000000" + }, + "7dcfaa795586c92f1ce7d5c7b10608fe6a773fe4": { + "balance": "183173395920000000000" + }, + "7ddd111cfdc3133f59b82568e3deefc3cf10b0d0": { + "balance": "5622149283840000000000" + }, + "7de81daaa7ed5cbf4d379cdd26ae353cbd5a2489": { + "balance": "10000000000000000000000" + }, + "7e0a11af993a41626c5564f719442c0dfd608ec5": { + "balance": "1532083534600000000000" + }, + "7e34971b187047e7f7980650630b936eedc11023": { + "balance": "10000000000000000000000" + }, + "7e5214e16851b33c4a4d29e5a06929461d3d9555": { + "balance": "371790231197000000000" + }, + "7e52ae9c7e4b888015a3a5af7a91444510aa18e2": { + "balance": "109879329128000000000" + }, + "7e69b383671f96b7abc2d1fed8b61477b87a58dd": { + "balance": "10000000000000000000000" + }, + "7e733b1fcadc9a20dc038fba74e236af0b5a39b3": { + "balance": "43583614302000000000" + }, + "7eadcf955c90040668fb0f75a61f687e4e41f314": { + "balance": "332201682206000000000" + }, + "7eb51f3ead1dd0f5384c199ad5518ec55f77d35c": { + "balance": "38487884822000000000" + }, + "7ee73c0d64caf46f47f439969060092ecafdecd9": { + "balance": "15063618320000000000" + }, + "7ee8e4c6742a4c6d8efbfacc4d56119bc6c74ea4": { + "balance": "31882319329000000000" + }, + "7f16d981521c06347db8324da38b25eab3cee23c": { + "balance": "400000000000000" + }, + "7f6ff7db81a26fe78dd80636f0b178c669344393": { + "balance": "10000000000000000" + }, + "7f792b094c0b96d6819823cf21bc0c402fc27bf9": { + "balance": "50000000000000000000000" + }, + "7f84ae97c21cc45a7e56603ddf97449d803fb246": { + "balance": "81000000000000000000" + }, + "7f89c2b9daba034841f19ae843cfb6cd6f75b1d7": { + "balance": "20000000000000000000000" + }, + "7fb18f8b0e1fd1ed8c863a66226082bdc0429ee6": { + "balance": "11465417544634000000000" + }, + "7fb4e30579c64efe981d0057204e5bd8770a1f87": { + "balance": "249801873762000000000" + }, + "7fcc4de10e837d98691acc52732e1568c890304a": { + "balance": "1000000000000000000" + }, + "7fcc77798cd50345b2784a78b81a25dd4c1e64ab": { + "balance": "2676882485895000000000" + }, + "7fe33e773a02b995278ff595d55a0741813b19d4": { + "balance": "5788279057355000000000" + }, + "7ff32b13d531ceef500ca6c6806ffc0773639264": { + "balance": "1000000000000000" + }, + "801380158ef8f24316bdceaa00eb89c3d886707e": { + "balance": "35627521347898000000000" + }, + "804fdccdc8603858d15dec88666437505b2a106a": { + "balance": "14607090269617000000000" + }, + "807915567eed99bb9146354a32409812b9490d70": { + "balance": "1083142734057000000000" + }, + "8092ceeb2be5b271f4c156d85fe14977e919c7e0": { + "balance": "761607160308000000000" + }, + "80962bf961d0d713395dbe00379a6e207b425a76": { + "balance": "524215754483000000000" + }, + "80a9787124075c8cd44b9c8674967a54445e2354": { + "balance": "7600078997429000000000" + }, + "80aacd59dd76bf443c47ca02976178af8453f23a": { + "balance": "411856023767000000000" + }, + "80db788f7fbd7613f0fff66c21389eedbbd4bd35": { + "balance": "956888725645000000000" + }, + "80e449a70e3c7707d6441ae8863a44aee2d7f3f2": { + "balance": "16260784762856000000000" + }, + "811a2c3d0ba4e1c36a848495585da824ec3a7620": { + "balance": "36000000000000000000" + }, + "812a3c55234d5849a854ad76891c34ee90c8a0e3": { + "balance": "703378980438000000000" + }, + "814b4b5eb67afb8d1a60e3d240fe804bb752f632": { + "balance": "17578964576000000000" + }, + "817025619f37838470b90d0a25af2c02de80dae6": { + "balance": "96000000000000000000" + }, + "817233a104d87cac34d9c90243aebd7f68e0a9ea": { + "balance": "510051038684000000000" + }, + "818be95c0c13c3018b4084ea177556705e84c1f5": { + "balance": "332239667000000000" + }, + "819618c19a4a490b821f8156c5633749ea782ca2": { + "balance": "10000000000000000000000" + }, + "81a80d26b70626e07e8747bc1569dd2855834f7c": { + "balance": "521696417321000000000" + }, + "81b2fb0db882bf2538cf8788bae1ad850cef3bab": { + "balance": "102457067052000000000" + }, + "81d4c3bf72837b21203b2a4f90bf42fda10acf48": { + "balance": "10000000000000000000000" + }, + "81df59e5d7b9a2db5463b53be83b4d7c7673d163": { + "balance": "887372337013000000000" + }, + "81ef38d074e0aa9ad618deaab01bcd135301fb67": { + "balance": "24072930558567000000000" + }, + "81f3a4c5291f13f8f97a067a6ed744a686331eaf": { + "balance": "56612148225000000000" + }, + "820610d0ddd3e9f3893f7cc13f32b1ad0d169f81": { + "balance": "50000000000000000000" + }, + "822d6388145e96cdeb2900420a0e0436e940b670": { + "balance": "20000000000000000000000" + }, + "82323b748fdee9f18e34aefc4ddebd4993ac6293": { + "balance": "112752706047881000000000" + }, + "82324995b36f4ff15be3559ccee14742d5b4c75a": { + "balance": "1184047304377000000000" + }, + "8235bfba0bf0fb664271ebe534616456a78852ce": { + "balance": "6804584686000000000" + }, + "824df7b17a61392f88f7e3067f8c261abb48806b": { + "balance": "144857897574000000000" + }, + "82555a7aebfc95a01a3773aa5370394cadef0302": { + "balance": "40069354268401000000000" + }, + "82831d451b8f92fbf6a763adb708010a3e66bb60": { + "balance": "8750983992240000000000" + }, + "8294176178418f46bb18440cc87a07cf40c1669d": { + "balance": "4439783816461000000000" + }, + "82a1c733c3c937ba0a1a49481e4d1f6226157d2a": { + "balance": "50000000000000000000000" + }, + "82ad0b5dc23bc763da0352f5983efceeaee6ea08": { + "balance": "171723633433000000000" + }, + "82b4a3d16655fd71f4020e6a562592a621ff6e1c": { + "balance": "190211621484000000000" + }, + "8357d5a016a00aa5e3ef05d3ce210826adf4c501": { + "balance": "10000000000000000" + }, + "836c41d7f9e72131eff839b7d510fd0ed412f939": { + "balance": "15575572364757000000000" + }, + "8377fff2b0eb03393543ddf5ffae90b3311af5d3": { + "balance": "2058810049054000000000" + }, + "838859e6fd751539a88d00581b0e19bc98c37e47": { + "balance": "338264241636000000000" + }, + "838da0414211392b644e73541e51e9f0fba26615": { + "balance": "20000000000000000000000" + }, + "83958896a43d23ef4ba01bdf6757c36105985096": { + "balance": "9000000000000000000" + }, + "83b88314b606df40d5e716df488980bc64125b46": { + "balance": "10985538717083000000000" + }, + "83bf53fa162e1d85751be0bc6f46e8ec881392e2": { + "balance": "1497107276676000000000" + }, + "83d7c52608b445e18fb1e28dc6198908d66bb6d8": { + "balance": "265446362740000000000" + }, + "83ee8ebaed62092d2116de6b4e90778454e8dfc4": { + "balance": "1000000000000000000000000" + }, + "8402fe573658250f50fbe111596ce35ea9ec01ca": { + "balance": "3479737676000000000" + }, + "8412b877e708a7d5db2a38d9b0f4f23d12231f63": { + "balance": "9225027744855000000000" + }, + "8418dcc09fe052febf2946ee22bcc8c53d548eb6": { + "balance": "3000000000000000" + }, + "84199f54ef96bda5e14f60aa1723e811f755d3bb": { + "balance": "129197612052433000000000" + }, + "841b1400f97ecd2ca008e7b4f5a95274bc3e99dc": { + "balance": "2095180906854000000000" + }, + "844177191a120d2dc4be9169ddbc3b5430e9e238": { + "balance": "3620793599287000000000" + }, + "84578fcffc73be7d65bfa81b0cdafd26885bafbc": { + "balance": "37592478429000000000" + }, + "8460acb05c6c476ca26495aec7224c2bf90996fc": { + "balance": "8999580000000000000" + }, + "84696cdb9f018d3e7bf453efdc174e1a586e9c25": { + "balance": "118007806297016000000000" + }, + "846a8a91d2890000d1e995fc1663cf5b7c22211c": { + "balance": "27266838638307000000000" + }, + "846b5ef52d5f7ccc17d9c7e5f49db807908c63f3": { + "balance": "375423381758000000000" + }, + "847409e5d6ed2c4e54ff97f2ed58217ac5fc3d68": { + "balance": "23972870617025000000000" + }, + "84bf432c967540caafb8bf49cdc9983e8953a18a": { + "balance": "453476687224000000000" + }, + "84eba1bb76f7a3f6d2b9052d068cc6c48d449d76": { + "balance": "17655334922000000000" + }, + "851245ef1637a07578241b3c35acf215908e1898": { + "balance": "1269389304110000000000" + }, + "853708e974fd4810655d9cd19fc8dbfd3d5e1e36": { + "balance": "18000534000000000000" + }, + "8547989af8c99a3432038a03d3fb30a054d90413": { + "balance": "10000000000000000000000" + }, + "854ba39bac4c7bf619804b6773fe43bc71f3255d": { + "balance": "15999580000000000000" + }, + "85636f3e113cbe1d1bbd1b3a23e9e98edbcb94f2": { + "balance": "1199038399611000000000" + }, + "857167896b859394babf897c4c6fa57b3a057117": { + "balance": "921057404898000000000" + }, + "85799226a1474371ca76f05597a1e3835c17e7d7": { + "balance": "562141544946000000000" + }, + "85a2221cbbb47e8b74fc2617d6087a98f47e2738": { + "balance": "10000000000000000000000" + }, + "85be0bd55fb9143ff17387914a82d0a2650224c4": { + "balance": "4038654147145000000000" + }, + "85c5ff0e4956ef0fb662a2cbf6a86325a53dac8a": { + "balance": "28690160424000000000" + }, + "85caff4ec0e1719ad963e97c1c02828683070370": { + "balance": "2022427900763000000000" + }, + "8630cc2780fee566f172ed0437264c45421ce675": { + "balance": "669721278148000000000" + }, + "8633d245c5f1b63403e3d7828dc197ce1cfafc0f": { + "balance": "10000000000000000000000" + }, + "867ccceae3192a27751d870ae13b1d3d2c3584dc": { + "balance": "1491436265909000000000" + }, + "868bed241f77983ff4a7a8d0bf121299b6b2248b": { + "balance": "5600000000000000000" + }, + "868ddd283a76a26c8bbb9761df3ca647bea267e2": { + "balance": "9000000000000000000" + }, + "8696e546f96f6e51f405905e095902db8bb90118": { + "balance": "533558981421000000000" + }, + "86ac0eae4e4c20cb7019325f4dbebad053f92213": { + "balance": "697960117764000000000" + }, + "86bef47f9d2cd7526495454eb4d1737510696a5f": { + "balance": "2938307902381000000000" + }, + "86ddd4e3f444b395be8b2b2b75c35c78877fefb7": { + "balance": "15615434748526000000000" + }, + "86f115ed19a32aba4f98270b8ad45820abbc4653": { + "balance": "151868798605000000000" + }, + "870f19e7ee358de61ad0fd3c7710441156d68f66": { + "balance": "674715936435000000000" + }, + "87141a2d3857fb8a328ef8e7b503ed965294c85d": { + "balance": "1609607183158000000000" + }, + "87257783d866af25a7a71b46ea6c2bd1e9ab9596": { + "balance": "64000000000000000000" + }, + "87298979a9a0dbc272b0e15b7e5f2e42639c9912": { + "balance": "722087160930000000000" + }, + "8757b784015f88d072229176cabefa358a0e95a4": { + "balance": "204003337866000000000" + }, + "8760e60a56c5b8b61276634a571400023f08e3ac": { + "balance": "1000000000000000000" + }, + "877e54ea7e8ab03bb8e2b842dadab16bf4ae0a4c": { + "balance": "341020957932000000000" + }, + "87919285fc5d98169bbd073cebb1b3a564264dd8": { + "balance": "579080463078000000000" + }, + "87c39cfaa9c82d84119f306e6a233a3abfbb0ad1": { + "balance": "121753433796000000000" + }, + "87d479659a472af7c8ea78a3c658605f8c40bec6": { + "balance": "20000000000000000000000" + }, + "87d933ad6fba603950da9d245b9387880e6d9def": { + "balance": "1087642723520000000000" + }, + "87ec448309024bb1b756116b81652ea518cf353d": { + "balance": "344562808694000000000" + }, + "87fbbe010837f8907cc01a5bbd967f402a216488": { + "balance": "185411503628000000000" + }, + "8805a3c529bef4d19a6491f3b7d7b1b7232bb93d": { + "balance": "264150205918000000000" + }, + "880ec9548864fcd51f711ab731d847260ed0e3d5": { + "balance": "723225945994000000000" + }, + "8818d160b56b18e196871a6c7ccf02112dc13342": { + "balance": "2857439182291000000000" + }, + "8836e25baa08c19a9b0155c57072582b49f7dbef": { + "balance": "5468425690148000000000" + }, + "885b6303d06142accf2ddddbbdd4a9379d1cd124": { + "balance": "11853214736000000000" + }, + "88656958d9cd758d71546ba52c4ea646b658c84c": { + "balance": "10000000000000000000000" + }, + "88740acdf9ab5711d015391fe8cf4a7c70a0bc86": { + "balance": "510027156671000000000" + }, + "8874966976d776c3154261afa802692afedf3d3d": { + "balance": "305634301700000000000" + }, + "88aea53c727d7a5dd8a416e49faba1c4f741f01a": { + "balance": "15358334295959000000000" + }, + "88b67d05997ae3852259ca638a00ce9b9e7e4a61": { + "balance": "278125551806452000000000" + }, + "88d730e074a102048008de81d3adcba831335736": { + "balance": "5984576042159000000000" + }, + "88da27b1f0a604a87fdedd9ea51087a331179cb4": { + "balance": "10000000000000000000000" + }, + "88efaa91dab9671f5c903e69aa6ca4d9a04b5ddb": { + "balance": "1996126782729000000000" + }, + "89a9d702f64f14fae4d1a69717744dd700208d9a": { + "balance": "251686323241000000000" + }, + "89ac81571265bebbf9d3c09e9459fd1ba7fb1297": { + "balance": "162368080974000000000" + }, + "89c75c4f0ce41d283587beba1a3e3efab05ca6ad": { + "balance": "16000000000000000000" + }, + "89d44cb81cc5a1bdf4d573c4954ee641f3cb91d1": { + "balance": "97965629614355000000000" + }, + "89e2fef4f7b7c255b36afa81cf4033b22de3db25": { + "balance": "7278615226888000000000" + }, + "89fe5d3cb5283c7b87daf6103bb568f92a230631": { + "balance": "64000000000000000000" + }, + "8a07242231f4a654aeea65b857d1519385a18065": { + "balance": "20000000000000000000000" + }, + "8a5a415f0fe2a8329e14628493d11ca20d4e482a": { + "balance": "157274758238000000000" + }, + "8a6ce9f270fe3ec33a013be9e5b1ef823c0dab53": { + "balance": "20672772672000000000" + }, + "8a6fe4fa2f86f879ec9b2bf643beeb0876da46d4": { + "balance": "1041983771868000000000" + }, + "8a765ff2b429dcdf59b65a34c4bb41798dfb5886": { + "balance": "355487172996000000000" + }, + "8a9b9b65a3d443a6e4dcf696a64983f3b625774f": { + "balance": "3185351572575000000000" + }, + "8ab1f5443cf9149773b9ddb69de3e6ea047ae38f": { + "balance": "161619949415000000000" + }, + "8abeacee0078e07fb417277e8bf15dcc2cdb9fa7": { + "balance": "144000000000000000000" + }, + "8ac0d9e0e77aa4ada4080604f2118b3a5a0f8102": { + "balance": "100000000000000000" + }, + "8adae0dc99300f60d31bfa619ec83d45b48ea22b": { + "balance": "697262590215000000000" + }, + "8aef59e59a27a8662043f1a4abcaf945a5e3fafc": { + "balance": "26780431538000000000" + }, + "8b3386f32e2d77526c223ee8bb95b7dd111ced92": { + "balance": "2179932854210000000000" + }, + "8b34d5e457ef6451bb7f5ecc93c80678a30e3194": { + "balance": "31492358338840000000000" + }, + "8b47e07f192c33bd7d298bae717dfcd68a8097ae": { + "balance": "1000000000000000000000000" + }, + "8b55bff4b281f6a24ab428d66b91f9bab06f7b96": { + "balance": "1596248680941000000000" + }, + "8b576b1e2391f22193bb4f91bec5f2a8aec02af7": { + "balance": "29660301836269000000000" + }, + "8b9097b762c7bc38a487974f3551fea697087553": { + "balance": "260887123991000000000" + }, + "8b92c50e1c39466f900a578edb20a49356c4fe24": { + "balance": "35654824979000000000" + }, + "8ba3933337108841a997accf0b5735e005373f53": { + "balance": "574965182000000000" + }, + "8ba3eeb2d1b27e021ed6bf5827280807f32c7897": { + "balance": "64000000000000000000" + }, + "8bb23a5b8c48ec5bde84f39b463559b7c048c853": { + "balance": "16186405874000000000" + }, + "8be0b6ab14e15b46905335d07df03726fb1df0e8": { + "balance": "500000000000000000000000" + }, + "8bfc53af1ae6931f47ad7f7ed2f807f70fddb24e": { + "balance": "20000000000000000000" + }, + "8c0599df87df142d3aea37d50c975c1813ecb642": { + "balance": "871085782287000000000" + }, + "8c2deeeaf095be075a2646ed7b8764d3665acf14": { + "balance": "10000000000000000000000" + }, + "8c3e7381b0598356ff81e860faf25390ae7de9d9": { + "balance": "36000000000000000000" + }, + "8c5671a6f4610ddbd05a5139659c7190f54117b5": { + "balance": "50000000000000000000000" + }, + "8c60582c4e4e60da665b4a5a2d18f514ded6c49d": { + "balance": "16806447782991000000000" + }, + "8c8464ea6b17687eec36ef04966d59c7c91fa092": { + "balance": "1872124465602000000000" + }, + "8c85c5a318cc0227576adba3e91dce6adc73f6a2": { + "balance": "52479305517000000000" + }, + "8c8f3796a2942a2298d14ff1a9e3264e9f63f2bd": { + "balance": "10000000000000000000000" + }, + "8cec1886f2cc71b09ca32a1cf77a280ae3a6a9fe": { + "balance": "500000000000000000000000" + }, + "8d0b26d57eb52a62814d7876d64c8274f4371464": { + "balance": "20794037603000000000" + }, + "8d40b92e41f3cfec06e767d64b4dafc5612133b6": { + "balance": "25000000000000000000" + }, + "8d41ea1cfb70d0ef1f6572fd72a6b417739ac7dc": { + "balance": "738777348304000000000" + }, + "8d4eb54646f9d14882fc8ebb0ef15f6056d1afbb": { + "balance": "1003867239086000000000" + }, + "8d51ab29ccd190bfe12bcd94a651e9f49a003253": { + "balance": "442251355663000000000" + }, + "8d6c0c8e4ca47626115433b39feb939014b8738f": { + "balance": "119828137027000000000" + }, + "8d7acd92d664a485625bb9884e7cac9cc6077f41": { + "balance": "1381910232084000000000" + }, + "8d7ee7a9c1c263ba8061f54dcf62d9f8420e2008": { + "balance": "20000000000000000000000" + }, + "8d941c5d0c6e2b8e2934c9f80f8a63e2fb5868ef": { + "balance": "116443644149000000000" + }, + "8da0dc43ed3ccefb18f21aa13f3fa42c13e540a6": { + "balance": "516000000000000000000" + }, + "8dab4500316475e8fc3bb6494be09f549dedf026": { + "balance": "2736245677000000000" + }, + "8db39a95f4e63bde0bd8c02e386122ce2c57a30f": { + "balance": "12577347153000000000" + }, + "8dc718b49fb68584d9472490743f9be1b0ad683b": { + "balance": "50000000000000000000000" + }, + "8dd05e26224aa8a6deb0904b6d3bbb34d268e901": { + "balance": "613146658282863000000000" + }, + "8dda0e7ddde515480ef08cf90a1eb4e78f50a2c4": { + "balance": "19265526663314000000000" + }, + "8dedad1511c11798c338334dde7be967de96e9b2": { + "balance": "50000000000000000000000" + }, + "8df63c04f18a854d7bb397bca3e2ba19202e9da1": { + "balance": "1479940547081000000000" + }, + "8dfd7edb7d28e8b3df1faab70a8ef9e3b923d998": { + "balance": "10000000000000000000000" + }, + "8e2c3af057e931b5f82e83873b336a7f68e7eb03": { + "balance": "27138009123000000000" + }, + "8e2f4eaddd60468bdc09d47f65839b96f50596ef": { + "balance": "970529157231000000000" + }, + "8e750010c88ba99d75b0b5943c716d6fc0d01802": { + "balance": "42271114987000000000" + }, + "8e889d47f3307a18490e53f2108dc31b14d6300e": { + "balance": "115722965933000000000" + }, + "8e9e1953c82217ba56365e7a9c54b1ded73914bd": { + "balance": "6248835752208000000000" + }, + "8ec980d3066cb6afa793577cf88ccb46ce8d13f2": { + "balance": "100000000000000000000000" + }, + "8ef324c861de7e042c445776bcc8ac026533bc15": { + "balance": "1869634994148000000000" + }, + "8efd14464465e50af087a80a5fbe652445de373d": { + "balance": "1157403424927000000000" + }, + "8f1b57304406fd8b2eb5dabcbd322e326dd873f5": { + "balance": "194188733254000000000" + }, + "8f36ffd921e12083e374335d3cc43fcfeeadfa46": { + "balance": "100000000000000000000000" + }, + "8f813b88e6e125eab71a63455f326322ef505501": { + "balance": "19087691927734000000000" + }, + "8f83892d4d2892cd57828fde2318610a54b14498": { + "balance": "22833507983000000000" + }, + "8f89c1bcba85757cf1718d5b9eb007e27e5195ab": { + "balance": "2241600478705000000000" + }, + "8f927ab63df4c2ce46f1ea35bc875a0c006d2d4f": { + "balance": "327487123409000000000" + }, + "8fc3c231df0f93a84bbe348aff12ab576284d70f": { + "balance": "25000000000000000000" + }, + "8ffa089b07ed1388a5d1a428daf54d9591e734e6": { + "balance": "1347580402248000000000" + }, + "90040e00f585f8be44c82597037fde452472e741": { + "balance": "2746884591879000000000" + }, + "9034eb46aad2a76bdb812c981565d4701dc10718": { + "balance": "10000000000000000000" + }, + "904ca1ac2381702bd18472b175262a8928cde5f1": { + "balance": "304421909590000000000" + }, + "90502c1123692c3b86e99b328d07fae473d4a283": { + "balance": "227491252462000000000" + }, + "9052ca7e9623c1bbe3568668673d6d252b56a764": { + "balance": "35268091378000000000" + }, + "9093d12d8410193293e1fda0cca98a43b85b91a8": { + "balance": "6829489147119000000000" + }, + "909ba8cdc707c12ba577dcd8ed1df1c02a7ce2ef": { + "balance": "60524108169000000000" + }, + "90a2cc3aa73495531691e027a8c02783cea7941d": { + "balance": "65263780625000000000" + }, + "90d7c82615f151953a8d71a68096cee4d428619c": { + "balance": "298774379499000000000" + }, + "90e02deb31d98b9c85fcaa7876eb5ec51d721dd4": { + "balance": "2000000000000000000" + }, + "90e538746bbfc6181514338a608181a3c4286d1d": { + "balance": "6069511690189000000000" + }, + "9106dddc1b693e7dcb85f1dc13563d6c7c9d8a6e": { + "balance": "1977000091291000000000" + }, + "910d1e0d3f71054835ee0d4cd87054dd7add3e38": { + "balance": "40104690362000000000" + }, + "912e2349b791fe702692a6c1ccbf6f0f06b826db": { + "balance": "6305336897000000000" + }, + "9144cc61c01eb819e654b46730620c230da9e936": { + "balance": "144000000000000000000" + }, + "91478d4c15d9ba02816456030915be08fa3aa208": { + "balance": "200078339107000000000" + }, + "9160c466b5f9020b0ab1c0ff497bf0345598ec90": { + "balance": "17705350930000000000" + }, + "919025625787101c572d8340ead1444a96593424": { + "balance": "2418027749789000000000" + }, + "91926323868c65f91b6d74c85c07279610651ede": { + "balance": "538073886450000000000" + }, + "91950cd6e2dd99e024854b65c09c5a7476777a21": { + "balance": "11629505934425000000000" + }, + "91ae8d74c26d3dcc291db208fc0783347fcc197f": { + "balance": "7604593786920000000000" + }, + "91b9ac26869abc9eb3090f1d8140eabe97f41001": { + "balance": "25000000000000000000" + }, + "91c349651afb604f9b00a08e097e02c0964e148a": { + "balance": "117290771022000000000" + }, + "91ddc95cadeb6dcf6ebbdb3300a29699ac8ded39": { + "balance": "20000000000000000000000" + }, + "91ebbd36714cc069f8ce46f3e0eda5504fdd3aa2": { + "balance": "203944728497000000000" + }, + "91f2765125b84923bd506a719d72b0c1de030e32": { + "balance": "452269960816000000000" + }, + "91f2e54a9d61ef52a33d150da50d5a8f2ebcd6bf": { + "balance": "242321058694000000000" + }, + "920dc90d11e087a0d8912c1d43db102e9ba4f43e": { + "balance": "20000000000000000000000" + }, + "922ff522cf7f3ce0bab9312132df51704caa755b": { + "balance": "1414824682473000000000" + }, + "9251449b0f757ef62f63c2774eb63ba15bf3712b": { + "balance": "102688517037000000000" + }, + "926255c17386720fdc1701747a2f024475063d4a": { + "balance": "25000000000000000000" + }, + "92808a38ffc5a339b1ab6b0b472f9975718d4a07": { + "balance": "500000000000000000000000" + }, + "9286c4497e820845341e3b9127813c1b7c884830": { + "balance": "101241387488275000000000" + }, + "9298e1df6730e91e9892d19f7ce18a3db9b5d2a1": { + "balance": "169000000000000000000" + }, + "92d98aed335c29402a43ba96c610251bed97308b": { + "balance": "3032350763000000000" + }, + "9319153f24814a81d920c60cbee9b5f2f275fac0": { + "balance": "56619610984000000000" + }, + "9347532d6396bc0b86bcd34eb80facd4c3690684": { + "balance": "258912194626000000000" + }, + "93487691d71e6248d88f06b1fbaee58b6fe34615": { + "balance": "1593901704394000000000" + }, + "9375154a7f19783b26ae1c9e48f114e1cfd1307a": { + "balance": "9000000000000000000" + }, + "9377947e0db688bb09c9ca3838ca2197fb262a1e": { + "balance": "323993393587000000000" + }, + "939ca9030b28d356dc1b071169f98b0728a9aef3": { + "balance": "218900305967000000000" + }, + "93b71636b8332515c2af031aac7a8805de716a62": { + "balance": "1640174743698000000000" + }, + "93bca153afd427b0c3c1de4a5584610e4a6595b7": { + "balance": "654782426410000000000" + }, + "93cb3b73fee80cedacf5197f8b4ac8f18f0d0184": { + "balance": "100000000000000000000" + }, + "940fcd215bab373d1b736e354f2def501244885a": { + "balance": "13133641534585000000000" + }, + "943f4bc76f20580b6546b6aff2800448f82cfdc0": { + "balance": "1927982550280000000000" + }, + "946ddb5c46fb13010b9c7ec56e4055b4f3e24b4a": { + "balance": "1410000000000000000" + }, + "947961dc367226f78d722361d5821cced52db01b": { + "balance": "115598797369000000000" + }, + "948eab3ffe44d5f1f381de2c8cadcb311c25df2a": { + "balance": "870664355820000000000" + }, + "94bf674593378243fb6b811f331f77561efb4106": { + "balance": "226539311455000000000" + }, + "94ce082887dd6324d7dcfa6cae17b653be021b25": { + "balance": "420000000000000000000" + }, + "94e2aaa4b5e2b36a12f866c96e3382a1150a97b4": { + "balance": "7344059136611000000000" + }, + "94ea5b1cdceb3f1a9d5ecacb6ac8dd2db9a461d7": { + "balance": "1951787237292000000000" + }, + "95218633176c0fe2f32fb55ad3df9f387e63aed1": { + "balance": "99999999580000000000000" + }, + "9543cb22853a46cce3aadc60e46cbddbd3fcf593": { + "balance": "2806074281914000000000" + }, + "958842c5389656d156aab05ac1731a20656716ff": { + "balance": "391064461038000000000" + }, + "958fd9bbc96531a00adc5c484d06dc61ccd717b6": { + "balance": "8021794447667000000000" + }, + "9593ce72919cb0648ddacc58af233d942963e2e6": { + "balance": "32322940730755000000000" + }, + "95a8e371af9128c97c9d4d7c4d58f5f75f2d07d4": { + "balance": "49000000000000000000" + }, + "95b9a9ad563a4c1ff7b6ebcf5fabcf5dbdb4a6a3": { + "balance": "10000000000000000000000" + }, + "95ef5fac6aa3ab1b4a87246fa800cfceff43dec7": { + "balance": "119666779022000000000" + }, + "961a3aa8015cd520de43bd47d81f5194ee4dfdc2": { + "balance": "248589901007000000000" + }, + "962bad39df25d64ee1c6b4ae9c14a18d316bfc06": { + "balance": "2404608291000000000" + }, + "96392119198c4b644c64284c9a75f61210a6292d": { + "balance": "1000000000000000000" + }, + "963c82319380587eeba0bd7b07eb63ea7042984b": { + "balance": "1480123630618000000000" + }, + "963e05fb6245ec11d67ed80e9feba6e2c0a8b4ae": { + "balance": "276053287417000000000" + }, + "964452b86b0d1d4b34aa881509a99e7b631d4a85": { + "balance": "64000000000000000000" + }, + "9644a2af2ff70eb43584a4351bfbe027c42ba3f9": { + "balance": "500000000000000000000000" + }, + "96572a017489450f2dfc0e31928576acd3bc6808": { + "balance": "1140183097730000000000" + }, + "9686bfcc0dc3de20604eb77787d0dba818cc5016": { + "balance": "10593448987804000000000" + }, + "96879780764b4433589d26573fc221f5218f1877": { + "balance": "154136576560000000000" + }, + "96ac1e62c95e33dbbd4f6ed389007e16c00b205e": { + "balance": "4130528000000000" + }, + "96ba703df3a8a6dc3c5d6be02cbf6a4afa2d1650": { + "balance": "2885298549532000000000" + }, + "96d516ded110f1d7e0290716689fd1b7964d9d42": { + "balance": "40665675241000000000" + }, + "96d75950c9354cec6084ba11058dd52d00fdb1f2": { + "balance": "903158106646000000000" + }, + "96f362c59c72fa1d39ae3ec37a7b715d2dd23679": { + "balance": "110000000000000000" + }, + "97115f7544cb05009b3fad2f0c2817f3ee77dd4d": { + "balance": "10000000000000000000000" + }, + "971cbaeafd4b0fdbad24fab946051b8949efaebf": { + "balance": "8462381628000000000" + }, + "971e195e980b4fd4db8d279c80968ca1bd390edd": { + "balance": "10000000000000000000" + }, + "9722648970c455929d621546fddbff27c49acd3c": { + "balance": "70337427969000000000" + }, + "9772027a4ea991eb9eb5ae6b8f34d750a917538b": { + "balance": "148918416138000000000" + }, + "97797e3919aa35567b9eb1224be87f96c6c2e1b4": { + "balance": "973342196399000000000" + }, + "9780a9c86160e27f627179535c3d3f23b6b29917": { + "balance": "10000000000000000000000" + }, + "97a85f4e3f53aa066825de15f1d0e25d4189b037": { + "balance": "2435764858719000000000" + }, + "97f46465e99910539bd3593c16a572e159bac87d": { + "balance": "25000000000000000000" + }, + "9882505fcb54ca2d2f4f79b03f0a5ead61936979": { + "balance": "249999580000000000000" + }, + "9898e969629502a891b758efecc9fdc5ada7d32c": { + "balance": "20000000000000000000000" + }, + "98a52d325e28ca9b4474846c7e4c07a223440fab": { + "balance": "418260286015000000000" + }, + "98a9b2f7d1ba7838e3242b5e4cbf1f2897aa4bc5": { + "balance": "500000000000000000000000" + }, + "98b8308c37a2f6cc1bb382dba2ba95a3c5ca2834": { + "balance": "10000000000000000000000" + }, + "98bf0170a61f98ab0710a68810bf152b7f6c56fd": { + "balance": "2279761566089000000000" + }, + "98c8a323a0022bd147a466fa1ac867977e12eb92": { + "balance": "10000000000000000000000" + }, + "98cd102caf0866ba0a74604b01f54049503905d6": { + "balance": "34739921273310000000000" + }, + "98d7e89c2765aaac224d4015aa277fef208953c3": { + "balance": "1291811952000000000" + }, + "98fe96bfd1e10fb60b343e512b15e955aefc0778": { + "balance": "464922897623000000000" + }, + "99064a57d693e45559a1a910c9ef7d46cce0e703": { + "balance": "8969733492948000000000" + }, + "991ea5429b91a8bfc4352a1d93304dc463be5b90": { + "balance": "149367286734000000000" + }, + "9921d405fada890fee6bf76acc39141fd34e5d2b": { + "balance": "5021308706457000000000" + }, + "9938d357d3d5dcc6f6fc7fb47a98405c0ab6830e": { + "balance": "516293591974000000000" + }, + "994f4e6521a3a5752359308b9f6b2722922c60b1": { + "balance": "23993133615000000000" + }, + "995a6a1c38f037b3a9f0a2e915b8fc0efdea082a": { + "balance": "1403498530728000000000" + }, + "99709e57748a7da6556b1670ba4f15c45aef4689": { + "balance": "36000000000000000000" + }, + "99789f65655c6f917d575169f4ba8192440e659a": { + "balance": "393071814319000000000" + }, + "998f66cbde2693603fa109ad7aaa8bc42a8765a9": { + "balance": "49000000000000000000" + }, + "99afd42a58af31daa54ad9ba35b06954330107ba": { + "balance": "25000000000000000000" + }, + "99b6a9ff2b2ac9ac0361af007aba107695ff5fad": { + "balance": "12860157225353000000000" + }, + "99d16a5955d43723ed8e2b1a642f8f1195f38b64": { + "balance": "62907829047000000000" + }, + "99df609926ca536ed3be80e35dbaecc42ae67f2f": { + "balance": "316809833612000000000" + }, + "99f3faf97a36fabea7306979b30b08fa70110e29": { + "balance": "173292373556000000000" + }, + "9a26110067b473e3bdc0fc32951b39596c967a56": { + "balance": "78192198764000000000" + }, + "9a3a8eff6fb82377da6c17ba658dca87ca0dfe26": { + "balance": "50000000000000000000000" + }, + "9a3b06257088ef8c17410a8f2d63392edb9b55ce": { + "balance": "239567000000000" + }, + "9a426842301802866cca0ef89794d928d3e8f843": { + "balance": "776173297821000000000" + }, + "9a5f2c0a6d41131d9aacdb4f8c274958cbdd377e": { + "balance": "441954000000000000000" + }, + "9a6893023ac6f34b493d33e4dc63ef697169a58d": { + "balance": "439689418527000000000" + }, + "9a86eefd848acafcbd9960003e90b22162b15ef9": { + "balance": "294190908093575000000000" + }, + "9aa711f3e4eb67d2f6405b5ee6290a014d203a72": { + "balance": "9101556549634000000000" + }, + "9abf9ccf6abb8d55ede458d2d12a279d0a823944": { + "balance": "17609693072000000000" + }, + "9ac1909b983c754f0800559174025c0f0baa9d31": { + "balance": "80921948093000000000" + }, + "9ad62cd855d629e1ddab632874a6dc2b812f2348": { + "balance": "2068118534000000000" + }, + "9afc2c33aa2c9a42600abb18aedaefa433326122": { + "balance": "2485353229354000000000" + }, + "9b18d230b221a99c74877d4a1dbdee2214c7d60c": { + "balance": "4024172228743000000000" + }, + "9b18e27788c9d59053072032a480569e142595a0": { + "balance": "110789164888000000000" + }, + "9b4535b23af0b8e5f488a6f318ff6badf71d16c1": { + "balance": "84756740661000000000" + }, + "9b5e7cf43aece7b38ea2af6d08bebe2d3b926840": { + "balance": "262771268227000000000" + }, + "9b77dac92fedd0ad3eb4326d4fafe0f4315a8844": { + "balance": "3616321626000000000" + }, + "9b8f6f223641f9b1bab319dd1e88c49fd411a765": { + "balance": "2054417462086000000000" + }, + "9b9f94861d80365464912e5c7213403405a6cd8d": { + "balance": "2367093088000000000" + }, + "9ba24397002929e6239848596b67b18a8dea1eef": { + "balance": "5000000000000000000" + }, + "9ba99736c5ac468d6b644e39b8d515c39151f51d": { + "balance": "311900650761999999999" + }, + "9bf2d4ff366e1bb2313ae9a93ccca75d6bc0d232": { + "balance": "764870206925000000000" + }, + "9bfce7dbfc9ae62d450e862261d1e21e68bac92c": { + "balance": "1000000000000000000000" + }, + "9c003e74b62f192a864045d678639580c672fc22": { + "balance": "50000000000000000000000" + }, + "9c128bd2c0c96b896db6c0f398e908c98302809e": { + "balance": "3251059363800000000000" + }, + "9c255daa89ee16f32fc0ab1ed8e22db39342e6ca": { + "balance": "37695843594589000000000" + }, + "9c32e714bcb601a56a8a4e6b3f7bcd9e1c7a1b54": { + "balance": "50000000000000000000" + }, + "9c503e087b04a540ed87056c9371d591afa72df2": { + "balance": "64229084991000000000" + }, + "9c54297dd3527cbbb8ca8c305291b89bfb7ab39d": { + "balance": "61682466962052000000000" + }, + "9c55bb1db3b2bb06e605a66ced9ea2ac95718205": { + "balance": "16512365324000000000" + }, + "9c59dbc48b9cf53fe668784e89d30493da9995b3": { + "balance": "50000000000000000000000" + }, + "9c61b58aa760265f7fd1b9e749df70122ea81175": { + "balance": "50590272373000000000" + }, + "9c6c7eaf4bec0566a7bf8acd30e10311a963267c": { + "balance": "999999999580000000000000" + }, + "9c91dd4006f9d01d8caf5f5fb4f2c4f35ee63ffc": { + "balance": "175730980227000000000" + }, + "9c99275f5dee14b426302b1a47a8488c16432f2b": { + "balance": "2000000000000000000" + }, + "9ccf7b23528d062da63f6af3e26531b775c83c52": { + "balance": "928373869120000000000" + }, + "9cd21c30ccbc1087c9b351395fdea17ad669cc2e": { + "balance": "529762292313000000000" + }, + "9cfee47d6f24880af7b281cc00e1fc58e0a4a718": { + "balance": "198888257958000000000" + }, + "9d08251f7d4cfd66d15c17e1ea6bae5c795e290b": { + "balance": "813841349140000000000" + }, + "9d5411490ce89359bfbacf9f9957ebfbbc18debb": { + "balance": "22263187467000000000" + }, + "9d61e1dfaa7d0e0c5f5d733a24a1883c4e201f3d": { + "balance": "144000000000000000000" + }, + "9d754d94a15ab6d738e511fe4c775ee6d20a53ee": { + "balance": "20000000000000000000000" + }, + "9daccedf104fdcc3c39f2961ddfa1c64eb632476": { + "balance": "1237093270947000000000" + }, + "9dad4968c0e44aa729fc5732f3ee903c6799637b": { + "balance": "838788687517000000000" + }, + "9db73ca677bacbb622f44fe90b53ee1d9f0c2009": { + "balance": "472858335000000000" + }, + "9dbcb5026e0f444a33197da240856f108db14ff0": { + "balance": "10000000000000000000000" + }, + "9dc46cf729187ceed8001c4ab14fa4fc21c35f32": { + "balance": "3320792646995000000000" + }, + "9dd895c1bdac2ed9864134aaa8c543473ee5f19b": { + "balance": "1430620966869000000000" + }, + "9de2687242cbf9fb94fee0ad873acc7494ebd2bf": { + "balance": "20000000000000000000000" + }, + "9deec036282717aac93ad5cc1b6d4a5354e85c2e": { + "balance": "2048627955362000000000" + }, + "9df8dc66395aeae9b4c831b4d63bdf48db08811a": { + "balance": "215874670561486000000000" + }, + "9e1fe68a70abd8ab517878b03961da8564b43eb5": { + "balance": "67908329894526000000000" + }, + "9e33293006982abc668e199aab20260b9b754463": { + "balance": "49000000000000000000" + }, + "9e65616282a0baf89469a58915fd8fdbed210e3f": { + "balance": "829209872657000000000" + }, + "9e7b7b522834dd7e83ff2bb6b6e4cd2972330899": { + "balance": "500000000000000000000000" + }, + "9ed134b3a8feccb4056b2e511cea9a8ec58a3e77": { + "balance": "18787546978390000000000" + }, + "9edcf477687a9dee79341ed5d89d576c9a854c2d": { + "balance": "500449025554000000000" + }, + "9eeb06d4b532118afa013a01c9e89216fe0475ae": { + "balance": "1823939486758000000000" + }, + "9ef20a338e85044922f08f3648355e834874d551": { + "balance": "50000000000000000000000" + }, + "9f0855f9cc429fd3590c6ad05bb66a9e038efdca": { + "balance": "8017999878252000000000" + }, + "9f3befcc1884d16b65ae429228d26fffc146c8dc": { + "balance": "1016482445089000000000" + }, + "9f4571748463eee19e59ff9bd734a62a66613850": { + "balance": "20000000000000000000000" + }, + "9f51de282745f77b8e531e1de0b7c14e3369ba54": { + "balance": "1010657089383000000000" + }, + "9f6527175a2b581cc79f2a68c35202e0a7f2af20": { + "balance": "216495522463000000000" + }, + "9f70204d1194f539c042a8b0f9a88b0a03bbcd8b": { + "balance": "10000000000000000000000" + }, + "9f70e44704049633110ecd444f9540e241b50783": { + "balance": "9139000000000000" + }, + "9f73fea741e8506ba7acb477745dab1cfab8366e": { + "balance": "4461472359634000000000" + }, + "9f88d33d26c90e74c39c9676b8b580d21bbad124": { + "balance": "54437240781000000000" + }, + "9fa47455be14ad2eecce495281ed0eea926ec6a6": { + "balance": "10000000000000000000000" + }, + "9fbb15b595d154754a2ae77c77283db9d4e9f27b": { + "balance": "6195722646556000000000" + }, + "9fc480ab1823a59fd6130c3948980f95ac99f1d2": { + "balance": "24101151540000000000" + }, + "9fe5f054165fbf1943b1b02c01063f04e0c3890b": { + "balance": "1000000000000000000" + }, + "9fe7d3d5976e7b8b5ad6baa15ceae96c43c60fea": { + "balance": "55000000000000000000000000" + }, + "9ff116ea0e219814970cf0030932f5ce2cd9a56f": { + "balance": "36000000000000000000" + }, + "a01f6c36193839bc3a31e6d0792324771040fc05": { + "balance": "48298750000000000000" + }, + "a0264706d668522b737bbdbe949ce3e5a60fe314": { + "balance": "1423066922869000000000" + }, + "a02b13bb3b13027045ffb9b44bc7380a942e8ebb": { + "balance": "86845430807181000000000" + }, + "a03d246a931c3d422e5d2bf90f64975923a93643": { + "balance": "5834171660287000000000" + }, + "a046caaee59425ea1040867c62a6fcda11652a23": { + "balance": "83087966538000000000" + }, + "a04b57b2dd8b2082c53517d956f5909d25e14b69": { + "balance": "4518538234851000000000" + }, + "a074ef9e0ffe15619103e3de490f5813be53dcbb": { + "balance": "4568113810000000000" + }, + "a07bae42b44c085067de16e7d9846db529059acf": { + "balance": "4000000000000000000" + }, + "a08530e5fb7e569102b2c226aa5e53dc74483e4e": { + "balance": "2325665286793000000000" + }, + "a095a2c666f4f3203a2714fb04867c13c2add4be": { + "balance": "14768043990000000000" + }, + "a0a967418a3fcb3ee3827a08efa851347c528a60": { + "balance": "20000000000000000000000" + }, + "a0bb293071e07418ecb2fefc073136569ebd1736": { + "balance": "25871128320000000000" + }, + "a0c6c220a53b7dc790f7a5b462a106245c761f70": { + "balance": "1000000000000000000000000" + }, + "a0f06c86c49b248f4835bff405b620d12ec80d07": { + "balance": "484572382390000000000" + }, + "a10bc9f4d05678b26c4ffd2d92ab358163020b61": { + "balance": "10000000000000000000000" + }, + "a10c1197f7bc96639d01a652df73e49c669165dc": { + "balance": "1205859101575000000000" + }, + "a1221b2001f85f71e0655551e300ce115284b8dd": { + "balance": "1376698025177000000000" + }, + "a13fce836d65124fe5bcfa2d817ab2a043acbcf8": { + "balance": "55000000000000000000000000" + }, + "a15f1f609f7464906e0eb9d5e1d26468b90d9198": { + "balance": "16000000000000000000" + }, + "a1617dcf3acda60737e5ca9e4d0ecd82a98ef667": { + "balance": "500000000000000000000000" + }, + "a165c5f151d0daab905ba4a6d1fe5d5114fd7686": { + "balance": "41039049526000000000" + }, + "a17d5bed36c1059561e184a8a90a38ce955b92e4": { + "balance": "10000000000000000000000" + }, + "a18efb4e0950e7ac95970cd4591dacc286241246": { + "balance": "12403188476000000000" + }, + "a191fa6be64f2f6d2b4a7fb5a586416a605552c6": { + "balance": "60340281461000000000" + }, + "a194c15518cefbe94edbef3a2421586b51f7e1f6": { + "balance": "4153525550636000000000" + }, + "a1d0e41aacf83fc62fbecf35f8e873f8d734ecaf": { + "balance": "9000000000000000000" + }, + "a1ddd1f615ed483ef895e341f3266b6891f9b59c": { + "balance": "180411786335000000000" + }, + "a1f4d1e03114707a56ef9069bc20c6094e810d34": { + "balance": "51949145435222000000000" + }, + "a1fe101a65616cd03e3af03092be63434b7bf203": { + "balance": "1005401878265000000000" + }, + "a25a8225ce67c54048737601eac5e0d063c2fa17": { + "balance": "272038848571000000000" + }, + "a2714999233bcaff7294fa3e3b64c63ad45a928b": { + "balance": "14560781294000000000" + }, + "a28db3f7fb1771a3d77dfb19b54f88fd55b15c8c": { + "balance": "8000940572576000000000" + }, + "a290101bfe5fbc73146c4ec3ab5266c043eb701c": { + "balance": "1397563244603000000000" + }, + "a2924cfbcd37d0b321d6abbe57c645f9ce32340e": { + "balance": "200000000000000000" + }, + "a2a26c34f3d950c795fc965f6b1df3990e111403": { + "balance": "34525064429023000000000" + }, + "a2a2855851711bfc051c1f298821ae89e4c872c5": { + "balance": "491025000000000" + }, + "a2b956dd6f1934a4a44a026a18ac345ddabe42d5": { + "balance": "20096625821563000000000" + }, + "a2b9a118a79be81711d95485aa12e3efe78ca256": { + "balance": "10451051632647000000000" + }, + "a2bcf08ddd1778b30ea7882518148edfba2d9b20": { + "balance": "347033754668000000000" + }, + "a2bd489ec4790f4145f8a9a95c9c829c5c020146": { + "balance": "100311110878000000000" + }, + "a2ee35300ddf6a2491ec0e1848f8b56defafd7fe": { + "balance": "500000000000000000000000" + }, + "a31adf082ffd212df18d5a84b105a937e83b1b1a": { + "balance": "7124891785000000000" + }, + "a32c944e6c5fe186794b88d6bcbf51c47bea55ab": { + "balance": "732129357042000000000" + }, + "a33105d543f5d2b1220d4e1ecfdcf85699324dad": { + "balance": "74798779358000000000" + }, + "a3330c73e2d79355a14e570da1ec2e80f8048c69": { + "balance": "10000000000000000000000" + }, + "a3580034590e3052b9de5abd635e514ec5ba8694": { + "balance": "10000000000000000000000" + }, + "a360d8e2519dc6d7793cc371d91ad6add75e3314": { + "balance": "192622260840000000000" + }, + "a36b9b8b2adb20fb4a84d3025bf2e35baa8b7fef": { + "balance": "20000000000000000000000" + }, + "a3771b191237bef48339aa77ad5357f6227b358c": { + "balance": "512633055119000000000" + }, + "a3892bfd25705387cfb4eeb6d21089753c22e3e2": { + "balance": "258136912825000000000" + }, + "a38c793775ebfc7330b4331fe2dc848abb862b73": { + "balance": "1193250172232000000000" + }, + "a39417002ab94845541aded4a614a5a04af8187b": { + "balance": "1185722898000000000" + }, + "a3a79a9f929b54075de43689adb665ef914812ca": { + "balance": "100000000000000000000" + }, + "a3b59ea3d366f818ca09980846ac533d4685c121": { + "balance": "59734700360000000000" + }, + "a3c7b7c594a64225922e02039669e4d0b43fc458": { + "balance": "11779233750000000000" + }, + "a3cc39a68184e51f6445d3ba681a55f4157d4383": { + "balance": "10000000000000000000" + }, + "a3d414d9f210f7b77f90790ce09f6128abe50adc": { + "balance": "10000000000000000000000" + }, + "a3dfda16e5ae534ac100f56741b77b6f86786615": { + "balance": "9000000000000000000" + }, + "a3f79b9d1fc9d6dbaaef49d48fa9c9fb5a822536": { + "balance": "108910000000000000000" + }, + "a3f87414bc9e6f01c2fbde966fc8fb6edbf58c29": { + "balance": "441000000000000000000" + }, + "a3fa3f58c802d9a9690de760716275f14449045a": { + "balance": "437227558095000000000" + }, + "a417ec5a9749064a6521ca2bf9d05f208eeaed54": { + "balance": "959205202638000000000" + }, + "a484d5b883d2b99b81b7bef27e307957ecb64b15": { + "balance": "126491152120000000000" + }, + "a488cd48258e57d66f44e73a60c121f963cb29f5": { + "balance": "20000000000000000000000" + }, + "a488e3b5096e964b21cdeba12ab423f391765b6d": { + "balance": "1712050478592000000000" + }, + "a49dba65f28909e9bd2ce5675bd091f498c6c5db": { + "balance": "216802821062000000000" + }, + "a49eb6a791022c1324facc23d8813f9954d1c639": { + "balance": "287438914902000000000" + }, + "a4cc080a5c4649f511b5844a8e0b031927e13a87": { + "balance": "20333578449000000000" + }, + "a4d2624ac5e027f72edaa625ef22134217203b5d": { + "balance": "1000000000000000000" + }, + "a4d30e35c9617eafeda82866c96c3ce6bf14400e": { + "balance": "1223254927978000000000" + }, + "a4deae7355bd2e1d57eefa56600601b8b475a501": { + "balance": "36000000000000000000" + }, + "a4ff3b5abfe4e50adad16d01aaf62c3d4cdb5260": { + "balance": "20000000000000000000000" + }, + "a502b109869ef07451576bf0e13ab294e1f236b9": { + "balance": "94843398055000000000" + }, + "a517a3b5e4324197902e16f8a29e47335cf39c11": { + "balance": "100000000000000000000" + }, + "a51e101088da23c82907e3e2c65a058f0454b131": { + "balance": "196000000000000000000" + }, + "a52bcff6a7e2e70cd714058bc30a16138fe39899": { + "balance": "30429750204000000000" + }, + "a544e84c2bc4b17859d06f136b6e377e4e398b22": { + "balance": "143977568178000000000" + }, + "a54ddacbc17a98b9fb6292aab3d92f4c5753fd0a": { + "balance": "100583192014000000000" + }, + "a557754f6637a19c1a48cb9bf58c1fe897acf434": { + "balance": "2087038692036000000000" + }, + "a56649205d9ea247b49e03dacbed6c78c21beb4a": { + "balance": "5046177099585000000000" + }, + "a568136446ee6b3bf62a20238db3b11397a065f2": { + "balance": "11652249158033000000000" + }, + "a56a7865b526e315a9eb41f4847485c7e0c952fd": { + "balance": "50000000000000000000000" + }, + "a56bab2a9aac9d08a7bc9265864a80089b68570d": { + "balance": "37138466291329000000000" + }, + "a5965a601c5df7765cd70e5dad27dd23da67ac99": { + "balance": "10000000000000000" + }, + "a5a3161c44c34c441784b7df795067760b0ee569": { + "balance": "35053289069000000000" + }, + "a5c245cf843e691956007b94e259b437a4e6b7e3": { + "balance": "18749166170000000000" + }, + "a5d7de961c3b991dc78f2d6c0448fa6225116d3f": { + "balance": "1574510758868000000000" + }, + "a5f47d2081ef728808786128549a28a5662e92a8": { + "balance": "1750000000000000000" + }, + "a610c90f5b7e5f33044956ba431a3887de1c969f": { + "balance": "25000000000000000000" + }, + "a61c1919bc3f3181dc94e2230d35574cfc972d78": { + "balance": "8990565120000000000" + }, + "a62f1aabd91cbc0112e796d1ec3727fcd26fa293": { + "balance": "1311277302001000000000" + }, + "a64fff0bb32e32f81a541c393982bc59fa183b1e": { + "balance": "8291357610655000000000" + }, + "a673dae555d367b8d4a784274577a1884615b9d9": { + "balance": "27416452091330000000000" + }, + "a6c780b585355d84d9d3c13be5bd05374588e240": { + "balance": "913657165911000000000" + }, + "a6cc1f6f51862c2798adaa1d266988022005a71a": { + "balance": "284500645805000000000" + }, + "a6d9c82784fa20dcf28266d047db441cfeb8855b": { + "balance": "10000000000000000000000" + }, + "a6dae08f99e4fb57b066a645a259d8e4f7ac2bc8": { + "balance": "9044922773690000000000" + }, + "a6f49f36f8d10a796bc2afc9e069cb0c76004ddd": { + "balance": "128555691078000000000" + }, + "a721ce1c294a0f1957ebf9be20b0fffcf90111ad": { + "balance": "3392103457630000000000" + }, + "a72b82c33bd3d6060e8a04392d236775d48ec3ae": { + "balance": "1434465940701000000000" + }, + "a7344654f2a1a44b3774e236f130dff8a4721e82": { + "balance": "100000000000000000000000" + }, + "a748cced92a87066db8b29f931fb92e827488a9e": { + "balance": "5487679824758000000000" + }, + "a78dcb2bcbec2d0a60661e1715c9a95c9d573a68": { + "balance": "346798292989000000000" + }, + "a7a6c0505e7090e0b2c21394877f91c50be6b45f": { + "balance": "4125233658872000000000" + }, + "a7dcdd9b9785a44a2dd4c5eeeb863ac1feae0f66": { + "balance": "10000000000000000000000" + }, + "a8013e9dca1bd38975748de2fb6cb3af5cae74d9": { + "balance": "10000000000000000000000" + }, + "a807bf78b15c15cd9e8edcf586849db716fedbb1": { + "balance": "1458293606310000000000" + }, + "a83410ff00fb4b913dd0ea2003b38c5c3247350a": { + "balance": "2876442029807000000000" + }, + "a848f61298a409e77a03900712017572f35a3319": { + "balance": "2783106133600000000000" + }, + "a85bb81d0dc57f824a763814759fd93fe3020569": { + "balance": "4558027813744000000000" + }, + "a860611cd098ce98974313030d9f6f462bb274d4": { + "balance": "961594154368000000000" + }, + "a8799eeff72929ee6cbfb5b0c02985cd4841be3c": { + "balance": "500000000000000000000000" + }, + "a8c29b9b1349fac0be9a65873e1911b7439c9a63": { + "balance": "1264035560749000000000" + }, + "a8c321024a3c015d881efca33bd1b2c1788b379e": { + "balance": "528752788000000000" + }, + "a8d02e8925ed48f4274d8bee62253dc0d4f2989c": { + "balance": "209083880937000000000" + }, + "a8d2bde2ccd6bad67ee1b9550c9310accb37cd79": { + "balance": "49000000000000000000" + }, + "a8d61abc6a403adc183aeb74c83e4221fd28ee1e": { + "balance": "50000000000000000000" + }, + "a8eb6aa5a0c5b6d9260a202dc76ab674d9a5f3b9": { + "balance": "1041257515142000000000" + }, + "a8efc57efc776dcaaf4003a8cfa63f215ab0284d": { + "balance": "166144142685000000000" + }, + "a8faba86d87678294e311cfa7f8cbeb6f9d8a499": { + "balance": "124541781000000000" + }, + "a912e02f8eab0cb620316129875f919455201117": { + "balance": "6454482105955000000000" + }, + "a929ac95281d1a77a3eda3b5ac90a761ef03ff16": { + "balance": "1074305309650000000000" + }, + "a92a4e40519003813f5574397ce328d046f75802": { + "balance": "9188437500000000000" + }, + "a93850ba8fff3bd18ab259f87c58bbce84165fff": { + "balance": "39018890852058000000000" + }, + "a9843660a17c2d972246028cb8045472abdd346d": { + "balance": "1052681604185000000000" + }, + "a9866c6271733971e46df3c9bb27b3d3c513c166": { + "balance": "200000000000000000000" + }, + "a9b1299c0c064e766f9f29f4301a78c6e4931fcd": { + "balance": "267785134400000000000" + }, + "a9bc33b9c99dd5a3967387c1e99766f9bc74d591": { + "balance": "65356157048000000000" + }, + "a9ccf1cd2f816b15182997e3207d9a681bf21b06": { + "balance": "17521053440000000000" + }, + "a9e54bd9826f853f65e0be1ec0bb9c28f95e0eea": { + "balance": "6260000000000000000000" + }, + "a9ef563c872342f49817a903a5725b504d455ea9": { + "balance": "50134015139000000000000" + }, + "aa0d69c7e1382cd16c527a3fee48db19c38e1398": { + "balance": "142562301500000000000" + }, + "aa12abcc3ab373d07bf560fd200652c8580fd967": { + "balance": "5509242259903000000000" + }, + "aa1d6b968b3f8046a94f128864bfc612fc2e2700": { + "balance": "489179780895000000000" + }, + "aa20b8559d6dd1543e8c528775ae4b04c6242471": { + "balance": "169000000000000000000" + }, + "aa227e9d6074a60ecd43e1cc24092ee58560374c": { + "balance": "596190898010000000000" + }, + "aa7b660fec7b05968ba656eae9a8aaef4481720e": { + "balance": "674642002744000000000" + }, + "aa9e04077d44d288978a3a3ab0d7c251c0447a4c": { + "balance": "10000000000000000000000" + }, + "aaaac1e72955e9d67625cf8bed73fa643fb1cc1a": { + "balance": "9781187987000000000" + }, + "aab46c0c2db4e330834081f97678906252746f97": { + "balance": "16440184245000000000" + }, + "aade5358c52b8aa5ad8ff285c6b297e86f49fa0f": { + "balance": "982846000000000" + }, + "aaedb3fa2cf0ebca0ef4a121a28a406264ccc900": { + "balance": "100000000000000000000000" + }, + "aaf30bf76362a03450aefaf5bd68d28b84eb4962": { + "balance": "509106199370000000000" + }, + "aafbaaa6b6369e986ba72b196bd5f08cc458e344": { + "balance": "216372214000000000" + }, + "abb03c888d61c9102827a1dc0950145beb9d96b3": { + "balance": "144000000000000000000" + }, + "abc6dc937d7703a6b0c83659a328cde0d5008e32": { + "balance": "4052429106341000000000" + }, + "abd3910139a97cb92dc09a8a0352575bcc9ebed3": { + "balance": "24028359215749000000000" + }, + "abdc3953ef293c98989802063f8cb55e0e506432": { + "balance": "64000000000000000000" + }, + "abf1a47c582bc87d36e47cfce24e0ad249f42e73": { + "balance": "71947491720909000000000" + }, + "ac0b6e7aadfb5ffafd5cb3ef3620ebb0691cc3fe": { + "balance": "10000000000000000000000" + }, + "ac1a182607046b56e7a4bbab87cc1182874f79ef": { + "balance": "453499500178000000000" + }, + "ac251b311f781ad7a43d01b0b4b20fe891004e7e": { + "balance": "304621378298000000000" + }, + "ac258cec5ef49f96612d659f66dd4e6ea88e3c87": { + "balance": "255185373455000000000" + }, + "ac4000d9ad080740ef4a2ebe4a3075877bea277e": { + "balance": "10000000000000000000000" + }, + "ac7445c09372f15259fd852cc458783d6140c0db": { + "balance": "10000000000000000000000" + }, + "ac8d29dc05ea6c2f5409a76abe04321bf9381f32": { + "balance": "22464474197854000000000" + }, + "accd52b63822d8cb5117d9deb56596e072462614": { + "balance": "20000000000000000000000" + }, + "ace63a86a2ddfc79f677344e93dc0c4750b8fdcf": { + "balance": "1355066360964000000000" + }, + "ace83deb83fa8d319979658592b75ed13bdf97c7": { + "balance": "20000000000000000000000" + }, + "acf91515df16b21f1e5f5474dbefe596e4929b96": { + "balance": "1153047238967000000000" + }, + "ad04381f7ba89220e8fcd7e200f98a476683a904": { + "balance": "2000000000000000000" + }, + "ad22225bf225d8f705f93bdcda8d301180ea28dd": { + "balance": "1272512717188000000000" + }, + "ad3f74034ff5ca89f97b2585edf12376820307ab": { + "balance": "12303261515593000000000" + }, + "ad43a3527ad2b9445417cb73cbcb42965a5f469c": { + "balance": "67607364133000000000" + }, + "ad61cf9bf560bd5da75d55738477bd9aa25fb0b8": { + "balance": "4358939446693000000000" + }, + "ad649e8a3e1436e0604b0b8c9b1a5f1c09e06d7c": { + "balance": "344000000000000000000" + }, + "ad6b584813814db4c72c4c7eb31447d224074b46": { + "balance": "18445595367000000000" + }, + "ad7d404afc67c0e457fd3ce142cd30b506408683": { + "balance": "48218702840000000000" + }, + "adaf4d39b6806d132128ac438c2862c0a1650cff": { + "balance": "500000000000000000000000" + }, + "adda124baed2e1fdc1acc7b4a048eab0cd249212": { + "balance": "1074765673925000000000" + }, + "adef437c429d90a350b99750d4b72bc8538c5f98": { + "balance": "931901903135000000000" + }, + "adf826a0ea7dc4322d26e9d8c54c4180c1827216": { + "balance": "323567723315099000000000" + }, + "ae01d8b1668f8bfe6e225bd9bc746f7e839ac0d8": { + "balance": "321211880744000000000" + }, + "ae17de3ae6127022e53ebcf9e08457174cdee0e9": { + "balance": "3817903000000000" + }, + "ae243b0186793eddc6ebbb1a2c1f0b1cd574b07c": { + "balance": "9000000000000000000" + }, + "ae3ae1d41dfb16e19a1817b3639cd4300fd166c1": { + "balance": "55437674845679000000000" + }, + "ae506999882d4c6f05cc7979c342c0ce559a8df0": { + "balance": "1391755905401000000000" + }, + "ae524cee5aa23025d6ad185ccab75a6974335d53": { + "balance": "797132751509000000000" + }, + "ae5a55075d0541f179b085152bfc8c72c74abe23": { + "balance": "589408139567000000000" + }, + "ae63d02b18b464f0bbab4de943766bdc7ba2926d": { + "balance": "300261019201000000000" + }, + "aed8ffb86a49c09ae3a83e93d9045851434a9f0c": { + "balance": "1031991707237000000000" + }, + "aee18a9a2ccdf6025d61005827753ce4f510f7e8": { + "balance": "1818639022863000000000" + }, + "aee67910c514fa63a228769d5e15ca40bc4b26c2": { + "balance": "5688989238568000000000" + }, + "aef744eb2ec682dca128dc3149afcf881e367121": { + "balance": "818801643225000000000" + }, + "af04430b3e40e746127623532353a0f177a88fe3": { + "balance": "100000000000000000000000" + }, + "af181833edb15c9b2ee2329dcf1845b977361b7d": { + "balance": "93228805338000000000" + }, + "af30db29765b4fda6f075af96e8acd5046b099c4": { + "balance": "1000000000000000000" + }, + "af31fd30cfb10f1b0a12c2e7dd7ca56bdf517745": { + "balance": "36000000000000000000" + }, + "af70d6820e1d26194b0a9965b55254a287b162f3": { + "balance": "87593999609754000000000" + }, + "af96a573fa86c07389a71db797bea689419b23ca": { + "balance": "36000000000000000000" + }, + "afa4c5b674934e31a9aa5e3e723d85060d51c4d0": { + "balance": "10000000000000000000000" + }, + "afa6e4b4060c2e5969c2329d13cc42924412efde": { + "balance": "127502378589556000000000" + }, + "aff2308ac607f85392f4c8a6a043af67b7b849cd": { + "balance": "11130371831000000000" + }, + "b00ea9c459105b650def1e8569c85fa01837454d": { + "balance": "94928352162000000000" + }, + "b02a7d16ea8663c88416e6f64eaf57787d230be3": { + "balance": "17215604601000000000" + }, + "b03f4e9aa5c352cb1cec953d1123c2f22cd94b5b": { + "balance": "206022552274000000000" + }, + "b051459b91d253c5e8251a5a68282c291833466a": { + "balance": "297127749975000000000" + }, + "b055bdc874ca5a7d2f4bcbc51f1cfc3671b55f72": { + "balance": "1421913523478000000000" + }, + "b06156b99b891b756262c5b40db9bbe39fddc77f": { + "balance": "49000000000000000000" + }, + "b076893b9841d2775ec8883f05b74f1e5aec327c": { + "balance": "22591055478000000000" + }, + "b095de644af3c9f960f67502da6ac5eb050a158e": { + "balance": "4958067562725000000000" + }, + "b0a1f794cf70422395f74395abc9a7d0b271846c": { + "balance": "812057322000000000" + }, + "b0d36e0f426a99416425689c657fc6d64ad698ca": { + "balance": "1157727077158000000000" + }, + "b0f35fa554d6ed657bf3996cc027d045c3971fcc": { + "balance": "64000000000000000000" + }, + "b0f76b4c9afdfe35c41d588265642da60f1b97d1": { + "balance": "1000000000000000000000000" + }, + "b0f76b4c9afdfe35c41d588265b42da60f1b97d1": { + "balance": "2028311808491377000000000" + }, + "b1445842d56c56bc532d2f33ab9b93509c732a3b": { + "balance": "13522982470164000000000" + }, + "b156bafe05973bc839c4f115be847bbde8a67cb1": { + "balance": "10000000000000000000000" + }, + "b182e4d318893dc1c4c585195dbde52a84ed4ffd": { + "balance": "329498977335000000000" + }, + "b18f506e77df4db80ca57cefeaca4f1010f78f50": { + "balance": "956339304078000000000" + }, + "b1b6f617b110dd79c8fd77e729584d1fdfa9aa09": { + "balance": "16000000000000000000" + }, + "b1bba36e2d9e272e0131f4bae09bcfd92e0a63db": { + "balance": "64000000000000000000" + }, + "b2285651e57ae0ff27c619207cceacd20884d152": { + "balance": "1345938295122000000000" + }, + "b2419a93732d0d324daf7707fac3782a77b0dff8": { + "balance": "625000000000000000000" + }, + "b27206e9f2ac430841fb8da69b49d505f1558b8b": { + "balance": "29507819229000000000" + }, + "b2801fe902c7bbc987ba12ecae98765c99980fef": { + "balance": "240016083000000000" + }, + "b2843d5215ceb761e78f281402a1660c3abadf5b": { + "balance": "3335539720927000000000" + }, + "b2a22e6a04a2ce3287da3b8b6eed4ea1f18f05dd": { + "balance": "99999978999999999999" + }, + "b2d55a061fc6f90d2a05e0cbd26ffe0a1c3321c2": { + "balance": "1000000000000000000" + }, + "b326aec1cd523948ffec2fd1e8f21bd2b4308f40": { + "balance": "913000000000000000" + }, + "b32abc82b251e2d310ea7588cae4ad4acb657cd9": { + "balance": "26946233911000000000" + }, + "b36924d578973aec05ce7ab556d7ed00004949ca": { + "balance": "393041705867000000000" + }, + "b37482114c83e857c730588d7d959d300b8142da": { + "balance": "29429544454000000000" + }, + "b39998bade135ac6ccadff41cd709e161d01aa60": { + "balance": "26272579375000000000" + }, + "b3a995ee94f1d63d12f10cea5ab3d596c7c6f284": { + "balance": "64000000000000000000" + }, + "b3bf35e936fdbb7d0bbeeb1cf076f243855ed477": { + "balance": "754081187934000000000" + }, + "b3c2ac85b99abed4a2a52b5f96a2c98040d16022": { + "balance": "50000000000000000000000" + }, + "b3d1a2c0ab2d8987446d74f49e357adf5bf15986": { + "balance": "10000000000000000000000" + }, + "b3fbcd24c8394a5d2b7fe877f18681a109a404e5": { + "balance": "2558689648423000000000" + }, + "b4110f4e38405adfc054e55ff73c55842db8e2cd": { + "balance": "129000000000000000000" + }, + "b417f4681fdd4e53cfdf8550e3d326dbb0a557ec": { + "balance": "1000000000000000000" + }, + "b422970fb8799d83642b7ff715fc941d69e86053": { + "balance": "81000000000000000000" + }, + "b4237be71920497715826eae8d85c26cb3c111a8": { + "balance": "10499979000000000000" + }, + "b431839de4b21dfb44150cfc6ed00ea430a81687": { + "balance": "26839560174813000000000" + }, + "b43a0d6399c7d1be943c4b45838156a47c88f909": { + "balance": "10000000000000000000" + }, + "b44ec608b95d0d51105ce5f4b48de5dd72f346fd": { + "balance": "448125120000000000" + }, + "b47f63e14f6de6c3413b2be95a725e367ac18fb6": { + "balance": "500000000000000000000000" + }, + "b48071cd1b15f45028e9dec2237f14f10b7aedf9": { + "balance": "38042711385000000000" + }, + "b4b874b323b560aa0e4811ca574bd48b65b3fc72": { + "balance": "18063913676592000000000" + }, + "b4e4d4af0667f8158cf817bf1bc3eada08a551ca": { + "balance": "2149067370317000000000" + }, + "b4ecd625ffe470ee1fa1d97832e42ddf3f9ddf6a": { + "balance": "1181738860120000000000" + }, + "b53f380ce92787c1db461524290e8fcede552fe7": { + "balance": "12640674931821000000000" + }, + "b547e04ab8a44d3cae38704356f1f59408457b67": { + "balance": "286604155735000000000" + }, + "b562e4010a0a5fd0906a4cd9f47fc28f6f51e210": { + "balance": "1000000000000000000000000" + }, + "b584de7b38a2a2e3d9ff9c055b309ca56e5da5a9": { + "balance": "237896887904000000000" + }, + "b5c1129961c4a43673324aaedb8296f5ade82516": { + "balance": "4213058948283000000000" + }, + "b5da6711c72bf27c87923aed4a39349b4192e6b4": { + "balance": "55180742586465000000000" + }, + "b5eac5e7e03b9d31e40393e16e956cd588cb7566": { + "balance": "4508019435556000000000" + }, + "b5fd46ee4e02946dca3485439f98bdab290c82b7": { + "balance": "108321600045000000000" + }, + "b5ff2a3caef6ec30365f4f0ecbecbdeec1cacbba": { + "balance": "979696597242000000000" + }, + "b609d05242f7c13a4ae4036f6da9c0bae18dd70c": { + "balance": "229121731278000000000" + }, + "b611156a2f87fb45c431a5cf5740ded90c2dc542": { + "balance": "401783365700000000000" + }, + "b61c7623144afbd0f6cf44c951e4219ef8096119": { + "balance": "36000000000000000000" + }, + "b61cbe0e58ff6fa4c810ad03c759c79d9ff052a5": { + "balance": "1034495371371000000000" + }, + "b622bb67e95a03f58dc9aecf82c217e86f2cf7c3": { + "balance": "500000000000000000000000" + }, + "b62a50be3ce0e7cf8f61991daf8fa7e23775141e": { + "balance": "1000000000000000000" + }, + "b63cbff6b1747ad5cda101d5f919ce81dd67e363": { + "balance": "2570089937000000000000" + }, + "b65e80551a8687c9cef2d852949177c0e3b56e51": { + "balance": "100000000000000000000" + }, + "b68126ebbcb5ab9b0371b62597a38d5c1685b0df": { + "balance": "671140851028000000000" + }, + "b69f5830c371cad5a74ae823eb8892d153ef3c23": { + "balance": "18446744063709551616" + }, + "b6b4468c4db64e0b85cddc251d02f32fffcd1f7c": { + "balance": "10308006217291000000000" + }, + "b6c129312505e571148dbe69833d30550efc12c9": { + "balance": "5105834767567000000000" + }, + "b6cee8ef00b8674a9a96447e4511b30d6564ff67": { + "balance": "667754569888000000000" + }, + "b70f805aeba260d44f0730f0a9dec60f2b4f54a1": { + "balance": "2751303297000000000" + }, + "b71a901dc4b6c6463f7d221f868677bcadbcc680": { + "balance": "169000000000000000000" + }, + "b7385bd8f8257331f4c7a87c7a23724f615cff8e": { + "balance": "196000000000000000000" + }, + "b755692bc027e30730dc1d0e0b2a883830a84115": { + "balance": "30713083153428000000000" + }, + "b765305dda3c1e069a7a022ec127ff2140d0a820": { + "balance": "603122990932000000000" + }, + "b77403a4c56ffc7715b4bfdfe4b054336aeca466": { + "balance": "130840969728386000000000" + }, + "b78b2f6dc731d7d84b7eea151805f9208a1d0cf0": { + "balance": "142084687500000000000" + }, + "b792a0fd762c002a7585cfdefd36cf7ffb42fc05": { + "balance": "10000000000000000000000" + }, + "b7ccd7164aa7fb871726d9d043a8f8f890068c0f": { + "balance": "1170997140237000000000" + }, + "b801f49018317caf30f310dbe116f4e876184874": { + "balance": "50000000000000000000000" + }, + "b81ca2bc63cb4008cebdda3ce8f4eaba322efca6": { + "balance": "4678481047354000000000" + }, + "b82e3d50bf8c5b471c525ec8dd37b06688ed6178": { + "balance": "1202448975553000000000" + }, + "b841162a7a8876296f10794d8847d8095426aa54": { + "balance": "73500210754000000000" + }, + "b8421d375c3f954e22b6fd304235dd7c43b68bd0": { + "balance": "6499782706009000000000" + }, + "b859b76d77eb604728093c61fcabe6f9d22433b0": { + "balance": "196000000000000000000" + }, + "b86536268ace9be93a1db2012d6e3e59023ef2cb": { + "balance": "52878034904067000000000" + }, + "b87e1ac4fc423ab37e10ffd221df8056537b1d03": { + "balance": "119159824674000000000" + }, + "b8825a99806c5a968423e69d22f2b61a2f0ae9e4": { + "balance": "999999999580000000000000" + }, + "b8835acaf63e0e5d41fb743eb0f954040a38d381": { + "balance": "64000000000000000000" + }, + "b8844c74b227781d4b3fafd32e39ff6fa9857f77": { + "balance": "490694157000000000" + }, + "b8962e8bcbcf0f69144f8fcd2ec3ae8e54c05034": { + "balance": "1425313342735000000000" + }, + "b898b4ece8e0eea375f6eb85615652cc5c221593": { + "balance": "2284038029169000000000" + }, + "b8a949bfd9751c29c4cd547cca2e584d8dac4e12": { + "balance": "50000000000000000000000" + }, + "b8ad5ce2ae781e2d245919c15bbbc992185e5ada": { + "balance": "733786526623000000000" + }, + "b8cb6a9bc5a52b9cfce26869e627b2af0ff5ed4a": { + "balance": "98364826821577000000000" + }, + "b8cf6aac7b9028649f0d55a57b61640d70cef120": { + "balance": "104799890645000000000" + }, + "b8e827b5d1e10a3944039adb1a3dd7ff6949145c": { + "balance": "172413427060000000000" + }, + "b8f6d7f33ee5755ba56647ab8fc9ca27b8aba677": { + "balance": "1430769696978000000000" + }, + "b9221177e2b09725bc95f08c72c17c42887eea62": { + "balance": "1212779749827000000000" + }, + "b936e0d83cde9bb810b85ad58eb5ff0fa9c11654": { + "balance": "4999580000000000000" + }, + "b961d435c457e205fdbed5442c8614ecfd59616c": { + "balance": "27847452621284000000000" + }, + "b969e9d89f32002cd4f90ef5907bebbbdca6fe6a": { + "balance": "12455448454838000000000" + }, + "b981c9137cfca5389f0123927852278d2d7ff618": { + "balance": "92180707865000000000" + }, + "b98abf0fe91b0d3a16c6ed37aea446baea33fd23": { + "balance": "560454425563614000000000" + }, + "b99ab4e6ae277b9fb04537adbb781e8390b490ad": { + "balance": "32814665223319000000000" + }, + "b99d0a433d7994743dd675894c18ed03164436e1": { + "balance": "16000000000000000000" + }, + "b9d8b6f0a505d217709bb9327f3b9b3f84813e00": { + "balance": "81000000000000000000" + }, + "b9dbd64e3c8e6ad84c9c67c66e678c06ea7bcb91": { + "balance": "1161140466507000000000" + }, + "ba361f7a6dff16a96f957c63e08267dec8f9ecf7": { + "balance": "2170060167590000000000" + }, + "ba47f4136f74b566f62ba373651332b59e74e1db": { + "balance": "906249296535000000000" + }, + "ba5287cf15de91daeaea2465da4d4c1a14dea716": { + "balance": "98978398162000000000" + }, + "ba77d056d52f84e740579aa527792f826591c858": { + "balance": "50000000000000000000000" + }, + "ba895406774ced5fd2e759b58f9ffaed5e04fb14": { + "balance": "10000000000000000000000" + }, + "ba96fab21a4926fd1137558ae996b52ec14538a6": { + "balance": "10000000000000000000000" + }, + "baacc247801eddbf152fd6ec39d659f265935743": { + "balance": "2661902597584000000000" + }, + "bab2eb9fab8e699a958699b15ddc7ada5428d33a": { + "balance": "27006404153000000000" + }, + "babeacd7933c817472875c86bf126e6d11886f8c": { + "balance": "2461234517292000000000" + }, + "baf7021d4d754d4478d3c3624c2376e3f1d4ee5e": { + "balance": "1352066301857000000000" + }, + "bb0760bd1da973d8f70dd0caa6cadfcfd8199231": { + "balance": "177674700430000000000" + }, + "bb278c6a52eebd0b8950e9b78ba211453ccb1b6a": { + "balance": "25000000000000000000" + }, + "bb327e5f260b2dfe25fb180c2d3f4b63211c1dee": { + "balance": "7694972715000000000" + }, + "bb643e768ab20c135e7df3f400284cf04c40a6f7": { + "balance": "385756449779000000000" + }, + "bb73d1d1c289b4953d0033b52d9d2d0d92573d22": { + "balance": "11000000000000000000" + }, + "bb89936d562b19e4c599826ce7cd0c60cb02b512": { + "balance": "725910446589000000000" + }, + "bbc509b7999b0e94534477b98ec8927cba879677": { + "balance": "20000000000000000000000" + }, + "bbcfa9ab62f4eab14d6a1b09c1aa554dae113183": { + "balance": "589417352665000000000" + }, + "bbe78301134249b52b74d73ee3855e7e3d288a40": { + "balance": "4456159000000000" + }, + "bbe7bb4c4f1b506b58f7e3334e6c89011cf2d6a7": { + "balance": "3889127030000000000" + }, + "bc016690596e077273465d1728d18553b185654c": { + "balance": "185932953686000000000" + }, + "bc16b2ab9c7ab309249f93b496b75c6a7392cb10": { + "balance": "5000000000000000000" + }, + "bc254e5405b154b98abb5fe5508d3e7c98663f4e": { + "balance": "144000000000000000000" + }, + "bc258aeb0f18150d3ca253c6bb04f63d657d99ac": { + "balance": "6011905701701000000000" + }, + "bc2620b5ebac12a88b287b625fa5b336568e7869": { + "balance": "534886892259000000000" + }, + "bc318687cfaae2be4c5ece4a18bb9252486a19d0": { + "balance": "147226513970000000000" + }, + "bc32dd123fcc2ef0dc36484c3ab1bae5d9890761": { + "balance": "16000000000000000000" + }, + "bc5c5151be06aaf6180bc9c1058b181a5a30366e": { + "balance": "113865120384000000000" + }, + "bc66241ca430dc31a3e2f44dedba868e16b9a6a1": { + "balance": "50000000000000000000000" + }, + "bc7c371af0688b1c409f4b07662609a1c9efd120": { + "balance": "20000000000000000000000" + }, + "bc9454f7efc86e25d18a8e8b6e230de42a51d967": { + "balance": "148103676062000000000" + }, + "bc9d5456b975bf0b95c161c3355e4ceb28898fd9": { + "balance": "28083912047000000000" + }, + "bce0b47bf13e4517c53bbbe6e51544b99f3147f6": { + "balance": "919711480389000000000" + }, + "bce2d1ec7c41b426f72b352f5f2b7da3edac4157": { + "balance": "908085365725000000000" + }, + "bcf0756789a57f16206dd78bf6e1322ba9b9b85b": { + "balance": "110888224252000000000" + }, + "bd0bc4a0730f9f55a2f65f62662c7553db52238e": { + "balance": "8440290043000000000" + }, + "bd29fda37c2581a3f040c77eead3143cff24a346": { + "balance": "126022762542000000000" + }, + "bd4c1270322a26a1b825040b239008a447c31918": { + "balance": "727012140904000000000" + }, + "bd6a3da2db66dc9fa26fa2b63b14003d26ef91d0": { + "balance": "5492112771780000000000" + }, + "bd80fcccac60078fcf09f5bddd8a25a92fb9cfdf": { + "balance": "10000000000000000000" + }, + "bd92dc94b6e81a3da5dc3ae6bd80782622658196": { + "balance": "10000000000000000000000" + }, + "bdb35c2c595fe7a2864ebe20dd56d6ddaf9d447c": { + "balance": "4346566125000000000" + }, + "bded4718cbad2150c9b6df9ee7356e0f5c713cea": { + "balance": "311694803600000000000" + }, + "be1804630ecd95ac411b935566cecc5a24c6f18a": { + "balance": "85033246331000000000" + }, + "be2318ad50b0a85b95870a81dce5c31029636159": { + "balance": "5185298019030000000000" + }, + "be3de52fc1119f02f4707f353c040b7c4222d847": { + "balance": "25267399461000000000" + }, + "be4feae01d429c872601ae84dfae8fddc3372686": { + "balance": "20000000000000000000000" + }, + "be7c09d704d16e4b2c9e19cc8c07808bb335f926": { + "balance": "25000000000000000000" + }, + "be873a9525899bdad5e4376b0115950e534dea2f": { + "balance": "404116929377000000000" + }, + "be891b1680ad835aab1ac05a30c0813306cf20f2": { + "balance": "144000000000000000000" + }, + "be8ed2d85a5e3f83c6105db1a1f304e9f174bfce": { + "balance": "50000000000000000000" + }, + "beb1cd80c2f8fabc27ee3a3b2a15e35fa52e7879": { + "balance": "11539095431000000000" + }, + "beb67375e46950830906bf281209be133075452f": { + "balance": "1305262446956000000000" + }, + "bebe54437722c6000bc6a8843f159538a2abf613": { + "balance": "41042548942568000000000" + }, + "bef2a05e283ae948efa9b0e3a6ab5d26a57f1de0": { + "balance": "180614450853000000000" + }, + "bf03950f265a4182b4402703723a0311158eef4f": { + "balance": "158997402149000000000" + }, + "bf06393654baa1ad15c2e717e06dbaa61834c214": { + "balance": "34409427774000000000" + }, + "bf2b867313a44bd04aceaa644771d1e95317c881": { + "balance": "10000000000000000000000" + }, + "bf350ccad91a2a2aff4cf27a291323a297a78009": { + "balance": "124593326152000000000" + }, + "bf3d86edfcf52733e91a9c59be606a95bd921885": { + "balance": "20000000000000000000000" + }, + "bf5b21d5e339752b33b180064d0e6047338650a5": { + "balance": "1000000000000000000" + }, + "bf64c2715db8f353600a45b9264e1f22a40ef8c1": { + "balance": "2952972677360000000000" + }, + "bfaff32c8b04a61658ff94f94e4687232b8d2d7a": { + "balance": "1117691379350000000000" + }, + "bfb00182321502e0729d9a0862ec1df1b3e2208e": { + "balance": "500000000000000000000000" + }, + "bfcdfc9f60610f0ca279ca2c89b9af831332aece": { + "balance": "1431082635308000000000" + }, + "bfe14356e86f6b2ad470bc77d250517c8dc03d15": { + "balance": "310115085185000000000" + }, + "c008bd3fb881da9dca4cadcc56b1d99c56db9abd": { + "balance": "12899598792000000000" + }, + "c01efea456d30360a78ee10c790d46bcb889ee61": { + "balance": "103203021492000000000" + }, + "c03d622627bba7d5db1a9f699924e9d5ff5640f2": { + "balance": "95102233308870000000000" + }, + "c0465ed806ce7ee730e5b6eb7b86a754bfd196a9": { + "balance": "1654379359619000000000" + }, + "c061c5b0d0ce7af95ded1805abb23f743e13c455": { + "balance": "500000000000000000000000" + }, + "c074f2024f79cf8d7aab2d858dd110fc2ee89d41": { + "balance": "18382732686000000000" + }, + "c085147a76d0336b4bd6e7d5b60d394bfd3c6f42": { + "balance": "3236912707535000000000" + }, + "c089416d2d679cb2abf44251de227d0a08fa1206": { + "balance": "497124416350000000000" + }, + "c09d8cfd85989397dc723f2df821dbfb2c0c39b3": { + "balance": "833485701262000000000" + }, + "c0aaf130e3b67250d9775d62e7cd3963daf0a627": { + "balance": "1249947125780000000000" + }, + "c0aebdb5c2e8c5ff9870535c738bfe892c9365dd": { + "balance": "360097616959000000000" + }, + "c0db5680ba88052652bfd5a617c4e8a5be188077": { + "balance": "509051625766000000000" + }, + "c0ee350e5e09a2daeff332a66a6e117fad102112": { + "balance": "10000000000000000000000" + }, + "c12c0a3fd42501f8772e4ad5d262eef3f0bc4701": { + "balance": "120398848512531000000000" + }, + "c135b48c7fd11670bbfba923b28767d21d7923ea": { + "balance": "20000000000000000000" + }, + "c1397c66b7f150c0062b0e87c981c107d771b109": { + "balance": "87751498250000000000" + }, + "c1507ee435cf506fc5d8e4cb62515f2ea0f3a7ae": { + "balance": "4935384099000000000" + }, + "c150d185e2cf203054a6e328b72d8c35bfbbcc33": { + "balance": "21044148271000000000" + }, + "c163098f8b8f0736862274860b3842cf14bd2288": { + "balance": "119025568966000000000" + }, + "c1687fbbc7d504b73fe3e71af440b3dec0da88b2": { + "balance": "229520711528000000000" + }, + "c172bf224080d448261b3b66453074b28628daf7": { + "balance": "7903438287958000000000" + }, + "c18e9bc05dfee2a39fe2b6778a24a48d5bf0f141": { + "balance": "500000000000000000000000" + }, + "c198fec4069c95300d34b9c7109d7441b8e62745": { + "balance": "50000000000000000" + }, + "c1b4134f4757d19a687d05bd7087872b5625405f": { + "balance": "20000000000000000000000" + }, + "c1b43ca2af534ac6bcad8f23c30c07ba07e7e8fb": { + "balance": "194999622000000000000" + }, + "c1c2249507d2dcaf4a9103fcea2cfb47aa4957f7": { + "balance": "571416394325000000000" + }, + "c1e90af40fb64427aeb79a13607debbae9270b52": { + "balance": "50000000000000000000" + }, + "c1ffc8938f3412d19d428b8450f17fd394ae539a": { + "balance": "36000000000000000000" + }, + "c20013e25ae53d0d41bf365aa767822bbbe70936": { + "balance": "10000000000000000000000" + }, + "c20e9eadffa5529ce58a39f5898f39906dcd4b78": { + "balance": "757301065305000000000" + }, + "c211fc2623d51846d26952628d140643efa5156c": { + "balance": "865384323985000000000" + }, + "c2546c312570b30ad2ed05edb13b6469494c5b92": { + "balance": "5000000000000000000" + }, + "c25b2280ed0f835538f8ffd9dfc08a3b853f1ccf": { + "balance": "1000000000000000000" + }, + "c260e43b89a7a4e84bcc4c21dc43d4b5e6923f3a": { + "balance": "1000000000000000000" + }, + "c26aeef0e1f382c88bbdb1eb8c01afa7f58218ce": { + "balance": "79774757760000000000" + }, + "c27dd2645254bc30b6cf7bf418803b02ac808b5e": { + "balance": "4419594173874000000000" + }, + "c2b4f6cf92d6d63a20034e409a358df1803159b8": { + "balance": "1630820442000000000" + }, + "c2ba4a7ea6ca2d17231fb17ebd5dd2dfc0964de4": { + "balance": "221662324727000000000" + }, + "c2bc18f24b8097208a8b2418c444ea58beb94281": { + "balance": "1766754009521000000000" + }, + "c2c028dd17f8a89b9131b7daaeae9cb1dddf86e7": { + "balance": "10000000000000000000000" + }, + "c2ed78a0cb850c12ce8e6ff3873e8c18ffc9f4b9": { + "balance": "1017518755567000000000" + }, + "c2fd7296210b7013d476205d2517d51b21c9e76c": { + "balance": "500000000000000000000000" + }, + "c3041d3d650ff6ac3e35b60371b6798360727651": { + "balance": "1011071365226000000000" + }, + "c328ab9ce1fddd5623e0383828714a7e3ff12eff": { + "balance": "285042661579000000000" + }, + "c34ab008ddddf376dd866cccae4a4d6eb88403e2": { + "balance": "2798642711076000000000" + }, + "c3511391c4515cf8f27e9bc0f777a02a4125c8b1": { + "balance": "20000000000000000000000" + }, + "c36916a9fdf656bb1a8c2f7fb752a3489020f6ff": { + "balance": "689483152953000000000" + }, + "c37598a388d6f4e8e046923265ee9256456e40ab": { + "balance": "62865106394696000000000" + }, + "c38813db256eb221a7142d042b81ba2babab2c31": { + "balance": "98477603778000000000" + }, + "c3acd30f0bc3146fc2cab8d54904f98289021374": { + "balance": "17820000000000000000" + }, + "c3ede34dc1cd995fda1c5cb6e9ffd0c0da080587": { + "balance": "1080428143758000000000" + }, + "c3f04dffe2be55a1d6cdaa78e5c09a79d0477e7b": { + "balance": "59747493842929000000000" + }, + "c3f09f681cfb57d3cabc547dc32a71d2a6585c1a": { + "balance": "1757648436173000000000" + }, + "c3f3bb6444d853614f18c04a3c81f7d26e62e96a": { + "balance": "9022830778000000000" + }, + "c3fe4534327a2fc4144e2d3d3392f7b78d2aabc5": { + "balance": "1759225739027000000000" + }, + "c424f5be9490ec7f0f1e2debc3f72bd83e35f587": { + "balance": "1774372626989000000000" + }, + "c434f64eb937207f80e9a02d2f77ca34bfc63aa2": { + "balance": "960850858644000000000" + }, + "c438b6fa5801a4b8dea450530d975f174cdd47ef": { + "balance": "64000000000000000000" + }, + "c446effb984ff3e5ed92280e7b3dcdb1284230b3": { + "balance": "503490303680000000000" + }, + "c453ae9f94253ebdb871e9dac19056b13d1747a3": { + "balance": "1621494076559000000000" + }, + "c4a473b5e3a6bfb51f963d4dcf109bddedf4fb43": { + "balance": "104273242373000000000" + }, + "c4b8058e9e5416e526ea16e37f29dc221d28a003": { + "balance": "1833513486496000000000" + }, + "c4c09f4bbae0ee06f2a52ff0ef0de1978b5305e9": { + "balance": "20000000000000000000000" + }, + "c4c5981f5ac0a9a3701663b887c4aaac3a3a4d1d": { + "balance": "1411640000000000" + }, + "c4f7a493d16aab4d18e88e530e75e3095a3439ee": { + "balance": "191606419322000000000" + }, + "c5259c18bbd8b0485ca83d069d5ac235b28f24ea": { + "balance": "1276479076242000000000" + }, + "c526ef1124c7d0549b117e7b7463539a24209290": { + "balance": "9106523141000000000" + }, + "c5278b9eeff2221604f30f002c307ca2882fba97": { + "balance": "20875716591000000000" + }, + "c527ca73562846de9fca1649fe5144e5068a2f6e": { + "balance": "25000000000000000000" + }, + "c52a960c5df55169ed5d5cb0109a576321ab82fa": { + "balance": "1097338876493000000000" + }, + "c533ab799e5a04e0ba4e4780d632e0044262d216": { + "balance": "200529941482000000000" + }, + "c5389e3ee2f043ac2b6481f254440a97a9cf3bdb": { + "balance": "84047554571000000000" + }, + "c5594292b324c1d63f797c588a589c895c680ed0": { + "balance": "334298857161000000000" + }, + "c55d7ae4f29d857182d5f1ac2a78cbf35a694dc2": { + "balance": "500000000000000000000000" + }, + "c55ead0ece8fcfbecc573666c0170228e089aefb": { + "balance": "438775082956000000000" + }, + "c55f7d73491cdba391b631581029de32755a09b8": { + "balance": "1340000000000000000" + }, + "c56cb4e8308d6462eded0bbc74965ee135e23e11": { + "balance": "568187503785000000000" + }, + "c5b0c5f840f579536d5977a77262458d72ef1490": { + "balance": "5880686297881000000000" + }, + "c5b129c764daac8bfbf023646b9306d817a8ebdd": { + "balance": "10000000000000000000000" + }, + "c5bba43db949e2ed3de3036caf7a6e42558b1ef2": { + "balance": "763947031151000000000" + }, + "c5d57171e5b9cbafaba7d2c13cca3ec9d81bda49": { + "balance": "25000000000000000000" + }, + "c604e6c539c857ae9e60ca20d1906308ba431892": { + "balance": "100000000000000000000" + }, + "c607bdc5ad2f189e9356edb4d7975c7ba9300836": { + "balance": "55828814399000000000" + }, + "c60b0d2341ecada6c3faf1efcc9027125d99e17a": { + "balance": "121000000000000000000" + }, + "c61e1b993c3fd91a1023ba5b92d06a0aa539d92c": { + "balance": "23863993763643000000000" + }, + "c624656ee5298786cb3d0de045b0ac089c5341d6": { + "balance": "2210389938000000000" + }, + "c6573a023d6f4b5e151f266af4ec0045df0d1518": { + "balance": "52505006485983000000000" + }, + "c66b1d84c42018b16dbc4777409bf50a49febba9": { + "balance": "9078953000000000" + }, + "c69e4de93457f251b1e0879b5250b26e57839fec": { + "balance": "500000000000000000000000" + }, + "c6c51205c9f0bcaea05dce8e47e91d94a3f63c2a": { + "balance": "2720612321571000000000" + }, + "c6d237e0936c4714e701823aadb368fdc471451d": { + "balance": "541700595551000000000" + }, + "c6dcac15739872089cb3d23287e8cd546487ecf2": { + "balance": "1023857245227000000000" + }, + "c6f40b81a5860dece34305f53570be61cdf9a8fa": { + "balance": "20000000000000000000000" + }, + "c7147a95cc4f6bedce6292e8f95539caf550e9d6": { + "balance": "20000000000000000000000" + }, + "c7185b1a680d8b0893065d8213de54375d086420": { + "balance": "11564622085000000000" + }, + "c71b3876613c928197aadf3dd7888db3665f28f0": { + "balance": "112276274428000000000" + }, + "c72200bb380db62a3fd741713d332be77bc1a4ed": { + "balance": "6962060809000000000" + }, + "c7345cd5a7eafc9d7ebdc17d674f83e23336538c": { + "balance": "4425703195684000000000" + }, + "c734f9dc3ee2d857ac826b101129eb77a4a22256": { + "balance": "100000000000000000000" + }, + "c736fa9550b73f4a4ca0ac1cd94bf6f42ccbb11b": { + "balance": "449139000000000000" + }, + "c74128ea37f5d1ee016086a38e470bb332eb5270": { + "balance": "40479951869000000000" + }, + "c7647ec91e823cfe57e8a3433ddafd7b4f675b80": { + "balance": "307102062000000000000" + }, + "c76d49334ce25f5fc62841e5a87d4e03ab3edd9f": { + "balance": "109999979000000000000" + }, + "c771093ed5c4df518536b76e013e8142ecc3f9ed": { + "balance": "5247752820195000000000" + }, + "c780dfb4cdcba4dc89245a8be8a93de1a3e82d3c": { + "balance": "205580199482642000000000" + }, + "c79c6c3a0a46052f723a26b1f107a332474df3a1": { + "balance": "50370325181000000000" + }, + "c7a4e02d2c0f00fa56662cc9f323cabeff82759f": { + "balance": "1163435680762000000000" + }, + "c7c0632cff11812130c30163c83746839a625f95": { + "balance": "10000000000000000000000" + }, + "c82238664bedfa8ded51e91969a39f13a8262a37": { + "balance": "10000000000000000000000" + }, + "c877d228c350ec0d8d97802e7d874d3130171813": { + "balance": "199845203467946000000000" + }, + "c88b8a2e498fee366a1290a575a7f09da12ea8b2": { + "balance": "50895598476000000000" + }, + "c8bbd0e52b11ae6a20adc5f6bbe4d34d7440e8ca": { + "balance": "114566193776000000000" + }, + "c8ca2bd1bef02b505f0333996bcb6bf730648390": { + "balance": "1177250974576000000000" + }, + "c92c3358910418fdb3950e1a378af7246553ae38": { + "balance": "81000000000000000000" + }, + "c9325c9b6d2af226bc5ae1cc975e00cc11274cd1": { + "balance": "2927587698197000000000" + }, + "c95ae8dbc8bb075e7dcb2b2c6d9411bedf26244e": { + "balance": "931878010706000000000" + }, + "c98fc33c1d980052d75fee8b34d08796734b6a4d": { + "balance": "8671327034000000000" + }, + "c99fba8321d16cb19c55703b407c54ed106dcdc4": { + "balance": "20000000000000000000000" + }, + "c9a0da2a3be799e751738e61b9cc376eb06e2b00": { + "balance": "50000000000000000000000" + }, + "c9afc551058c32e89bc2d6704d0d00e92f5ef6d7": { + "balance": "11135553563900000000000" + }, + "c9bfa2ad4b3e9c624255c6ede116421b04487d65": { + "balance": "105514983171000000000" + }, + "c9e4b61d8ddeee339e31ba088efb5d608c3464a5": { + "balance": "20000000000000000000000" + }, + "c9e9090d9f95f401c87c7240f3bf88ca9b540f8b": { + "balance": "553735838243000000000" + }, + "c9fd40bb35284e3d7f0dd3b43a1d9e958f7c86e0": { + "balance": "50480449695128000000000" + }, + "ca038c7c9e66531ad79e4d67b42d7920b7f05c26": { + "balance": "64000000000000000000" + }, + "ca0d08f6019884f94f2b5b191ac9bb247150cd13": { + "balance": "25078089364984000000000" + }, + "ca2c6e6ed3d6a1d030807f91e1fd5c79d36af86f": { + "balance": "849454139892000000000" + }, + "ca7c7bbc24cac0f3aabfdccc77df21004672e634": { + "balance": "6952718700000000000" + }, + "ca998c74383b55c8dcddd46b49f95456fb056b7a": { + "balance": "2000000000000000000000" + }, + "caa989e6a1e934532aaae6cad282c18b1a0b9fd6": { + "balance": "2335540529729000000000" + }, + "cab32ee5cce74e0ee88bbd4b505aa587ef2e4bbf": { + "balance": "75914058971000000000" + }, + "cabe9f0d0a18de8d3495dd063b04c6a33584a8c1": { + "balance": "116083536145000000000" + }, + "cacde94daeafc06e46c86b1e20387a23d909ace8": { + "balance": "1521003430346000000000" + }, + "cafbad01b81ad6cc401883773994a9dd6e6ed913": { + "balance": "10000000000000000000" + }, + "cb343b882cfe866f73cd5f0f31fc68cebaddd882": { + "balance": "221801563082000000000" + }, + "cb3a7aa2e97517b6ea8d9ed0ac270a6a9cc6e079": { + "balance": "958830201738000000000" + }, + "cbd2c4916211ab2c234bc8a51e6f680b59aff782": { + "balance": "24279462419000000000" + }, + "cbea4ed5e8d2ffad442e482fa5f8d551ef2a58e6": { + "balance": "26730000000000000000" + }, + "cc001ce4f4417505116486bed9fdf04bf97ca246": { + "balance": "31740534557000000000" + }, + "cc0b53b26b6dee9f8226f25b834085bde13f5eb5": { + "balance": "132440104515963000000000" + }, + "cc174862456f02f349303d1b8328495de8ccd789": { + "balance": "155951512603000000000" + }, + "cc2af3921727d6d2de31d5f656f837a5475de6cf": { + "balance": "10000000000000000000000" + }, + "cc3201749f55f0d7b450110bc11f65b1ce165d2a": { + "balance": "123428947550000000000" + }, + "cc3f37ad6b449e39c544e26bbdf4d7be66b9dab0": { + "balance": "348574664284000000000" + }, + "cc5b36c9ecea12ebfd0721a58ac11b0c340a3f44": { + "balance": "384197170701000000000" + }, + "cc5b410c7797faa05ac4233eb31b468ee4bf279f": { + "balance": "10000000000000000" + }, + "cc60b223554cc6425374c5e2424df7007621368a": { + "balance": "1128118098000000000" + }, + "cc7027381d98c2e883c82bb9c2f85b985e1e7b4c": { + "balance": "1370000000000000000000" + }, + "cca378f16e07258b9c15921233110fb4729645d2": { + "balance": "151974946930000000000" + }, + "cca781d996c3ef985bf7d2b4d68d55f52efe1905": { + "balance": "2217463190039000000000" + }, + "ccd0b9f6ffb0383553c355c6a14be1200966d47d": { + "balance": "12917165349191000000000" + }, + "ccfa4594129bbb9d07cb4ae8dc2b1c8f3bf98508": { + "balance": "524845286088000000000" + }, + "cd19c879df458106d179bbb5b7f44609d68e6e5f": { + "balance": "8601633489844000000000" + }, + "cd1c55037a0570e8f9aaa95ef157ae81a1969250": { + "balance": "10000000000000000000" + }, + "cd1e47695b0fc93b82cffd0326852dc04d8441f0": { + "balance": "144000000000000000000" + }, + "cd1f90c388d76b3aeaf77850f2191f12a2311f51": { + "balance": "1728456799866000000000" + }, + "cd3aecd58de07f80b64044875fa6ad4f18f72789": { + "balance": "2648597880142000000000" + }, + "cd4f39123ece1e0ab52cfa2a5d059b49c4d63c3f": { + "balance": "1661718859439000000000" + }, + "cd6ed2f7ab49515f8fd70aeb4d72bfae8956b5f1": { + "balance": "183807926254000000000" + }, + "cd9d9d07fcf476a8ee7240324a602449606d75f4": { + "balance": "100000000000000000000000" + }, + "cda66d375a10a22f13dff8a9c40b63461daddab3": { + "balance": "1116940051064000000000" + }, + "cdb0832ee5b26da24b1775c4cf0dfd669b94ce00": { + "balance": "23919219542965000000000" + }, + "cdba5805f17df1f3e47647464de978944ed36b62": { + "balance": "4204539000000000" + }, + "cdd1df8bd54941e26ea26eebbd537e751f64f5f7": { + "balance": "5000000000000000000000" + }, + "cddf5b34342200c37ba96eb0dd662ca4c29f89f8": { + "balance": "10000000000000000000000" + }, + "cdf6c838980afd91a600e3fff755a4848d138568": { + "balance": "25000000000000000000" + }, + "cdf7f55a5a16572d2f2bbf7faeffe3c4d64f86ab": { + "balance": "3115969322502000000000" + }, + "ce0f1dbbfa3490a21ee4b28232db612f44bb7bf1": { + "balance": "9227310122000000000" + }, + "ce33184573c33dd859450304984fa63ea4f2b62d": { + "balance": "7055925237496000000000" + }, + "ce33a3db107f01c51d30b24a8db80faf05308bb7": { + "balance": "10996113113089000000000" + }, + "ce4922b3daef62914f0580a55c524e6a02e31d83": { + "balance": "5541295938315000000000" + }, + "ce4ce8a8540678dda16380c211482dd8c8b71092": { + "balance": "6224176337062000000000" + }, + "ce62cfd71abb9979a0acc398c17dbb5cb6da4721": { + "balance": "13448605175000000000" + }, + "ce724bb30c7821a9c847e0a3e9c12843c3471f9d": { + "balance": "252657175031000000000" + }, + "ce8af01494c2c5b4e74bb02dc6de982e7234fed2": { + "balance": "77349533545000000000" + }, + "ce8c774b7f92045faec43e9cc1711224a3b32435": { + "balance": "370287579971000000000" + }, + "ce8c9ed5018559f36ec72e5a9b0701724e498b51": { + "balance": "142866501748000000000" + }, + "ce995c13568a8b1521d4c9721cfc11da4891860b": { + "balance": "1000000000000000000" + }, + "ceab9dddc767a9651e98527fcf51f6e85c9ae402": { + "balance": "5251411770975000000000" + }, + "ceace25f8c7cf853500a461df007f9c9703ac4a5": { + "balance": "1428847332255000000000" + }, + "ceb0c49dad36f6169ec82a2f0d80da36c87e4209": { + "balance": "459821324064000000000" + }, + "cee8083233bcb4d50ddbf2121c90b5c2019ca58d": { + "balance": "557985245088000000000" + }, + "cf0c6bcc66eb75899bc7f8ed4b8d2b29437bfe85": { + "balance": "3252418478000000000" + }, + "cf32c5bf1d7ef0cb0f2f190f8468b01a4f2d93e2": { + "balance": "6593164924646000000000" + }, + "cf6e47463382153fcf0ec6738880925dbc08116a": { + "balance": "1091910654350000000000" + }, + "cf7539096fd0cd97cd316efcfe9d3c87a101a74c": { + "balance": "741847588809000000000" + }, + "cf9439bf2fbab65cecd783e135a37127f585f1e5": { + "balance": "50100000000000000000" + }, + "cf9bdc902604fab070c611ebf6a989ac4a785c82": { + "balance": "1501000000000000000000" + }, + "cfbbefc0e6013fa2caeabc54ac05f45dbf17ca13": { + "balance": "230809632301000000000" + }, + "cfd53f18ac7d94cadd032a0f4cdbdffaf4765d6e": { + "balance": "64000000000000000000" + }, + "cfe66dc4aa9ac9c9f87fdd05c1b2b95da5211703": { + "balance": "1656993051100000000000" + }, + "cff376eef4d69c4a47d6c7916583228fab3b5967": { + "balance": "5904462494391000000000" + }, + "cfffcb819302d05ed763026bdf84b48818938fb0": { + "balance": "289619807900000000000" + }, + "d000aa72a77d55911a5e66c2906da9206db86633": { + "balance": "3008989624945000000000" + }, + "d02d7b42213e873f91e789cbaffc734ffabd1087": { + "balance": "144960809826000000000" + }, + "d02db5279e918b3e93ff81d00d4025cc71dccaf6": { + "balance": "2386625717975000000000" + }, + "d0802cbcca2bb516f251b873eb20bb5e94af7f37": { + "balance": "9287997718210000000000" + }, + "d0c07380308972a36f57d1cd9081d7389d0421cb": { + "balance": "1280367167470000000000" + }, + "d0c131c1b60891b91e58fbed787ee4567e3f2038": { + "balance": "6360752089492000000000" + }, + "d0c71159d46c4d2af7699f682a055c79a1a68a0d": { + "balance": "1527974433762000000000" + }, + "d0d5d9f242f2613079b3b443c359c2e18ed5faab": { + "balance": "637334647476000000000" + }, + "d0dd208ce92da02eee3ee3de335e67f819581a33": { + "balance": "100000000000000000000" + }, + "d0e55ec0ad0f8986dd9fa9d738007c5bdc22f840": { + "balance": "53012893797000000000" + }, + "d0f222cec657ee444e284c07228d585155b82c0a": { + "balance": "7368748129592000000000" + }, + "d11efb07887d8b5b87a77d8fd388190614e8c077": { + "balance": "4703283503278000000000" + }, + "d129f1b89045ebfb4d1df1d9077e9359fd2990f7": { + "balance": "14496053137000000000" + }, + "d15a509424c4e04868bdcf59cbee09882ba04c8d": { + "balance": "65042393236903000000000" + }, + "d162416912b03fa65f3972a63e357ceaa3b621f7": { + "balance": "325650177224000000000" + }, + "d166183164b81bd049b2146a3ccfcc78cc6a0bdd": { + "balance": "1000000000000000000" + }, + "d173d759f0916e61400d56ca690cbf1743fe27b0": { + "balance": "53550838679000000000" + }, + "d18dc883e3881bf4c7db2afaa097bc2d33656724": { + "balance": "5000000000000000000" + }, + "d19dc9b5ae689dea1ccbfea8b44ec6034559e326": { + "balance": "135552499885000000000" + }, + "d1c79160d0b8c1a1546b86db5123e87645a45d13": { + "balance": "10000000000000000000000" + }, + "d1cccaa22259c547993df3c147d5b545f003adb8": { + "balance": "10000000000000000000000" + }, + "d209c9f32f3292ac4d15ef353fbe6f6efcd4e49d": { + "balance": "81000000000000000000" + }, + "d21ac89a20d67e309f96f64adf05fc48f55918a9": { + "balance": "500000000000000000000000" + }, + "d21f6e7adbf480600295af683091f9b9833f5330": { + "balance": "1229445878922000000000" + }, + "d22700a47a0edb137d2f0348aa0f8d4b6dbc5850": { + "balance": "21301422923000000000" + }, + "d258ddc9372e3b70ff53da171252239655ca9886": { + "balance": "16000000000000000000" + }, + "d274c69317dd836df48562455e8f5a7bd2e47d19": { + "balance": "156091832558000000000" + }, + "d286b68a358fcf8a6cec70b83467079664632ae9": { + "balance": "90377010699000000000" + }, + "d29284915d9b924ae5673e8a4a557478f68a7471": { + "balance": "324678197320000000000" + }, + "d297e64ac2bd8e98e6d276d6fe080679c398a26a": { + "balance": "3401930527000000000" + }, + "d2a1e7b51f6b5930a0d9e2ee55736f3d83a1b323": { + "balance": "44578900750000000000" + }, + "d2c9b0b0bbe61de504e4f210c168fa5999c9c23d": { + "balance": "76537483113000000000" + }, + "d2d49f650d222ec3e2cecba163ee92f0e934ca14": { + "balance": "3312486482635000000000" + }, + "d2d803bf10ba18adef5716b4056c1b1d61c45abf": { + "balance": "964679698000000000" + }, + "d2f673b589df7ef5cb32fdeef842d48d66130567": { + "balance": "1079010447581000000000" + }, + "d2ffaceef1af3f1c3e3f35e4062cd9f9abd1da59": { + "balance": "3041453068594000000000" + }, + "d30a74f5041ec6e73d066a375a105116699ce177": { + "balance": "21814020745000000000" + }, + "d30d849a2d8ff5041304014ecf6752dc769bf004": { + "balance": "1247532881540000000000" + }, + "d3113f558c6376321691931c9b21205e31f4a56e": { + "balance": "572224428451000000000" + }, + "d314bac1bf85eedeac0b359dd2106dbae8fc6947": { + "balance": "20000000000000000000000" + }, + "d3283e17112028b324327ef64a238183ba189207": { + "balance": "136000000000000000000" + }, + "d33ce3c3b64d1b3d399651432c15ecb943d16c70": { + "balance": "10000000000000000000000" + }, + "d33e1e4b10a98e82810f6d161df5d35e5677e35f": { + "balance": "10169656674000000000" + }, + "d34699fd152fe38caacd3c096f6abb1cd79e88b2": { + "balance": "25056644550000000000" + }, + "d369c0e01b9a9d519b3b099a98fead19867c019c": { + "balance": "100000000000000000000000" + }, + "d388dcfe55a9b710d05c686f033fdbdd7861ab71": { + "balance": "1439589263065000000000" + }, + "d391a7d45c7b454b743bd867f8f62f56894f9b65": { + "balance": "484904747488000000000" + }, + "d39a75b4831543e1bc99e7a5ca8875c4f69da45b": { + "balance": "10000000000000000000000" + }, + "d39ed6978b6a90fea29e735f8ea3f1d20e0fbd15": { + "balance": "144000000000000000000" + }, + "d3a0a1a00dcbd6bc44c9803ce351a4b36a69c929": { + "balance": "191222401916000000000" + }, + "d3bf1c0a6b0470c30fc49d995025af5e6b639e61": { + "balance": "10000000000000000000000" + }, + "d3cda762bafaf204469f85e6896ec64147a3452c": { + "balance": "468094119213000000000" + }, + "d3d04d78c1ab9e6887a9467b8b1e31b5c9910e5c": { + "balance": "81000000000000000000" + }, + "d3e1bfdd9396aba00d3e78646ddcdaf139a967c0": { + "balance": "833333174120000000000" + }, + "d3e502c42ff0274da12ba87ffd45fa593bba052a": { + "balance": "100409899947269000000000" + }, + "d3e76066c2e32d9a693161de07f2d3b7e6ea07eb": { + "balance": "10000000000000000000000" + }, + "d3e8d577323d97407246b198c4c61f7943c468cd": { + "balance": "10000000000000000000000" + }, + "d3fd4d1b0edbc314b103d350fff023ab75b7d7cd": { + "balance": "84129547428000000000" + }, + "d40087fca8feb72d130bbc9622575d4987f12895": { + "balance": "1000000000000000000" + }, + "d407d4126cbf3619a422c532ccf20c3da1495dbd": { + "balance": "99622000000000000" + }, + "d41a28761c8e5de8c803813667f1dc0918a105be": { + "balance": "157507410260000000000" + }, + "d46ed38228a3c3d78065b2d8b71b325bf0f0e685": { + "balance": "6787045850000000000" + }, + "d4a7463d202e804b39a93bccd77491d8791baf58": { + "balance": "171694163573000000000" + }, + "d4c20716ff7288d811d05fd6f0696a9f5627a11d": { + "balance": "100000000000000000000" + }, + "d4d95059c808cf41e64f7f353246ffae635419d4": { + "balance": "10000000000000000000000" + }, + "d4ef925157c6d0e2d649332f44416b85f8abe69e": { + "balance": "1392945162611000000000" + }, + "d4f0cb25801794f6d803306878763e08209d19f4": { + "balance": "64000000000000000000" + }, + "d55fbebc4dcf2de6341c2325448e9c198f0f06a3": { + "balance": "14206622892000000000" + }, + "d566968c40211fb25114105e36b5a7219cde9d5f": { + "balance": "4898442964000000000" + }, + "d5817b95c6b504a6d07f64faccc9aedf408b0ac4": { + "balance": "54387832478000000000" + }, + "d59679fc40a71897065bf1b3a73f331226cdae72": { + "balance": "20000000000000000000000" + }, + "d5a7deec4a5898f094e1600f9b15768d8aada258": { + "balance": "100000000000000000000000" + }, + "d5b91c29bf772ad3ba04033dfb86b672b245ad77": { + "balance": "100500000000000000000" + }, + "d5c1a9bcc5e68b7547354178fefb3d870572fd67": { + "balance": "2252066779089000000000" + }, + "d5da2a826f5909a221bfd8561dbd7dbf4aca4c35": { + "balance": "13839784966766000000000" + }, + "d5dcc82fa169b4677a3fc26d78f38e27dcc763f3": { + "balance": "10000000000000000000000" + }, + "d5f344ee8a1b954ae5fd8fc7ac702174749bc8a4": { + "balance": "1398836216771000000000" + }, + "d61cd03afbfc1bea186e5a3a51347c2c4ee3a2c3": { + "balance": "109879472702000000000" + }, + "d647fd7ca17203a0049c28ec6759612d767cfcce": { + "balance": "162681136487000000000" + }, + "d656d14acfb2f0fbde2ed2a137a52d852bb6288b": { + "balance": "20000000000000000000000" + }, + "d68130b421b19c193d03a9017b2dc687c7307d26": { + "balance": "128569735484000000000" + }, + "d69a41f7ca76b40ee94b0d04a3780a00c6c651ba": { + "balance": "2801054372864000000000" + }, + "d69af2a796a737a103f12d2f0bcc563a13900e6f": { + "balance": "7412286547000000000" + }, + "d6a5a7e149cbccb72a50b0a3ae00e6756b0a7eda": { + "balance": "1075352201657000000000" + }, + "d6aa9957f141f0dfed77e943c39aeed978834fdf": { + "balance": "20920740110000000000" + }, + "d6e99ccb72d24e8a60f24d47afd4074b1d1fd336": { + "balance": "15415994387186000000000" + }, + "d6ea4a9dda8d5bc832229c916fa45f05f99c093a": { + "balance": "27075799893190000000000" + }, + "d71de419d746ac277baa955761cced4b34c376ec": { + "balance": "1388473506822000000000" + }, + "d71ec6b5e5d4c604f741bafde0974eca49c56156": { + "balance": "61938809628000000000" + }, + "d72f90d9879f6d2d407b4fdf5d128b98d518f1a5": { + "balance": "10000000000000000000000" + }, + "d743d7925a0cfd08150814cce8cd5d3f7099e1c9": { + "balance": "25681376856000000000" + }, + "d7575a09e7498f21cda3e9e7266b7fde91dfe19b": { + "balance": "9841565066000000000" + }, + "d75c2eb5e0a2b2ee72ef4fa7249c1a1ce03f333d": { + "balance": "134491489751000000000" + }, + "d77088329ec1e280ea7a087ad20c5e965721ff4d": { + "balance": "3949070941222000000000" + }, + "d78d564bb79ea19e4a93975a38fe0882018f177c": { + "balance": "992717434142000000000" + }, + "d78efb176b252ce67b5648e04088d12c4668aad1": { + "balance": "10070463674000000000" + }, + "d7a25e43d7d4e23744f0b10e2b4f2911fd3b3bc1": { + "balance": "1000000000000000000" + }, + "d7a941cd82f8aa63c55baa81db44bcb347b8e529": { + "balance": "49000000000000000000" + }, + "d7b34387880daede6cbdad11bb3db67daf942975": { + "balance": "20000000000000000000000" + }, + "d7bca0770e2f890c1e93c3595641241454a31045": { + "balance": "2000000000000000000" + }, + "d7cb675cea1c0dafded44f611c9c344e2a5e053c": { + "balance": "25000000000000000000" + }, + "d7e53a2d8eaefd18e02bbadb7e64906ca8613151": { + "balance": "166599594268000000000" + }, + "d8076b9db0b7496efbd198b73c4bfcf51ac080fd": { + "balance": "210272077089000000000" + }, + "d81dcf5756da397ff1f783ffe5391d1ffd4ff227": { + "balance": "500000000000000000000000" + }, + "d833c6d08f5fff8f77628ab1e86584d052976d1f": { + "balance": "10000000000000000000000" + }, + "d835732e85953baf2af9e49f770bac1caa1dac23": { + "balance": "152211441541000000000" + }, + "d84005fea447e8c6aa0b5436ad79654a75348456": { + "balance": "22563694224690000000000" + }, + "d84d9c59a445911922e88c0f22cc6534f33ca3de": { + "balance": "3054115413381000000000" + }, + "d84e69926216065749e624d87783e90ce3015b82": { + "balance": "1420803164313000000000" + }, + "d884bdbdb7e13cc523e7f192310230c7bdbb4a07": { + "balance": "10000000000000000000000" + }, + "d88eedca1dd9249702f5ffc807c1e439eee1c5e5": { + "balance": "36000000000000000000" + }, + "d8a23fd234bada1c726622925ade62d3021e0037": { + "balance": "1567046607931000000000" + }, + "d8b1aee24264efebd1c677fcab6ada6e0f000cc5": { + "balance": "20000000000000000000000" + }, + "d8ba7afbb8bf2910b983a114aedec626eb7426c1": { + "balance": "275491152435000000000" + }, + "d8c8af55ebf116ba3c3904f8ac39d3a7d31aadc5": { + "balance": "1499999998278000000000000" + }, + "d8d97645f5f62aa89bf0046362dd0f45d40f821f": { + "balance": "25000000000000000000" + }, + "d8ea0e24a7e28285c4454f54181d581324da2583": { + "balance": "53039425000000000" + }, + "d8f5d258164747ccf790f5ed358162c756de49db": { + "balance": "323009990690000000000" + }, + "d9477bb62d3eb668a83a9679f3a7ef43f17c9e4d": { + "balance": "14045557127869000000000" + }, + "d9585e1b03fc86636dde1e64aed3cad77868549a": { + "balance": "1000000000000000000000" + }, + "d975f9ce3fe773fac3f8338a034a757c58f6e11f": { + "balance": "25000000000000000000" + }, + "d97e490faf19de612fb49c041d3f9e7877d3c0bb": { + "balance": "65766847746000000000" + }, + "d98117b74b2f2888d7078d3116d5758e2d09bfca": { + "balance": "1749157484422000000000" + }, + "d990b3f69ec700bdc095c184b3804551c832d612": { + "balance": "509385034698000000000" + }, + "d99b35298e709e5f54e6a5c612a326a83f4268c4": { + "balance": "71963571266000000000" + }, + "d99d9ec76005da26ccc721ec26be4ed9b3b1c586": { + "balance": "469607736824000000000" + }, + "d9bc61075c3201351584a026e5bdfb7cf9a7b6ab": { + "balance": "200000000000000000000" + }, + "d9d07b72f83491b6db26602f6b7039aeebfe6b61": { + "balance": "144000000000000000000" + }, + "d9f6f1ddf03e836b3744d008b62a6424544c67a5": { + "balance": "74347470143000000000" + }, + "d9fceff07ad69bf3b4aef54a7eee541368980cf6": { + "balance": "1143407707495000000000" + }, + "da0285fb7e37fd4be66fb862b248cea94ea8f6db": { + "balance": "80770216661309000000000" + }, + "da05c7aa330fcc5834e19deeb0a808e9ab7f3d99": { + "balance": "169000000000000000000" + }, + "da129e4481bd25450e6c7b42fe417c87ee2ce7a7": { + "balance": "256000000000000000000" + }, + "da32e3ec421993db088c71e256263158f7855b61": { + "balance": "18540215888567000000000" + }, + "da3c99669acd202ccbe6f80902c807588eca0880": { + "balance": "1000000000000000" + }, + "da72a7bec114d43aee6449db830d2d3f16e4d9b6": { + "balance": "744534872932000000000" + }, + "da72ec2cd7b8e3924f8baaea75d5ed23ef39394c": { + "balance": "38646377617204000000000" + }, + "da73078957f491827d62cb3ca0c484c2d1004ba7": { + "balance": "891774109242000000000" + }, + "da828e50c7c8580c6ce81718f11fbd43b2b0541f": { + "balance": "66094097819000000000" + }, + "da91483db6a6a034e068e69a6b46674838c5bc80": { + "balance": "4000000000000000000000" + }, + "da9551b635c3619f81641571e267755b89f7fe1e": { + "balance": "670841942250000000000" + }, + "da9b43a9c1c574580ec43da9f6acb687fc2f8c68": { + "balance": "761695404114000000000" + }, + "daa7f446923f7481115ad285ca468c865147e563": { + "balance": "10000000000000000000000" + }, + "dac6bfd15954efa4c9254e24e5831ab1884f8d67": { + "balance": "960042043423000000000" + }, + "dad85d0b8bb5ebf6ef811d0d35c89f9f343c833c": { + "balance": "37664599958479000000000" + }, + "dad9b01652de5d50bf30f9bcb0c6edc6315139e3": { + "balance": "21500996724000000000" + }, + "dae9c7d6bb0efe3f7ea20442b184f6d99b2a2c12": { + "balance": "937830189066000000000" + }, + "db0d6c28e9b913f611accaab15cc887f9b770f58": { + "balance": "20000000000000000000000" + }, + "db0e5341d64817885721c5abff04c30bd38df40f": { + "balance": "62600679700000000000" + }, + "db387dd404d14478babb60bad2391720d68b92ed": { + "balance": "115096708329000000000" + }, + "db3fb19e8a4a6ace4d8c6c02085d4cbba528b532": { + "balance": "1000000000000000000" + }, + "db4f05a66c0ccf0532ea1ecb931e05a400a6f4a7": { + "balance": "20000000000000000000000" + }, + "db571f1cdf8e83fbff6fb48cc0c81ef95ede12a0": { + "balance": "118317387393000000000" + }, + "db6a6a6db2aef3f43afbfe23027b670ebb3d33bf": { + "balance": "9960755220000000000" + }, + "db8bed34f8f34f45cb83ab19ed33fad76437d217": { + "balance": "21003651205000000000" + }, + "dbeba6a2a7f66c20c6db7b9270a5aee74de3f441": { + "balance": "4086905723945000000000" + }, + "dc04efeac13b2dab3d07833a7e7fa728fc23d18a": { + "balance": "1161834099120000000000" + }, + "dc092386c3a3e28b6b2d7d70db8f3d11e79ef5df": { + "balance": "124362293793000000000" + }, + "dc10be66aa11acbd42a2b1953714f09b5281681b": { + "balance": "20000000000000000000000" + }, + "dc2d58a383ce0bd40bed859ec2f25412b68eca0a": { + "balance": "104917823922000000000" + }, + "dc2e38183dceb2bc82b23e8ccf48dd96ea1c97b6": { + "balance": "2847787376064000000000" + }, + "dc5d9d94530d88451cf081fe7f2ac33667af9d8f": { + "balance": "65321904051000000000000" + }, + "dc993112a8d89136e0e73d67e2f26191583a50ec": { + "balance": "1000000000000000000" + }, + "dc9bb69b295945589a41feb794406558ce65dedc": { + "balance": "104077637254454000000000" + }, + "dcb0109d4fca2dace08ddca5d989a09d470161a0": { + "balance": "28897833222000000000" + }, + "dcce3a4ec516d833f5a9790c40ad0334b0d2dd01": { + "balance": "25000000000000000000" + }, + "dcdb21cc811ab733c2a80a2d5c8e5bb49cb2ddc4": { + "balance": "16000000000000000000" + }, + "dcdf8dd3ce03a2fe0d72835dbbd58725e1ed2c57": { + "balance": "113330414284000000000" + }, + "dd2165839ab95d6b24591307adcde9ee1819927a": { + "balance": "20260199589072000000000" + }, + "dd3015a5fdef66e749a000585d5574f975e3432d": { + "balance": "85465001652000000000" + }, + "dd37c478727f44943c5fd79ace30f21fae5a589a": { + "balance": "108577233510000000000" + }, + "dd3fb5810c31d37652bd17b92497ed479faf123d": { + "balance": "669996966072000000000" + }, + "ddc3bda30f7cf36bd535de4e20c9becb78d159f4": { + "balance": "99998278000000000000" + }, + "ddcce2d2431b67d4157c7ac4bd77f20c24831de6": { + "balance": "36160893899000000000" + }, + "dddcebe609f8b4354a1f27ab1915135e25800344": { + "balance": "1457846339959000000000" + }, + "dde223eb48f81748abde6cbc08cf1e6b0e8e4e5a": { + "balance": "1501921107087000000000" + }, + "ddf4ba402007060d9940a96f8e7c39f0a2c6108a": { + "balance": "377268151287000000000" + }, + "de05d9ada6626a8492acd137c7c7f7080a987cd1": { + "balance": "222144234923000000000" + }, + "de0fab89f79c4edf9766c3b7b1f508cb43c5495e": { + "balance": "8278000000000000" + }, + "de1070f3ff6c47237768fbdead88b2d5184fbe2f": { + "balance": "1000000000000000000" + }, + "de2b16d7f36f630329287822f550ec19415acb3a": { + "balance": "25000000000000000000" + }, + "de3faf6884337a99e54ac5d3f08b34be51b0755b": { + "balance": "51926806905184000000000" + }, + "de4614fd632ddac888d177de0858e62bbbf7dc11": { + "balance": "52506376589000000000" + }, + "de54cabb241dc5def530191f948f67db942a85b0": { + "balance": "9691177060000000000" + }, + "de81e488284acc4f8f6061d3a73bad112efa7a40": { + "balance": "14654060992000000000" + }, + "dea86ac3a661272691c877c1bad8355789382b69": { + "balance": "903877103000000000" + }, + "deadfc79f2a722dbf1c1a92f2824da8874189fea": { + "balance": "98905944986000000000" + }, + "decf1af47e153f6f3749a1b7abadefdcf1607a0f": { + "balance": "529000000000000000000" + }, + "dede5fa984f0def639d5b633f54c60fc5aaa272a": { + "balance": "8193771708654000000000" + }, + "df23607c63b3fd4b5fde6aab093c0c56d1188f95": { + "balance": "14687379916000000000" + }, + "df5b74bf02902e4c466821de798406b663d4d73e": { + "balance": "9000000000000000000" + }, + "df6402ee3f37389e7f65720561b54e26e5f1cbaf": { + "balance": "358266132937000000000" + }, + "df83ea5b770d5abeccac7f0cae803e8bd7b9831d": { + "balance": "25000000000000000000" + }, + "df92802ffe9892c7704875755bdec648914430e6": { + "balance": "20000000000000000000000" + }, + "dfa108bcd80e824a255679a38b2450d428e2f939": { + "balance": "489209553654000000000" + }, + "dfa9f18e859353796afe384d05353dc80b3ffc43": { + "balance": "121000000000000000000" + }, + "dfb0d6580f011e68a39d7727818b0890e70f3036": { + "balance": "537675412560000000000" + }, + "dfdf006abf2293aadc58feea6af6b35db428675e": { + "balance": "9000000000000000000" + }, + "dfdf2ba93bd47d7243b7419413458a947effcf67": { + "balance": "45080282196110000000000" + }, + "dff01277ac23a8cf93383595a80a7c070eafe5c6": { + "balance": "312778552103000000000" + }, + "e0450154c441e52c5e507e8316d4e9376c59c12b": { + "balance": "170163401434000000000" + }, + "e059374d6a7e6c63e609b65642272869fa3b2b3c": { + "balance": "300122497803000000000" + }, + "e0c0d8e739a2f274a43f019a07f7f61d7d8e11a7": { + "balance": "2630310240000000000" + }, + "e0e779e4e3573ea77096daec252ac2b3f1c0013a": { + "balance": "10000000000000000000000" + }, + "e1325eb586180a67873718a2016172afeb03c6a5": { + "balance": "531691399657000000000" + }, + "e13958af480da6443b9ec1067f0f33440634a282": { + "balance": "10000000000000000000000" + }, + "e142daac753b2c4d215372797999e9c88b65dfc9": { + "balance": "585813299366000000000" + }, + "e142ea343bc36ec49989fd43ad5c403c70a40dbe": { + "balance": "656734902975000000000" + }, + "e14d0a3d259db6bfec2fc4ef6e18729e4d93b007": { + "balance": "210234446279000000000" + }, + "e16a5316e3a113f27bafdf3d4fe44fe30ae9c210": { + "balance": "16000000000000000000" + }, + "e1770944aec145a96c9491497eacf7f3fb03c1b2": { + "balance": "335417250470000000000" + }, + "e199ac237661dcac0a4cfab404876abde72ee209": { + "balance": "340000000000000000000" + }, + "e1ad427471023f38cbdf07fdca3728ec343810c4": { + "balance": "343957267368000000000" + }, + "e1ae0223cecd738c8e530a0007ef05e8f3b33769": { + "balance": "950528515289000000000" + }, + "e1d2d4ef39f01a60c3bb5d671af91c5298d87711": { + "balance": "121000000000000000000" + }, + "e1d4a8888cbb383f3671ca96e7b55310b59a2541": { + "balance": "242387826125000000000" + }, + "e1da9039ddfe117e6a0b484fd3962426c112871c": { + "balance": "3710499693813000000000" + }, + "e1da9f16d57c601af8b6d102323c20408af8531a": { + "balance": "3135322588771000000000" + }, + "e1e1c163f391ffad2d0be68641253b0860485a95": { + "balance": "10000000000000000000000" + }, + "e1ec6361df67ad915df9e9661cd0932186db034a": { + "balance": "4279936304854000000000" + }, + "e224050bcd723e63f1fc0567a86942546aaf8d13": { + "balance": "12007628539000000000" + }, + "e2342c7f411d7ca3a86484af59a9c3f3180e2f0f": { + "balance": "16000000000000000000" + }, + "e26f2b026a258ce5801c90bb8fd6f7a152b8d267": { + "balance": "304593714834000000000" + }, + "e2717eb5fd0a1da51272b50ca8d12858009c7016": { + "balance": "506943817535000000000" + }, + "e27546d5620e6398829260e58e8cf4a3a03f4164": { + "balance": "3000000000000000000000" + }, + "e2762bb64e0606a5d635032e15164b01f612a74f": { + "balance": "884716158811000000000" + }, + "e2882066ed0a3c041d09c00c8532850fc42eac06": { + "balance": "42441412728970000000000" + }, + "e294c5d64daf7b7c0994aa9d03669c4b2658c9cf": { + "balance": "6996693830997000000000" + }, + "e2b179f0ed6870a6268aea64b0c7b39d98d97fcf": { + "balance": "334205318353000000000" + }, + "e2d1f6f7e3128340b789565b527bb91de96d54bf": { + "balance": "100000000000000000000" + }, + "e2f136d3693aa0b2346a968a22aca6707fc1d0e5": { + "balance": "10000000000000000000000" + }, + "e2f229054293e32cf3e83f9bb88d9cf1d6acd66b": { + "balance": "20000000000000000000000" + }, + "e33b8f4c9a49554c8b134861f88c8fffc399e456": { + "balance": "83552502198000000000" + }, + "e33cfc7727b1460324b34277dde14cc49bcb273d": { + "balance": "100000000000000000" + }, + "e36af9bfed4f912cae21f3d899f7354e1c902601": { + "balance": "31474316356000000000" + }, + "e36eff7c061dec48446d47675f176b4da3c2e950": { + "balance": "10000000000000000000000" + }, + "e383f3cf431f3cf645f26c7d5e5e2f77348ede6f": { + "balance": "776224304171000000000" + }, + "e398b9f004a4f891cf871a57d9124a97b56e89e9": { + "balance": "84846187740000000000" + }, + "e39ab2415144b46db522e92ed51b8089a5ec01fd": { + "balance": "4158925896363000000000" + }, + "e3aa7ac7e15e9a8a6f54565067234a9d4bf7b569": { + "balance": "1080385576951000000000" + }, + "e3ec5ebd3e822c972d802a0ee4e0ec080b8237ba": { + "balance": "2129139289000000000" + }, + "e3f1fbff8686af23ab95eeeee6a6a03782d72416": { + "balance": "401776848194000000000" + }, + "e4001b830fbd86df257ebab54aec0c66314ef9aa": { + "balance": "518220809325000000000" + }, + "e40790bff894f0b3e534942b5ad6f6592cd6e896": { + "balance": "25000000000000000000" + }, + "e409170a296e46fc96d85a2395e4324212a470ee": { + "balance": "1072528749756000000000" + }, + "e41546f68bbe1771febbdac2a4a5999eef50edf3": { + "balance": "1000000000000000000000000" + }, + "e425d63d711a9996c09d928ba8df94c88163aea9": { + "balance": "10000000000000000000000" + }, + "e4432ff1aee13f97f73a8407e4c7d6e768b8040b": { + "balance": "700508995102000000000" + }, + "e4690f5d024a395355a7cb5238fb7e0dc921b1e8": { + "balance": "1000000000000000000000000" + }, + "e4829684fb36f054766a61fb2a8f6ecdf27c9e87": { + "balance": "73885178137000000000" + }, + "e48a68e1ac007e14ac08c1b3b0df2b5602081ec2": { + "balance": "1389262869176000000000" + }, + "e4d699b3f4117eba7ed27b323048c9ffcb46ed42": { + "balance": "183131036697000000000" + }, + "e4db688c29fdf9a1c16114f99797d8409545955f": { + "balance": "16000000000000000000" + }, + "e535b94d370190d1e0955d3c0d12480e558f00dd": { + "balance": "20000000000000000000000" + }, + "e53966d4bb17fa9b50d29b44ddf3951c9ca67caa": { + "balance": "6400630678000000000" + }, + "e56f2656fdd1a5f7d3716e65dd89a37dd6e42dcc": { + "balance": "1000000000000000000" + }, + "e5a364113076273352e0c31bf505028e0b7edbaa": { + "balance": "10000000000000000000000" + }, + "e5a3c80518fab6a0a721ccbdc3e673680a65f6de": { + "balance": "171727917465000000000" + }, + "e5c71c7170e5c9b07e62cc307d81a4a3053ed64c": { + "balance": "10000000000000000000000" + }, + "e5fb6408db128c55cfb3e7fa1942d6347e34932c": { + "balance": "10000000000000000000" + }, + "e606883236f8b2045393c574153a100675cd4b90": { + "balance": "14005226900000000000" + }, + "e61869d1cf72f25e195898217f5bf5bcec9c9038": { + "balance": "50000000000000000000000" + }, + "e61e2e29c0719457ab1bf7d6d9fe442bd6107b07": { + "balance": "30943034333100000000000" + }, + "e61eb97093e9ee609647bd55f434a27bb30a9401": { + "balance": "200951434577471000000000" + }, + "e62812ad5834747f17c92435d863639e84d132fc": { + "balance": "3017271391299000000000" + }, + "e630b92aa8443eb077e1f6990a2e194d99cf53ec": { + "balance": "1000000000000000000000000" + }, + "e656fd1641c15e1a4b753be41bc4aa438b44b42c": { + "balance": "26972744083000000000" + }, + "e663f0257b98dfa80602a2af1bea1f901c4a7612": { + "balance": "97075813547000000000" + }, + "e66e411a8a9d019b53bf2e0a7e44703e1aa93ac1": { + "balance": "25000000000000000000" + }, + "e6712675d13fff27af43bb1cb3f2f283755bacf5": { + "balance": "227572496234000000000" + }, + "e68e8f04b2cff484da2d41dd639ae8880920f781": { + "balance": "20000000000000000000000" + }, + "e6972b5d7e0fe8c722dec9146b92f89291a0207a": { + "balance": "2115924954211000000000" + }, + "e698b491330cb55ecc4cc4b74015cd94eb927fc4": { + "balance": "1038111785278000000000" + }, + "e6c411e67b90109dbb0fa75f0f07ae8a504e9637": { + "balance": "123792105420000000000" + }, + "e6fb1dabc624edb45b040ad66f30dae010a6b634": { + "balance": "16076893670852000000000" + }, + "e71dac161206e7d3686d13b98fd922ab73587988": { + "balance": "500000000000000000000000" + }, + "e773f9be9b3f4b35ac149b4d759b9e47c8000bdb": { + "balance": "329623043336000000000" + }, + "e781cbbd2dccfdf68595d54fa44104a80d52dd22": { + "balance": "188679476509000000000" + }, + "e793666c7850a409b1d5494f576d122e85cfed9c": { + "balance": "1141845197779000000000" + }, + "e7a5527c6deb922e9f84309c502048f49f0c8f14": { + "balance": "81415566708000000000" + }, + "e7b0f75f9c69ae464b1b63cf295555d0815fc532": { + "balance": "10000000000000000000000" + }, + "e7b43cc673e321e607190a6fde996b71508f4d81": { + "balance": "103958781426000000000" + }, + "e7bfcf3125e37755e57804dfe4479657b212a8ca": { + "balance": "10000000000000000000000" + }, + "e7d33cbbd4eb38365c5be04ce32658a5ac741cfa": { + "balance": "1545192252109000000000" + }, + "e84cfbd7844f6aa3e830258a6b1069b6a7ff5b7e": { + "balance": "543989509107945000000000" + }, + "e8aa0cbc5c1f59fadf3ec122fa8a59ebfc60b5b6": { + "balance": "61271973066000000000" + }, + "e8adb5303c30a8ee044dc09c49818c02a16f4254": { + "balance": "737375689166000000000" + }, + "e8aeef5114e19d467c3064938c5965d04830f2ae": { + "balance": "51130466380000000000" + }, + "e8b5a83497198a513fb2e244bcf05f9d4cf09d62": { + "balance": "10000000000000000000000" + }, + "e8b6818cf0d24bd0e7ded854b3d368662a150dab": { + "balance": "63697741112000000000" + }, + "e8b68b9cb24169fd688db7a626d79d0363777c75": { + "balance": "427222669643000000000" + }, + "e8b8b57b23ea953943da3ef7efaefced9cdbb44c": { + "balance": "16000000000000000000" + }, + "e8f85dca364d26c2149b767904c6c06249c3d88a": { + "balance": "199342917246000000000" + }, + "e916c7801cdcf1b6cf640fcd9dcc1e3148c80105": { + "balance": "9000756000000000000" + }, + "e93cbef13277324caae7816c3d601e2f6bb42589": { + "balance": "121000000000000000000" + }, + "e9415fedcdf8939b551999900128530195a2a5f0": { + "balance": "85165078941891000000000" + }, + "e9a79ade714ce48a07fe88532a20d8f8ed27bac9": { + "balance": "30768493367842000000000" + }, + "e9b35c7ca775661bbd3a4844e2c6bc5effcdea58": { + "balance": "134719523000000000" + }, + "e9b819dffb600373bfd1b1608fc9744cc9167855": { + "balance": "1537634693002000000000" + }, + "e9c5ef50d4a194e53928659b4486a1c456df9e56": { + "balance": "50000000000000000000000" + }, + "e9e21f4523b11567516f6fc525e8967ac707f988": { + "balance": "2498740681000000000" + }, + "ea02821d6c730e061a9947b75188eb8bc0bbf9f1": { + "balance": "12822292582000000000" + }, + "ea3bca3a17c7e724ac0e15acab6442f222cd8688": { + "balance": "2789689549000000000" + }, + "ea4f7923d7045a148d50153f5f4620dbd31a74da": { + "balance": "113595858930000000000" + }, + "ea6d4cbae3cfe49ffd36653bb0d64c01b2bbc0b8": { + "balance": "49325017701000000000" + }, + "ea76cd4cff825301932a5c1d3a1de55a0ff00797": { + "balance": "1282028021000000000" + }, + "ea8e4c8c6500856777e2b41832ff00443db291ce": { + "balance": "553674550359000000000" + }, + "eab52191e5afc804b8685fe13d7ad6f5dc64fc12": { + "balance": "244412435341000000000" + }, + "eac1b0868b710e40d6d5c66a461dfc8f78abbaa9": { + "balance": "10000000000000000000000" + }, + "eacac2c75920b8f6e65f37ad81deb113d526d031": { + "balance": "53028042076000000000" + }, + "eacc9ef8b534143560f420031a8a7f030ff1a36e": { + "balance": "381111853842000000000" + }, + "eaf2cc9fdfe6272de269f32486b2d4c248a05afe": { + "balance": "2793234915237000000000" + }, + "eb0220406832a8a5d4f242538e82c80bd83d0ac6": { + "balance": "10000000000000000000000" + }, + "eb20efc0e0af48c8e6da4b21efa9c9f02d92d29f": { + "balance": "152958793764000000000" + }, + "eb41bce8e3aac2bcf662854a3151e3c83d98c6f3": { + "balance": "219455327737000000000" + }, + "eb44c591306972c29a7084079720d8ee5fb9b0a1": { + "balance": "49000000000000000000" + }, + "eb4b26ab55dc35df2e78d47a90fc43148a6de881": { + "balance": "12139574483030000000000" + }, + "eb4f53510db5edcaad6ea169e521bd094e8da4b1": { + "balance": "100000000000000000" + }, + "eb4fbfb7c0082aa0e7edaed934c5166fee955e5b": { + "balance": "299713748180000000000" + }, + "eb6067ab544af6289a73111e7693dc449d5c2134": { + "balance": "20000000000000000000" + }, + "eb86fea82d10d309b1365237e4855a48684e0e49": { + "balance": "81510415589000000000" + }, + "eb8abbcadeb6e19ab4392cded7a407c8d5df2d5c": { + "balance": "25000000000000000000" + }, + "eba44ca2d6f36df8221a2021bf0644cf6cb59452": { + "balance": "500000000000000000000000" + }, + "ebacbc0eace170f66415df48f74d98eb31828d15": { + "balance": "19046465915296000000000" + }, + "ebc72fb8a1029139d8abdc08da23dc559f87e1a8": { + "balance": "24177703742991000000000" + }, + "ebd561bb9001991cb6b02c8ff9e7ece8a3d73dde": { + "balance": "6684606759000000000" + }, + "ebe1dc3ee857ae4add6fa6636b678af8451d1701": { + "balance": "1485349608007000000000" + }, + "ebe68dc904c737be83aa2ee7f613dd51a6d436e4": { + "balance": "11206782120918000000000" + }, + "ebecf4db55a99f018bf136173ae823528f211380": { + "balance": "191817711082000000000" + }, + "ec15ad0aafe0c0f18089de50b2397509e15a20de": { + "balance": "20000000000000000000000" + }, + "ec2e56973a6cbd8b37d0294b16ef806ab5943ec7": { + "balance": "12031630315394000000000" + }, + "ec432a6a4685ebf6c1e872001d1de246140c8d98": { + "balance": "280056522277000000000" + }, + "ec866ba1bdadb91ca25f5ae035b0f69421ed4377": { + "balance": "431849961155000000000" + }, + "ec9be854224d3d371b79ffc1230fe704ba03be2b": { + "balance": "3692428502391000000000" + }, + "ecc2d6e129c7daa37a93f559c6d4f575171d8386": { + "balance": "20000000000000000000000" + }, + "ecc3aca2a21cb317c5b9debdcb2090f3931d5cd7": { + "balance": "100000000000000000000000" + }, + "eccc9a49ff40aa4b07aa0e1271cfb6713de683dd": { + "balance": "617207728367000000000" + }, + "ecccf24530629033fd6234ae32bde2052ebaa640": { + "balance": "16000000000000000000" + }, + "ed16770d5a56dced87224d4ff68a361a2285fef2": { + "balance": "10000000000000000000000" + }, + "ed23b8e782d5ddf203f9b80e5df83ec32e484fc6": { + "balance": "5000000000000000000" + }, + "ed3244e4168e669ae9d54175173c3f0f0e7c4c7a": { + "balance": "803397672115000000000" + }, + "ed48f39d3f022b321c0864d4955e1cdc8cf54834": { + "balance": "64000000000000000000" + }, + "ed4cb42fa6737cbbbf095f181e1425b3bc3ab4f6": { + "balance": "8974148344000000000" + }, + "ed560f7d83c27a26965f84dcface3930bc447fc5": { + "balance": "2092287996000000000" + }, + "ed6ace91369ec3b06cce474e67d1ce4aba6475a6": { + "balance": "1227081000000000000" + }, + "ed8249dd4a91f70176ffff310e5546e7e0c30b91": { + "balance": "813069034369000000000" + }, + "ed8987fa3d4d42bb8f009c99cda5868633d94f5a": { + "balance": "174952234860000000000" + }, + "ed99b72a58a519ca7aa8f46b8d254c3f1eeea0d6": { + "balance": "10000000000000000000000" + }, + "edb720c9bde4801e204e90282de2a6cf1c44c4ad": { + "balance": "10000000000000000000000" + }, + "edbea23cd0cfde3705d83aada88e78b9f4bb1a50": { + "balance": "4000000000000000000000" + }, + "edc1f174655205bb961ddf94a997cdfd24f1c2ed": { + "balance": "65211537189000000000" + }, + "edd1d2dcba881202bc546943194d64e59bf74bfd": { + "balance": "10000000000000000000000" + }, + "eded28fbd959f2351b4252abc71f0e809562fd4c": { + "balance": "1000000000000000000" + }, + "edfe4d4c83c7db76e5e8a9ccafa34d9841669dac": { + "balance": "2578239411258000000000" + }, + "ee1ef79de869b89334d883ba766e65150f3f6cf5": { + "balance": "779780646165000000000" + }, + "ee27b2da240e862f0848d31116a7b4ed91835c8d": { + "balance": "111637484977461000000000" + }, + "ee3195bdb69e97796911c63fdd3fcebad61ffe9b": { + "balance": "214483035823000000000" + }, + "ee43306530c21793c4fd6039b51cf54fbc912bf0": { + "balance": "374531713769000000000" + }, + "ee4515e30ee1b8dba4779ef213d89e8dfff26ea6": { + "balance": "1166743135013000000000" + }, + "ee591e9ca7948b8485eb210e2a3f706b97e6f9e2": { + "balance": "27793157052774000000000" + }, + "ee5ba6c854d633a04f7656d311817e5104c6de14": { + "balance": "289361919166000000000" + }, + "ee909db4ee48bff3adb9e43db940245a8e5e094d": { + "balance": "582143490064000000000" + }, + "ee94d1afa82de70eb65aad0662f48ef3170495cb": { + "balance": "242490158636000000000" + }, + "ee97e18e09bbb16137a7b4aaae464e97d70e6606": { + "balance": "442709862861000000000" + }, + "eebe957af00050c2841f3ef8768c6a77a5394012": { + "balance": "9000000000000000000" + }, + "eec052f4e2902f7cc496162ca6525997d2b3ede4": { + "balance": "69349303517000000000" + }, + "eed30e1a939d5f0b4a39598967a5f149a7b7cb8c": { + "balance": "1637195595000000000" + }, + "eed7bf1ba39bfdad0ce1b6b8d4c9bb31dc1a9843": { + "balance": "203331701702000000000" + }, + "eee276140ea24e36eccb4fd748f675df1acd3b73": { + "balance": "1000000000000000000000000" + }, + "eefb33b290741c4cded862cea777efe4b14a76da": { + "balance": "64000000000000000000" + }, + "ef17a60d15ecf68a62b4bfd5e3acd6201e1931af": { + "balance": "113292502078000000000" + }, + "ef3f4df42127d3e94b4b5883ca97ee63f90b68b5": { + "balance": "17819622000000000000" + }, + "ef4aa6833a69cf72fbf3eaac57da236970aa4241": { + "balance": "1638520372091000000000" + }, + "ef958a1db06e5b8e12547148f3b01da9a8841aad": { + "balance": "12847752197000000000" + }, + "ef9fa861eefe12a3b4c161a47db5d94b1fa873a9": { + "balance": "49000000000000000000" + }, + "efd9b1ce6bc3932961e41e875edaaa367d318b36": { + "balance": "1626378762077000000000" + }, + "efdce7f577c77f0dac6afc78dcbf5ebadc1c3a73": { + "balance": "627500067619000000000" + }, + "eff3f26bc45638d89f28b3ea7a5471af0b680b72": { + "balance": "1650959950189000000000" + }, + "eff6d78814ddae79d6d09d830dd44de55f3f919d": { + "balance": "44409266093000000000" + }, + "eff739e22b9aeb3781dc301da70761fdd178f08f": { + "balance": "574842224234000000000" + }, + "f0059b3c8a32d3d012b4fcb993431a484b67762f": { + "balance": "516933429840000000000" + }, + "f06747d8e2c76b8827bbd0bf4ea3a68d390ee8f3": { + "balance": "8124594790100000000000" + }, + "f0e29fc0aecc36d1bdd818148878ea7d01957476": { + "balance": "79821431871000000000" + }, + "f0e42acf4e027aa61ac2f56e3d2c171ec0fd6ebf": { + "balance": "672499252575000000000" + }, + "f14338307bc5e6ab71fa202447ce240947568b3c": { + "balance": "13990001528784000000000" + }, + "f14f9a1206eb436a3d2e4ba9b3976137f67a6596": { + "balance": "1086707451000000000" + }, + "f15fcf1772fa5b2a578ce4f9270996430d533000": { + "balance": "496026996898000000000" + }, + "f18c691a5827ff1fdc44b54bd9a64fabd53c1cf4": { + "balance": "3112912699000000000000" + }, + "f1960640b52af75fc71101aec2611499c17cd9c6": { + "balance": "195957678178000000000" + }, + "f1abf01ddd474949713bd7fa67ec81d6b56c87b7": { + "balance": "121000000000000000000" + }, + "f1b93a6cfd4b1c7e0e89ebed119c5fe55af2035e": { + "balance": "1000000000000000000000000" + }, + "f1d14c7659a10ff38f4ea74ff5b07ac035984b6a": { + "balance": "9986323720000000000" + }, + "f1dbf37470a2c4fef98b1023026870ae8f7df2c0": { + "balance": "132757602000000000000" + }, + "f220b958b619d5d848597dd00824ab8b1401ebd2": { + "balance": "1461699635849000000000" + }, + "f2484911e0aa707f88d9dd970db21e8f24b9de2f": { + "balance": "20000000000000000000000" + }, + "f264c15790fd7a36d9ce7a454f6bfbe878708a50": { + "balance": "64000000000000000000" + }, + "f2662356cb3ae7b82efd6c82c3591ee40854892b": { + "balance": "50000000000000000000000" + }, + "f27ae5783b96ef637bde4179080a8f5af63ae692": { + "balance": "784985848611000000000" + }, + "f2a62fc212717e411f72f9a694e30b8da21bb31b": { + "balance": "614971541702000000000" + }, + "f2d0a9594231efb87ac833c365b80944251f29d7": { + "balance": "478622654587000000000" + }, + "f2df99a3df0b9b448d0ea48b9fd5cb1ce9ce50cf": { + "balance": "851116673037000000000" + }, + "f2dff0ae1f5f74808624e4f26fa814e4e19c216a": { + "balance": "404457730686000000000" + }, + "f2ea1ac6282364ad5904c6f058827a4382111d94": { + "balance": "5502482915000000000" + }, + "f2fafdcdb2d887eb13b5362eb76be2a682868643": { + "balance": "6174264174000000000" + }, + "f314adfc2fbf632a6e5d8a261385b6054aca31b6": { + "balance": "1267558242119000000000" + }, + "f31a66a88394ed7dd6609aff07dd26a60a219bd8": { + "balance": "346102834465000000000" + }, + "f3535f2b42d8613363e6d9717cc21a8ec3a74fe0": { + "balance": "35723093185103000000000" + }, + "f36a149466982c030ce3b9717f34b593613804d5": { + "balance": "10000000000000000000000" + }, + "f3828b0eaba4acfbbcf3c58277ceb4616a34b630": { + "balance": "633998941064000000000" + }, + "f38f767eeb8002ef051b32fe2f40193bf0751d92": { + "balance": "50000000000000000000000" + }, + "f39bce177817a7338b1adaf713222e515c0d762b": { + "balance": "1128231726329000000000" + }, + "f3ac7ea27a1cefc7787e5ba54dacfd8385ee4afc": { + "balance": "11364602682758000000000" + }, + "f3d9ea511335ed418b1837766da11832aedf5578": { + "balance": "29188596603509000000000" + }, + "f3ef05ccd19df167e06797d962f6afe16037e134": { + "balance": "144000000000000000000" + }, + "f3f630148eccea0ad7bd67bb806bd5676a4ea4cb": { + "balance": "87187208643000000000" + }, + "f3ff31784e0b8c3cd2f7e18cfd07c682a42d1c8d": { + "balance": "10515373125000000000" + }, + "f40b976e8519a2c97f64783bca495ed3f2e4a7c0": { + "balance": "780184503985000000000" + }, + "f416a3af7f3181ad9c8a916989949d35b0b636ec": { + "balance": "16114504005275000000000" + }, + "f419759927eea6afe77701c4cf4a98791a709ad1": { + "balance": "1032589347112000000000" + }, + "f4368f9c9ad8236b56413f174562d6b6fef21d1c": { + "balance": "5447645343000000000" + }, + "f43c57f984b0e2b7ce4d703e82f41195585504a4": { + "balance": "1135809111749000000000" + }, + "f4449f52895de96a4638c927dc389f010bbd530c": { + "balance": "693196063498000000000" + }, + "f449bd417a674c8bfa1db3a3e09c2b03da0f0c04": { + "balance": "106343287319000000000" + }, + "f44dec8340986c06d64dc98d78772a8a9cdc41ec": { + "balance": "1379381904815000000000" + }, + "f4642be1a7685aea0dc7b362d36f58f15d806b72": { + "balance": "4717509847323000000000" + }, + "f4712925f57391043e0cc2e671f33124a0bc8613": { + "balance": "419736833200000000000" + }, + "f47317fba5927dd8dffc4049d4f3277fcef503d6": { + "balance": "149279442682000000000" + }, + "f47ce4c5aaef82692e47f7a810ba38d1faec0eea": { + "balance": "10000000000000000000000" + }, + "f491ffc412bf142788bb82d48bd4eccbe9e0a286": { + "balance": "77276422315000000000" + }, + "f4a1e27e669c29f15b9f89ac15f702340a135743": { + "balance": "324000000000000000000" + }, + "f4b5cbfa50a6c4f5f7db7a93fa565362cc7aceac": { + "balance": "195951823248000000000" + }, + "f4b949c6e10615b651675016f0d7d6ff64e31aee": { + "balance": "35516207325223000000000" + }, + "f4c5e2f043ef3548a2c1c27d968087bec65e2f7d": { + "balance": "100000000000000000000000" + }, + "f4c79ea9c6f7297e016c39296d86f0304070c31d": { + "balance": "71036374423000000000" + }, + "f4dde3733a72872a7efc095cb412672c50928f1b": { + "balance": "129914864759880000000000" + }, + "f4ed736a413464eb93f8a430e093a64f0bd4222d": { + "balance": "10000000000000000000000" + }, + "f4f07e45560fb63d5207ed7e8d7cf4fe29e06d18": { + "balance": "293103814503448000000000" + }, + "f50eac35eef0a1bfa23ba31020ef60e89bf8e9df": { + "balance": "10000000000000000000000" + }, + "f51236dfd888929ccb2fe1f1fc5554abc5df4ce2": { + "balance": "25000000000000000000" + }, + "f521eb42e9092350f2ad4391ddb42bfe7abb4db9": { + "balance": "217462745186000000000" + }, + "f54e7062b6a9a8b283acf00fcbad58aca0737676": { + "balance": "7327357122437000000000" + }, + "f553301efd81629d0856d9c95c70f4a962e602ed": { + "balance": "1500355826530000000000" + }, + "f55c555b0991b2413f2f2764d8ed6a0d77825965": { + "balance": "1174679810163000000000" + }, + "f56ff110d521ceaec29dbf2842f1e78b24463cea": { + "balance": "20000000000000000000000" + }, + "f573fec366236ab87ba041f7dc6a88d92b1fc9b7": { + "balance": "4659857040000000000" + }, + "f59987743b239379aac9353e17e0e4442aa2c684": { + "balance": "25000000000000000000" + }, + "f5a9ca298e88c5492dd44a66d815b649c2f01d39": { + "balance": "95879585325000000000" + }, + "f5b4933164c55b5ba99db906ecaa52bba4f95164": { + "balance": "25663623936000000000" + }, + "f5d20af68c6fed98144718b6beab82fde00dfedc": { + "balance": "16000000000000000000" + }, + "f5e49ce72be9b17ff39688860e5cf6fd500a886c": { + "balance": "106142276914000000000" + }, + "f5f472405a4530075805fbc11928544770fd61fe": { + "balance": "64000000000000000000" + }, + "f62096c7305eb97b221bb637f4269246fe59262b": { + "balance": "855993602798000000000" + }, + "f622bf9b8f7be2f75d5ed73d318a0e7fa62a587f": { + "balance": "20000000000000000000000" + }, + "f6231f31d524ccc444bd046123ba33bc224bdd52": { + "balance": "97550810879000000000" + }, + "f641b4a721dcefa497274fd06888eb998b9bc038": { + "balance": "39401014566340000000000" + }, + "f64f0c5172c99d74b2450a4685c3ec715b379922": { + "balance": "28337413668000000000" + }, + "f65841061cd55cbf20843d9594bce9ee133aa644": { + "balance": "9064540188290000000000" + }, + "f65f0106f3d148d0660547f0683ded4dffc12fe9": { + "balance": "87334071785367000000000" + }, + "f677961296ed933db9e1dd887711387540c0436d": { + "balance": "3982789899000000000" + }, + "f68ba7530f423b8df1625cee36f8df2363a57c49": { + "balance": "5000000000000000000000" + }, + "f69c6eaf077b795f19a9590ee8b578543558e4c4": { + "balance": "10000000000000000000000" + }, + "f69dfe3f0f76e50e2850e44e9e36b6966e277eaa": { + "balance": "288231750575462000000000" + }, + "f6a73c4b958b4d6044f3f4da7147d0fa80e2ea31": { + "balance": "50000000000000000000000" + }, + "f6b0864be5f7bbc4210a3420aa3ead614a8fe7e2": { + "balance": "880968828000000000" + }, + "f6f43a6d9517471436d2ce5047a2b707580e7149": { + "balance": "20000000000000000000000" + }, + "f6fb414d1ca7c29be35b5f97096c817bbf70b070": { + "balance": "15156317416682000000000" + }, + "f707b491ac27b2d2e5e1f9d4123635ee0af92c5c": { + "balance": "500000000000000000000000" + }, + "f71179583a471767a1b399842d7d29caefe57a5e": { + "balance": "429648186876000000000" + }, + "f71ed909eca6bfd574cd670389bc9250493d686d": { + "balance": "38189267531000000000" + }, + "f72ccdc70b7878cdb94f42ee72ca5b4b35a46238": { + "balance": "86065647347000000000" + }, + "f74035e85dbfdb961037bf689ee7dfdcfaf32d64": { + "balance": "398451682882000000000" + }, + "f77668db085a87b0a0405a275e1c2516d3e02b66": { + "balance": "10000000000000000000000" + }, + "f78990d9e50876b49f933e9d74bda44197e9aa7d": { + "balance": "51984216556000000000" + }, + "f79b9df28b7d94d1b4491fca1cbe50bd36aedb3a": { + "balance": "11546152485156000000000" + }, + "f7c773b89be413848dc4a96f064693a0c3a2eab0": { + "balance": "7084247258755000000000" + }, + "f7e29c20bb0023e9ae079da589346fdfd960dae3": { + "balance": "93132014782000000000" + }, + "f8124428ea619d30a335ecc4c2f64e36500abdcb": { + "balance": "8838170798391000000000" + }, + "f843c9d70226e6c2c8cd4cef78e2db66a8eac027": { + "balance": "498377670361000000000" + }, + "f84bb3c0d872dcdbe99d6abcc57c6b5c2b2e35ad": { + "balance": "1405105232436000000000" + }, + "f8679b915ae94e4668f2e27d1094cbb2d97cf428": { + "balance": "1000000000000000000" + }, + "f86dbb82c634cdfa818e4d0dbcfcc9a5c47a9ddb": { + "balance": "196000000000000000000" + }, + "f88bad7726aa66bc1d0ca5824044072f3551fd15": { + "balance": "37432374800000000000" + }, + "f8ab07d0751a2c283ebe2a7e28c5b6e57867e1d1": { + "balance": "25000000000000000000" + }, + "f8afb4f5684c56ff7ce71b4e4cf7e42062470e08": { + "balance": "10000000000000000000000" + }, + "f8c28df0d1a0982289ddfa2a6d562e5c75a5dd01": { + "balance": "1447386977682000000000" + }, + "f8cca137f9c12b48eafd43f038e55e2d3c481919": { + "balance": "35370515421000000000" + }, + "f8e50d1816a5e5c649756ae208209b03b1ece0c3": { + "balance": "48449640035000000000" + }, + "f8fb33ba1d93112d9c3672806e0939083f09a88e": { + "balance": "419743187776000000000" + }, + "f903bebfcc6a7050fc2c5bd14248af9b300f1600": { + "balance": "473363252199000000000" + }, + "f90ab9078f26dd881fb054b4b6e3b3e17fa94718": { + "balance": "156449634345000000000" + }, + "f93e3f392efc057f0af3a91416858a515c1ed996": { + "balance": "1147663044625000000000" + }, + "f94eac538ca66931869c312acb67721c4337842f": { + "balance": "368103335377000000000" + }, + "f94fda503c3f792491fa77b3702fd465f028810d": { + "balance": "317241487661000000000" + }, + "f95dcedbefee8ed01086c91d91a4c115ad8fc947": { + "balance": "147059838786000000000" + }, + "f961a293bbce366a6fcc98d2ba0342e2ef3c5519": { + "balance": "10000000000000000000000" + }, + "f966fdbc4a42f055f8f52d31c23ad7b6a07a5e22": { + "balance": "10000000000000000000000" + }, + "f9a3a61a2f1469835240bb0641eae40c07451e30": { + "balance": "218000000000000" + }, + "f9adcf232180378b08a46d6c8d9d97f01802e01b": { + "balance": "15658216517944000000000" + }, + "f9c68991ff7ac307e41ea1c673f8ebb1a6afbd99": { + "balance": "10000000000000000000000" + }, + "f9cc0c60431d7bdb0c7581a9ae7f011b0abefeb1": { + "balance": "16000000000000000000" + }, + "f9d43c329b61ca2169600e45c8fad3c94226adb8": { + "balance": "120128558137000000000" + }, + "f9ef5d4e2ca8888216b939d3d938438a34dd9da2": { + "balance": "144000000000000000000" + }, + "f9f3d14cd3bd09e2c4c89035b4f50e93f6175cef": { + "balance": "725000000000000000000" + }, + "fa0f5a03601bd1fc76865cdd69d9671ba6073592": { + "balance": "225298289139000000000" + }, + "fa12f10db0eb552b719194becef20af9f45de8db": { + "balance": "1012484659496000000000" + }, + "fa146c58a0709951bc2e9bccddcd002c5a0bb7dd": { + "balance": "199563276701000000000" + }, + "fa159185c156f35fa450b77c48846c2dab6349b7": { + "balance": "100660066567000000000" + }, + "fa193312655f79c7b0ee7d7ef904486836180026": { + "balance": "48141690266000000000" + }, + "fa2484de744918bd8c91350fbabc0dab8b8a44f0": { + "balance": "36000000000000000000" + }, + "fa36dc463b026d8edfeb8ac4acac43a51d643457": { + "balance": "9608761064478000000000" + }, + "fa84199010be2bf53e803c23771e0d15fd025386": { + "balance": "1474902394742000000000" + }, + "fa958bbfa367a745bcd0904db2c4e30445edaefb": { + "balance": "175679888121000000000" + }, + "fa98bcaeb55285ad7ead12ccaa15cf488f567ede": { + "balance": "136105143781000000000" + }, + "faa1be631da42b41a026774f4166c1b831ef41e9": { + "balance": "86358861589000000000" + }, + "faaa857e7f149968434f313ab8db596e1b0ae75d": { + "balance": "36000000000000000000" + }, + "fac2b85ab274055cf1415d57394e8aca4541857d": { + "balance": "289000000000000000000" + }, + "fb23a508ccdb4e91b252f5c06c465c55ed59b1db": { + "balance": "14698710175236000000000" + }, + "fb24d4e47ba70aa4b984372b4852ad3d082daa24": { + "balance": "4526648424830000000000" + }, + "fb27a7e8b8b4ae43c69ce025b46187e538608769": { + "balance": "121000000000000000000" + }, + "fb2cdb5e85872f52c99985f219b8fb4125c6a8b7": { + "balance": "8568367153000000000" + }, + "fb3d76c8165bcb3c93fd3b2b10c20588d0fa97aa": { + "balance": "500000000000000000000000" + }, + "fb5161b2cc9d48a53f47d66002905f0458e3cd9e": { + "balance": "225000000000000000000" + }, + "fb72756c4845f18ab35d29f632b662c0c0d4b94f": { + "balance": "883095068524000000000" + }, + "fb8b7efb02ea5292304c0f0abc8c555684653587": { + "balance": "10000000000000000000000" + }, + "fb9ee61e337a5c7b57c5140e84919101570e2cb7": { + "balance": "16000000000000000000" + }, + "fbae69f44b116c186a86cb0de79323ca3d6b99eb": { + "balance": "1359504686067000000000" + }, + "fbbd399eb9e5d3dd67efc48927973601dcd84321": { + "balance": "2049018637367000000000" + }, + "fbc9a3c3c429990cc306710b3dd44174dcc72ad4": { + "balance": "55507457947000000000" + }, + "fbce66a6898ecd70893db6b4b8c3d00afef8e20b": { + "balance": "20857164902458000000000" + }, + "fbe8fe04084fc93dff8228861fe100bfeeb057b6": { + "balance": "10000000000000000000000" + }, + "fbfb717f902ad79ef63565f9ab57f041ff5f7626": { + "balance": "16000000000000000000" + }, + "fc0b6c8c6be79bf0c9554f7855dc8c4a617d02c9": { + "balance": "17347593956000000000" + }, + "fc17518d05e605807847bbf6f407da89037bca00": { + "balance": "1796383702108000000000" + }, + "fc2793424c809cc80938a1be1292813adbc8ac8c": { + "balance": "10000000000000000000" + }, + "fc35930abb108ae6cae33fd065dfb799808ea326": { + "balance": "912737460000000000000" + }, + "fc5a9209799e563ae8d958774dc86345a3bc7ed2": { + "balance": "29049176573000000000" + }, + "fc8011850c09c9288e737ea58ca5c15cded6dc8d": { + "balance": "10000000000000000000000" + }, + "fc9183ed137be071ad183d025395a0ebe2674654": { + "balance": "500000000000000000000000" + }, + "fc98c9d88b1fbbb68dbdd6448aa6a32e8282800d": { + "balance": "900000000000000000000" + }, + "fc9f4b9da7a46c2bfcd50cafe1f892b9984be0ee": { + "balance": "21577116424370000000000" + }, + "fca525b732a673b953f1c23083c276cc8cbcb86c": { + "balance": "77653618624000000000" + }, + "fca57b6a4798f33478b6e23622173cda3fe1b9a0": { + "balance": "793368066098000000000" + }, + "fca79b446c513a7bed643603c42f35ff0fa89f49": { + "balance": "998082799053000000000" + }, + "fcab42f7f07735a7b09074c1f1769287069c88c8": { + "balance": "94824830574000000000" + }, + "fcacbbc6810c586522012ad32c3dfac80eb563b4": { + "balance": "10000000000000000000000" + }, + "fcb38809b63810b6673dcb4c947e01f7b49fb1b3": { + "balance": "725937240372000000000" + }, + "fcc0e531d9f6265672aa885af361534464a11015": { + "balance": "22121462657000000000" + }, + "fcc49c62d7738fa1b92aa6a69a12b671e4c7c8d9": { + "balance": "50000000000000000000000" + }, + "fcc95394fd796ca5bd8f3814883b1150d74dd9a5": { + "balance": "144000000000000000000" + }, + "fccdb068dfd599d7d5c290a6ae65eba9151d5b29": { + "balance": "5369426564000000000" + }, + "fcde41ae28bdf9084a28f47a9348d8aac5b3dd43": { + "balance": "409599263197000000000" + }, + "fce5816f066ca32d1fa02e9e8b5eb8a7fa3e4dea": { + "balance": "1193272309645000000000" + }, + "fcf9fb8996d6d9175ade6d6063be0742de20ea1f": { + "balance": "16852526239339000000000" + }, + "fd10488d55e6861cb67f7f50950d78892e7032ad": { + "balance": "165069902909000000000" + }, + "fd23e8263d89256add0dfe93da153d305ad917c7": { + "balance": "26633825496000000000" + }, + "fd3a98cc3b3f1439af35f806de2fb05fef98f279": { + "balance": "1043321187464000000000" + }, + "fd3d79185a91984a117ee6f9fd304725875094e2": { + "balance": "2349991833898000000000" + }, + "fd5e6ac22634f04ec4ace5da8996c2b7b70b22f4": { + "balance": "10000000000000000" + }, + "fd62ed1cf7a535c989fbd742b1660205a2f69dd0": { + "balance": "49000000000000000000" + }, + "fd645043bd4d7b71e63e30409b91e9fdda3a86c0": { + "balance": "362957768837969000000000" + }, + "fd7014fc1c70af482115247ff94ff6bdbd3d364d": { + "balance": "743383172317000000000" + }, + "fda0cfe95df9021497752b04863c3ec44d13e853": { + "balance": "15586809617955000000000" + }, + "fdb5b964808bcb974d3e888cbb45bcd57e57c907": { + "balance": "5549247772273000000000" + }, + "fdbaaa865ec38da13e80554b6d0abc437f60d8a5": { + "balance": "3736861227131000000000" + }, + "fdbb8693b3c20c0eac5fb585e2347d41debbffce": { + "balance": "100000000000000000" + }, + "fdbdaec57829f25ad48e18d94e0b8533f2801818": { + "balance": "6934630922926000000000" + }, + "fdc318ba5b1f8ad33e00528828b93a840592e2fb": { + "balance": "10000000000000000000000" + }, + "fdcf6a997bb10806e4d87eb4222e9f93b4202179": { + "balance": "1000000000000000000" + }, + "fde5a9911a10770d733db4d32ca9a5493478399c": { + "balance": "20000000000000000000000" + }, + "fe39185a6b84378820ee215f630533e658731ca9": { + "balance": "17022202932000000000" + }, + "fe3b1032e524674cba5f329f940c837850fa53ed": { + "balance": "50000000000000000000000" + }, + "fe3bc4ff2c3b66bc582558314b80030407e7de96": { + "balance": "1669870860988000000000" + }, + "fe668dbb1f3de744d16e13e0ed6f5708c2c15d1f": { + "balance": "39974355655263000000000" + }, + "fe95bfb97fa60341f8af2ad621e606b85e3c2e57": { + "balance": "528601649597478000000000" + }, + "fe99cf2a1fbbe7c46e4235b2d135a3a093fcf16c": { + "balance": "7271022106877000000000" + }, + "fec1f6ed4b3ff01e7ebe13fb53f60ee5a3b9e191": { + "balance": "1316316072034000000000" + }, + "fed9bec1b2145452ed5535e4ba29fafac6c35fbb": { + "balance": "10799354586000000000" + }, + "fedced7aa1cf3f3a7eec321cc0274759b154ea8e": { + "balance": "11740927210323000000000" + }, + "fef5063701a93ad02676fe0b99d0f4d2da0ccd67": { + "balance": "10178531012000000000" + }, + "fefd5627a408ca099587892ee2a46fa8cc89be19": { + "balance": "458504035686000000000" + }, + "ff1fc0f6f26188cbe18cf65d8a344d3775aecc6d": { + "balance": "81000000000000000000" + }, + "ff4fe483b3c04ebc8d6705c699ecee3e92071715": { + "balance": "1000000000000000000" + }, + "ff51bfe823394b2bce05947a6068bd5158d4af0e": { + "balance": "692533626783000000000" + }, + "ff6652e4e45f6b0f95ad4c9ec2bc80476e3f7fc6": { + "balance": "46457898024000000000" + }, + "ff68246ac7640091e5e58345736b249e036364fc": { + "balance": "2626125272000000000" + }, + "ff6d4b8a8393a503047ff829dbf2bf8e9172dc6d": { + "balance": "2865001878255000000000" + }, + "ff6fe19e056a7211b7e484c2c540d5aa5f1d83e5": { + "balance": "36000000000000000000" + }, + "ff7fa33529e1781c1b2951e57581780b229e3fda": { + "balance": "10000000000000000000" + }, + "ff82d1052538539d07cf3955476cc9a5027d8e4e": { + "balance": "83572023121000000000" + }, + "ff8acfe75afcc1efb1bc44be9f9bb242a94f73f7": { + "balance": "7556034521000000000" + }, + "ffa2b5f1685de9fcf1af4653cd3a584db1beed64": { + "balance": "114892199805000000000" + }, + "ffb1e9be68ae8be8d7d066c473589921e68825a2": { + "balance": "484660652980000000000" + }, + "ffbf91a9d1a6377b7435e3e734132e7b34188dac": { + "balance": "20000000000000000000000" + }, + "ffbff1fab9f2bc2f387d0cc9cc28f6aac533c813": { + "balance": "10000000000000000000000" + }, + "ffc4ff6433ea35544e7a07fda170e62c451301df": { + "balance": "29238210920000000000" + }, + "ffc7534b64a8fe8760e931a710883119d28ae106": { + "balance": "500000000000000000000000" + }, + "ffda6b8e3de72d7f7c18b892e6a8b80b886d5fa5": { + "balance": "214366938289000000000" + }, + "ffddb1fb7521c9772ea4886aaf022c4375ef904d": { + "balance": "554864446437000000000" + } + } } diff --git a/ethcore/res/ethereum/transition_test.json b/ethcore/res/ethereum/transition_test.json index 7c18fce4e54..9dc00fd5d8c 100644 --- a/ethcore/res/ethereum/transition_test.json +++ b/ethcore/res/ethereum/transition_test.json @@ -8,10 +8,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": "0", - "eip150Transition": "0", - "eip160Transition": "0", - "eip161abcTransition": "0", - "eip161dTransition": "0", "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": "5", "eip649Transition": "5" @@ -27,6 +23,10 @@ "networkID" : "0x1", "maxCodeSize": 24576, "maxCodeSizeTransition": "0", + "eip150Transition": "0", + "eip160Transition": "0", + "eip161abcTransition": "0", + "eip161dTransition": "0", "eip98Transition": "5", "eip140Transition": "5", "eip211Transition": "5", diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 1bd3805ef3b..9c6db25cbca 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -46,14 +46,6 @@ pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]); pub struct EthashExtensions { /// Homestead transition block number. pub homestead_transition: BlockNumber, - /// EIP150 transition block number. - pub eip150_transition: BlockNumber, - /// Number of first block where EIP-160 rules begin. - pub eip160_transition: u64, - /// Number of first block where EIP-161.abc begin. - pub eip161abc_transition: u64, - /// Number of first block where EIP-161.d begins. - pub eip161d_transition: u64, /// DAO hard-fork transition block (X). pub dao_hardfork_transition: u64, /// DAO hard-fork refund contract address (C). @@ -66,10 +58,6 @@ impl From<::ethjson::spec::EthashParams> for EthashExtensions { fn from(p: ::ethjson::spec::EthashParams) -> Self { EthashExtensions { homestead_transition: p.homestead_transition.map_or(0, Into::into), - eip150_transition: p.eip150_transition.map_or(0, Into::into), - eip160_transition: p.eip160_transition.map_or(0, Into::into), - eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into), - eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into), dao_hardfork_transition: p.dao_hardfork_transition.map_or(u64::max_value(), Into::into), dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into), dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or_else(Vec::new).into_iter().map(Into::into).collect(), @@ -267,19 +255,8 @@ impl EthereumMachine { Some(ref ext) => { if block_number < ext.homestead_transition { Schedule::new_frontier() - } else if block_number < ext.eip150_transition { - Schedule::new_homestead() } else { - let max_code_size = self.params.max_code_size(block_number); - let mut schedule = Schedule::new_post_eip150( - max_code_size as _, - block_number >= ext.eip160_transition, - block_number >= ext.eip161abc_transition, - block_number >= ext.eip161d_transition - ); - - self.params.update_schedule(block_number, &mut schedule); - schedule + self.params.schedule(block_number) } } }; @@ -503,10 +480,6 @@ mod tests { fn get_default_ethash_extensions() -> EthashExtensions { EthashExtensions { homestead_transition: 1150000, - eip150_transition: u64::max_value(), - eip160_transition: u64::max_value(), - eip161abc_transition: u64::max_value(), - eip161d_transition: u64::max_value(), dao_hardfork_transition: u64::max_value(), dao_hardfork_beneficiary: "0000000000000000000000000000000000000001".into(), dao_hardfork_accounts: Vec::new(), diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 1ee8cf70323..fa25c8894eb 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -78,6 +78,14 @@ pub struct CommonParams { pub min_gas_limit: U256, /// Fork block to check. pub fork_block: Option<(BlockNumber, H256)>, + /// EIP150 transition block number. + pub eip150_transition: BlockNumber, + /// Number of first block where EIP-160 rules begin. + pub eip160_transition: u64, + /// Number of first block where EIP-161.abc begin. + pub eip161abc_transition: u64, + /// Number of first block where EIP-161.d begins. + pub eip161d_transition: u64, /// Number of first block where EIP-98 rules begin. pub eip98_transition: BlockNumber, /// Number of first block where EIP-658 rules begin. @@ -134,9 +142,20 @@ pub struct CommonParams { impl CommonParams { /// Schedule for an EVM in the post-EIP-150-era of the Ethereum main net. pub fn schedule(&self, block_number: u64) -> ::vm::Schedule { - let mut schedule = ::vm::Schedule::new_post_eip150(self.max_code_size(block_number) as _, true, true, true); - self.update_schedule(block_number, &mut schedule); - schedule + if block_number < self.eip150_transition { + ::vm::Schedule::new_homestead() + } else { + let max_code_size = self.max_code_size(block_number); + let mut schedule = ::vm::Schedule::new_post_eip150( + max_code_size as _, + block_number >= self.eip160_transition, + block_number >= self.eip161abc_transition, + block_number >= self.eip161d_transition + ); + + self.update_schedule(block_number, &mut schedule); + schedule + } } /// Returns max code size at given block. @@ -197,6 +216,10 @@ impl From for CommonParams { } else { None }, + eip150_transition: p.eip150_transition.map_or(0, Into::into), + eip160_transition: p.eip160_transition.map_or(0, Into::into), + eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into), + eip161d_transition: p.eip161d_transition.map_or(0, Into::into), eip98_transition: p.eip98_transition.map_or(0, Into::into), eip155_transition: p.eip155_transition.map_or(0, Into::into), validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into), diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs index afa8b596823..66f6913e578 100644 --- a/json/src/spec/ethash.rs +++ b/json/src/spec/ethash.rs @@ -73,21 +73,6 @@ pub struct EthashParams { #[serde(rename="eip100bTransition")] pub eip100b_transition: Option, - /// See main EthashParams docs. - #[serde(rename="eip150Transition")] - pub eip150_transition: Option, - - /// See main EthashParams docs. - #[serde(rename="eip160Transition")] - pub eip160_transition: Option, - - /// See main EthashParams docs. - #[serde(rename="eip161abcTransition")] - pub eip161abc_transition: Option, - /// See main EthashParams docs. - #[serde(rename="eip161dTransition")] - pub eip161d_transition: Option, - /// See main EthashParams docs. #[serde(rename="ecip1010PauseTransition")] pub ecip1010_pause_transition: Option, @@ -190,11 +175,7 @@ mod tests { "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", "bombDefuseTransition": "0x41", - "eip100bTransition": "0x42", - "eip150Transition": "0x43", - "eip160Transition": "0x45", - "eip161abcTransition": "0x46", - "eip161dTransition": "0x47" + "eip100bTransition": "0x42" } }"#; @@ -237,10 +218,6 @@ mod tests { difficulty_hardfork_bound_divisor: Some(Uint(U256::from(0x0200))), bomb_defuse_transition: Some(Uint(U256::from(0x41))), eip100b_transition: Some(Uint(U256::from(0x42))), - eip150_transition: Some(Uint(U256::from(0x43))), - eip160_transition: Some(Uint(U256::from(0x45))), - eip161abc_transition: Some(Uint(U256::from(0x46))), - eip161d_transition: Some(Uint(U256::from(0x47))), ecip1010_pause_transition: None, ecip1010_continue_transition: None, ecip1017_era_rounds: None, @@ -285,10 +262,6 @@ mod tests { difficulty_hardfork_bound_divisor: None, bomb_defuse_transition: None, eip100b_transition: None, - eip150_transition: None, - eip160_transition: None, - eip161abc_transition: None, - eip161d_transition: None, ecip1010_pause_transition: None, ecip1010_continue_transition: None, ecip1017_era_rounds: None, diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 0addf52e4af..f171a881019 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -51,6 +51,21 @@ pub struct Params { #[serde(rename="forkCanonHash")] pub fork_hash: Option, + /// See main EthashParams docs. + #[serde(rename="eip150Transition")] + pub eip150_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip160Transition")] + pub eip160_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip161abcTransition")] + pub eip161abc_transition: Option, + /// See main EthashParams docs. + #[serde(rename="eip161dTransition")] + pub eip161d_transition: Option, + /// See `CommonParams` docs. #[serde(rename="eip98Transition")] pub eip98_transition: Option, From 027504cb2975a738a164f90fecf136760e2dd864 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 06:32:05 +0200 Subject: [PATCH 115/147] Remove HostInfo::client_version() and secret() (#8677) --- util/network-devp2p/src/handshake.rs | 3 ++- util/network-devp2p/src/host.rs | 14 +++++++------- util/network/src/lib.rs | 4 ---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index a203af5b4b4..7aef4d4f0d7 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -26,7 +26,8 @@ use node_table::NodeId; use io::{IoContext, StreamToken}; use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; use ethkey::crypto::{ecdh, ecies}; -use network::{Error, ErrorKind, HostInfo}; +use network::{Error, ErrorKind, HostInfo as HostInfoTrait}; +use host::HostInfo; #[derive(PartialEq, Eq, Debug)] enum HandshakeState { diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index f3446845fb1..5ccab2e4db2 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -215,19 +215,19 @@ impl HostInfo { self.nonce = keccak(&self.nonce); self.nonce } -} -impl HostInfoTrait for HostInfo { - fn id(&self) -> &NodeId { - self.keys.public() + pub(crate) fn client_version(&self) -> &str { + &self.config.client_version } - fn secret(&self) -> &Secret { + pub(crate) fn secret(&self) -> &Secret { self.keys.secret() } +} - fn client_version(&self) -> &str { - &self.config.client_version +impl HostInfoTrait for HostInfo { + fn id(&self) -> &NodeId { + self.keys.public() } } diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 0137543fdd5..d16403cd34e 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -330,10 +330,6 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { pub trait HostInfo { /// Returns public key fn id(&self) -> &NodeId; - /// Returns secret key - fn secret(&self) -> &Secret; - /// Returns the client version. - fn client_version(&self) -> &str; } /// Network IO protocol handler. This needs to be implemented for each new subprotocol. From 87d835958757f6baa9c2adb0ef620ac8e74fcd26 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 06:34:01 +0200 Subject: [PATCH 116/147] Move connection_filter to the network crate (#8674) --- Cargo.lock | 1 + ethcore/node_filter/Cargo.toml | 1 + ethcore/node_filter/src/lib.rs | 6 ++++-- ethcore/sync/src/api.rs | 5 +++-- ethcore/sync/src/lib.rs | 4 ++-- util/network-devp2p/src/host.rs | 2 +- util/network-devp2p/src/lib.rs | 2 -- util/network-devp2p/src/service.rs | 2 +- util/{network-devp2p => network}/src/connection_filter.rs | 0 util/network/src/lib.rs | 2 ++ 10 files changed, 15 insertions(+), 10 deletions(-) rename util/{network-devp2p => network}/src/connection_filter.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e2fa0a9db8f..646bc906456 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,6 +1805,7 @@ dependencies = [ "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", "ethcore-io 1.12.0", + "ethcore-network 1.12.0", "ethcore-network-devp2p 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index 25b5ec59f4e..0d204e29ff8 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -8,6 +8,7 @@ authors = ["Parity Technologies "] [dependencies] ethcore = { path = ".."} +ethcore-network = { path = "../../util/network" } ethcore-network-devp2p = { path = "../../util/network-devp2p" } ethereum-types = "0.3" log = "0.3" diff --git a/ethcore/node_filter/src/lib.rs b/ethcore/node_filter/src/lib.rs index 715b7ae3e98..c731ad356ad 100644 --- a/ethcore/node_filter/src/lib.rs +++ b/ethcore/node_filter/src/lib.rs @@ -18,7 +18,8 @@ extern crate ethabi; extern crate ethcore; -extern crate ethcore_network_devp2p as network; +extern crate ethcore_network as network; +extern crate ethcore_network_devp2p as devp2p; extern crate ethereum_types; extern crate lru_cache; extern crate parking_lot; @@ -43,7 +44,8 @@ use parking_lot::Mutex; use ethcore::client::{BlockChainClient, BlockId}; use ethereum_types::{H256, Address}; -use network::{NodeId, ConnectionFilter, ConnectionDirection}; +use network::{ConnectionFilter, ConnectionDirection}; +use devp2p::NodeId; use_contract!(peer_set, "PeerSet", "res/peer_set.json"); diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index e901528e411..56ea8526edf 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -19,9 +19,10 @@ use std::collections::{HashMap, BTreeMap}; use std::io; use std::time::Duration; use bytes::Bytes; -use devp2p::{NetworkService, ConnectionFilter}; +use devp2p::NetworkService; use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, ProtocolId, - NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, Error, ErrorKind}; + NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, Error, ErrorKind, + ConnectionFilter}; use ethereum_types::{H256, H512, U256}; use io::{TimerToken}; use ethcore::ethstore::ethkey::Secret; diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index 3eb2e8332b4..c00ea5e4404 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -74,6 +74,6 @@ mod api; pub use api::*; pub use chain::{SyncStatus, SyncState}; -pub use devp2p::{validate_node_url, ConnectionFilter, ConnectionDirection}; -pub use network::{NonReservedPeerMode, Error, ErrorKind}; +pub use devp2p::validate_node_url; +pub use network::{NonReservedPeerMode, Error, ErrorKind, ConnectionFilter, ConnectionDirection}; pub use private_tx::{PrivateTxHandler, NoopPrivateTxHandler, SimplePrivateTxHandler}; diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 5ccab2e4db2..3ab7b7f849c 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -45,7 +45,7 @@ use discovery::{Discovery, TableUpdates, NodeEntry}; use ip_utils::{map_external_address, select_public_address}; use path::restrict_permissions_owner; use parking_lot::{Mutex, RwLock}; -use connection_filter::{ConnectionFilter, ConnectionDirection}; +use network::{ConnectionFilter, ConnectionDirection}; type Slab = ::slab::Slab; diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index e5bb95f2207..244997a6545 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -106,10 +106,8 @@ mod discovery; mod service; mod node_table; mod ip_utils; -mod connection_filter; pub use service::NetworkService; -pub use connection_filter::{ConnectionFilter, ConnectionDirection}; pub use host::NetworkContext; pub use io::TimerToken; diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 10a1e9abc85..3ac1ec7f717 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -21,7 +21,7 @@ use io::*; use parking_lot::RwLock; use std::sync::Arc; use ansi_term::Colour; -use connection_filter::ConnectionFilter; +use network::ConnectionFilter; struct HostHandler { public_url: RwLock> diff --git a/util/network-devp2p/src/connection_filter.rs b/util/network/src/connection_filter.rs similarity index 100% rename from util/network-devp2p/src/connection_filter.rs rename to util/network/src/connection_filter.rs diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index d16403cd34e..f3012e4c376 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -27,8 +27,10 @@ extern crate snappy; #[macro_use] extern crate error_chain; +mod connection_filter; mod error; +pub use connection_filter::{ConnectionFilter, ConnectionDirection}; pub use io::TimerToken; pub use error::{Error, ErrorKind, DisconnectReason}; From c6f9c65af7ac0befce456e92003d78b3adaaaaad Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 06:35:13 +0200 Subject: [PATCH 117/147] Remove the error when stopping the network (#8671) --- ethcore/sync/src/api.rs | 6 ++---- util/io/src/service_mio.rs | 10 ++++++---- util/network-devp2p/src/host.rs | 5 ++--- util/network-devp2p/src/service.rs | 7 +++---- util/network-devp2p/tests/tests.rs | 2 +- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 56ea8526edf..2f90e410aed 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -475,7 +475,7 @@ impl ChainNotify for EthSync { fn stop(&self) { self.eth_handler.snapshot_service.abort_restore(); - self.network.stop().unwrap_or_else(|e| warn!("Error stopping network: {:?}", e)); + self.network.stop(); } fn broadcast(&self, message_type: ChainMessageType) { @@ -833,9 +833,7 @@ impl ManageNetwork for LightSync { fn stop_network(&self) { self.proto.abort(); - if let Err(e) = self.network.stop() { - warn!("Error stopping network: {}", e); - } + self.network.stop(); } fn network_config(&self) -> NetworkConfiguration { diff --git a/util/io/src/service_mio.rs b/util/io/src/service_mio.rs index f7c9f1976cf..2ae3d55e0ff 100644 --- a/util/io/src/service_mio.rs +++ b/util/io/src/service_mio.rs @@ -162,11 +162,13 @@ impl IoContext where Message: Send + Sync + 'static { } /// Unregister current IO handler. - pub fn unregister_handler(&self) -> Result<(), IoError> { - self.channel.send_io(IoMessage::RemoveHandler { + pub fn unregister_handler(&self) { + // `send_io` returns an error only if the channel is closed, which means that the + // background thread is no longer running. Therefore the handler is no longer active and + // can be considered as unregistered. + let _ = self.channel.send_io(IoMessage::RemoveHandler { handler_id: self.handler, - })?; - Ok(()) + }); } } diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 3ab7b7f849c..fbbeb89ff8e 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -396,7 +396,7 @@ impl Host { format!("{}", Node::new(info.id().clone(), info.local_endpoint.clone())) } - pub fn stop(&self, io: &IoContext) -> Result<(), Error> { + pub fn stop(&self, io: &IoContext) { self.stopping.store(true, AtomicOrdering::Release); let mut to_kill = Vec::new(); for e in self.sessions.read().iter() { @@ -408,8 +408,7 @@ impl Host { trace!(target: "network", "Disconnecting on shutdown: {}", p); self.kill_connection(p, io, true); } - io.unregister_handler()?; - Ok(()) + io.unregister_handler(); } /// Get all connected peers. diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 3ac1ec7f717..eb2e9685d42 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -125,15 +125,14 @@ impl NetworkService { Ok(()) } - /// Stop network IO - pub fn stop(&self) -> Result<(), Error> { + /// Stop network IO. + pub fn stop(&self) { let mut host = self.host.write(); if let Some(ref host) = *host { let io = IoContext::new(self.io_service.channel(), 0); //TODO: take token id from host - host.stop(&io)?; + host.stop(&io); } *host = None; - Ok(()) } /// Get a list of all connected peers by id. diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index e8c8eddde4b..a1d178d6544 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -112,7 +112,7 @@ fn net_start_stop() { let config = NetworkConfiguration::new_local(); let service = NetworkService::new(config, None).unwrap(); service.start().unwrap(); - service.stop().unwrap(); + service.stop(); service.start().unwrap(); } From 84e10d421e6c5ae073734ef80ee7f7046ac2fdd6 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 19:07:27 +0200 Subject: [PATCH 118/147] Allow making direct RPC queries from the C API (#8588) --- parity-clib-example/main.cpp | 17 +++++++++++++++-- parity-clib/parity.h | 16 ++++++++++++++++ parity-clib/src/lib.rs | 31 ++++++++++++++++++++++++++++++ parity/rpc.rs | 2 +- parity/run.rs | 35 ++++++++++++++++++++++++++++++---- rpc/src/v1/types/provenance.rs | 4 ++++ 6 files changed, 98 insertions(+), 7 deletions(-) diff --git a/parity-clib-example/main.cpp b/parity-clib-example/main.cpp index 1fadf1b5b56..becce8598eb 100644 --- a/parity-clib-example/main.cpp +++ b/parity-clib-example/main.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include @@ -8,8 +11,8 @@ int main() { ParityParams cfg = { 0 }; cfg.on_client_restart_cb = on_restart; - const char* args[] = {"--light"}; - size_t str_lens[] = {7}; + const char* args[] = {"--no-ipc"}; + size_t str_lens[] = {8}; if (parity_config_from_cli(args, str_lens, 1, &cfg.configuration) != 0) { return 1; } @@ -19,6 +22,16 @@ int main() { return 1; } + const char* rpc = "{\"method\":\"parity_versionInfo\",\"params\":[],\"id\":1,\"jsonrpc\":\"2.0\"}"; + size_t out_len = 256; + char* out = (char*)malloc(out_len + 1); + if (parity_rpc(parity, rpc, strlen(rpc), out, &out_len)) { + return 1; + } + out[out_len] = '\0'; + printf("RPC output: %s", out); + free(out); + sleep(5); if (parity != NULL) { parity_destroy(parity); diff --git a/parity-clib/parity.h b/parity-clib/parity.h index b61da8e458b..f647395ce9a 100644 --- a/parity-clib/parity.h +++ b/parity-clib/parity.h @@ -86,6 +86,22 @@ int parity_start(const ParityParams* params, void** out); /// must not call this function. void parity_destroy(void* parity); +/// Performs an RPC request. +/// +/// Blocks the current thread until the request is finished. You are therefore encouraged to spawn +/// a new thread for each RPC request that requires accessing the blockchain. +/// +/// - `rpc` and `len` must contain the JSON string representing the RPC request. +/// - `out_str` and `out_len` point to a buffer where the output JSON result will be stored. If the +/// buffer is not large enough, the function fails. +/// - `out_len` will receive the final length of the string. +/// - On success, the function returns 0. On failure, it returns 1. +/// +/// **Important**: Keep in mind that this function doesn't write any null terminator on the output +/// string. +/// +int parity_rpc(void* parity, const char* rpc, size_t len, char* out_str, size_t* out_len); + #ifdef __cplusplus } #endif diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs index b08d6487d1a..fe631ce8a83 100644 --- a/parity-clib/src/lib.rs +++ b/parity-clib/src/lib.rs @@ -23,6 +23,7 @@ use std::os::raw::{c_char, c_void, c_int}; use std::panic; use std::ptr; use std::slice; +use std::str; #[repr(C)] pub struct ParityParams { @@ -131,3 +132,33 @@ pub extern fn parity_destroy(client: *mut c_void) { }); } } + +#[no_mangle] +pub extern fn parity_rpc(client: *mut c_void, query: *const char, len: usize, out_str: *mut c_char, out_len: *mut usize) -> c_int { + unsafe { + panic::catch_unwind(|| { + let client: &mut parity::RunningClient = &mut *(client as *mut parity::RunningClient); + + let query_str = { + let string = slice::from_raw_parts(query as *const u8, len); + match str::from_utf8(string) { + Ok(a) => a, + Err(_) => return 1, + } + }; + + if let Some(output) = client.rpc_query_sync(query_str) { + let q_out_len = output.as_bytes().len(); + if *out_len < q_out_len { + return 1; + } + + ptr::copy_nonoverlapping(output.as_bytes().as_ptr(), out_str as *mut u8, q_out_len); + *out_len = q_out_len; + 0 + } else { + 1 + } + }).unwrap_or(1) + } +} diff --git a/parity/rpc.rs b/parity/rpc.rs index 66a2715d42b..21bc9a40969 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -355,7 +355,7 @@ fn with_domain(items: Option>, domain: &str, ui_address: &Option(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler> +pub fn setup_apis(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler> where D: rpc_apis::Dependencies { let mut handler = MetaIoHandler::with_middleware( diff --git a/parity/run.rs b/parity/run.rs index 73113055bbf..fd16085c46c 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -41,7 +41,7 @@ use miner::external::ExternalMiner; use node_filter::NodeFilter; use node_health; use parity_reactor::EventLoop; -use parity_rpc::{NetworkSettings, informant, is_major_importing}; +use parity_rpc::{Origin, Metadata, NetworkSettings, informant, is_major_importing}; use updater::{UpdatePolicy, Updater}; use parity_version::version; use ethcore_private_tx::{ProviderConfig, EncryptorConfig, SecretStoreEncryptor}; @@ -56,6 +56,7 @@ use cache::CacheConfig; use user_defaults::UserDefaults; use dapps; use ipfs; +use jsonrpc_core; use modules; use rpc; use rpc_apis; @@ -369,6 +370,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: }; // start rpc servers + let rpc_direct = rpc::setup_apis(rpc_apis::ApiSet::All, &dependencies); let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies, dapps_middleware)?; @@ -878,6 +882,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: Ok(RunningClient { inner: RunningClientInner::Full { + rpc: rpc_direct, informant, client, keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), @@ -890,16 +895,18 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: /// Should be destroyed by calling `shutdown()`, otherwise execution will continue in the /// background. pub struct RunningClient { - inner: RunningClientInner + inner: RunningClientInner, } enum RunningClientInner { Light { + rpc: jsonrpc_core::MetaIoHandler>, informant: Arc>, client: Arc, keep_alive: Box, }, Full { + rpc: jsonrpc_core::MetaIoHandler>, informant: Arc>, client: Arc, keep_alive: Box, @@ -907,25 +914,45 @@ enum RunningClientInner { } impl RunningClient { + /// Performs a synchronous RPC query. + /// Blocks execution until the result is ready. + pub fn rpc_query_sync(&self, request: &str) -> Option { + let metadata = Metadata { + origin: Origin::CApi, + session: None, + }; + + match self.inner { + RunningClientInner::Light { ref rpc, .. } => { + rpc.handle_request_sync(request, metadata) + }, + RunningClientInner::Full { ref rpc, .. } => { + rpc.handle_request_sync(request, metadata) + }, + } + } + /// Shuts down the client. pub fn shutdown(self) { match self.inner { - RunningClientInner::Light { informant, client, keep_alive } => { + RunningClientInner::Light { rpc, informant, client, keep_alive } => { // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); + drop(rpc); drop(keep_alive); informant.shutdown(); drop(informant); drop(client); wait_for_drop(weak_client); }, - RunningClientInner::Full { informant, client, keep_alive } => { + RunningClientInner::Full { rpc, informant, client, keep_alive } => { info!("Finishing work, please wait..."); // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); // drop this stuff as soon as exit detected. + drop(rpc); drop(keep_alive); // to make sure timer does not spawn requests while shutdown is in progress informant.shutdown(); diff --git a/rpc/src/v1/types/provenance.rs b/rpc/src/v1/types/provenance.rs index b52f0cb7746..6bcd43a21fa 100644 --- a/rpc/src/v1/types/provenance.rs +++ b/rpc/src/v1/types/provenance.rs @@ -49,6 +49,9 @@ pub enum Origin { /// Session id session: H256 }, + /// From the C API + #[serde(rename="c-api")] + CApi, /// Unknown #[serde(rename="unknown")] Unknown, @@ -68,6 +71,7 @@ impl fmt::Display for Origin { Origin::Ipc(ref session) => write!(f, "IPC (session: {})", session), Origin::Ws { ref session, ref dapp } => write!(f, "{} via WebSocket (session: {})", dapp, session), Origin::Signer { ref session, ref dapp } => write!(f, "{} via UI (session: {})", dapp, session), + Origin::CApi => write!(f, "C API"), Origin::Unknown => write!(f, "unknown origin"), } } From 71b7bcada3a9509954bd41eaf7b34ada4ce99aee Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 23 May 2018 10:27:45 +0100 Subject: [PATCH 119/147] Fix cli signer (#8682) * Update ethereum-types so `{:#x}` applies 0x prefix --- Cargo.lock | 102 +++++++++++++++++++-------------------- rpc/Cargo.toml | 2 +- rpc/src/v1/types/uint.rs | 8 +-- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 646bc906456..c0aae6664f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,7 +248,7 @@ name = "common-types" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", @@ -385,7 +385,7 @@ name = "dir" version = "0.1.0" dependencies = [ "app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", ] @@ -457,7 +457,7 @@ version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -530,7 +530,7 @@ dependencies = [ "ethcore-miner 1.12.0", "ethcore-stratum 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -591,7 +591,7 @@ version = "0.1.0" name = "ethcore-crypto" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -628,7 +628,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethcore-network 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -678,7 +678,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -706,7 +706,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -726,7 +726,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethcore-logger 1.12.0", "ethcore-network 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -764,7 +764,7 @@ dependencies = [ "ethcore-logger 1.12.0", "ethcore-miner 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "fetch 0.1.0", @@ -798,7 +798,7 @@ dependencies = [ "ethcore-logger 1.12.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -847,7 +847,7 @@ version = "1.12.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -871,7 +871,7 @@ dependencies = [ "ethcore-network-devp2p 1.12.0", "ethcore-private-tx 1.0.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -895,7 +895,7 @@ dependencies = [ name = "ethcore-transaction" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "evm 0.1.0", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "ethereum-types" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -917,7 +917,7 @@ dependencies = [ "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -932,7 +932,7 @@ dependencies = [ name = "ethjson" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -947,7 +947,7 @@ dependencies = [ "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "ethcore-crypto 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", @@ -979,7 +979,7 @@ version = "0.2.0" dependencies = [ "dir 0.1.0", "ethcore-crypto 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1019,7 +1019,7 @@ name = "evm" version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1038,7 +1038,7 @@ dependencies = [ "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "evm 0.1.0", "panic_hook 0.1.0", @@ -1178,7 +1178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "hardware-wallet" version = "1.12.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", @@ -1194,7 +1194,7 @@ name = "hashdb" version = "0.1.1" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1342,7 +1342,7 @@ version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", @@ -1456,7 +1456,7 @@ dependencies = [ name = "keccak-hash" version = "0.1.2" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1492,7 +1492,7 @@ name = "kvdb-rocksdb" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1644,7 +1644,7 @@ name = "memorydb" version = "0.1.1" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", @@ -1807,7 +1807,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethcore-network 1.12.0", "ethcore-network-devp2p 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1866,7 +1866,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1978,7 +1978,7 @@ dependencies = [ "ethcore-service 0.1.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fake-fetch 0.0.1", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2044,7 +2044,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-devtools 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2109,7 +2109,7 @@ dependencies = [ "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "fake-fetch 0.0.1", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2133,7 +2133,7 @@ dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2162,7 +2162,7 @@ dependencies = [ name = "parity-machine" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2192,7 +2192,7 @@ dependencies = [ "ethcore-private-tx 1.0.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -2331,7 +2331,7 @@ dependencies = [ "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-sync 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2376,7 +2376,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-network 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2438,7 +2438,7 @@ dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2494,7 +2494,7 @@ name = "plain_hasher" version = "0.1.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2593,7 +2593,7 @@ version = "0.1.0" dependencies = [ "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2766,7 +2766,7 @@ version = "0.2.1" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2974,7 +2974,7 @@ name = "shell32-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3444,7 +3444,7 @@ name = "transaction-pool" version = "1.12.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", @@ -3471,7 +3471,7 @@ name = "trie-standardmap" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "rlp 0.2.1", ] @@ -3481,7 +3481,7 @@ name = "triehash" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "rlp 0.2.1", "trie-standardmap 0.1.0", @@ -3489,7 +3489,7 @@ dependencies = [ [[package]] name = "uint" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3596,7 +3596,7 @@ name = "util-error" version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3628,7 +3628,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3647,7 +3647,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3847,7 +3847,7 @@ dependencies = [ "checksum ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "210c9e21d164c15b6ef64fe601e0e12a3c84a031d5ef558e38463e53edbd22ed" "checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" -"checksum ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3ae691a36ce5d25b433e63128ce5579f4a18457b6a9c849832b2c9e0fec92a" +"checksum ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c48729b8aea8aedb12cf4cb2e5cef439fdfe2dda4a89e47eeebd15778ef53b6" "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" @@ -4045,7 +4045,7 @@ dependencies = [ "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "715254c8f0811be1a79ad3ea5e6fa3c8eddec2b03d7f5ba78cf093e56d79c24f" "checksum trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)" = "" -"checksum uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6477b2716357758c176c36719023e1f9726974d762150e4fc0a9c8c75488c343" +"checksum uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38051a96565903d81c9a9210ce11076b2218f3b352926baa1f5f6abbdfce8273" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 731544a55f2..8fdb9ed5740 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -47,7 +47,7 @@ ethcore-miner = { path = "../miner" } ethcore-private-tx = { path = "../ethcore/private-tx" } ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } -ethereum-types = "0.3" +ethereum-types = "0.3.2" ethjson = { path = "../json" } ethkey = { path = "../ethkey" } diff --git a/rpc/src/v1/types/uint.rs b/rpc/src/v1/types/uint.rs index e887322dbae..4e2a189a63f 100644 --- a/rpc/src/v1/types/uint.rs +++ b/rpc/src/v1/types/uint.rs @@ -55,7 +55,7 @@ macro_rules! impl_uint { impl fmt::LowerHex for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:#x}", self.0) + fmt::LowerHex::fmt(&self.0, f) } } @@ -102,19 +102,19 @@ impl_uint!(U64, u64, 1); impl serde::Serialize for U128 { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(&format!("0x{:x}", self.0)) + serializer.serialize_str(&format!("{:#x}", self)) } } impl serde::Serialize for U256 { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(&format!("0x{:x}", self.0)) + serializer.serialize_str(&format!("{:#x}", self)) } } impl serde::Serialize for U64 { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(&format!("0x{:x}", self.0)) + serializer.serialize_str(&format!("{:#x}", self)) } } From 6c0307a1031f7173fcc39e731a555a5677d92f70 Mon Sep 17 00:00:00 2001 From: Vlad Lupashevskyi Date: Wed, 23 May 2018 17:21:19 +0300 Subject: [PATCH 120/147] Fix tx permission tests --- ethcore/src/tx_filter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index e09e81ac161..24b113f8821 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -237,7 +237,7 @@ mod test { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000001")).unwrap(); From c832c4f99221ea39c9f2f510cceee63e81259280 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 24 May 2018 04:39:52 +0200 Subject: [PATCH 121/147] Use impl Future in the light client RPC helpers (#8628) --- rpc/src/v1/helpers/light_fetch.rs | 69 +++++++++++++++---------------- rpc/src/v1/impls/eth_pubsub.rs | 2 +- rpc/src/v1/impls/light/eth.rs | 2 +- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index d8a157da21b..413670d5210 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -25,7 +25,7 @@ use ethcore::ids::BlockId; use ethcore::filter::Filter as EthcoreFilter; use ethcore::receipt::Receipt; -use jsonrpc_core::{BoxFuture, Result}; +use jsonrpc_core::{Result, Error}; use jsonrpc_core::futures::{future, Future}; use jsonrpc_core::futures::future::Either; use jsonrpc_macros::Trailing; @@ -139,58 +139,57 @@ impl LightFetch { } /// Get a block header from the on demand service or client, or error. - pub fn header(&self, id: BlockId) -> BoxFuture { + pub fn header(&self, id: BlockId) -> impl Future + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; - - self.send_requests(reqs, |res| + Either::B(self.send_requests(reqs, |res| extract_header(&res, header_ref) .expect("these responses correspond to requests that header_ref belongs to \ therefore it will not fail; qed") - ) + )) } /// Helper for getting contract code at a given block. - pub fn code(&self, address: Address, id: BlockId) -> BoxFuture> { + pub fn code(&self, address: Address, id: BlockId) -> impl Future, Error = Error> + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::Account { header: header_ref.clone(), address: address }.into()); let account_idx = reqs.len() - 1; reqs.push(request::Code { header: header_ref, code_hash: Field::back_ref(account_idx, 0) }.into()); - self.send_requests(reqs, |mut res| match res.pop() { + Either::B(self.send_requests(reqs, |mut res| match res.pop() { Some(OnDemandResponse::Code(code)) => code, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Helper for getting account info at a given block. /// `None` indicates the account doesn't exist at the given block. - pub fn account(&self, address: Address, id: BlockId) -> BoxFuture> { + pub fn account(&self, address: Address, id: BlockId) -> impl Future, Error = Error> + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::Account { header: header_ref, address: address }.into()); - self.send_requests(reqs, |mut res|match res.pop() { + Either::B(self.send_requests(reqs, |mut res|match res.pop() { Some(OnDemandResponse::Account(acc)) => acc, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Helper for getting proved execution. - pub fn proved_execution(&self, req: CallRequest, num: Trailing) -> BoxFuture { + pub fn proved_execution(&self, req: CallRequest, num: Trailing) -> impl Future + Send { const DEFAULT_GAS_PRICE: u64 = 21_000; // starting gas when gas not provided. const START_GAS: u64 = 50_000; @@ -280,39 +279,39 @@ impl LightFetch { } /// Get a block itself. Fails on unknown block ID. - pub fn block(&self, id: BlockId) -> BoxFuture { + pub fn block(&self, id: BlockId) -> impl Future + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::Body(header_ref).into()); - self.send_requests(reqs, |mut res| match res.pop() { + Either::B(self.send_requests(reqs, |mut res| match res.pop() { Some(OnDemandResponse::Body(b)) => b, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Get the block receipts. Fails on unknown block ID. - pub fn receipts(&self, id: BlockId) -> BoxFuture> { + pub fn receipts(&self, id: BlockId) -> impl Future, Error = Error> + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::BlockReceipts(header_ref).into()); - self.send_requests(reqs, |mut res| match res.pop() { + Either::B(self.send_requests(reqs, |mut res| match res.pop() { Some(OnDemandResponse::Receipts(b)) => b, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Get transaction logs - pub fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { + pub fn logs(&self, filter: EthcoreFilter) -> impl Future, Error = Error> + Send { use std::collections::BTreeMap; use jsonrpc_core::futures::stream::{self, Stream}; @@ -326,9 +325,9 @@ impl LightFetch { }; match (block_number(filter.to_block), block_number(filter.from_block)) { - (Some(to), Some(from)) if to < from => return Box::new(future::ok(Vec::new())), + (Some(to), Some(from)) if to < from => return Either::A(future::ok(Vec::new())), (Some(_), Some(_)) => {}, - _ => return Box::new(future::err(errors::unknown_block())), + _ => return Either::A(future::err(errors::unknown_block())), } let maybe_future = self.sync.with_context(move |ctx| { @@ -362,15 +361,15 @@ impl LightFetch { }); match maybe_future { - Some(fut) => Box::new(fut), - None => Box::new(future::err(errors::network_disabled())), + Some(fut) => Either::B(Either::A(fut)), + None => Either::B(Either::B(future::err(errors::network_disabled()))), } } // Get a transaction by hash. also returns the index in the block. // Only returns transactions in the canonical chain. pub fn transaction_by_hash(&self, tx_hash: H256, eip86_transition: u64) - -> BoxFuture> + -> impl Future, Error = Error> + Send { let params = (self.sync.clone(), self.on_demand.clone()); let fetcher: Self = self.clone(); @@ -426,7 +425,7 @@ impl LightFetch { })) } - fn send_requests(&self, reqs: Vec, parse_response: F) -> BoxFuture where + fn send_requests(&self, reqs: Vec, parse_response: F) -> impl Future + Send where F: FnOnce(Vec) -> T + Send + 'static, T: Send + 'static, { @@ -439,7 +438,7 @@ impl LightFetch { match maybe_future { Some(recv) => recv, - None => Box::new(future::err(errors::network_disabled())) + None => Box::new(future::err(errors::network_disabled())) as Box + Send> } } } @@ -457,7 +456,7 @@ struct ExecuteParams { // has a peer execute the transaction with given params. If `gas_known` is false, // this will double the gas on each `OutOfGas` error. -fn execute_tx(gas_known: bool, params: ExecuteParams) -> BoxFuture { +fn execute_tx(gas_known: bool, params: ExecuteParams) -> impl Future + Send { if !gas_known { Box::new(future::loop_fn(params, |mut params| { execute_tx(true, params.clone()).and_then(move |res| { @@ -480,7 +479,7 @@ fn execute_tx(gas_known: bool, params: ExecuteParams) -> BoxFuture Ok(future::Loop::Break(failed)), } }) - })) + })) as Box + Send> } else { trace!(target: "light_fetch", "Placing execution request for {} gas in on_demand", params.tx.gas); @@ -501,8 +500,8 @@ fn execute_tx(gas_known: bool, params: ExecuteParams) -> BoxFuture Box::new(fut), - None => Box::new(future::err(errors::network_disabled())), + Some(fut) => Box::new(fut) as Box + Send>, + None => Box::new(future::err(errors::network_disabled())) as Box + Send>, } } } diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index 30459594466..c0789910c33 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -199,7 +199,7 @@ impl LightClient for LightFetch { } fn logs(&self, filter: EthFilter) -> BoxFuture> { - LightFetch::logs(self, filter) + Box::new(LightFetch::logs(self, filter)) as BoxFuture<_> } } diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 35f7792b52c..10ad024f244 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -538,7 +538,7 @@ impl Filterable for EthClient { } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { - self.fetcher().logs(filter) + Box::new(self.fetcher().logs(filter)) as BoxFuture<_> } fn pending_logs(&self, _block_number: u64, _filter: &EthcoreFilter) -> Vec { From c9ea2209a0acf590973bff50fe6edcc5884e5de6 Mon Sep 17 00:00:00 2001 From: Thibaut S <33178835+Tbaut@users.noreply.github.com> Date: Thu, 24 May 2018 10:53:37 +0200 Subject: [PATCH 122/147] Update mod.rs (#8695) - Update interfaces affected by unsafe-expose - replace `{{ }}` as this throws an error in Jekyll (wiki) --- parity/cli/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 34e3bf03a11..a064baeac56 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -315,7 +315,7 @@ usage! { ["Convenience options"] FLAG flag_unsafe_expose: (bool) = false, or |c: &Config| c.misc.as_ref()?.unsafe_expose, "--unsafe-expose", - "All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --{{ws,jsonrpc,ui,ipfs,secret_store,stratum}}-interface=all --*-hosts=all This option is UNSAFE and should be used with great care!", + "All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --[ws,jsonrpc,ui,ipfs-api,secretstore,stratum,dapps,secretstore-http]-interface=all --*-hosts=all This option is UNSAFE and should be used with great care!", ARG arg_config: (String) = "$BASE/config.toml", or |_| None, "-c, --config=[CONFIG]", From 2a962df5520445796569f920c8810ec19ed51cdf Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 24 May 2018 13:06:48 +0200 Subject: [PATCH 123/147] remove empty file (#8705) --- ethstore/tests/cli.rs | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 ethstore/tests/cli.rs diff --git a/ethstore/tests/cli.rs b/ethstore/tests/cli.rs deleted file mode 100644 index f90ec463dc4..00000000000 --- a/ethstore/tests/cli.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - From 0a5298fa3b3938ea9214a1b087af5accb7196dfb Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 May 2018 17:29:28 +0200 Subject: [PATCH 124/147] Set the request index to that of the current request (#8683) * Set the request index to that of the current request When setting up the chain of (two) requests to look up a block by hash, the second need to refer to the first. This fixes an issue where the back ref was set to the subsequent request, not the current one. When the requests are executed we loop through them in order and ensure the requests that should produce headers all match up. We do this by index so they better be right. In other words: off by one. --- rpc/src/v1/helpers/light_fetch.rs | 3 +-- rpc/src/v1/tests/eth.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index 413670d5210..1baf9a76471 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -129,9 +129,8 @@ impl LightFetch { } } BlockId::Hash(h) => { - reqs.push(request::HeaderByHash(h.into()).into()); - let idx = reqs.len(); + reqs.push(request::HeaderByHash(h.into()).into()); Ok(HeaderRef::Unresolved(idx, h.into())) } _ => Err(errors::unknown_block()) // latest, earliest, and pending will have all already returned. diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 4b83710bc02..26117471cee 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -204,6 +204,18 @@ fn eth_get_block() { assert_eq!(tester.handler.handle_request_sync(req_block).unwrap(), res_block); } +#[test] +fn eth_get_block_by_hash() { + let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test"); + let tester = EthTester::from_chain(&chain); + + // We're looking for block number 4 from "RPC_API_Test_Frontier" + let req_block = r#"{"method":"eth_getBlockByHash","params":["0x9c9bdab4cb53fd834e790b13545597f026494d42112e84c0aca9dd6bcc545295",false],"id":1,"jsonrpc":"2.0"}"#; + + let res_block = r#"{"jsonrpc":"2.0","result":{"author":"0x8888f1f195afa192cfee860698584c030f4c9db1","difficulty":"0x200c0","extraData":"0x","gasLimit":"0x1dd8112","gasUsed":"0x5458","hash":"0x9c9bdab4cb53fd834e790b13545597f026494d42112e84c0aca9dd6bcc545295","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x8888f1f195afa192cfee860698584c030f4c9db1","mixHash":"0xaddea8d25bb0f955fa6c1d58d74ab8a3fec99d37943e2a261e3b12f97d6bff7c","nonce":"0x8e18bed16d5a88da","number":"0x4","parentHash":"0x2cbf4fc930c5b4c87598f43fc8eb26dccdab2f58a7d0d3ca92ec60a5444a330e","receiptsRoot":"0x7ed8026cf72ed0e98e6fd53ab406e51ffd34397d9da0052494ff41376fda7b5f","sealFields":["0xa0addea8d25bb0f955fa6c1d58d74ab8a3fec99d37943e2a261e3b12f97d6bff7c","0x888e18bed16d5a88da"],"sha3Uncles":"0x75cc08a7cb2cf8081446659fecb2633fb6b922d26edd59bd2272b1f5cae1c78b","size":"0x661","stateRoot":"0x68805721294e365020aca15ed56c360d9dc2cf03cbeff84c9b84b8aed023bfb5","timestamp":"0x59d662ff","totalDifficulty":"0xa0180","transactions":["0xb094b9dc356dbb8b256402c6d5709288066ad6a372c90c9c516f14277545fd58"],"transactionsRoot":"0x97a593d8d7e15b57f5c6bb25bc6c325463ef99f874bc08a78656c3ab5cb23262","uncles":["0xa1e9c9ecd2af999e0723aae1dc55dd9789ca618e0b34badcc8ac7d9a3dad3af2","0x81d429b6b6635214a2b0f976cc4b2ed49808140d6bede50129bc10d22ac9249e"]},"id":1}"#; + assert_eq!(tester.handler.handle_request_sync(req_block).unwrap(), res_block); +} + // a frontier-like test with an expanded gas limit and balance on known account. const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{ "name": "Frontier (Test)", From 4a35764b1107208253c4fd6763c8b3b57ba02f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 24 May 2018 19:43:18 +0200 Subject: [PATCH 125/147] parity: trim whitespace when parsing duration strings (#8692) --- parity/helpers.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/parity/helpers.rs b/parity/helpers.rs index 80ade509834..a5ec3c99d4b 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -47,11 +47,11 @@ fn to_seconds(s: &str) -> Result { "1minute" | "1 minute" | "minute" => Ok(60), "hourly" | "1hour" | "1 hour" | "hour" => Ok(60 * 60), "daily" | "1day" | "1 day" | "day" => Ok(24 * 60 * 60), - x if x.ends_with("seconds") => x[0..x.len() - 7].parse().map_err(bad), - x if x.ends_with("minutes") => x[0..x.len() - 7].parse::().map_err(bad).map(|x| x * 60), - x if x.ends_with("hours") => x[0..x.len() - 5].parse::().map_err(bad).map(|x| x * 60 * 60), - x if x.ends_with("days") => x[0..x.len() - 4].parse::().map_err(bad).map(|x| x * 24 * 60 * 60), - x => x.parse().map_err(bad), + x if x.ends_with("seconds") => x[0..x.len() - 7].trim().parse().map_err(bad), + x if x.ends_with("minutes") => x[0..x.len() - 7].trim().parse::().map_err(bad).map(|x| x * 60), + x if x.ends_with("hours") => x[0..x.len() - 5].trim().parse::().map_err(bad).map(|x| x * 60 * 60), + x if x.ends_with("days") => x[0..x.len() - 4].trim().parse::().map_err(bad).map(|x| x * 24 * 60 * 60), + x => x.trim().parse().map_err(bad), } } @@ -350,6 +350,8 @@ mod tests { assert_eq!(to_duration("1day").unwrap(), Duration::from_secs(1 * 24 * 60 * 60)); assert_eq!(to_duration("2days").unwrap(), Duration::from_secs(2 * 24 *60 * 60)); assert_eq!(to_duration("15days").unwrap(), Duration::from_secs(15 * 24 * 60 * 60)); + assert_eq!(to_duration("15 days").unwrap(), Duration::from_secs(15 * 24 * 60 * 60)); + assert_eq!(to_duration("2 seconds").unwrap(), Duration::from_secs(2)); } #[test] From 1f2b646116e4dcb96d89112e872b0a8e1d542a1e Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 25 May 2018 13:19:32 +0200 Subject: [PATCH 126/147] Implement recursive Debug for Nodes in patrica_trie::TrieDB (#8697) fixes #8184 --- util/patricia_trie/src/triedb.rs | 228 ++++++++++++++++++++++--------- 1 file changed, 164 insertions(+), 64 deletions(-) diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index aed683117d3..259525e2ee2 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -78,64 +78,9 @@ impl<'db> TrieDB<'db> { /// Get the data of the root node. fn root_data(&self) -> super::Result { - self.db.get(self.root).ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) - } - - /// Indentation helper for `format_all`. - fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result { - for _ in 0..size { - write!(f, " ")?; - } - Ok(()) - } - - /// Recursion helper for implementation of formatting trait. - fn fmt_all(&self, node: Node, f: &mut fmt::Formatter, deepness: usize) -> fmt::Result { - match node { - Node::Leaf(slice, value) => writeln!(f, "'{:?}: {:?}.", slice, value.pretty())?, - Node::Extension(ref slice, ref item) => { - write!(f, "'{:?} ", slice)?; - if let Ok(node) = self.get_raw_or_lookup(&*item) { - match Node::decoded(&node) { - Ok(n) => self.fmt_all(n, f, deepness)?, - Err(err) => writeln!(f, "ERROR decoding node extension Rlp: {}", err)?, - } - } - }, - Node::Branch(ref nodes, ref value) => { - writeln!(f, "")?; - if let Some(ref v) = *value { - self.fmt_indent(f, deepness + 1)?; - writeln!(f, "=: {:?}", v.pretty())? - } - for i in 0..16 { - let node = self.get_raw_or_lookup(&*nodes[i]); - match node.as_ref() { - Ok(n) => { - match Node::decoded(&*n) { - Ok(Node::Empty) => {}, - Ok(n) => { - self.fmt_indent(f, deepness + 1)?; - write!(f, "'{:x} ", i)?; - self.fmt_all(n, f, deepness + 1)?; - } - Err(e) => { - write!(f, "ERROR decoding node branch Rlp: {}", e)? - } - } - } - Err(e) => { - write!(f, "ERROR: {}", e)?; - } - } - } - }, - // empty - Node::Empty => { - writeln!(f, "")?; - } - }; - Ok(()) + self.db + .get(self.root) + .ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) } /// Given some node-describing data `node`, return the actual node RLP. @@ -174,15 +119,58 @@ impl<'db> Trie for TrieDB<'db> { } } +// This is for pretty debug output only +struct TrieAwareDebugNode<'db, 'a> { + trie: &'db TrieDB<'db>, + key: &'a[u8] +} + +impl<'db, 'a> fmt::Debug for TrieAwareDebugNode<'db, 'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(node) = self.trie.get_raw_or_lookup(self.key) { + match Node::decoded(&node) { + Ok(Node::Leaf(slice, value)) => f.debug_struct("Node::Leaf") + .field("slice", &slice) + .field("value", &value) + .finish(), + Ok(Node::Extension(ref slice, ref item)) => f.debug_struct("Node::Extension") + .field("slice", &slice) + .field("item", &TrieAwareDebugNode{trie: self.trie, key: item}) + .finish(), + Ok(Node::Branch(ref nodes, ref value)) => { + let nodes: Vec = nodes.into_iter().map(|n| TrieAwareDebugNode{trie: self.trie, key: n} ).collect(); + f.debug_struct("Node::Branch") + .field("nodes", &nodes) + .field("value", &value) + .finish() + }, + Ok(Node::Empty) => f.debug_struct("Node::Empty").finish(), + + Err(e) => f.debug_struct("BROKEN_NODE") + .field("key", &self.key) + .field("error", &format!("ERROR decoding node branch Rlp: {}", e)) + .finish() + } + } else { + f.debug_struct("BROKEN_NODE") + .field("key", &self.key) + .field("error", &"Not found") + .finish() + } + } +} + + impl<'db> fmt::Debug for TrieDB<'db> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "c={:?} [", self.hash_count)?; let root_rlp = self.db.get(self.root).expect("Trie root not found!"); - match Node::decoded(&root_rlp) { - Ok(node) => self.fmt_all(node, f, 0)?, - Err(e) => writeln!(f, "ERROR decoding node rlp: {}", e)?, - } - writeln!(f, "]") + f.debug_struct("TrieDB") + .field("hash_count", &self.hash_count) + .field("root", &TrieAwareDebugNode { + trie: self, + key: &root_rlp + }) + .finish() } } @@ -494,6 +482,118 @@ fn get_len() { assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None)); } + +#[test] +fn debug_output_supports_pretty_print() { + use memorydb::*; + use super::TrieMut; + use super::triedbmut::*; + + let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; + + let mut memdb = MemoryDB::new(); + let mut root = H256::new(); + let root = { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + for x in &d { + t.insert(x, x).unwrap(); + } + t.root().clone() + }; + let t = TrieDB::new(&memdb, &root).unwrap(); + + assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }"); + assert_eq!(format!("{:#?}", t), +"TrieDB { + hash_count: 0, + root: Node::Extension { + slice: 4, + item: Node::Branch { + nodes: [ + Node::Empty, + Node::Branch { + nodes: [ + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Branch { + nodes: [ + Node::Empty, + Node::Leaf { + slice: , + value: [ + 65, + 65 + ] + }, + Node::Leaf { + slice: , + value: [ + 65, + 66 + ] + }, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty + ], + value: None + }, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty + ], + value: Some( + [ + 65 + ] + ) + }, + Node::Leaf { + slice: , + value: [ + 66 + ] + }, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty + ], + value: None + } + } +}"); +} + // Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking //#[test] //fn test_lookup_with_corrupt_data_returns_decoder_error() { From 8f0997ede2a0e223f56bf7463b14e943a0f4abc0 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 28 May 2018 16:32:29 +0200 Subject: [PATCH 127/147] Remove unused imports (#8722) --- util/network/src/lib.rs | 2 +- util/patricia_trie/src/triedb.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index f3012e4c376..207a05075d2 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -42,7 +42,7 @@ use std::sync::Arc; use std::time::Duration; use ipnetwork::{IpNetwork, IpNetworkError}; use ethkey::Secret; -use ethereum_types::{H256, H512}; +use ethereum_types::H512; use rlp::{Decodable, DecoderError, Rlp}; /// Protocol handler level packet id diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index 259525e2ee2..ed2c19e0690 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -21,7 +21,7 @@ use super::node::{Node, OwnedNode}; use super::lookup::Lookup; use super::{Trie, TrieItem, TrieError, TrieIterator, Query}; use ethereum_types::H256; -use bytes::{ToPretty, Bytes}; +use bytes::Bytes; /// A `Trie` implementation using a generic `HashDB` backing database. /// @@ -501,7 +501,7 @@ fn debug_output_supports_pretty_print() { t.root().clone() }; let t = TrieDB::new(&memdb, &root).unwrap(); - + assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }"); assert_eq!(format!("{:#?}", t), "TrieDB { From c048ed984855d86fb84da6f9bee65478349008a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 28 May 2018 16:39:26 +0200 Subject: [PATCH 128/147] Update dev chain (#8717) * Make dev chain more foundation-like and enable wasm. * Fix compilation warnings. --- ethcore/res/instant_seal.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index acd1b49ed04..36832e698e6 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -10,10 +10,20 @@ "minGasLimit": "0x1388", "networkID" : "0x11", "registrar" : "0x0000000000000000000000000000000000001337", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff", + "maxCodeSize": 24576, + "maxCodeSizeTransition": "0x0", "eip140Transition": "0x0", "eip211Transition": "0x0", "eip214Transition": "0x0", - "eip658Transition": "0x0" + "eip658Transition": "0x0", + "wasmActivationTransition": "0x0" }, "genesis": { "seal": { From df39c507bdf6ad7cb31c6fce848242533a07b35f Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 May 2018 16:41:08 +0200 Subject: [PATCH 129/147] Add a test for decoding corrupt data (#8713) --- util/patricia_trie/src/triedb.rs | 50 +++++++++++++++----------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index ed2c19e0690..c18e4fce967 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -594,29 +594,27 @@ fn debug_output_supports_pretty_print() { }"); } -// Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking -//#[test] -//fn test_lookup_with_corrupt_data_returns_decoder_error() { -// use memorydb::*; -// use super::TrieMut; -// use super::triedbmut::*; -// use rlp; -// use ethereum_types::H512; -// -// let mut memdb = MemoryDB::new(); -// let mut root = H256::new(); -// { -// let mut t = TrieDBMut::new(&mut memdb, &mut root); -// t.insert(b"A", b"ABC").unwrap(); -// t.insert(b"B", b"ABCBA").unwrap(); -// } -// -// let t = TrieDB::new(&memdb, &root).unwrap(); -// -// // query for an invalid data type to trigger an error -// let q = rlp::decode::; -// let lookup = Lookup{ db: t.db, query: q, hash: root }; -// let query_result = lookup.look_up(NibbleSlice::new(b"A")); -// let expected = Box::new(TrieError::DecoderError(::rlp::DecoderError::RlpIsTooShort)); -// assert_eq!(query_result.unwrap_err(), expected); -//} +#[test] +fn test_lookup_with_corrupt_data_returns_decoder_error() { + use memorydb::*; + use super::TrieMut; + use super::triedbmut::*; + use rlp; + use ethereum_types::H512; + + let mut memdb = MemoryDB::new(); + let mut root = H256::new(); + { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + t.insert(b"A", b"ABC").unwrap(); + t.insert(b"B", b"ABCBA").unwrap(); + } + + let t = TrieDB::new(&memdb, &root).unwrap(); + + // query for an invalid data type to trigger an error + let q = rlp::decode::; + let lookup = Lookup{ db: t.db, query: q, hash: root }; + let query_result = lookup.look_up(NibbleSlice::new(b"A")); + assert_eq!(query_result.unwrap().unwrap().unwrap_err(), rlp::DecoderError::RlpIsTooShort); +} From 710c06eb263f13c3bce28872746e046046c7c1c6 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 May 2018 17:10:29 +0200 Subject: [PATCH 130/147] Fix compilation error on nightly rust (#8707) On nightly rust passing `public_url` works but that breaks on stable. This works for both. --- util/network-devp2p/src/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index eb2e9685d42..1b46ca1ae33 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -32,7 +32,7 @@ impl IoHandler for HostHandler { if let NetworkIoMessage::NetworkStarted(ref public_url) = *message { let mut url = self.public_url.write(); if url.as_ref().map_or(true, |uref| uref != public_url) { - info!(target: "network", "Public node URL: {}", Colour::White.bold().paint(public_url.as_ref())); + info!(target: "network", "Public node URL: {}", Colour::White.bold().paint(AsRef::::as_ref(public_url))); } *url = Some(public_url.to_owned()); } From 79046ed067a7011e239741b7cbd8e13298920f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 29 May 2018 09:16:08 +0200 Subject: [PATCH 131/147] network-devp2p: handle UselessPeer disconnect (#8686) --- util/network-devp2p/src/host.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index fbbeb89ff8e..2f577821a7a 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -686,14 +686,17 @@ impl Host { Err(e) => { let s = session.lock(); trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); - if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() { - if let Some(id) = s.id() { - if !self.reserved_nodes.read().contains(id) { - let mut nodes = self.nodes.write(); - nodes.note_failure(&id); - nodes.mark_as_useless(id); + match *e.kind() { + ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) | ErrorKind::Disconnect(DisconnectReason::UselessPeer) => { + if let Some(id) = s.id() { + if !self.reserved_nodes.read().contains(id) { + let mut nodes = self.nodes.write(); + nodes.note_failure(&id); + nodes.mark_as_useless(id); + } } - } + }, + _ => {}, } kill = true; break; From 769e9e9421958f82f1669343d4a72a6549814177 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Tue, 29 May 2018 12:23:15 +0200 Subject: [PATCH 132/147] Shutdown the Snapshot Service early (#8658) * Shutdown the Snapshot Service when shutting down the runner * Rename `service` to `client_service` * Fix tests --- ethcore/service/src/service.rs | 7 ++++++- ethcore/src/snapshot/service.rs | 4 ++++ ethcore/src/snapshot/traits.rs | 3 +++ ethcore/sync/src/tests/snapshot.rs | 4 ++++ parity/run.rs | 9 +++++++-- rpc/src/v1/tests/helpers/snapshot_service.rs | 1 + 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 5f46799796a..f703329d611 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -29,7 +29,7 @@ use sync::PrivateTxHandler; use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage}; use ethcore::miner::Miner; use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams}; -use ethcore::snapshot::{RestorationStatus}; +use ethcore::snapshot::{SnapshotService as _SnapshotService, RestorationStatus}; use ethcore::spec::Spec; use ethcore::account_provider::AccountProvider; @@ -168,6 +168,11 @@ impl ClientService { /// Get a handle to the database. pub fn db(&self) -> Arc { self.database.clone() } + + /// Shutdown the Client Service + pub fn shutdown(&self) { + self.snapshot.shutdown(); + } } /// IO interface for the Client handler diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 17c362e0440..942015d0f10 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -743,6 +743,10 @@ impl SnapshotService for Service { trace!("Error sending snapshot service message: {:?}", e); } } + + fn shutdown(&self) { + self.abort_restore(); + } } impl Drop for Service { diff --git a/ethcore/src/snapshot/traits.rs b/ethcore/src/snapshot/traits.rs index 2b6ee9df9f4..d951f4c5341 100644 --- a/ethcore/src/snapshot/traits.rs +++ b/ethcore/src/snapshot/traits.rs @@ -54,4 +54,7 @@ pub trait SnapshotService : Sync + Send { /// Feed a raw block chunk to the service to be processed asynchronously. /// no-op if currently restoring. fn restore_block_chunk(&self, hash: H256, chunk: Bytes); + + /// Shutdown the Snapshot Service by aborting any ongoing restore + fn shutdown(&self); } diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index 864f3d4dc6e..ffb71d7a730 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -133,6 +133,10 @@ impl SnapshotService for TestSnapshotService { self.block_restoration_chunks.lock().insert(hash, chunk); } } + + fn shutdown(&self) { + self.abort_restore(); + } } #[test] diff --git a/parity/run.rs b/parity/run.rs index fd16085c46c..31f8779c0fa 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -885,7 +885,8 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: rpc: rpc_direct, informant, client, - keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + client_service: Arc::new(service), + keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), } }) } @@ -909,6 +910,7 @@ enum RunningClientInner { rpc: jsonrpc_core::MetaIoHandler>, informant: Arc>, client: Arc, + client_service: Arc, keep_alive: Box, }, } @@ -946,11 +948,14 @@ impl RunningClient { drop(client); wait_for_drop(weak_client); }, - RunningClientInner::Full { rpc, informant, client, keep_alive } => { + RunningClientInner::Full { rpc, informant, client, client_service, keep_alive } => { info!("Finishing work, please wait..."); // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); + // Shutdown and drop the ServiceClient + client_service.shutdown(); + drop(client_service); // drop this stuff as soon as exit detected. drop(rpc); drop(keep_alive); diff --git a/rpc/src/v1/tests/helpers/snapshot_service.rs b/rpc/src/v1/tests/helpers/snapshot_service.rs index 099773ab522..91cd14d73f1 100644 --- a/rpc/src/v1/tests/helpers/snapshot_service.rs +++ b/rpc/src/v1/tests/helpers/snapshot_service.rs @@ -50,4 +50,5 @@ impl SnapshotService for TestSnapshotService { fn abort_restore(&self) { } fn restore_state_chunk(&self, _hash: H256, _chunk: Bytes) { } fn restore_block_chunk(&self, _hash: H256, _chunk: Bytes) { } + fn shutdown(&self) { } } From 413664bbcc52efb1d745fabe21876736ee8258b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 30 May 2018 11:34:49 +0200 Subject: [PATCH 133/147] Fix local transactions policy. (#8691) --- miner/src/pool/scoring.rs | 33 +++++++++++++++++++++++++++++++++ miner/src/pool/tests/mod.rs | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs index eaf06983328..aedc40e1f2c 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -107,6 +107,15 @@ impl txpool::Scoring for NonceAndGasPrice { } } + // Always kick out non-local transactions in favour of local ones. + if new.priority().is_local() && !old.priority().is_local() { + return true; + } + // And never kick out local transactions in favour of external ones. + if !new.priority().is_local() && old.priority.is_local() { + return false; + } + self.choose(old, new) == txpool::scoring::Choice::ReplaceOld } } @@ -119,6 +128,30 @@ mod tests { use pool::tests::tx::{Tx, TxExt}; use txpool::Scoring; + #[test] + fn should_replace_non_local_transaction_with_local_one() { + // given + let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); + let tx1 = { + let tx = Tx::default().signed().verified(); + txpool::Transaction { + insertion_id: 0, + transaction: Arc::new(tx), + } + }; + let tx2 = { + let mut tx = Tx::default().signed().verified(); + tx.priority = ::pool::Priority::Local; + txpool::Transaction { + insertion_id: 0, + transaction: Arc::new(tx), + } + }; + + assert!(scoring.should_replace(&tx1, &tx2)); + assert!(!scoring.should_replace(&tx2, &tx1)); + } + #[test] fn should_calculate_score_correctly() { // given diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 5d80c2d5bf6..85dedaaa45b 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -766,4 +766,35 @@ fn should_reject_big_transaction() { verifier::Transaction::Local(PendingTransaction::new(big_tx, transaction::Condition::Timestamp(1000).into())) ]); assert_eq!(res, vec![Err(transaction::Error::TooBig)]); -} \ No newline at end of file +} + +#[test] +fn should_include_local_transaction_to_a_full_pool() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 1, + max_per_sender: 2, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let tx1 = Tx::gas_price(10_000).signed().unverified(); + let tx2 = Tx::gas_price(1).signed().local(); + + let res = txq.import(TestClient::new().with_balance(1_000_000_000), vec![tx1]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + // when + let res = txq.import(TestClient::new(), vec![tx2]); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.status().status.transaction_count, 1); +} From 423fa2f967baafe58d6775a525e3232fef5a86f4 Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Wed, 30 May 2018 16:42:37 +0300 Subject: [PATCH 134/147] Add a deadlock detection thread (#8727) * Add a deadlock detection thread Expose it under a feature flag: `cargo build --features "deadlock_detection"` * Address Nicklas's comments --- Cargo.lock | 36 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + parity/lib.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c0aae6664f1..c8e60dce693 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1092,6 +1092,11 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fixedbitset" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "flate2" version = "1.0.1" @@ -1939,6 +1944,11 @@ dependencies = [ "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ordermap" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "owning_ref" version = "0.3.3" @@ -2420,10 +2430,13 @@ name = "parking_lot_core" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2454,6 +2467,15 @@ name = "percent-encoding" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "petgraph" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "phf" version = "0.7.21" @@ -3183,6 +3205,16 @@ dependencies = [ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread-id" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.4" @@ -3851,6 +3883,7 @@ dependencies = [ "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" +"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -3931,6 +3964,7 @@ dependencies = [ "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efa535d5117d3661134dbf1719b6f0ffe06f2375843b13935db186cd094105eb" "checksum ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58d25b6c0e47b20d05226d288ff434940296e7e2f8b877975da32f862152241f" +"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "261c025c67ba416e9fe63aa9b3236520ce3c74cfbe43590c9cdcec4ccc8180e4" "checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "" @@ -3943,6 +3977,7 @@ dependencies = [ "checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" +"checksum petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8b30dc85588cd02b9b76f5e386535db546d21dc68506cff2abebee0b6445e8e4" "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc" "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f" "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" @@ -4021,6 +4056,7 @@ dependencies = [ "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" +"checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" diff --git a/Cargo.toml b/Cargo.toml index de1a78bf4fa..24649eff454 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ evm-debug-tests = ["ethcore/evm-debug-tests"] slow-blocks = ["ethcore/slow-blocks"] secretstore = ["ethcore-secretstore"] final = ["parity-version/final"] +deadlock_detection = ["parking_lot/deadlock_detection"] [lib] path = "parity/lib.rs" diff --git a/parity/lib.rs b/parity/lib.rs index 4d9d1a2c95f..6ef332da65e 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -141,6 +141,35 @@ fn print_hash_of(maybe_file: Option) -> Result { } } +#[cfg(feature = "deadlock_detection")] +fn run_deadlock_detection_thread() { + use std::thread; + use std::time::Duration; + use parking_lot::deadlock; + + info!("Starting deadlock detection thread."); + // Create a background thread which checks for deadlocks every 10s + thread::spawn(move || { + loop { + thread::sleep(Duration::from_secs(10)); + let deadlocks = deadlock::check_deadlock(); + if deadlocks.is_empty() { + continue; + } + + warn!("{} {} detected", deadlocks.len(), Style::new().bold().paint("deadlock(s)")); + for (i, threads) in deadlocks.iter().enumerate() { + warn!("{} #{}", Style::new().bold().paint("Deadlock"), i); + for t in threads { + warn!("Thread Id {:#?}", t.thread_id()); + warn!("{:#?}", t.backtrace()); + } + } + } + }); +} + + /// Action that Parity performed when running `start`. pub enum ExecutionAction { /// The execution didn't require starting a node, and thus has finished. @@ -161,6 +190,9 @@ fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res // they want let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed"); + #[cfg(feature = "deadlock_detection")] + run_deadlock_detection_thread(); + match command.cmd { Cmd::Run(run_cmd) => { if run_cmd.ui_conf.enabled && !run_cmd.ui_conf.info_page_only { From 666d8cf7592e6f5ecbe58fcd6953af040c42d0a8 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 31 May 2018 15:06:22 +0800 Subject: [PATCH 135/147] Remove unused function new_pow_test_spec (#8735) --- ethcore/src/spec/spec.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index fa25c8894eb..98720647d8f 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -923,11 +923,6 @@ impl Spec { pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") } - - /// Create a new spec for a PoW chain - pub fn new_pow_test_spec() -> Self { - load_bundled!("ethereum/olympic") - } } #[cfg(test)] From 30f86ae71610f8300905f2760a3210044fc85a10 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 31 May 2018 13:36:47 +0200 Subject: [PATCH 136/147] Add 'interface' option to cli (#8699) Additionally as to the port, the new command line option now allows the user to specify the network interface the P2P-Parity listens, too. With support for 'all' and 'local' like in all other versions of this flag. Default is 'all' (aka ). --- parity/cli/mod.rs | 7 +++++++ parity/configuration.rs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index a064baeac56..fea060d5933 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -438,6 +438,10 @@ usage! { "--port=[PORT]", "Override the port on which the node should listen.", + ARG arg_interface: (String) = "all", or |c: &Config| c.network.as_ref()?.interface.clone(), + "--interface=[IP]", + "Network interfaces. Valid values are 'all', 'local' or the ip of the interface you want parity to listen to.", + ARG arg_min_peers: (Option) = None, or |c: &Config| c.network.as_ref()?.min_peers.clone(), "--min-peers=[NUM]", "Try to maintain at least NUM peers.", @@ -1119,6 +1123,7 @@ struct Network { warp: Option, warp_barrier: Option, port: Option, + interface: Option, min_peers: Option, max_peers: Option, snapshot_peers: Option, @@ -1567,6 +1572,7 @@ mod tests { // -- Networking Options flag_no_warp: false, arg_port: 30303u16, + arg_interface: "all".into(), arg_min_peers: Some(25u16), arg_max_peers: Some(50u16), arg_max_pending_peers: 64u16, @@ -1823,6 +1829,7 @@ mod tests { warp: Some(false), warp_barrier: None, port: None, + interface: None, min_peers: Some(10), max_peers: Some(20), max_pending_peers: Some(30), diff --git a/parity/configuration.rs b/parity/configuration.rs index 3151621801c..6bec636e2cb 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -767,7 +767,7 @@ impl Configuration { fn net_addresses(&self) -> Result<(SocketAddr, Option), String> { let port = self.args.arg_ports_shift + self.args.arg_port; - let listen_address = SocketAddr::new("0.0.0.0".parse().unwrap(), port); + let listen_address = SocketAddr::new(self.interface(&self.args.arg_interface).parse().unwrap(), port); let public_address = if self.args.arg_nat.starts_with("extip:") { let host = &self.args.arg_nat[6..]; let host = host.parse().map_err(|_| format!("Invalid host given with `--nat extip:{}`", host))?; From f5e3d0a7a6135693b65758b6148da42ac89d268c Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 31 May 2018 13:38:46 +0200 Subject: [PATCH 137/147] Fix some nits using clippy (#8731) * fix some nits using clippy * fix tests --- util/network-devp2p/src/handshake.rs | 10 +++--- util/network-devp2p/src/host.rs | 30 +++++++++--------- util/network-devp2p/src/ip_utils.rs | 42 ++++++++++++------------- util/network-devp2p/src/node_table.rs | 44 +++++++++++++-------------- util/network-devp2p/src/service.rs | 2 +- util/network-devp2p/src/session.rs | 16 +++++----- whisper/cli/src/main.rs | 3 ++ 7 files changed, 75 insertions(+), 72 deletions(-) diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 7aef4d4f0d7..891dd7c2578 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -84,12 +84,12 @@ impl Handshake { /// Create a new handshake object pub fn new(token: StreamToken, id: Option<&NodeId>, socket: TcpStream, nonce: &H256) -> Result { Ok(Handshake { - id: if let Some(id) = id { id.clone()} else { NodeId::new() }, + id: if let Some(id) = id { *id } else { NodeId::new() }, connection: Connection::new(token, socket), originated: false, state: HandshakeState::New, ecdhe: Random.generate()?, - nonce: nonce.clone(), + nonce: *nonce, remote_ephemeral: Public::new(), remote_nonce: H256::new(), remote_version: PROTOCOL_VERSION, @@ -166,7 +166,7 @@ impl Handshake { self.remote_version = remote_version; let shared = *ecdh::agree(host_secret, &self.id)?; let signature = H520::from_slice(sig); - self.remote_ephemeral = recover(&signature.into(), &(&shared ^ &self.remote_nonce))?; + self.remote_ephemeral = recover(&signature.into(), &(shared ^ self.remote_nonce))?; Ok(()) } @@ -189,7 +189,7 @@ impl Handshake { } Err(_) => { // Try to interpret as EIP-8 packet - let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + let total = ((u16::from(data[0]) << 8 | (u16::from(data[1]))) as usize) + 2; if total < V4_AUTH_PACKET_SIZE { debug!(target: "network", "Wrong EIP8 auth packet size"); return Err(ErrorKind::BadProtocol.into()); @@ -232,7 +232,7 @@ impl Handshake { } Err(_) => { // Try to interpret as EIP-8 packet - let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + let total = (((u16::from(data[0])) << 8 | (u16::from(data[1]))) as usize) + 2; if total < V4_ACK_PACKET_SIZE { debug!(target: "network", "Wrong EIP8 ack packet size"); return Err(ErrorKind::BadProtocol.into()); diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 2f577821a7a..f9180700fe3 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -116,11 +116,11 @@ impl<'s> NetworkContext<'s> { ) -> NetworkContext<'s> { let id = session.as_ref().map(|s| s.lock().token()); NetworkContext { - io: io, - protocol: protocol, + io, + protocol, session_id: id, - session: session, - sessions: sessions, + session, + sessions, _reserved_peers: reserved_peers, } } @@ -280,7 +280,7 @@ impl Host { let tcp_listener = TcpListener::bind(&listen_address)?; listen_address = SocketAddr::new(listen_address.ip(), tcp_listener.local_addr()?.port()); debug!(target: "network", "Listening at {:?}", listen_address); - let udp_port = config.udp_port.unwrap_or(listen_address.port()); + let udp_port = config.udp_port.unwrap_or_else(|| listen_address.port()); let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port }; let boot_nodes = config.boot_nodes.clone(); @@ -325,7 +325,7 @@ impl Host { match Node::from_str(id) { Err(e) => { debug!(target: "network", "Could not add node {}: {:?}", id, e); }, Ok(n) => { - let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; + let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id }; self.nodes.write().add_node(n); if let Some(ref mut discovery) = *self.discovery.lock() { @@ -338,9 +338,9 @@ impl Host { pub fn add_reserved_node(&self, id: &str) -> Result<(), Error> { let n = Node::from_str(id)?; - let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; - self.reserved_nodes.write().insert(n.id.clone()); - self.nodes.write().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); + let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id }; + self.reserved_nodes.write().insert(n.id); + self.nodes.write().add_node(Node::new(entry.id, entry.endpoint.clone())); if let Some(ref mut discovery) = *self.discovery.lock() { discovery.add_node(entry); @@ -349,10 +349,10 @@ impl Host { Ok(()) } - pub fn set_non_reserved_mode(&self, mode: NonReservedPeerMode, io: &IoContext) { + pub fn set_non_reserved_mode(&self, mode: &NonReservedPeerMode, io: &IoContext) { let mut info = self.info.write(); - if info.config.non_reserved_mode != mode { + if &info.config.non_reserved_mode != mode { info.config.non_reserved_mode = mode.clone(); drop(info); if let NonReservedPeerMode::Deny = mode { @@ -388,12 +388,12 @@ impl Host { pub fn external_url(&self) -> Option { let info = self.info.read(); - info.public_endpoint.as_ref().map(|e| format!("{}", Node::new(info.id().clone(), e.clone()))) + info.public_endpoint.as_ref().map(|e| format!("{}", Node::new(*info.id(), e.clone()))) } pub fn local_url(&self) -> String { let info = self.info.read(); - format!("{}", Node::new(info.id().clone(), info.local_endpoint.clone())) + format!("{}", Node::new(*info.id(), info.local_endpoint.clone())) } pub fn stop(&self, io: &IoContext) { @@ -554,7 +554,7 @@ impl Host { // iterate over all nodes, reserved ones coming first. // if we are pinned to only reserved nodes, ignore all others. let nodes = reserved_nodes.iter().cloned().chain(if !pin { - self.nodes.read().nodes(allow_ips) + self.nodes.read().nodes(&allow_ips) } else { Vec::new() }); @@ -752,7 +752,7 @@ impl Host { let entry = NodeEntry { id: id, endpoint: endpoint }; let mut nodes = self.nodes.write(); if !nodes.contains(&entry.id) { - nodes.add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); + nodes.add_node(Node::new(entry.id, entry.endpoint.clone())); let mut discovery = self.discovery.lock(); if let Some(ref mut discovery) = *discovery { discovery.add_node(entry); diff --git a/util/network-devp2p/src/ip_utils.rs b/util/network-devp2p/src/ip_utils.rs index 7c3d5c0fd3b..3d7d33a0661 100644 --- a/util/network-devp2p/src/ip_utils.rs +++ b/util/network-devp2p/src/ip_utils.rs @@ -109,7 +109,7 @@ impl SocketAddrExt for Ipv4Addr { fn is_within(&self, ipnet: &IpNetwork) -> bool { match ipnet { - &IpNetwork::V4(ipnet) => ipnet.contains(*self), + IpNetwork::V4(ipnet) => ipnet.contains(*self), _ => false } } @@ -167,7 +167,7 @@ impl SocketAddrExt for Ipv6Addr { fn is_within(&self, ipnet: &IpNetwork) -> bool { match ipnet { - &IpNetwork::V6(ipnet) => ipnet.contains(*self), + IpNetwork::V6(ipnet) => ipnet.contains(*self), _ => false } } @@ -212,28 +212,28 @@ impl SocketAddrExt for IpAddr { #[cfg(not(any(windows, target_os = "android")))] mod getinterfaces { - use std::{mem, io, ptr}; + use std::{mem, io}; use libc::{AF_INET, AF_INET6}; use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6}; use std::net::{Ipv4Addr, Ipv6Addr, IpAddr}; fn convert_sockaddr(sa: *mut sockaddr) -> Option { - if sa == ptr::null_mut() { return None; } + if sa.is_null() { return None; } - let (addr, _) = match unsafe { *sa }.sa_family as i32 { + let (addr, _) = match i32::from(unsafe { *sa }.sa_family) { AF_INET => { - let sa: *const sockaddr_in = unsafe { mem::transmute(sa) }; - let sa = & unsafe { *sa }; + let sa: *const sockaddr_in = sa as *const sockaddr_in; + let sa = unsafe { &*sa }; let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port); (IpAddr::V4(Ipv4Addr::new( - (addr & 0x000000FF) as u8, - ((addr & 0x0000FF00) >> 8) as u8, - ((addr & 0x00FF0000) >> 16) as u8, - ((addr & 0xFF000000) >> 24) as u8)), + (addr & 0x0000_00FF) as u8, + ((addr & 0x0000_FF00) >> 8) as u8, + ((addr & 0x00FF_0000) >> 16) as u8, + ((addr & 0xFF00_0000) >> 24) as u8)), port) }, AF_INET6 => { - let sa: *const sockaddr_in6 = unsafe { mem::transmute(sa) }; + let sa: *const sockaddr_in6 = sa as *const sockaddr_in6; let sa = & unsafe { *sa }; let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port); let addr: [u16; 8] = unsafe { mem::transmute(addr) }; @@ -266,7 +266,7 @@ mod getinterfaces { let mut ret = Vec::new(); let mut cur: *mut ifaddrs = ifap; - while cur != ptr::null_mut() { + while !cur.is_null() { if let Some(ip_addr) = convert_ifaddrs(cur) { ret.push(ip_addr); } @@ -297,16 +297,16 @@ pub fn select_public_address(port: u16) -> SocketAddr { //prefer IPV4 bindings for addr in &list { //TODO: use better criteria than just the first in the list match addr { - &IpAddr::V4(a) if !a.is_reserved() => { - return SocketAddr::V4(SocketAddrV4::new(a, port)); + IpAddr::V4(a) if !a.is_reserved() => { + return SocketAddr::V4(SocketAddrV4::new(*a, port)); }, _ => {}, } } for addr in &list { match addr { - &IpAddr::V6(a) if !a.is_reserved() => { - return SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)); + IpAddr::V6(a) if !a.is_reserved() => { + return SocketAddr::V6(SocketAddrV6::new(*a, port, 0, 0)); }, _ => {}, } @@ -319,7 +319,7 @@ pub fn select_public_address(port: u16) -> SocketAddr { pub fn map_external_address(local: &NodeEndpoint) -> Option { if let SocketAddr::V4(ref local_addr) = local.address { - match search_gateway_from_timeout(local_addr.ip().clone(), Duration::new(5, 0)) { + match search_gateway_from_timeout(*local_addr.ip(), Duration::new(5, 0)) { Err(ref err) => debug!("Gateway search error: {}", err), Ok(gateway) => { match gateway.get_external_ip() { @@ -327,17 +327,17 @@ pub fn map_external_address(local: &NodeEndpoint) -> Option { debug!("IP request error: {}", err); }, Ok(external_addr) => { - match gateway.add_any_port(PortMappingProtocol::TCP, SocketAddrV4::new(local_addr.ip().clone(), local_addr.port()), 0, "Parity Node/TCP") { + match gateway.add_any_port(PortMappingProtocol::TCP, SocketAddrV4::new(*local_addr.ip(), local_addr.port()), 0, "Parity Node/TCP") { Err(ref err) => { debug!("Port mapping error: {}", err); }, Ok(tcp_port) => { - match gateway.add_any_port(PortMappingProtocol::UDP, SocketAddrV4::new(local_addr.ip().clone(), local.udp_port), 0, "Parity Node/UDP") { + match gateway.add_any_port(PortMappingProtocol::UDP, SocketAddrV4::new(*local_addr.ip(), local.udp_port), 0, "Parity Node/UDP") { Err(ref err) => { debug!("Port mapping error: {}", err); }, Ok(udp_port) => { - return Some(NodeEndpoint { address: SocketAddr::V4(SocketAddrV4::new(external_addr, tcp_port)), udp_port: udp_port }); + return Some(NodeEndpoint { address: SocketAddr::V4(SocketAddrV4::new(external_addr, tcp_port)), udp_port }); }, } }, diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 8640901cd09..d5d0207ecd6 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -26,7 +26,7 @@ use std::hash::{Hash, Hasher}; use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; use std::path::PathBuf; use std::str::FromStr; -use std::{fs, mem, slice}; +use std::{fs, slice}; use std::time::{self, Duration, SystemTime}; use rand::{self, Rng}; @@ -45,8 +45,8 @@ pub struct NodeEndpoint { impl NodeEndpoint { pub fn udp_address(&self) -> SocketAddr { match self.address { - SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)), - SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())), + SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(*a.ip(), self.udp_port)), + SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(*a.ip(), self.udp_port, a.flowinfo(), a.scope_id())), } } @@ -61,10 +61,10 @@ impl NodeEndpoint { pub fn is_allowed_by_predefined(&self, filter: &AllowIP) -> bool { match filter { - &AllowIP::All => true, - &AllowIP::Private => self.address.ip().is_usable_private(), - &AllowIP::Public => self.address.ip().is_usable_public(), - &AllowIP::None => false, + AllowIP::All => true, + AllowIP::Private => self.address.ip().is_usable_private(), + AllowIP::Public => self.address.ip().is_usable_public(), + AllowIP::None => false, } } @@ -75,13 +75,13 @@ impl NodeEndpoint { let address = match addr_bytes.len() { 4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))), 16 => unsafe { - let o: *const u16 = mem::transmute(addr_bytes.as_ptr()); + let o: *const u16 = addr_bytes.as_ptr() as *const u16; let o = slice::from_raw_parts(o, 8); Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0))) }, _ => Err(DecoderError::RlpInconsistentLengthAndData) }?; - Ok(NodeEndpoint { address: address, udp_port: udp_port }) + Ok(NodeEndpoint { address, udp_port }) } pub fn to_rlp(&self, rlp: &mut RlpStream) { @@ -90,7 +90,7 @@ impl NodeEndpoint { rlp.append(&(&a.ip().octets()[..])); } SocketAddr::V6(a) => unsafe { - let o: *const u8 = mem::transmute(a.ip().segments().as_ptr()); + let o: *const u8 = a.ip().segments().as_ptr() as *const u8; rlp.append(&slice::from_raw_parts(o, 16)); } }; @@ -184,8 +184,8 @@ pub struct Node { impl Node { pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { Node { - id: id, - endpoint: endpoint, + id, + endpoint, peer_type: PeerType::Optional, last_contact: None, } @@ -214,8 +214,8 @@ impl FromStr for Node { }; Ok(Node { - id: id, - endpoint: endpoint, + id, + endpoint, peer_type: PeerType::Optional, last_contact: None, }) @@ -258,7 +258,7 @@ impl NodeTable { pub fn add_node(&mut self, mut node: Node) { // preserve node last_contact node.last_contact = self.nodes.get(&node.id).and_then(|n| n.last_contact); - self.nodes.insert(node.id.clone(), node); + self.nodes.insert(node.id, node); } /// Returns a list of ordered nodes according to their most recent contact @@ -315,7 +315,7 @@ impl NodeTable { /// Returns node ids sorted by failure percentage, for nodes with the same failure percentage the absolute number of /// failures is considered. - pub fn nodes(&self, filter: IpFilter) -> Vec { + pub fn nodes(&self, filter: &IpFilter) -> Vec { self.ordered_entries().iter() .filter(|n| n.endpoint.is_allowed(&filter)) .map(|n| n.id) @@ -327,7 +327,7 @@ impl NodeTable { pub fn entries(&self) -> Vec { self.ordered_entries().iter().map(|n| NodeEntry { endpoint: n.endpoint.clone(), - id: n.id.clone(), + id: n.id, }).collect() } @@ -344,7 +344,7 @@ impl NodeTable { /// Apply table changes coming from discovery pub fn update(&mut self, mut update: TableUpdates, reserved: &HashSet) { for (_, node) in update.added.drain() { - let entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone())); + let entry = self.nodes.entry(node.id).or_insert_with(|| Node::new(node.id, node.endpoint.clone())); entry.endpoint = node.endpoint; } for r in update.removed { @@ -389,7 +389,7 @@ impl NodeTable { return; } path.push(NODES_FILE); - let node_ids = self.nodes(IpFilter::default()); + let node_ids = self.nodes(&IpFilter::default()); let nodes = node_ids.into_iter() .map(|id| self.nodes.get(&id).expect("self.nodes() only returns node IDs from self.nodes")) .take(MAX_NODES) @@ -428,7 +428,7 @@ impl NodeTable { Ok(table) => { table.nodes.into_iter() .filter_map(|n| n.into_node()) - .map(|n| (n.id.clone(), n)) + .map(|n| (n.id, n)) .collect() }, Err(e) => { @@ -625,7 +625,7 @@ mod tests { // unknown - node 6 - let r = table.nodes(IpFilter::default()); + let r = table.nodes(&IpFilter::default()); assert_eq!(r[0][..], id4[..]); // most recent success assert_eq!(r[1][..], id3[..]); @@ -662,7 +662,7 @@ mod tests { { let table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned())); - let r = table.nodes(IpFilter::default()); + let r = table.nodes(&IpFilter::default()); assert_eq!(r[0][..], id2[..]); // latest success assert_eq!(r[1][..], id1[..]); // unknown assert_eq!(r[2][..], id3[..]); // oldest failure diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 1b46ca1ae33..d8105f649c5 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -165,7 +165,7 @@ impl NetworkService { let host = self.host.read(); if let Some(ref host) = *host { let io_ctxt = IoContext::new(self.io_service.channel(), 0); - host.set_non_reserved_mode(mode, &io_ctxt); + host.set_non_reserved_mode(&mode, &io_ctxt); } } diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index 47eb2cf7283..cd8ef56bd4a 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -117,7 +117,7 @@ impl Session { capabilities: Vec::new(), peer_capabilities: Vec::new(), ping: None, - originated: originated, + originated, remote_address: "Handshake".to_owned(), local_address: local_addr, }, @@ -131,7 +131,7 @@ impl Session { fn complete_handshake(&mut self, io: &IoContext, host: &HostInfo) -> Result<(), Error> where Message: Send + Sync + Clone { let connection = if let State::Handshake(ref mut h) = self.state { - self.info.id = Some(h.id.clone()); + self.info.id = Some(h.id); self.info.remote_address = h.connection.remote_addr_str(); EncryptedConnection::new(h)? } else { @@ -204,7 +204,7 @@ impl Session { } } if let Some(data) = packet_data { - return Ok(self.read_packet(io, data, host)?); + return Ok(self.read_packet(io, &data, host)?); } if create_session { self.complete_handshake(io, host)?; @@ -277,7 +277,7 @@ impl Session { None => packet_id }; let mut rlp = RlpStream::new(); - rlp.append(&(pid as u32)); + rlp.append(&(u32::from(pid))); let mut compressed = Vec::new(); let mut payload = data; // create a reference with local lifetime if self.compression { @@ -329,7 +329,7 @@ impl Session { } } - fn read_packet(&mut self, io: &IoContext, packet: Packet, host: &HostInfo) -> Result + fn read_packet(&mut self, io: &IoContext, packet: &Packet, host: &HostInfo) -> Result where Message: Send + Sync + Clone { if packet.data.len() < 2 { return Err(ErrorKind::BadProtocol.into()); @@ -390,7 +390,7 @@ impl Session { match *self.protocol_states.entry(protocol).or_insert_with(|| ProtocolState::Pending(Vec::new())) { ProtocolState::Connected => { trace!(target: "network", "Packet {} mapped to {:?}:{}, i={}, capabilities={:?}", packet_id, protocol, protocol_packet_id, i, self.info.capabilities); - Ok(SessionData::Packet { data: data, protocol: protocol, packet_id: protocol_packet_id } ) + Ok(SessionData::Packet { data, protocol, packet_id: protocol_packet_id } ) } ProtocolState::Pending(ref mut pending) => { trace!(target: "network", "Packet {} deferred until protocol connection event completion", packet_id); @@ -468,11 +468,11 @@ impl Session { self.info.peer_capabilities = peer_caps; if self.info.capabilities.is_empty() { trace!(target: "network", "No common capabilities with peer."); - return Err(From::from(self.disconnect(io, DisconnectReason::UselessPeer))); + return Err(self.disconnect(io, DisconnectReason::UselessPeer)); } if protocol < MIN_PROTOCOL_VERSION { trace!(target: "network", "Peer protocol version mismatch: {}", protocol); - return Err(From::from(self.disconnect(io, DisconnectReason::UselessPeer))); + return Err(self.disconnect(io, DisconnectReason::UselessPeer)); } self.compression = protocol >= MIN_COMPRESSION_PROTOCOL_VERSION; self.send_ping(io)?; diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index f245e99e482..d76c216be46 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -19,6 +19,9 @@ //! Spawns an Ethereum network instance and attaches the Whisper protocol RPCs to it. //! +#![warn(missing_docs)] +#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] + extern crate docopt; extern crate ethcore_network_devp2p as devp2p; extern crate ethcore_network as net; From f0adec19caaf624179a279c4f0ef633d116e520c Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 31 May 2018 13:39:25 +0200 Subject: [PATCH 138/147] Remove a couple of unnecessary `transmute()` (#8736) --- ethash/src/compute.rs | 5 ++--- util/plain_hasher/src/lib.rs | 17 +++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index 48906b9edeb..de2b57637fa 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -25,9 +25,8 @@ use seed_compute::SeedHashCompute; use shared::*; use std::io; -use std::mem; +use std::{mem, ptr}; use std::path::Path; -use std::ptr; const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4; const MIX_NODES: usize = MIX_WORDS / NODE_WORDS; @@ -111,7 +110,7 @@ pub fn quick_get_difficulty(header_hash: &H256, nonce: u64, mix_hash: &H256) -> let mut buf: [u8; 64 + 32] = mem::uninitialized(); ptr::copy_nonoverlapping(header_hash.as_ptr(), buf.as_mut_ptr(), 32); - ptr::copy_nonoverlapping(mem::transmute(&nonce), buf[32..].as_mut_ptr(), 8); + ptr::copy_nonoverlapping(&nonce as *const u64 as *const u8, buf[32..].as_mut_ptr(), 8); keccak_512::unchecked(buf.as_mut_ptr(), 64, buf.as_ptr(), 40); ptr::copy_nonoverlapping(mix_hash.as_ptr(), buf[64..].as_mut_ptr(), 32); diff --git a/util/plain_hasher/src/lib.rs b/util/plain_hasher/src/lib.rs index 54bad92f47e..d08d4dd1aba 100644 --- a/util/plain_hasher/src/lib.rs +++ b/util/plain_hasher/src/lib.rs @@ -2,9 +2,9 @@ extern crate crunchy; extern crate ethereum_types; -use std::{hash, mem}; -use std::collections::{HashMap, HashSet}; use ethereum_types::H256; +use std::collections::{HashMap, HashSet}; +use std::hash; /// Specialized version of `HashMap` with H256 keys and fast hashing function. pub type H256FastMap = HashMap>; @@ -28,16 +28,13 @@ impl hash::Hasher for PlainHasher { #[allow(unused_assignments)] fn write(&mut self, bytes: &[u8]) { debug_assert!(bytes.len() == 32); + let mut bytes_ptr = bytes.as_ptr(); + let mut prefix_ptr = &mut self.prefix as *mut u64 as *mut u8; - unsafe { - let mut bytes_ptr = bytes.as_ptr(); - let prefix_u8: &mut [u8; 8] = mem::transmute(&mut self.prefix); - let mut prefix_ptr = prefix_u8.as_mut_ptr(); - - unroll! { - for _i in 0..8 { + unroll! { + for _i in 0..8 { + unsafe { *prefix_ptr ^= (*bytes_ptr ^ *bytes_ptr.offset(8)) ^ (*bytes_ptr.offset(16) ^ *bytes_ptr.offset(24)); - bytes_ptr = bytes_ptr.offset(1); prefix_ptr = prefix_ptr.offset(1); } From 267ee39bc098217ba6d074aed6544e538b0b3bf7 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 31 May 2018 13:53:09 +0200 Subject: [PATCH 139/147] bump tinykeccak to 1.4 (#8728) --- ethcore/crypto/Cargo.toml | 2 +- ethcore/private-tx/Cargo.toml | 2 +- ethkey/Cargo.toml | 2 +- ethstore/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- secret_store/Cargo.toml | 2 +- util/network-devp2p/Cargo.toml | 2 +- whisper/Cargo.toml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ethcore/crypto/Cargo.toml b/ethcore/crypto/Cargo.toml index 4fe023f25c4..b57b8497c0e 100644 --- a/ethcore/crypto/Cargo.toml +++ b/ethcore/crypto/Cargo.toml @@ -8,5 +8,5 @@ ethereum-types = "0.3" quick-error = "1.2" ring = "0.12" rust-crypto = "0.2.36" -tiny-keccak = "1.3" +tiny-keccak = "1.4" diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index 0fa11aec84b..8283ab314aa 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -33,5 +33,5 @@ rustc-hex = "1.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" url = "1" diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index d6698f86d9f..952354739d5 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -16,4 +16,4 @@ parity-wordlist = "1.2" quick-error = "1.2" rand = "0.4" rustc-hex = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index 6330ce97ce7..6108143cb9e 100644 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -12,7 +12,7 @@ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" rustc-hex = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" time = "0.1.34" itertools = "0.5" parking_lot = "0.5" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 8fdb9ed5740..8a0b689c655 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -23,7 +23,7 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" tempdir = "0.3" -tiny-keccak = "1.3" +tiny-keccak = "1.4" tokio-timer = "0.1" transient-hashmap = "0.4" itertools = "0.5" diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index fee832d069c..261658903cc 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -16,7 +16,7 @@ serde_derive = "1.0" futures = "0.1" futures-cpupool = "0.1" rustc-hex = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" tokio = "0.1" tokio-core = "0.1" tokio-io = "0.1" diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index f4889fe26d4..4a5d2d942ec 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -11,7 +11,7 @@ log = "0.3" mio = "0.6.8" bytes = "0.4" rand = "0.4" -tiny-keccak = "1.3" +tiny-keccak = "1.4" rust-crypto = "0.2.34" slab = "0.2" igd = "0.7" diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index ed370e38a2d..e503a74fd6d 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -23,7 +23,7 @@ serde_derive = "1.0" serde_json = "1.0" slab = "0.3" smallvec = "0.4" -tiny-keccak = "1.3" +tiny-keccak = "1.4" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } From 450c2f4d36235c718dd5fb36912e227531a5c4f4 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 31 May 2018 15:07:35 +0300 Subject: [PATCH 140/147] ease tiny-keccak version requirements (1.4.1 -> 1.4) (#8726) --- util/hash/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/hash/Cargo.toml b/util/hash/Cargo.toml index e136ada305a..4ca503751aa 100644 --- a/util/hash/Cargo.toml +++ b/util/hash/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Parity Technologies "] [dependencies] ethereum-types = "0.3" -tiny-keccak = "1.4.1" +tiny-keccak = "1.4" [dev-dependencies] tempdir = "0.3" From 0b1581835bd5cb1a5dd55e1b12e3968e118a5e0b Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 31 May 2018 14:43:06 +0200 Subject: [PATCH 141/147] Remove -k/--insecure option from curl installer (#8719) Piping `curl` to `bash` while **disabling** certificate verification can lead to security problems. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9255d014b6c..8cba4205bdb 100644 --- a/README.md +++ b/README.md @@ -138,13 +138,13 @@ first. ## Simple one-line installer for Mac and Ubuntu ```bash -bash <(curl https://get.parity.io -Lk) +bash <(curl https://get.parity.io -L) ``` The one-line installer always defaults to the latest beta release. To install a stable release, run: ```bash -bash <(curl https://get.parity.io -Lk) -r stable +bash <(curl https://get.parity.io -L) -r stable ``` ## Start Parity From f8f234584154dc58b2149e180d893f11d5e3be8a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 31 May 2018 21:28:25 +0800 Subject: [PATCH 142/147] Fix PoW blockchains sealing notifications in chain_new_blocks (#8656) --- ethcore/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 5cfe8fce82c..b469cf45180 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2181,7 +2181,7 @@ impl ImportSealedBlock for Client { route }; let route = ChainRoute::from([route].as_ref()); - self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), true); + self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), self.engine.seals_internally().is_some()); self.notify(|notify| { notify.new_blocks( vec![h.clone()], From 47141bcea4218913b0fff9f9fdbe924e4c691b8c Mon Sep 17 00:00:00 2001 From: David Date: Fri, 1 Jun 2018 09:38:20 +0200 Subject: [PATCH 143/147] Print warnings when fetching pending blocks (#8711) * Lots of println to figure out what eth_getBlockByNumber does/should do * Remove debugging * Print warnings when fetching pending blocks When calling `eth_getBlockByNumber` with `pending`, we now print a deprecation warning and: * if a pending block is found, use it to respond * if no pending block is found, respond as if if was a request for `Latest` Addresses issue #8703 (not sure if it's enough to close it tbh) --- ethcore/src/miner/miner.rs | 10 ++++++---- rpc/src/v1/impls/eth.rs | 36 +++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 3168ff1a846..4904535a89b 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -290,10 +290,12 @@ impl Miner { { self.sealing.lock().queue .peek_last_ref() - .and_then(|b| if b.block().header().number() > latest_block_number { - Some(f(b)) - } else { - None + .and_then(|b| { + if b.block().header().number() > latest_block_number { + Some(f(b)) + } else { + None + } }) } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 389805c1765..ae8d611c120 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -108,6 +108,7 @@ pub struct EthClient where eip86_transition: u64, } +#[derive(Debug)] enum BlockNumberOrId { Number(BlockNumber), Id(BlockId), @@ -184,21 +185,30 @@ impl EthClient { let info = self.client.chain_info(); - let pending_block = self.miner.pending_block(info.best_block_number); - let difficulty = { - let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed"); - let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty()); + match self.miner.pending_block(info.best_block_number) { + Some(pending_block) => { + warn!("`Pending` is deprecated and may be removed in future versions."); - if let Some(difficulty) = pending_difficulty { - difficulty + latest_difficulty - } else { - latest_difficulty - } - }; + let difficulty = { + let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed"); + let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty()); + + if let Some(difficulty) = pending_difficulty { + difficulty + latest_difficulty + } else { + latest_difficulty + } + }; - let extra = pending_block.as_ref().map(|b| self.client.engine().extra_info(&b.header)); + let extra = self.client.engine().extra_info(&pending_block.header); - (pending_block.map(|b| encoded::Block::new(b.rlp_bytes())), Some(difficulty), extra, true) + (Some(encoded::Block::new(pending_block.rlp_bytes())), Some(difficulty), Some(extra), true) + }, + None => { + warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`"); + client_query(BlockId::Latest) + } + } }, BlockNumberOrId::Number(num) => { @@ -206,7 +216,7 @@ impl EthClient BlockId::Latest, BlockNumber::Earliest => BlockId::Earliest, BlockNumber::Num(n) => BlockId::Number(n), - BlockNumber::Pending => unreachable!(), // Already covered + BlockNumber::Pending => unreachable!() // Already covered }; client_query(id) From 2a4035b787457b3bcc54468e1272050358b27415 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 1 Jun 2018 00:42:45 -0700 Subject: [PATCH 144/147] Fix XOR distance calculation in discovery Kademlia impl (#8589) * network-devp2p: Test for discovery bucket insertion. All test values are randomly generated and the assertions are checked manually. Test fails because distance metric is implemented incorrectly. * network-devp2p: Fix discovery distance function. The Kademlia distance function (XOR) was implemented incorrectly as a population count. * network-devp2p: Refactor nearest_node_entries to be on instance. Optimizations are possible with more access to the discovery state. * network-devp2p: Fix loss of precision in nearest_node_entries. * network-devp2p: More efficient nearest node search. The discovery algorithm to identify the nearest k nodes does not need to scan all entries in all buckets. --- util/network-devp2p/src/discovery.rs | 221 +++++++++++++++++++++------ 1 file changed, 172 insertions(+), 49 deletions(-) diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index f14cd5ba6fd..af43546a5f3 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -16,7 +16,7 @@ use ethcore_bytes::Bytes; use std::net::SocketAddr; -use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; +use std::collections::{HashSet, HashMap, VecDeque}; use std::mem; use std::default::Default; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -34,9 +34,8 @@ use network::IpFilter; use PROTOCOL_VERSION; -const ADDRESS_BYTES_SIZE: u32 = 32; // Size of address type in bytes. -const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademlia]. -const NODE_BINS: u32 = ADDRESS_BITS - 1; // Size of m_state (excludes root, which is us). +const ADDRESS_BYTES_SIZE: usize = 32; // Size of address type in bytes. +const ADDRESS_BITS: usize = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademlia]. const DISCOVERY_MAX_STEPS: u16 = 8; // Max iterations of discovery. (discover) const BUCKET_SIZE: usize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. const ALPHA: usize = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. @@ -119,7 +118,7 @@ impl Discovery { discovery_round: 0, discovery_id: NodeId::new(), discovery_nodes: HashSet::new(), - node_buckets: (0..NODE_BINS).map(|_| NodeBucket::new()).collect(), + node_buckets: (0..ADDRESS_BITS).map(|_| NodeBucket::new()).collect(), udp_socket: socket, send_queue: VecDeque::new(), check_timestamps: true, @@ -155,8 +154,16 @@ impl Discovery { fn update_node(&mut self, e: NodeEntry) { trace!(target: "discovery", "Inserting {:?}", &e); let id_hash = keccak(e.id); + let dist = match Discovery::distance(&self.id_hash, &id_hash) { + Some(dist) => dist, + None => { + warn!(target: "discovery", "Attempted to update own entry: {:?}", e); + return; + } + }; + let ping = { - let bucket = &mut self.node_buckets[Discovery::distance(&self.id_hash, &id_hash) as usize]; + let bucket = &mut self.node_buckets[dist]; let updated = if let Some(node) = bucket.nodes.iter_mut().find(|n| n.address.id == e.id) { node.address = e.clone(); node.timeout = None; @@ -181,7 +188,15 @@ impl Discovery { /// Removes the timeout of a given NodeId if it can be found in one of the discovery buckets fn clear_ping(&mut self, id: &NodeId) { - let bucket = &mut self.node_buckets[Discovery::distance(&self.id_hash, &keccak(id)) as usize]; + let dist = match Discovery::distance(&self.id_hash, &keccak(id)) { + Some(dist) => dist, + None => { + warn!(target: "discovery", "Received ping from self"); + return + } + }; + + let bucket = &mut self.node_buckets[dist]; if let Some(node) = bucket.nodes.iter_mut().find(|n| &n.address.id == id) { node.timeout = None; } @@ -212,7 +227,7 @@ impl Discovery { trace!(target: "discovery", "Starting round {:?}", self.discovery_round); let mut tried_count = 0; { - let nearest = Discovery::nearest_node_entries(&self.discovery_id, &self.node_buckets).into_iter(); + let nearest = self.nearest_node_entries(&self.discovery_id).into_iter(); let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::>(); for r in nearest { let rlp = encode_list(&(&[self.discovery_id.clone()][..])); @@ -233,17 +248,17 @@ impl Discovery { self.discovery_round += 1; } - fn distance(a: &H256, b: &H256) -> u32 { - let d = *a ^ *b; - let mut ret:u32 = 0; - for i in 0..32 { - let mut v: u8 = d[i]; - while v != 0 { - v >>= 1; - ret += 1; + /// The base 2 log of the distance between a and b using the XOR metric. + fn distance(a: &H256, b: &H256) -> Option { + for i in (0..ADDRESS_BYTES_SIZE).rev() { + let byte_index = ADDRESS_BYTES_SIZE - i - 1; + let d: u8 = a[byte_index] ^ b[byte_index]; + if d != 0 { + let high_bit_index = 7 - d.leading_zeros() as usize; + return Some(i * 8 + high_bit_index); } } - ret + None // a and b are equal, so log distance is -inf } fn ping(&mut self, node: &NodeEndpoint) { @@ -286,36 +301,53 @@ impl Discovery { Ok(()) } - fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { - let mut found: BTreeMap> = BTreeMap::new(); - let mut count = 0; + fn nearest_node_entries(&self, target: &NodeId) -> Vec { let target_hash = keccak(target); + let target_distance = self.id_hash ^ target_hash; + + let mut ret = Vec::::with_capacity(BUCKET_SIZE); + + // Sort bucket entries by distance to target and append to end of result vector. + let append_bucket = |results: &mut Vec, bucket: &NodeBucket| -> bool { + let mut sorted_entries: Vec<&BucketEntry> = bucket.nodes.iter().collect(); + sorted_entries.sort_unstable_by_key(|entry| entry.id_hash ^ target_hash); + + let remaining_capacity = results.capacity() - results.len(); + let to_append = if remaining_capacity < sorted_entries.len() { + &sorted_entries[0..remaining_capacity] + } else { + &sorted_entries + }; + for entry in to_append.iter() { + results.push(entry.address.clone()); + } + results.len() == results.capacity() + }; - // Sort nodes by distance to target - for bucket in buckets { - for node in &bucket.nodes { - let distance = Discovery::distance(&target_hash, &node.id_hash); - found.entry(distance).or_insert_with(Vec::new).push(&node.address); - if count == BUCKET_SIZE { - // delete the most distant element - let remove = { - let (key, last) = found.iter_mut().next_back().expect("Last element is always Some when count > 0"); - last.pop(); - if last.is_empty() { Some(key.clone()) } else { None } - }; - if let Some(remove) = remove { - found.remove(&remove); - } - } - else { - count += 1; + // This algorithm leverages the structure of the routing table to efficiently find the + // nearest entries to a target hash. First, we compute the XOR distance from this node to + // the target. On a first pass, we iterate from the MSB of the distance, stopping at any + // buckets where the distance bit is set, and skipping the buckets where it is unset. These + // must be in order the nearest to the target. On a second pass, we traverse from LSB to + // MSB, appending the buckets skipped on the first pass. The reason this works is that all + // entries in bucket i have a common prefix of length exactly 32 - i - 1 with the ID of this + // node. + + for i in 0..ADDRESS_BITS { + if ((target_distance[i / 8] << (i % 8)) & 0x80) != 0 { + let bucket = &self.node_buckets[ADDRESS_BITS - i - 1]; + if !bucket.nodes.is_empty() && append_bucket(&mut ret, bucket) { + return ret; } } } - - let mut ret:Vec = Vec::new(); - for nodes in found.values() { - ret.extend(nodes.iter().map(|&n| n.clone())); + for i in (0..ADDRESS_BITS).rev() { + if ((target_distance[i / 8] << (i % 8)) & 0x80) == 0 { + let bucket = &self.node_buckets[ADDRESS_BITS - i - 1]; + if !bucket.nodes.is_empty() && append_bucket(&mut ret, bucket) { + return ret; + } + } } ret } @@ -453,7 +485,7 @@ impl Discovery { let target: NodeId = rlp.val_at(0)?; let timestamp: u64 = rlp.val_at(1)?; self.check_timestamp(timestamp)?; - let nearest = Discovery::nearest_node_entries(&target, &self.node_buckets); + let nearest = self.nearest_node_entries(&target); if nearest.is_empty() { return Ok(None); } @@ -614,7 +646,7 @@ mod tests { } discovery2.round(); } - assert_eq!(Discovery::nearest_node_entries(&NodeId::new(), &discovery2.node_buckets).len(), 3) + assert_eq!(discovery2.nearest_node_entries(&NodeId::new()).len(), 3) } #[test] @@ -625,7 +657,7 @@ mod tests { for _ in 0..1200 { discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); } - assert!(Discovery::nearest_node_entries(&NodeId::new(), &discovery.node_buckets).len() <= 16); + assert!(discovery.nearest_node_entries(&NodeId::new()).len() <= 16); let removed = discovery.check_expired(true).len(); assert!(removed > 0); } @@ -633,23 +665,114 @@ mod tests { #[test] fn find_nearest_saturated() { use super::*; - let mut buckets: Vec<_> = (0..256).map(|_| NodeBucket::new()).collect(); + + let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + for _ in 0..(16 + 10) { - buckets[0].nodes.push_back(BucketEntry { + discovery.node_buckets[0].nodes.push_back(BucketEntry { address: NodeEntry { id: NodeId::new(), endpoint: ep.clone() }, timeout: None, id_hash: keccak(NodeId::new()), }); } - let nearest = Discovery::nearest_node_entries(&NodeId::new(), &buckets); + let nearest = discovery.nearest_node_entries(&NodeId::new()); assert_eq!(nearest.len(), 16) } + #[test] + fn routing_table_insertions_lookups() { + use super::*; + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40448").unwrap(), udp_port: 40447 }; + let node_ids_hex: [&str; 32] = [ + "22536fa57acc12c4993295cbc26fef4550513496712b301ad2283d356c8108521244a362e64e6d907a0d0b4e65526699c5ae3cfebfc680505fe3b33d50672835", + "22c482f42401546f8dd7ed6b1c0cad976da6630730f1116614579ccb084791a528ff2676bfe94434de80e5d7e479f1ea1d7737077da3bd5e69a0f3e5bf596091", + "234c73e3a8f6835a7f9a9d2a896bff4908d66d21d5433a2c37d94f1fa9a6ca17d02388f31013ff87e3ad86506e76bd1006b9cac3815974a2b47c8d4f2124697e", + "2a5aaf4e2046c521e890dc82313c6151a55078f045a7e3d259f168238d029271cdd9a0943468d45c1e36a34a8a6d4de4b0262e48d3c8cfdd4c2aab5df42926b9", + "341d8c94d9670461186cfc1f66d4246cb12384940e9f621ec8d6c216b5d037cde5f7a41b70474ca36ced4a4f2fe91c9dc5a24a128414672661f78e8611d54bfd", + "3d9fd01851f3ae1bfd06b48e89738f29f9a2b4dce3ab7864df4fccca55d1ac88044956ba47d0c4cb44a19924626a3a3aa5a4de8958365cb7385111ce7b929200", + "406d5507a7fbc194a495800ae8cf408093336febc24d03d6c63756f522274ab02146ceb1b0213291a9a1544680503837519f88f1e8677d921de62c82935b4e6c", + "4c537f00805f320616ee49c7bc36e1d7e52a04a782b0cc00fd3d6b77200b027cef5f875ed38f1167fef4b02d7bd49a661812301d9d680bb62297131204c035f9", + "4fc8e3fdbdd7acad82b283ac52c121b805f3b15ffcaa6b2ca67b9e375aa88e978951ffa3d03ee13be99f0ee987db0bbfc6a7ca02b175e9123d79826025b4089d", + "55b5042a6910bc908a0520966e8cbcc92ac299bdb7efbfbcf703df1506fa0f9b09c5eeb930080de848d2864cca71f885942852c51233db0ee46fe0447306d61f", + "5d24f28b350c4c37fc4dad7f418e029992c9e4ac356bb3d9a1356ba1076339863c05044d7ceba233c65779401f8a3b38fe67b6a592c1be4834dc869f7bb932eb", + "5f6edaf2f2ae3003f4b4ff90b8e71a717c832c71a634d96e77fe046f9a88adc8de5718ff3c47659aea4cead5376df5b731e1b6530e6b0999f56ad75d4dabd3f6", + "6214c04211efe91abd23d65e2dc8e711b06d4fb13dcfd65b691dc51f58455b2145f9b38f523b72a45a12705a28d389308a34455720d774c9b805326df42b5a63", + "69df92573ddbbce88b72a930843dbb70728b2a020e0cc4e8ba805dcf7f19297bfc5def4ca447e9e6ec66971be1815b8f49042720431f698b6a87a185d94fa6c8", + "72ffc23de007cf8b6f4a117f7427b532d05861c314344ffa265175f57ee45dae041a710a4dc74124dba1dabdc0f52dfd21e3154d1d4285aab529810c6161d623", + "80b567f279a9512f3a66ebd8f87a93acd4d50bf66f5eff6d04039c1f5838e37021e981539659b33e0644b243fc9671209a80cbef40d1bcf7c7117d353cb45532", + "9009dc9e3bf50595f84271f46d4c7a5ad6971f7d2ffce1905bfc40a407d34fc5e2dcebd92746eadcd2c5fa4d5aaccb0e01b542d506b361851df3f19e6bc629a3", + "95264f56e091efeba911003fd01eeb2c81f6fc4bb7b10c92e4c7bfaf460b7246d232e61ad8a223d74870981a84e15b2d5134c25d931cb860c6912b20a2d3ac01", + "96013a472a9f7ff9c5c76b5ca958f14ee510d826703aa41d4c88eac51d30d14229b9f19f6e0469c37aaa6d2136a978a4aaa38ca766f48e53e569f84e44252962", + "a513c988cf8480ad2992caa64e3fa059ce07efda260dfeefed78e1d41ea3f97844603b8a9737eb633086fd9ac2f201200cb656cda8a91bf6cc500d6039db6f53", + "ab3311f38e3641c8b3b1fd36dd7f94b148166e267258e840d29d1859537c74f202bd3342359b3623f96c23fa662d1b65182a898bf20343744b37cb265182e500", + "ac8f41dbd637891a08c9cf715c23577bdd431ba40231682a5a9ba7fd6cb6d66c04f63d6d65c7d9f8737e641e05fdbeede57138a174f0d55e7835575dd6cddd98", + "accdad251888d53e4e18efee1e0d749d050216b14896efb657e9c7b1b78dab82a5b6fb3234017aa19a2f50475d73960f352d308b2e0e841cbebaf418362a4f21", + "b138622208f74d2b8e8fc10bcd4cf3302685cd77d339280a939474b92be8b93e441c50709e25c82cc88a2a4207e9f2938912d60600226efe322b43c6ef5e7aef", + "b4f64e1fa6a5cd6198b2515bde63fbdabaf7e7a31dbaf5369babbda4b8cd0bf5025ac4b7d2d6e6e3bc76c890df585d28d4815e464c8792ef677df9206864a12b", + "c1136e08a27c93812ae2dd47201d9e81c82d1995001b88dba9eec700e1d3385dfaf7ae834226c3c90a138f1808cd10b5502f49ee774a2bc707f34bd7d160b7bd", + "c203ae9b5d1953b0ac462e66338800ec26982e2af54bd444fc8978973191633d4f483e31b28233c07bb99f34d57c680fa5f8e093e64f13b235005b7ab6e2d594", + "c2e1067c58a9948e773e0a3637d946e26d95762f89ec9d35e2ad84f770309d94168d4e112c78d62b60efc6216bc5d31475f24307b1b8e0fa8dcbb18a10cb85f5", + "d60ecb1a89e0d5aeff14c9a95da9f5492eb15871c53563b86b7c5ddf0da74b4c29e682fdd22aae2290e0b16ef4b6d707ef55396ca98f755c95b689cf65ce5f80", + "df5ad4ea6242929df86f2162d1cc62b0e0a6f0a03428a39dea98f6a689335b5ceaf1f0696c17b717b141aeb45a29108d95c3a7d2d1d0bb3441219504ae672917", + "e1268f5dd9552a11989df9d4953bb388e7466711b2bd9882a3ed4d0767a21f046c53c20f9a18d66bae1d6a5544492857ddecb0b5b4818bd4557be252ddd66c71", + "e626019dc0b50b9e254461f19d29e69a4669c5256134a6352c6c30d3bc55d201a5b43fc2e006556cfaf29765b683e807e03093798942826244e4ee9e47c75d3f", + ]; + let node_entries = node_ids_hex.iter() + .map(|node_id_hex| NodeId::from_str(node_id_hex).unwrap()) + .map(|node_id| NodeEntry { id: node_id, endpoint: ep.clone() }) + .collect::>(); + + let secret_hex = "6c71d1b8930d29e6371be1081f2c909c64b46440a1716314c3c9df995cb3aed1"; + let key = Secret::from_str(secret_hex) + .and_then(|secret| KeyPair::from_secret(secret)) + .unwrap(); + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + + node_entries.iter().for_each(|entry| discovery.update_node(entry.clone())); + + let expected_bucket_sizes = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7, 8, 12 + ]; + let actual_bucket_sizes = discovery.node_buckets.iter() + .map(|ref bucket| bucket.nodes.len()) + .collect::>(); + assert_eq!(actual_bucket_sizes, expected_bucket_sizes); + + for entry in &node_entries { + let nearest = discovery.nearest_node_entries(&entry.id); + assert_eq!(nearest.len(), 16); + assert_eq!(nearest[0].id, entry.id); + + let mut expected_ids: Vec = node_entries.iter().map(|entry| entry.id).collect(); + expected_ids.sort_unstable_by_key(|id| keccak(id) ^ keccak(entry.id)); + expected_ids.resize(BUCKET_SIZE, NodeId::default()); + + let actual_ids: Vec = nearest.iter().map(|entry| entry.id).collect(); + assert_eq!(actual_ids, expected_ids); + } + } + #[test] fn packets() { let key = Random.generate().unwrap(); - let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40449").unwrap(), udp_port: 40449 }; let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); discovery.check_timestamps = false; let from = SocketAddr::from_str("99.99.99.99:40445").unwrap(); From 54cc7173c14e73dd7a5143b0b492f8236b58c4a7 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 1 Jun 2018 09:49:46 +0200 Subject: [PATCH 145/147] Remove NetworkService::config() (#8653) --- ethcore/sync/src/api.rs | 49 +++++++++++++++-------- parity/informant.rs | 5 ++- rpc/src/v1/impls/parity.rs | 5 ++- rpc/src/v1/tests/mocked/manage_network.rs | 5 ++- util/network-devp2p/src/service.rs | 28 +++++++++---- whisper/cli/src/main.rs | 2 +- 6 files changed, 62 insertions(+), 32 deletions(-) diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 2f90e410aed..9e6cdafa6ec 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeMap}; use std::io; +use std::ops::Range; use std::time::Duration; use bytes::Bytes; use devp2p::NetworkService; @@ -452,11 +453,18 @@ impl ChainNotify for EthSync { } fn start(&self) { - match self.network.start().map_err(Into::into) { - Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), - Err(err) => warn!("Error starting network: {}", err), + match self.network.start() { + Err((err, listen_address)) => { + match err.into() { + ErrorKind::Io(ref e) if e.kind() == io::ErrorKind::AddrInUse => { + warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", listen_address.expect("Listen address is not set.")) + }, + err => warn!("Error starting network: {}", err), + } + }, _ => {}, } + self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, &[ETH_PROTOCOL_VERSION_62, ETH_PROTOCOL_VERSION_63]) .unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e)); // register the warp sync subprotocol @@ -520,8 +528,10 @@ pub trait ManageNetwork : Send + Sync { fn start_network(&self); /// Stop network fn stop_network(&self); - /// Query the current configuration of the network - fn network_config(&self) -> NetworkConfiguration; + /// Returns the minimum and maximum peers. + /// Note that `range.end` is *exclusive*. + // TODO: Range should be changed to RangeInclusive once stable (https://github.com/rust-lang/rust/pull/50758) + fn num_peers_range(&self) -> Range; /// Get network context for protocol. fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)); } @@ -561,8 +571,8 @@ impl ManageNetwork for EthSync { self.stop(); } - fn network_config(&self) -> NetworkConfiguration { - NetworkConfiguration::from(self.network.config().clone()) + fn num_peers_range(&self) -> Range { + self.network.num_peers_range() } fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)) { @@ -815,11 +825,15 @@ impl ManageNetwork for LightSync { } fn start_network(&self) { - match self.network.start().map_err(Into::into) { - Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => { - warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")) - } - Err(err) => warn!("Error starting network: {}", err), + match self.network.start() { + Err((err, listen_address)) => { + match err.into() { + ErrorKind::Io(ref e) if e.kind() == io::ErrorKind::AddrInUse => { + warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", listen_address.expect("Listen address is not set.")) + }, + err => warn!("Error starting network: {}", err), + } + }, _ => {}, } @@ -836,8 +850,8 @@ impl ManageNetwork for LightSync { self.network.stop(); } - fn network_config(&self) -> NetworkConfiguration { - NetworkConfiguration::from(self.network.config().clone()) + fn num_peers_range(&self) -> Range { + self.network.num_peers_range() } fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)) { @@ -848,12 +862,13 @@ impl ManageNetwork for LightSync { impl LightSyncProvider for LightSync { fn peer_numbers(&self) -> PeerNumbers { let (connected, active) = self.proto.peer_count(); - let config = self.network_config(); + let peers_range = self.num_peers_range(); + debug_assert!(peers_range.end > peers_range.start); PeerNumbers { connected: connected, active: active, - max: config.max_peers as usize, - min: config.min_peers as usize, + max: peers_range.end as usize - 1, + min: peers_range.start as usize, } } diff --git a/parity/informant.rs b/parity/informant.rs index e2f3960b679..43788bc9d90 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -145,7 +145,8 @@ impl InformantData for FullNodeInformantData { let (importing, sync_info) = match (self.sync.as_ref(), self.net.as_ref()) { (Some(sync), Some(net)) => { let status = sync.status(); - let net_config = net.network_config(); + let num_peers_range = net.num_peers_range(); + debug_assert!(num_peers_range.end > num_peers_range.start); cache_sizes.insert("sync", status.mem_used); @@ -154,7 +155,7 @@ impl InformantData for FullNodeInformantData { last_imported_block_number: status.last_imported_block_number.unwrap_or(chain_info.best_block_number), last_imported_old_block_number: status.last_imported_old_block_number, num_peers: status.num_peers, - max_peers: status.current_max_peers(net_config.min_peers, net_config.max_peers), + max_peers: status.current_max_peers(num_peers_range.start, num_peers_range.end - 1), snapshot_sync: status.is_snapshot_syncing(), })) } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 08d5147202c..3fa9cb991bb 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -212,13 +212,14 @@ impl Parity for ParityClient where fn net_peers(&self) -> Result { let sync_status = self.sync.status(); - let net_config = self.net.network_config(); + let num_peers_range = self.net.num_peers_range(); + debug_assert!(num_peers_range.end > num_peers_range.start); let peers = self.sync.peers().into_iter().map(Into::into).collect(); Ok(Peers { active: sync_status.num_active_peers, connected: sync_status.num_peers, - max: sync_status.current_max_peers(net_config.min_peers, net_config.max_peers), + max: sync_status.current_max_peers(num_peers_range.start, num_peers_range.end - 1), peers: peers }) } diff --git a/rpc/src/v1/tests/mocked/manage_network.rs b/rpc/src/v1/tests/mocked/manage_network.rs index 3a901c8e9fd..da4f1aa5118 100644 --- a/rpc/src/v1/tests/mocked/manage_network.rs +++ b/rpc/src/v1/tests/mocked/manage_network.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use sync::{ManageNetwork, NetworkConfiguration}; +use std::ops::Range; +use sync::ManageNetwork; use self::ethcore_network::{ProtocolId, NetworkContext}; extern crate ethcore_network; @@ -29,6 +30,6 @@ impl ManageNetwork for TestManageNetwork { fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { Ok(()) } fn start_network(&self) {} fn stop_network(&self) {} - fn network_config(&self) -> NetworkConfiguration { NetworkConfiguration::new_local() } + fn num_peers_range(&self) -> Range { 25 .. 51 } fn with_proto_context(&self, _: ProtocolId, _: &mut FnMut(&NetworkContext)) { } } diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index d8105f649c5..f90c6606714 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -19,6 +19,8 @@ use network::{NetworkContext, PeerId, ProtocolId, NetworkIoMessage}; use host::Host; use io::*; use parking_lot::RwLock; +use std::net::SocketAddr; +use std::ops::Range; use std::sync::Arc; use ansi_term::Colour; use network::ConnectionFilter; @@ -92,9 +94,13 @@ impl NetworkService { &self.io_service } - /// Returns network configuration. - pub fn config(&self) -> &NetworkConfiguration { - &self.config + /// Returns the number of peers allowed. + /// + /// Keep in mind that `range.end` is *exclusive*. + pub fn num_peers_range(&self) -> Range { + let start = self.config.min_peers; + let end = self.config.max_peers + 1; + start .. end } /// Returns external url if available. @@ -109,17 +115,23 @@ impl NetworkService { host.as_ref().map(|h| h.local_url()) } - /// Start network IO - pub fn start(&self) -> Result<(), Error> { + /// Start network IO. + /// + /// In case of error, also returns the listening address for better error reporting. + pub fn start(&self) -> Result<(), (Error, Option)> { let mut host = self.host.write(); + let listen_addr = self.config.listen_address.clone(); if host.is_none() { - let h = Arc::new(Host::new(self.config.clone(), self.filter.clone())?); - self.io_service.register_handler(h.clone())?; + let h = Arc::new(Host::new(self.config.clone(), self.filter.clone()) + .map_err(|err| (err.into(), listen_addr))?); + self.io_service.register_handler(h.clone()) + .map_err(|err| (err.into(), listen_addr))?; *host = Some(h); } if self.host_handler.public_url.read().is_none() { - self.io_service.register_handler(self.host_handler.clone())?; + self.io_service.register_handler(self.host_handler.clone()) + .map_err(|err| (err.into(), listen_addr))?; } Ok(()) diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index d76c216be46..6f3aec8594e 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -218,7 +218,7 @@ fn execute(command: I) -> Result<(), Error> where I: IntoIterator, let network = devp2p::NetworkService::new(net::NetworkConfiguration::new_local(), None)?; // Start network service - network.start()?; + network.start().map_err(|(err, _)| err)?; // Attach whisper protocol to the network service network.register_protocol(whisper_network_handler.clone(), whisper::net::PROTOCOL_ID, From e30047275d086dfbfe8cafe8d83a9023c46f1ff7 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Fri, 1 Jun 2018 09:52:30 +0200 Subject: [PATCH 146/147] CI: Fixes for Android Pipeline (#8745) * ci: Remove check for shared libraries in gitlab script * ci: allow android arm build to fail --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 95a7ebcb5e4..c615be99ce4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -190,9 +190,9 @@ android-armv7: - triggers script: - cargo build --target=armv7-linux-androideabi - - if [ $(arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/debug/parity | grep -i 'c++_shared' | wc -l) -ne 0]; then echo "FAIL!!" fi tags: - rust-arm + allow_failure: true artifacts: paths: - parity.zip From f85253112c13972d9e58205a0001d9dfd8f837d9 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 1 Jun 2018 13:37:43 +0200 Subject: [PATCH 147/147] Custom Error Messages on ENFILE and EMFILE IO Errors (#8744) * Custom Error Messages on ENFILE and EMFILE IO Errors Add custom mapping of ENFILE and EMFILE IO Errors (Failure because of missing system resource) right when chaining ioError into ::util::Network::Error to improve Error Messages given to user Note: Adds libc as a dependency to util/network * Use assert-matches for more readable tests * Fix Wording and consistency --- Cargo.lock | 2 ++ util/network/Cargo.toml | 5 ++++ util/network/src/error.rs | 53 ++++++++++++++++++++++++++++++++++++++- util/network/src/lib.rs | 4 +++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c8e60dce693..680b9606ec0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,12 +703,14 @@ dependencies = [ name = "ethcore-network" version = "1.12.0" dependencies = [ + "assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", ] diff --git a/util/network/Cargo.toml b/util/network/Cargo.toml index f7131da0388..4ae699098dd 100644 --- a/util/network/Cargo.toml +++ b/util/network/Cargo.toml @@ -14,4 +14,9 @@ ethereum-types = "0.3" ethkey = { path = "../../ethkey" } ipnetwork = "0.12.6" rlp = { path = "../rlp" } +libc = "0.2" snappy = { git = "https://github.com/paritytech/rust-snappy" } + + +[dev-dependencies] +assert_matches = "1.2" diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 61044866966..50bd01e9bad 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::{io, net, fmt}; +use libc::{ENFILE, EMFILE}; use io::IoError; use {rlp, ethkey, crypto, snappy}; @@ -83,7 +84,6 @@ impl fmt::Display for DisconnectReason { error_chain! { foreign_links { SocketIo(IoError) #[doc = "Socket IO error."]; - Io(io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; Decompression(snappy::InvalidInput) #[doc = "Decompression error."]; } @@ -141,6 +141,34 @@ error_chain! { description("Packet is too large"), display("Packet is too large"), } + + #[doc = "Reached system resource limits for this process"] + ProcessTooManyFiles { + description("Too many open files in process."), + display("Too many open files in this process. Check your resource limits and restart parity"), + } + + #[doc = "Reached system wide resource limits"] + SystemTooManyFiles { + description("Too many open files on system."), + display("Too many open files on system. Consider closing some processes/release some file handlers or increas the system-wide resource limits and restart parity."), + } + + #[doc = "An unknown IO error occurred."] + Io(err: io::Error) { + description("IO Error"), + display("Unexpected IO error: {}", err), + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Self { + match err.raw_os_error() { + Some(ENFILE) => ErrorKind::ProcessTooManyFiles.into(), + Some(EMFILE) => ErrorKind::SystemTooManyFiles.into(), + _ => Error::from_kind(ErrorKind::Io(err)) + } } } @@ -191,3 +219,26 @@ fn test_errors() { _ => panic!("Unexpected error"), } } + +#[test] +fn test_io_errors() { + use libc::{EMFILE, ENFILE}; + + assert_matches!( + >::from( + io::Error::from_raw_os_error(ENFILE) + ).kind(), + ErrorKind::ProcessTooManyFiles); + + assert_matches!( + >::from( + io::Error::from_raw_os_error(EMFILE) + ).kind(), + ErrorKind::SystemTooManyFiles); + + assert_matches!( + >::from( + io::Error::from_raw_os_error(0) + ).kind(), + ErrorKind::Io(_)); +} diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 207a05075d2..87d3ed9b0e5 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -23,6 +23,10 @@ extern crate ethkey; extern crate rlp; extern crate ipnetwork; extern crate snappy; +extern crate libc; + +#[cfg(test)] #[macro_use] +extern crate assert_matches; #[macro_use] extern crate error_chain;