Merge branch 'master' into mining
This commit is contained in:
commit
f705f6957a
3
.gitignore
vendored
3
.gitignore
vendored
@ -27,3 +27,6 @@
|
|||||||
# jetbrains ide stuff
|
# jetbrains ide stuff
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
out/
|
||||||
|
@ -19,7 +19,7 @@ First (if you don't already have it) get multirust:
|
|||||||
|
|
||||||
- Linux:
|
- Linux:
|
||||||
```bash
|
```bash
|
||||||
curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes
|
curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes
|
||||||
```
|
```
|
||||||
|
|
||||||
- OSX with Homebrew:
|
- OSX with Homebrew:
|
||||||
|
@ -447,7 +447,7 @@ impl BlockChain {
|
|||||||
|
|
||||||
let mut write_details = self.block_details.write().unwrap();
|
let mut write_details = self.block_details.write().unwrap();
|
||||||
for (hash, details) in update.block_details.into_iter() {
|
for (hash, details) in update.block_details.into_iter() {
|
||||||
batch.put_extras(&hash, &details);
|
batch.put_extras(&hash, &details);
|
||||||
write_details.insert(hash, details);
|
write_details.insert(hash, details);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +572,7 @@ impl BlockChain {
|
|||||||
/// This function returns modified transaction addresses.
|
/// This function returns modified transaction addresses.
|
||||||
fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, TransactionAddress> {
|
fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, TransactionAddress> {
|
||||||
let block = BlockView::new(block_bytes);
|
let block = BlockView::new(block_bytes);
|
||||||
let transaction_hashes = block.transaction_hashes();
|
let transaction_hashes = block.transaction_hashes();
|
||||||
|
|
||||||
transaction_hashes.into_iter()
|
transaction_hashes.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@ -587,20 +587,20 @@ impl BlockChain {
|
|||||||
|
|
||||||
/// This functions returns modified blocks blooms.
|
/// This functions returns modified blocks blooms.
|
||||||
///
|
///
|
||||||
/// To accelerate blooms lookups, blomms are stored in multiple
|
/// To accelerate blooms lookups, blomms are stored in multiple
|
||||||
/// layers (BLOOM_LEVELS, currently 3).
|
/// layers (BLOOM_LEVELS, currently 3).
|
||||||
/// ChainFilter is responsible for building and rebuilding these layers.
|
/// ChainFilter is responsible for building and rebuilding these layers.
|
||||||
/// It returns them in HashMap, where values are Blooms and
|
/// It returns them in HashMap, where values are Blooms and
|
||||||
/// keys are BloomIndexes. BloomIndex represents bloom location on one
|
/// keys are BloomIndexes. BloomIndex represents bloom location on one
|
||||||
/// of these layers.
|
/// of these layers.
|
||||||
///
|
///
|
||||||
/// To reduce number of queries to databse, block blooms are stored
|
/// To reduce number of queries to databse, block blooms are stored
|
||||||
/// in BlocksBlooms structure which contains info about several
|
/// in BlocksBlooms structure which contains info about several
|
||||||
/// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms.
|
/// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms.
|
||||||
///
|
///
|
||||||
/// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex)
|
/// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex)
|
||||||
/// to bloom location in database (BlocksBloomLocation).
|
/// to bloom location in database (BlocksBloomLocation).
|
||||||
///
|
///
|
||||||
fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, BlocksBlooms> {
|
fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, BlocksBlooms> {
|
||||||
let block = BlockView::new(block_bytes);
|
let block = BlockView::new(block_bytes);
|
||||||
let header = block.header_view();
|
let header = block.header_view();
|
||||||
@ -766,32 +766,33 @@ mod tests {
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use rustc_serialize::hex::FromHex;
|
use rustc_serialize::hex::FromHex;
|
||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
|
use util::sha3::Hashable;
|
||||||
use blockchain::{BlockProvider, BlockChain, BlockChainConfig};
|
use blockchain::{BlockProvider, BlockChain, BlockChainConfig};
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use devtools::*;
|
use devtools::*;
|
||||||
|
use blockchain::helpers::generators::ChainGenerator;
|
||||||
|
use views::BlockView;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_tests_extra32() {
|
fn basic_blockchain_insert() {
|
||||||
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap();
|
let mut canon_chain = ChainGenerator::default();
|
||||||
|
let genesis = canon_chain.next().unwrap();
|
||||||
|
let first = canon_chain.next().unwrap();
|
||||||
|
let genesis_hash = BlockView::new(&genesis).header_view().sha3();
|
||||||
|
let first_hash = BlockView::new(&first).header_view().sha3();
|
||||||
|
|
||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
|
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
|
||||||
|
|
||||||
let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap();
|
|
||||||
|
|
||||||
assert_eq!(bc.genesis_hash(), genesis_hash.clone());
|
assert_eq!(bc.genesis_hash(), genesis_hash.clone());
|
||||||
assert_eq!(bc.best_block_number(), 0);
|
assert_eq!(bc.best_block_number(), 0);
|
||||||
assert_eq!(bc.best_block_hash(), genesis_hash.clone());
|
assert_eq!(bc.best_block_hash(), genesis_hash.clone());
|
||||||
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
|
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
|
||||||
assert_eq!(bc.block_hash(1), None);
|
assert_eq!(bc.block_hash(1), None);
|
||||||
assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]);
|
assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]);
|
||||||
|
|
||||||
let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap();
|
|
||||||
|
|
||||||
bc.insert_block(&first, vec![]);
|
bc.insert_block(&first, vec![]);
|
||||||
|
|
||||||
let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap();
|
|
||||||
|
|
||||||
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
|
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
|
||||||
assert_eq!(bc.best_block_number(), 1);
|
assert_eq!(bc.best_block_number(), 1);
|
||||||
assert_eq!(bc.best_block_hash(), first_hash.clone());
|
assert_eq!(bc.best_block_hash(), first_hash.clone());
|
||||||
@ -961,7 +962,7 @@ mod tests {
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
|
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
|
||||||
bc.insert_block(&b1, vec![]);
|
bc.insert_block(&b1, vec![]);
|
||||||
|
|
||||||
let transactions = bc.transactions(&b1_hash).unwrap();
|
let transactions = bc.transactions(&b1_hash).unwrap();
|
||||||
assert_eq!(transactions.len(), 7);
|
assert_eq!(transactions.len(), 7);
|
||||||
for t in transactions {
|
for t in transactions {
|
||||||
@ -981,7 +982,7 @@ mod tests {
|
|||||||
|
|
||||||
// prepare for fork (b1a, child of genesis)
|
// prepare for fork (b1a, child of genesis)
|
||||||
let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
|
let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
|
||||||
|
|
||||||
// fork (b2a, child of b1a, with higher total difficulty)
|
// fork (b2a, child of b1a, with higher total difficulty)
|
||||||
let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
|
let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
|
||||||
|
|
||||||
@ -1001,7 +1002,7 @@ mod tests {
|
|||||||
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
|
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
|
||||||
assert_eq!(blocks_b1, vec![]);
|
assert_eq!(blocks_b1, vec![]);
|
||||||
assert_eq!(blocks_b2, vec![]);
|
assert_eq!(blocks_b2, vec![]);
|
||||||
|
|
||||||
bc.insert_block(&b1, vec![]);
|
bc.insert_block(&b1, vec![]);
|
||||||
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5);
|
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5);
|
||||||
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
|
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
|
||||||
@ -1041,6 +1042,4 @@ mod tests {
|
|||||||
assert_eq!(blocks_b2, vec![2]);
|
assert_eq!(blocks_b2, vec![2]);
|
||||||
assert_eq!(blocks_ba, vec![3]);
|
assert_eq!(blocks_ba, vec![3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
154
ethcore/src/blockchain/helpers/generators.rs
Normal file
154
ethcore/src/blockchain/helpers/generators.rs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use util::rlp::*;
|
||||||
|
use util::hash::{H256, H2048};
|
||||||
|
use util::uint::{U256};
|
||||||
|
use util::bytes::Bytes;
|
||||||
|
use header::{BlockNumber, Header};
|
||||||
|
use transaction::SignedTransaction;
|
||||||
|
|
||||||
|
/// Chain iterator interface.
|
||||||
|
pub trait ChainIterator: Iterator {
|
||||||
|
/// Should be called to create a fork of current iterator.
|
||||||
|
/// Blocks generated by fork will have lower difficulty than current chain.
|
||||||
|
fn fork(&mut self) -> Self;
|
||||||
|
/// Should be called to create new block with given bloom.
|
||||||
|
fn next_with_bloom(&mut self, bloom: H2048) -> Option<Self::Item>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper structure, used for encoding blocks.
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Block {
|
||||||
|
header: Header,
|
||||||
|
transactions: Vec<SignedTransaction>,
|
||||||
|
uncles: Vec<Header>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for Block {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
s.begin_list(3);
|
||||||
|
s.append(&self.header);
|
||||||
|
s.append(&self.transactions);
|
||||||
|
s.append(&self.uncles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blockchain generator.
|
||||||
|
pub struct ChainGenerator {
|
||||||
|
/// Next block number.
|
||||||
|
number: BlockNumber,
|
||||||
|
/// Next block parent hash.
|
||||||
|
parent_hash: H256,
|
||||||
|
/// Next block difficulty.
|
||||||
|
difficulty: U256,
|
||||||
|
/// Number of forks of current block.
|
||||||
|
number_of_forks: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainGenerator {
|
||||||
|
fn prepare_block(&self) -> Block {
|
||||||
|
let mut block = Block::default();
|
||||||
|
block.header.parent_hash = self.parent_hash.clone();
|
||||||
|
block.header.number = self.number;
|
||||||
|
block.header.difficulty = self.difficulty;
|
||||||
|
block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ChainGenerator {
|
||||||
|
fn default() -> Self {
|
||||||
|
ChainGenerator {
|
||||||
|
number: 0,
|
||||||
|
parent_hash: H256::default(),
|
||||||
|
difficulty: U256::from(1000),
|
||||||
|
number_of_forks: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for ChainGenerator {
|
||||||
|
type Item = Bytes;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let block = self.prepare_block();
|
||||||
|
self.number += 1;
|
||||||
|
self.parent_hash = block.header.hash();
|
||||||
|
self.number_of_forks = 0;
|
||||||
|
Some(encode(&block).to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainIterator for ChainGenerator {
|
||||||
|
fn fork(&mut self) -> Self {
|
||||||
|
self.number_of_forks += 1;
|
||||||
|
ChainGenerator {
|
||||||
|
number: self.number,
|
||||||
|
parent_hash: self.parent_hash.clone(),
|
||||||
|
difficulty: self.difficulty - U256::from(self.number_of_forks),
|
||||||
|
number_of_forks: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_with_bloom(&mut self, bloom: H2048) -> Option<Self::Item> {
|
||||||
|
let mut block = self.prepare_block();
|
||||||
|
block.header.log_bloom = bloom;
|
||||||
|
self.number += 1;
|
||||||
|
self.parent_hash = block.header.hash();
|
||||||
|
self.number_of_forks = 0;
|
||||||
|
Some(encode(&block).to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use util::hash::H256;
|
||||||
|
use util::sha3::Hashable;
|
||||||
|
use views::BlockView;
|
||||||
|
use super::{ChainIterator, ChainGenerator};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn canon_chain_generator() {
|
||||||
|
let mut canon_chain = ChainGenerator::default();
|
||||||
|
|
||||||
|
let genesis_rlp = canon_chain.next().unwrap();
|
||||||
|
let genesis = BlockView::new(&genesis_rlp);
|
||||||
|
|
||||||
|
assert_eq!(genesis.header_view().parent_hash(), H256::default());
|
||||||
|
assert_eq!(genesis.header_view().number(), 0);
|
||||||
|
|
||||||
|
let b1_rlp = canon_chain.next().unwrap();
|
||||||
|
let b1 = BlockView::new(&b1_rlp);
|
||||||
|
|
||||||
|
assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3());
|
||||||
|
assert_eq!(b1.header_view().number(), 1);
|
||||||
|
|
||||||
|
let mut fork_chain = canon_chain.fork();
|
||||||
|
|
||||||
|
let b2_rlp_fork = fork_chain.next().unwrap();
|
||||||
|
let b2_fork = BlockView::new(&b2_rlp_fork);
|
||||||
|
|
||||||
|
assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3());
|
||||||
|
assert_eq!(b2_fork.header_view().number(), 2);
|
||||||
|
|
||||||
|
let b2_rlp = canon_chain.next().unwrap();
|
||||||
|
let b2 = BlockView::new(&b2_rlp);
|
||||||
|
|
||||||
|
assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3());
|
||||||
|
assert_eq!(b2.header_view().number(), 2);
|
||||||
|
assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty());
|
||||||
|
}
|
||||||
|
}
|
17
ethcore/src/blockchain/helpers/mod.rs
Normal file
17
ethcore/src/blockchain/helpers/mod.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
pub mod generators;
|
@ -23,6 +23,8 @@ mod bloom_indexer;
|
|||||||
mod cache;
|
mod cache;
|
||||||
mod tree_route;
|
mod tree_route;
|
||||||
mod update;
|
mod update;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig};
|
pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig};
|
||||||
pub use self::cache::CacheSize;
|
pub use self::cache::CacheSize;
|
||||||
|
@ -117,7 +117,7 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
|
fn logs(&self, _filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,19 @@ fn u256_mul(b: &mut Bencher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn u256_full_mul(b: &mut Bencher) {
|
||||||
|
b.iter(|| {
|
||||||
|
let n = black_box(10000);
|
||||||
|
(0..n).fold(U256([rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>()]),
|
||||||
|
|old, new| {
|
||||||
|
let U512(ref u512words) = old.full_mul(U256([rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>()]));
|
||||||
|
U256([u512words[0], u512words[2], u512words[2], u512words[3]])
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn u128_mul(b: &mut Bencher) {
|
fn u128_mul(b: &mut Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
|
@ -46,14 +46,14 @@ pub fn enumerate_geth_keys(path: &Path) -> Result<Vec<(Address, String)>, io::Er
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ImportError {
|
pub enum ImportError {
|
||||||
/// Io error reading geth file
|
/// Io error reading geth file
|
||||||
IoError(io::Error),
|
Io(io::Error),
|
||||||
/// format error
|
/// format error
|
||||||
FormatError,
|
Format,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for ImportError {
|
impl From<io::Error> for ImportError {
|
||||||
fn from (err: io::Error) -> ImportError {
|
fn from (err: io::Error) -> ImportError {
|
||||||
ImportError::IoError(err)
|
ImportError::Io(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,15 +65,15 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path)
|
|||||||
|
|
||||||
let mut json_result = Json::from_str(&buf);
|
let mut json_result = Json::from_str(&buf);
|
||||||
let mut json = match json_result {
|
let mut json = match json_result {
|
||||||
Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::FormatError)),
|
Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::Format)),
|
||||||
Err(_) => { return Err(ImportError::FormatError); }
|
Err(_) => { return Err(ImportError::Format); }
|
||||||
};
|
};
|
||||||
let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::FormatError)).clone();
|
let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::Format)).clone();
|
||||||
json.insert("crypto".to_owned(), Json::Object(crypto_object));
|
json.insert("crypto".to_owned(), Json::Object(crypto_object));
|
||||||
json.remove("Crypto");
|
json.remove("Crypto");
|
||||||
match KeyFileContent::load(&Json::Object(json.clone())) {
|
match KeyFileContent::load(&Json::Object(json.clone())) {
|
||||||
Ok(key_file) => try!(secret_store.import_key(key_file)),
|
Ok(key_file) => try!(secret_store.import_key(key_file)),
|
||||||
Err(_) => { return Err(ImportError::FormatError); }
|
Err(_) => { return Err(ImportError::Format); }
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path)
|
|||||||
pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> {
|
pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory));
|
let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory));
|
||||||
for &(ref address, ref file_path) in geth_files.iter() {
|
for &(ref address, ref file_path) in &geth_files {
|
||||||
let mut path = PathBuf::new();
|
let mut path = PathBuf::new();
|
||||||
path.push(geth_keyfiles_directory);
|
path.push(geth_keyfiles_directory);
|
||||||
path.push(file_path);
|
path.push(file_path);
|
||||||
|
@ -144,6 +144,7 @@ pub mod network;
|
|||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod panics;
|
pub mod panics;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
|
pub mod table;
|
||||||
|
|
||||||
pub use common::*;
|
pub use common::*;
|
||||||
pub use misc::*;
|
pub use misc::*;
|
||||||
|
@ -376,7 +376,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() };
|
let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() };
|
||||||
self.pinned_nodes.push(n.id.clone());
|
self.pinned_nodes.push(n.id.clone());
|
||||||
self.nodes.write().unwrap().add_node(n);
|
self.nodes.write().unwrap().add_node(n);
|
||||||
if let &mut Some(ref mut discovery) = self.discovery.lock().unwrap().deref_mut() {
|
if let Some(ref mut discovery) = *self.discovery.lock().unwrap().deref_mut() {
|
||||||
discovery.add_node(entry);
|
discovery.add_node(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -418,7 +418,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port }
|
Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup the server socket
|
// Setup the server socket
|
||||||
*tcp_listener = Some(TcpListener::bind(&listen_address).unwrap());
|
*tcp_listener = Some(TcpListener::bind(&listen_address).unwrap());
|
||||||
self.info.write().unwrap().public_endpoint = public_endpoint.clone();
|
self.info.write().unwrap().public_endpoint = public_endpoint.clone();
|
||||||
@ -697,7 +697,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } };
|
let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } };
|
||||||
self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
|
self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
|
||||||
let mut discovery = self.discovery.lock().unwrap();
|
let mut discovery = self.discovery.lock().unwrap();
|
||||||
if let &mut Some(ref mut discovery) = discovery.deref_mut() {
|
if let Some(ref mut discovery) = *discovery.deref_mut() {
|
||||||
discovery.add_node(entry);
|
discovery.add_node(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
254
util/src/table.rs
Normal file
254
util/src/table.rs
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! A collection associating pair of keys (row and column) with a single value.
|
||||||
|
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// 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<Col, Val>` for specific `Row`
|
||||||
|
pub struct Table<Row, Col, Val>
|
||||||
|
where Row: Eq + Hash + Clone,
|
||||||
|
Col: Eq + Hash {
|
||||||
|
map: HashMap<Row, HashMap<Col, Val>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Row, Col, Val> Table<Row, Col, Val>
|
||||||
|
where Row: Eq + Hash + Clone,
|
||||||
|
Col: Eq + Hash {
|
||||||
|
/// Creates new Table
|
||||||
|
pub fn new() -> Table<Row, Col, Val> {
|
||||||
|
Table {
|
||||||
|
map: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<Col, Val>> {
|
||||||
|
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<Col, Val>> {
|
||||||
|
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<Val> {
|
||||||
|
let (val, is_empty) = {
|
||||||
|
let row_map = self.map.get_mut(row);
|
||||||
|
if let None = row_map {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut 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<Val> {
|
||||||
|
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<usize, usize, bool> = 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<usize, usize, usize> = 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 mut 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);
|
||||||
|
}
|
||||||
|
}
|
257
util/src/uint.rs
257
util/src/uint.rs
@ -1097,6 +1097,157 @@ construct_uint!(U512, 8);
|
|||||||
construct_uint!(U256, 4);
|
construct_uint!(U256, 4);
|
||||||
construct_uint!(U128, 2);
|
construct_uint!(U128, 2);
|
||||||
|
|
||||||
|
impl U256 {
|
||||||
|
/// Multiplies two 256-bit integers to produce full 512-bit integer
|
||||||
|
/// No overflow possible
|
||||||
|
#[cfg(all(x64asm, target_arch="x86_64"))]
|
||||||
|
pub fn full_mul(self, other: U256) -> U512 {
|
||||||
|
let self_t: &[u64; 4] = unsafe { &mem::transmute(self) };
|
||||||
|
let other_t: &[u64; 4] = unsafe { &mem::transmute(other) };
|
||||||
|
let mut result: [u64; 8] = unsafe { mem::uninitialized() };
|
||||||
|
unsafe {
|
||||||
|
asm!("
|
||||||
|
mov $8, %rax
|
||||||
|
mulq $12
|
||||||
|
mov %rax, $0
|
||||||
|
mov %rdx, $1
|
||||||
|
|
||||||
|
mov $8, %rax
|
||||||
|
mulq $13
|
||||||
|
add %rax, $1
|
||||||
|
adc $$0, %rdx
|
||||||
|
mov %rdx, $2
|
||||||
|
|
||||||
|
mov $8, %rax
|
||||||
|
mulq $14
|
||||||
|
add %rax, $2
|
||||||
|
adc $$0, %rdx
|
||||||
|
mov %rdx, $3
|
||||||
|
|
||||||
|
mov $8, %rax
|
||||||
|
mulq $15
|
||||||
|
add %rax, $3
|
||||||
|
adc $$0, %rdx
|
||||||
|
mov %rdx, $4
|
||||||
|
|
||||||
|
mov $9, %rax
|
||||||
|
mulq $12
|
||||||
|
add %rax, $1
|
||||||
|
adc %rdx, $2
|
||||||
|
adc $$0, $3
|
||||||
|
adc $$0, $4
|
||||||
|
xor $5, $5
|
||||||
|
adc $$0, $5
|
||||||
|
xor $6, $6
|
||||||
|
adc $$0, $6
|
||||||
|
xor $7, $7
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $9, %rax
|
||||||
|
mulq $13
|
||||||
|
add %rax, $2
|
||||||
|
adc %rdx, $3
|
||||||
|
adc $$0, $4
|
||||||
|
adc $$0, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $9, %rax
|
||||||
|
mulq $14
|
||||||
|
add %rax, $3
|
||||||
|
adc %rdx, $4
|
||||||
|
adc $$0, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $9, %rax
|
||||||
|
mulq $15
|
||||||
|
add %rax, $4
|
||||||
|
adc %rdx, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $10, %rax
|
||||||
|
mulq $12
|
||||||
|
add %rax, $2
|
||||||
|
adc %rdx, $3
|
||||||
|
adc $$0, $4
|
||||||
|
adc $$0, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $10, %rax
|
||||||
|
mulq $13
|
||||||
|
add %rax, $3
|
||||||
|
adc %rdx, $4
|
||||||
|
adc $$0, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $10, %rax
|
||||||
|
mulq $14
|
||||||
|
add %rax, $4
|
||||||
|
adc %rdx, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $10, %rax
|
||||||
|
mulq $15
|
||||||
|
add %rax, $5
|
||||||
|
adc %rdx, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $11, %rax
|
||||||
|
mulq $12
|
||||||
|
add %rax, $3
|
||||||
|
adc %rdx, $4
|
||||||
|
adc $$0, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $11, %rax
|
||||||
|
mulq $13
|
||||||
|
add %rax, $4
|
||||||
|
adc %rdx, $5
|
||||||
|
adc $$0, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $11, %rax
|
||||||
|
mulq $14
|
||||||
|
add %rax, $5
|
||||||
|
adc %rdx, $6
|
||||||
|
adc $$0, $7
|
||||||
|
|
||||||
|
mov $11, %rax
|
||||||
|
mulq $15
|
||||||
|
add %rax, $6
|
||||||
|
adc %rdx, $7
|
||||||
|
"
|
||||||
|
: /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]),
|
||||||
|
/* $3 */ "={r11}"(result[3]), /* $4 */ "={r12}"(result[4]), /* $5 */ "={r13}"(result[5]),
|
||||||
|
/* $6 */ "={r14}"(result[6]), /* $7 */ "={r15}"(result[7])
|
||||||
|
|
||||||
|
: /* $8 */ "m"(self_t[0]), /* $9 */ "m"(self_t[1]), /* $10 */ "m"(self_t[2]),
|
||||||
|
/* $11 */ "m"(self_t[3]), /* $12 */ "m"(other_t[0]), /* $13 */ "m"(other_t[1]),
|
||||||
|
/* $14 */ "m"(other_t[2]), /* $15 */ "m"(other_t[3])
|
||||||
|
: "rax", "rdx"
|
||||||
|
:
|
||||||
|
);
|
||||||
|
}
|
||||||
|
U512(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiplies two 256-bit integers to produce full 512-bit integer
|
||||||
|
/// No overflow possible
|
||||||
|
#[cfg(not(all(x64asm, target_arch="x86_64")))]
|
||||||
|
pub fn full_mul(self, other: U256) -> U512 {
|
||||||
|
let self_512 = U512::from(self);
|
||||||
|
let other_512 = U512::from(other);
|
||||||
|
let (result, _) = self_512.overflowing_mul(other_512);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<U256> for U512 {
|
impl From<U256> for U512 {
|
||||||
fn from(value: U256) -> U512 {
|
fn from(value: U256) -> U512 {
|
||||||
let U256(ref arr) = value;
|
let U256(ref arr) = value;
|
||||||
@ -1855,5 +2006,111 @@ mod tests {
|
|||||||
let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0]));
|
let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0]));
|
||||||
assert!(overflow);
|
assert!(overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u256_multi_full_mul() {
|
||||||
|
let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([1, 0, 0, 0]).full_mul(U256([1, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([1, 0, 0, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([5, 0, 0, 0]).full_mul(U256([5, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([25, 0, 0, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([0, 5, 0, 0]).full_mul(U256([0, 5, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 25, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([0, 0, 0, 4]).full_mul(U256([4, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 16, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([0, 0, 0, 5]).full_mul(U256([2, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([0, 0, 2, 0]).full_mul(U256([0, 5, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([0, 3, 0, 0]).full_mul(U256([0, 0, 3, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 9, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([0, 0, 8, 0]).full_mul(U256([0, 0, 6, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 0, 48, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([9, 0, 0, 0]).full_mul(U256([0, 3, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 27, 0, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([1, ::std::u64::MAX-1, 0, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([0, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 1, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||||
|
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||||
|
assert_eq!(U512([1, 0, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||||
|
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||||
|
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||||
|
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||||
|
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||||
|
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||||
|
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||||
|
assert_eq!(U512([1, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||||
|
assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||||
|
assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||||
|
assert_eq!(U512([1, 0, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result);
|
||||||
|
|
||||||
|
let result = U256([0, 0, 0, ::std::u64::MAX]).full_mul(U256([0, 0, 0, ::std::u64::MAX]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 0, 0, 0, 1, ::std::u64::MAX-1]), result);
|
||||||
|
|
||||||
|
let result = U256([1, 0, 0, 0]).full_mul(U256([0, 0, 0, ::std::u64::MAX]));
|
||||||
|
assert_eq!(U512([0, 0, 0, ::std::u64::MAX, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([1, 2, 3, 4]).full_mul(U256([5, 0, 0, 0]));
|
||||||
|
assert_eq!(U512([5, 10, 15, 20, 0, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 6, 0, 0]));
|
||||||
|
assert_eq!(U512([0, 6, 12, 18, 24, 0, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 7, 0]));
|
||||||
|
assert_eq!(U512([0, 0, 7, 14, 21, 28, 0, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 0, 8]));
|
||||||
|
assert_eq!(U512([0, 0, 0, 8, 16, 24, 32, 0]), result);
|
||||||
|
|
||||||
|
let result = U256([1, 2, 3, 4]).full_mul(U256([5, 6, 7, 8]));
|
||||||
|
assert_eq!(U512([5, 16, 34, 60, 61, 52, 32, 0]), result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user