Ethereum-types and various libs upgrade (#315)
* Upgrade Eth types ethereum-types -> 0.9.2 rlp -> 0.4.6 keccak-hash -> 0.5.0 parity-crypto -> 0.6.2 ethabi -> 0.12.0 ethabi-derive -> 0.12.0 ethabi-contract -> 0.11.0 ethbloom -> 0.9.1 rand -> 0.7.3 trie-standardmap -> 0.15.2 triehash -> 0.5.0 * backport #10714. Small changes, merge fixes Co-authored-by: mdben1247 <mdben1247@users.noreply.github.com>
This commit is contained in:
parent
3f8e0cfec4
commit
a0f406e26b
828
Cargo.lock
generated
828
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
@ -47,12 +47,13 @@ ethcore-miner = { path = "crates/concensus/miner" }
|
|||||||
ethcore-network = { path = "crates/net/network" }
|
ethcore-network = { path = "crates/net/network" }
|
||||||
ethcore-service = { path = "crates/ethcore/service" }
|
ethcore-service = { path = "crates/ethcore/service" }
|
||||||
ethcore-sync = { path = "crates/ethcore/sync" }
|
ethcore-sync = { path = "crates/ethcore/sync" }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
ethkey = { path = "crates/accounts/ethkey" }
|
ethkey = { path = "crates/accounts/ethkey" }
|
||||||
ethstore = { path = "crates/accounts/ethstore" }
|
ethstore = { path = "crates/accounts/ethstore" }
|
||||||
fetch = { path = "crates/net/fetch" }
|
fetch = { path = "crates/net/fetch" }
|
||||||
node-filter = { path = "crates/net/node-filter" }
|
node-filter = { path = "crates/net/node-filter" }
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
|
||||||
|
rlp = { version = "0.4.6" }
|
||||||
cli-signer= { path = "crates/util/cli-signer" }
|
cli-signer= { path = "crates/util/cli-signer" }
|
||||||
parity-daemonize = "0.3"
|
parity-daemonize = "0.3"
|
||||||
parity-local-store = { path = "crates/concensus/miner/local-store" }
|
parity-local-store = { path = "crates/concensus/miner/local-store" }
|
||||||
@ -62,7 +63,7 @@ parity-version = { path = "crates/util/version" }
|
|||||||
parity-path = "0.1"
|
parity-path = "0.1"
|
||||||
dir = { path = "crates/util/dir" }
|
dir = { path = "crates/util/dir" }
|
||||||
panic_hook = { path = "crates/util/panic-hook" }
|
panic_hook = { path = "crates/util/panic-hook" }
|
||||||
keccak-hash = "0.1"
|
keccak-hash = "0.5.0"
|
||||||
migration-rocksdb = { path = "crates/db/migration-rocksdb" }
|
migration-rocksdb = { path = "crates/db/migration-rocksdb" }
|
||||||
kvdb = "0.1"
|
kvdb = "0.1"
|
||||||
kvdb-rocksdb = "0.1.3"
|
kvdb-rocksdb = "0.1.3"
|
||||||
@ -130,6 +131,3 @@ members = [
|
|||||||
"bin/evmbin",
|
"bin/evmbin",
|
||||||
"bin/chainspec"
|
"bin/chainspec"
|
||||||
]
|
]
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
heapsize = { git = "https://github.com/cheme/heapsize.git", branch = "ec-macfix" }
|
|
||||||
|
@ -9,6 +9,7 @@ docopt = "1.0"
|
|||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
ethkey = { path = "../../crates/accounts/ethkey" }
|
ethkey = { path = "../../crates/accounts/ethkey" }
|
||||||
panic_hook = { path = "../../crates/util/panic-hook" }
|
panic_hook = { path = "../../crates/util/panic-hook" }
|
||||||
|
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
|
||||||
parity-wordlist="1.3"
|
parity-wordlist="1.3"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
@ -18,6 +18,7 @@ extern crate docopt;
|
|||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate ethkey;
|
extern crate ethkey;
|
||||||
extern crate panic_hook;
|
extern crate panic_hook;
|
||||||
|
extern crate parity_crypto as crypto;
|
||||||
extern crate parity_wordlist;
|
extern crate parity_wordlist;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
@ -28,11 +29,11 @@ extern crate serde_derive;
|
|||||||
|
|
||||||
use std::{env, fmt, io, num::ParseIntError, process, sync};
|
use std::{env, fmt, io, num::ParseIntError, process, sync};
|
||||||
|
|
||||||
use docopt::Docopt;
|
use crypto::publickey::{
|
||||||
use ethkey::{
|
sign, verify_address, verify_public, Error as EthkeyError, Generator, KeyPair, Random,
|
||||||
brain_recover, sign, verify_address, verify_public, Brain, BrainPrefix, Error as EthkeyError,
|
|
||||||
Generator, KeyPair, Prefix, Random,
|
|
||||||
};
|
};
|
||||||
|
use docopt::Docopt;
|
||||||
|
use ethkey::{brain_recover, Brain, BrainPrefix, Prefix};
|
||||||
use rustc_hex::{FromHex, FromHexError};
|
use rustc_hex::{FromHex, FromHexError};
|
||||||
|
|
||||||
const USAGE: &'static str = r#"
|
const USAGE: &'static str = r#"
|
||||||
@ -202,15 +203,13 @@ where
|
|||||||
let result = if args.flag_brain {
|
let result = if args.flag_brain {
|
||||||
let phrase = args.arg_secret_or_phrase;
|
let phrase = args.arg_secret_or_phrase;
|
||||||
let phrase_info = validate_phrase(&phrase);
|
let phrase_info = validate_phrase(&phrase);
|
||||||
let keypair = Brain::new(phrase)
|
let keypair = Brain::new(phrase).generate();
|
||||||
.generate()
|
|
||||||
.expect("Brain wallet generator is infallible; qed");
|
|
||||||
(keypair, Some(phrase_info))
|
(keypair, Some(phrase_info))
|
||||||
} else {
|
} else {
|
||||||
let secret = args
|
let secret = args
|
||||||
.arg_secret_or_phrase
|
.arg_secret_or_phrase
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| EthkeyError::InvalidSecret)?;
|
.map_err(|_| EthkeyError::InvalidSecretKey)?;
|
||||||
(KeyPair::from_secret(secret)?, None)
|
(KeyPair::from_secret(secret)?, None)
|
||||||
};
|
};
|
||||||
Ok(display(result, display_mode))
|
Ok(display(result, display_mode))
|
||||||
@ -223,7 +222,7 @@ where
|
|||||||
let phrase = format!("recovery phrase: {}", brain.phrase());
|
let phrase = format!("recovery phrase: {}", brain.phrase());
|
||||||
(keypair, Some(phrase))
|
(keypair, Some(phrase))
|
||||||
} else {
|
} else {
|
||||||
(Random.generate()?, None)
|
(Random.generate(), None)
|
||||||
}
|
}
|
||||||
} else if args.cmd_prefix {
|
} else if args.cmd_prefix {
|
||||||
let prefix = args.arg_prefix.from_hex()?;
|
let prefix = args.arg_prefix.from_hex()?;
|
||||||
@ -254,7 +253,7 @@ where
|
|||||||
let secret = args
|
let secret = args
|
||||||
.arg_secret
|
.arg_secret
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| EthkeyError::InvalidSecret)?;
|
.map_err(|_| EthkeyError::InvalidSecretKey)?;
|
||||||
let message = args
|
let message = args
|
||||||
.arg_message
|
.arg_message
|
||||||
.parse()
|
.parse()
|
||||||
@ -274,7 +273,7 @@ where
|
|||||||
let public = args
|
let public = args
|
||||||
.arg_public
|
.arg_public
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| EthkeyError::InvalidPublic)?;
|
.map_err(|_| EthkeyError::InvalidPublicKey)?;
|
||||||
verify_public(&public, &signature, &message)?
|
verify_public(&public, &signature, &message)?
|
||||||
} else if args.cmd_address {
|
} else if args.cmd_address {
|
||||||
let address = args
|
let address = args
|
||||||
@ -301,7 +300,7 @@ where
|
|||||||
while let Some(phrase) = it.next() {
|
while let Some(phrase) = it.next() {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
let keypair = Brain::new(phrase.clone()).generate().unwrap();
|
let keypair = Brain::new(phrase.clone()).generate();
|
||||||
if keypair.address() == address {
|
if keypair.address() == address {
|
||||||
return Ok(Some((phrase, keypair)));
|
return Ok(Some((phrase, keypair)));
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ common-types = { path = "../../crates/ethcore/types", features = ["test-helpers"
|
|||||||
docopt = "1.0"
|
docopt = "1.0"
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
ethcore = { path = "../../crates/ethcore", features = ["test-helpers", "json-tests", "to-pod-full"] }
|
ethcore = { path = "../../crates/ethcore", features = ["test-helpers", "json-tests", "to-pod-full"] }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
ethjson = { path = "../../crates/ethjson" }
|
ethjson = { path = "../../crates/ethjson" }
|
||||||
evm = { path = "../../crates/vm/evm" }
|
evm = { path = "../../crates/vm/evm" }
|
||||||
panic_hook = { path = "../../crates/util/panic-hook" }
|
panic_hook = { path = "../../crates/util/panic-hook" }
|
||||||
|
@ -22,7 +22,7 @@ use super::config::Config;
|
|||||||
use bytes::ToPretty;
|
use bytes::ToPretty;
|
||||||
use display;
|
use display;
|
||||||
use ethcore::trace;
|
use ethcore::trace;
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{BigEndianHash, H256, U256};
|
||||||
use info as vm;
|
use info as vm;
|
||||||
|
|
||||||
/// JSON formatting informant.
|
/// JSON formatting informant.
|
||||||
@ -208,7 +208,10 @@ impl trace::VMTracer for Informant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some((pos, val)) = store_diff {
|
if let Some((pos, val)) = store_diff {
|
||||||
informant.storage.insert(pos.into(), val.into());
|
informant.storage.insert(
|
||||||
|
BigEndianHash::from_uint(&pos),
|
||||||
|
BigEndianHash::from_uint(&val),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !informant.subtraces.is_empty() {
|
if !informant.subtraces.is_empty() {
|
||||||
|
@ -22,7 +22,7 @@ use super::config::Config;
|
|||||||
use bytes::ToPretty;
|
use bytes::ToPretty;
|
||||||
use display;
|
use display;
|
||||||
use ethcore::{pod_state, trace};
|
use ethcore::{pod_state, trace};
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{BigEndianHash, H256, U256};
|
||||||
use info as vm;
|
use info as vm;
|
||||||
|
|
||||||
pub trait Writer: io::Write + Send + Sized {
|
pub trait Writer: io::Write + Send + Sized {
|
||||||
@ -237,7 +237,10 @@ impl<Trace: Writer, Out: Writer> trace::VMTracer for Informant<Trace, Out> {
|
|||||||
let subdepth = self.subdepth;
|
let subdepth = self.subdepth;
|
||||||
Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| {
|
Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| {
|
||||||
if let Some((pos, val)) = store_written {
|
if let Some((pos, val)) = store_written {
|
||||||
informant.storage.insert(pos.into(), val.into());
|
informant.storage.insert(
|
||||||
|
BigEndianHash::from_uint(&pos),
|
||||||
|
BigEndianHash::from_uint(&val),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ pub fn run_action<T: Informant>(
|
|||||||
Ok(r) => (Ok(r.return_data.to_vec()), Some(r.gas_left)),
|
Ok(r) => (Ok(r.return_data.to_vec()), Some(r.gas_left)),
|
||||||
Err(err) => (Err(err), None),
|
Err(err) => (Err(err), None),
|
||||||
};
|
};
|
||||||
(result.0, 0.into(), None, result.1, informant.drain())
|
(result.0, H256::zero(), None, result.1, informant.drain())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -262,6 +262,7 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use ethereum_types::Address;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
@ -291,7 +292,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let (inf, res) = informant(Config::default());
|
let (inf, res) = informant(Config::default());
|
||||||
let mut params = ActionParams::default();
|
let mut params = ActionParams::default();
|
||||||
params.code_address = 0x20.into();
|
params.code_address = Address::from_low_u64_be(0x20);
|
||||||
params.gas = 0xffff.into();
|
params.gas = 0xffff.into();
|
||||||
|
|
||||||
let spec = ::ethcore::ethereum::load(None, include_bytes!("../res/testchain.json"));
|
let spec = ::ethcore::ethereum::load(None, include_bytes!("../res/testchain.json"));
|
||||||
|
@ -429,6 +429,7 @@ fn die<T: fmt::Display>(msg: T) -> ! {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::{Args, USAGE};
|
use super::{Args, USAGE};
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
|
use ethereum_types::Address;
|
||||||
|
|
||||||
fn run<T: AsRef<str>>(args: &[T]) -> Args {
|
fn run<T: AsRef<str>>(args: &[T]) -> Args {
|
||||||
Docopt::new(USAGE)
|
Docopt::new(USAGE)
|
||||||
@ -468,8 +469,8 @@ mod tests {
|
|||||||
assert_eq!(args.flag_std_out_only, true);
|
assert_eq!(args.flag_std_out_only, true);
|
||||||
assert_eq!(args.gas(), Ok(1.into()));
|
assert_eq!(args.gas(), Ok(1.into()));
|
||||||
assert_eq!(args.gas_price(), Ok(2.into()));
|
assert_eq!(args.gas_price(), Ok(2.into()));
|
||||||
assert_eq!(args.from(), Ok(3.into()));
|
assert_eq!(args.from(), Ok(Address::from_low_u64_be(3)));
|
||||||
assert_eq!(args.to(), Ok(4.into()));
|
assert_eq!(args.to(), Ok(Address::from_low_u64_be(4)));
|
||||||
assert_eq!(args.code(), Ok(Some(vec![05])));
|
assert_eq!(args.code(), Ok(Some(vec![05])));
|
||||||
assert_eq!(args.data(), Ok(Some(vec![06])));
|
assert_eq!(args.data(), Ok(Some(vec![06])));
|
||||||
assert_eq!(args.flag_chain, Some("./testfile".to_owned()));
|
assert_eq!(args.flag_chain, Some("./testfile".to_owned()));
|
||||||
|
@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crypto::publickey;
|
||||||
use dir::Directories;
|
use dir::Directories;
|
||||||
use ethereum_types::Address;
|
use ethereum_types::{Address, H160};
|
||||||
use ethkey::Password;
|
use ethkey::Password;
|
||||||
|
|
||||||
use params::{AccountsConfig, SpecType};
|
use params::{AccountsConfig, SpecType};
|
||||||
@ -70,6 +71,7 @@ mod accounts {
|
|||||||
#[cfg(feature = "accounts")]
|
#[cfg(feature = "accounts")]
|
||||||
mod accounts {
|
mod accounts {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::str::FromStr;
|
||||||
use upgrade::upgrade_key_location;
|
use upgrade::upgrade_key_location;
|
||||||
|
|
||||||
pub use accounts::AccountProvider;
|
pub use accounts::AccountProvider;
|
||||||
@ -103,7 +105,8 @@ mod accounts {
|
|||||||
| SpecType::Goerli
|
| SpecType::Goerli
|
||||||
| SpecType::Sokol
|
| SpecType::Sokol
|
||||||
| SpecType::Dev => vec![],
|
| SpecType::Dev => vec![],
|
||||||
_ => vec!["00a329c0648769a73afac7f9381e08fb43dbea72".into()],
|
_ => vec![H160::from_str("00a329c0648769a73afac7f9381e08fb43dbea72")
|
||||||
|
.expect("the string is valid hex; qed")],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -216,9 +219,11 @@ mod accounts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn insert_dev_account(account_provider: &AccountProvider) {
|
fn insert_dev_account(account_provider: &AccountProvider) {
|
||||||
let secret: ethkey::Secret =
|
let secret = publickey::Secret::from_str(
|
||||||
"4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into();
|
"4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7",
|
||||||
let dev_account = ethkey::KeyPair::from_secret(secret.clone())
|
)
|
||||||
|
.expect("Valid account;qed");
|
||||||
|
let dev_account = publickey::KeyPair::from_secret(secret.clone())
|
||||||
.expect("Valid secret produces valid key;qed");
|
.expect("Valid secret produces valid key;qed");
|
||||||
if !account_provider.has_account(dev_account.address()) {
|
if !account_provider.has_account(dev_account.address()) {
|
||||||
match account_provider.insert_account(secret, &Password::from(String::new())) {
|
match account_provider.insert_account(secret, &Password::from(String::new())) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
use ansi_term::Colour;
|
use ansi_term::Colour;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use cli::{Args, ArgsError};
|
use cli::{Args, ArgsError};
|
||||||
|
use crypto::publickey::{Public, Secret};
|
||||||
use ethcore::{
|
use ethcore::{
|
||||||
client::VMType,
|
client::VMType,
|
||||||
miner::{stratum, MinerOptions},
|
miner::{stratum, MinerOptions},
|
||||||
@ -24,7 +25,6 @@ use ethcore::{
|
|||||||
verification::queue::VerifierSettings,
|
verification::queue::VerifierSettings,
|
||||||
};
|
};
|
||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use ethkey::{Public, Secret};
|
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use metrics::MetricsConfiguration;
|
use metrics::MetricsConfiguration;
|
||||||
use miner::pool;
|
use miner::pool;
|
||||||
@ -810,7 +810,7 @@ impl Configuration {
|
|||||||
ret.public_address = public.map(|p| format!("{}", p));
|
ret.public_address = public.map(|p| format!("{}", p));
|
||||||
ret.use_secret = match self.args.arg_node_key.as_ref().map(|s| {
|
ret.use_secret = match self.args.arg_node_key.as_ref().map(|s| {
|
||||||
s.parse::<Secret>()
|
s.parse::<Secret>()
|
||||||
.or_else(|_| Secret::from_unsafe_slice(&keccak(s)))
|
.or_else(|_| Secret::import_key(keccak(s).as_bytes()))
|
||||||
.map_err(|e| format!("Invalid key: {:?}", e))
|
.map_err(|e| format!("Invalid key: {:?}", e))
|
||||||
}) {
|
}) {
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -21,7 +21,7 @@ use ethcore::{
|
|||||||
client::{BlockId, ClientConfig, DatabaseCompactionProfile, Mode, VMType, VerifierType},
|
client::{BlockId, ClientConfig, DatabaseCompactionProfile, Mode, VMType, VerifierType},
|
||||||
miner::{Penalization, PendingSet},
|
miner::{Penalization, PendingSet},
|
||||||
};
|
};
|
||||||
use ethereum_types::{clean_0x, Address, U256};
|
use ethereum_types::{Address, U256};
|
||||||
use ethkey::Password;
|
use ethkey::Password;
|
||||||
use journaldb::Algorithm;
|
use journaldb::Algorithm;
|
||||||
use miner::pool::PrioritizationStrategy;
|
use miner::pool::PrioritizationStrategy;
|
||||||
@ -39,6 +39,14 @@ pub fn to_duration(s: &str) -> Result<Duration, String> {
|
|||||||
to_seconds(s).map(Duration::from_secs)
|
to_seconds(s).map(Duration::from_secs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clean_0x(s: &str) -> &str {
|
||||||
|
if s.starts_with("0x") {
|
||||||
|
&s[2..]
|
||||||
|
} else {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_seconds(s: &str) -> Result<u64, String> {
|
fn to_seconds(s: &str) -> Result<u64, String> {
|
||||||
let bad = |_| {
|
let bad = |_| {
|
||||||
format!(
|
format!(
|
||||||
|
@ -61,6 +61,7 @@ extern crate keccak_hash as hash;
|
|||||||
extern crate kvdb;
|
extern crate kvdb;
|
||||||
extern crate node_filter;
|
extern crate node_filter;
|
||||||
extern crate parity_bytes as bytes;
|
extern crate parity_bytes as bytes;
|
||||||
|
extern crate parity_crypto as crypto;
|
||||||
extern crate parity_local_store as local_store;
|
extern crate parity_local_store as local_store;
|
||||||
extern crate parity_path as path;
|
extern crate parity_path as path;
|
||||||
extern crate parity_rpc;
|
extern crate parity_rpc;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crypto::publickey;
|
||||||
use ethkey::Password;
|
use ethkey::Password;
|
||||||
use ethstore::PresaleWallet;
|
use ethstore::PresaleWallet;
|
||||||
use helpers::{password_from_file, password_prompt};
|
use helpers::{password_from_file, password_prompt};
|
||||||
@ -44,7 +45,7 @@ pub fn execute(cmd: ImportWallet) -> Result<String, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "accounts")]
|
#[cfg(feature = "accounts")]
|
||||||
pub fn import_account(cmd: &ImportWallet, kp: ethkey::KeyPair, password: Password) {
|
pub fn import_account(cmd: &ImportWallet, kp: publickey::KeyPair, password: Password) {
|
||||||
use accounts::{AccountProvider, AccountProviderSettings};
|
use accounts::{AccountProvider, AccountProviderSettings};
|
||||||
use ethstore::{accounts_dir::RootDiskDirectory, EthStore};
|
use ethstore::{accounts_dir::RootDiskDirectory, EthStore};
|
||||||
|
|
||||||
@ -57,4 +58,4 @@ pub fn import_account(cmd: &ImportWallet, kp: ethkey::KeyPair, password: Passwor
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "accounts"))]
|
#[cfg(not(feature = "accounts"))]
|
||||||
pub fn import_account(_cmd: &ImportWallet, _kp: ethkey::KeyPair, _password: Password) {}
|
pub fn import_account(_cmd: &ImportWallet, _kp: publickey::KeyPair, _password: Password) {}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
|
str::FromStr,
|
||||||
sync::{atomic, Arc, Weak},
|
sync::{atomic, Arc, Weak},
|
||||||
thread,
|
thread,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@ -606,7 +607,10 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
|
|||||||
fn verification_bad_blocks(spec: &SpecType) -> Vec<H256> {
|
fn verification_bad_blocks(spec: &SpecType) -> Vec<H256> {
|
||||||
match *spec {
|
match *spec {
|
||||||
SpecType::Ropsten => {
|
SpecType::Ropsten => {
|
||||||
vec!["1eac3d16c642411f13c287e29144c6f58fda859407c8f24c38deb168e1040714".into()]
|
vec![
|
||||||
|
H256::from_str("1eac3d16c642411f13c287e29144c6f58fda859407c8f24c38deb168e1040714")
|
||||||
|
.expect("Valid hex string"),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use account_utils::AccountProvider;
|
use account_utils::AccountProvider;
|
||||||
|
use crypto::publickey::{Public, Secret};
|
||||||
use dir::{default_data_path, helpers::replace_home};
|
use dir::{default_data_path, helpers::replace_home};
|
||||||
use ethcore::{client::Client, miner::Miner};
|
use ethcore::{client::Client, miner::Miner};
|
||||||
use ethereum_types::Address;
|
use ethereum_types::Address;
|
||||||
use ethkey::{Password, Public, Secret};
|
use ethkey::Password;
|
||||||
use parity_runtime::Executor;
|
use parity_runtime::Executor;
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
use sync::SyncProvider;
|
use sync::SyncProvider;
|
||||||
|
@ -12,11 +12,12 @@ common-types = { path = "../ethcore/types" }
|
|||||||
ethkey = { path = "ethkey" }
|
ethkey = { path = "ethkey" }
|
||||||
ethstore = { path = "ethstore" }
|
ethstore = { path = "ethstore" }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
|
@ -6,15 +6,15 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
edit-distance = "2.0"
|
edit-distance = "2.0"
|
||||||
parity-crypto = "0.3.0"
|
parity-crypto = { version = "0.6.2", features = ["publickey"] }
|
||||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", rev = "ccc06e7480148b723eb44ac56cf4d20eec380b6f" }
|
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", rev = "9791e79f21a5309dcb6e0bd254b1ef88fca2f1f4" }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
memzero = { path = "../../../crates/util/memzero" }
|
memzero = { path = "../../../crates/util/memzero" }
|
||||||
parity-wordlist = "1.3"
|
parity-wordlist = "1.3"
|
||||||
quick-error = "1.2.2"
|
quick-error = "1.2.2"
|
||||||
rand = "0.4"
|
rand = "0.7.3"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::{Generator, KeyPair, Secret};
|
use parity_crypto::{
|
||||||
use keccak::Keccak256;
|
publickey::{KeyPair, Secret},
|
||||||
|
Keccak256,
|
||||||
|
};
|
||||||
use parity_wordlist;
|
use parity_wordlist;
|
||||||
|
|
||||||
/// Simple brainwallet.
|
/// Simple brainwallet.
|
||||||
@ -29,12 +31,8 @@ impl Brain {
|
|||||||
pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> {
|
pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> {
|
||||||
parity_wordlist::validate_phrase(phrase, expected_words)
|
parity_wordlist::validate_phrase(phrase, expected_words)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Generator for Brain {
|
pub fn generate(&mut self) -> KeyPair {
|
||||||
type Error = ::Void;
|
|
||||||
|
|
||||||
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
|
|
||||||
let seed = self.0.clone();
|
let seed = self.0.clone();
|
||||||
let mut secret = seed.into_bytes().keccak256();
|
let mut secret = seed.into_bytes().keccak256();
|
||||||
|
|
||||||
@ -45,12 +43,10 @@ impl Generator for Brain {
|
|||||||
match i > 16384 {
|
match i > 16384 {
|
||||||
false => i += 1,
|
false => i += 1,
|
||||||
true => {
|
true => {
|
||||||
if let Ok(pair) =
|
if let Ok(pair) = Secret::import_key(&secret).and_then(KeyPair::from_secret) {
|
||||||
Secret::from_unsafe_slice(&secret).and_then(KeyPair::from_secret)
|
|
||||||
{
|
|
||||||
if pair.address()[0] == 0 {
|
if pair.address()[0] == 0 {
|
||||||
trace!("Testing: {}, got: {:?}", self.0, pair.address());
|
trace!("Testing: {}, got: {:?}", self.0, pair.address());
|
||||||
return Ok(pair);
|
return pair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,13 +58,12 @@ impl Generator for Brain {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use Brain;
|
use Brain;
|
||||||
use Generator;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_brain() {
|
fn test_brain() {
|
||||||
let words = "this is sparta!".to_owned();
|
let words = "this is sparta!".to_owned();
|
||||||
let first_keypair = Brain::new(words.clone()).generate().unwrap();
|
let first_keypair = Brain::new(words.clone()).generate();
|
||||||
let second_keypair = Brain::new(words.clone()).generate().unwrap();
|
let second_keypair = Brain::new(words.clone()).generate();
|
||||||
assert_eq!(first_keypair.secret(), second_keypair.secret());
|
assert_eq!(first_keypair.secret(), second_keypair.secret());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::{Brain, Error, Generator, KeyPair};
|
use super::Brain;
|
||||||
|
use parity_crypto::publickey::{Error, KeyPair};
|
||||||
use parity_wordlist as wordlist;
|
use parity_wordlist as wordlist;
|
||||||
|
|
||||||
/// Tries to find brain-seed keypair with address starting with given prefix.
|
/// Tries to find brain-seed keypair with address starting with given prefix.
|
||||||
@ -38,16 +39,12 @@ impl BrainPrefix {
|
|||||||
pub fn phrase(&self) -> &str {
|
pub fn phrase(&self) -> &str {
|
||||||
&self.last_phrase
|
&self.last_phrase
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Generator for BrainPrefix {
|
pub fn generate(&mut self) -> Result<KeyPair, Error> {
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn generate(&mut self) -> Result<KeyPair, Error> {
|
|
||||||
for _ in 0..self.iterations {
|
for _ in 0..self.iterations {
|
||||||
let phrase = wordlist::random_phrase(self.no_of_words);
|
let phrase = wordlist::random_phrase(self.no_of_words);
|
||||||
let keypair = Brain::new(phrase.clone()).generate().unwrap();
|
let keypair = Brain::new(phrase.clone()).generate();
|
||||||
if keypair.address().starts_with(&self.prefix) {
|
if keypair.address().as_ref().starts_with(&self.prefix) {
|
||||||
self.last_phrase = phrase;
|
self.last_phrase = phrase;
|
||||||
return Ok(keypair);
|
return Ok(keypair);
|
||||||
}
|
}
|
||||||
@ -60,7 +57,6 @@ impl Generator for BrainPrefix {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use BrainPrefix;
|
use BrainPrefix;
|
||||||
use Generator;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prefix_generator() {
|
fn prefix_generator() {
|
||||||
@ -68,6 +64,6 @@ mod tests {
|
|||||||
let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12)
|
let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12)
|
||||||
.generate()
|
.generate()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(keypair.address().starts_with(&prefix));
|
assert!(keypair.address().as_bytes().starts_with(&prefix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,10 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use edit_distance::edit_distance;
|
use edit_distance::edit_distance;
|
||||||
|
use parity_crypto::publickey::Address;
|
||||||
use parity_wordlist;
|
use parity_wordlist;
|
||||||
|
|
||||||
use super::{Address, Brain, Generator};
|
use super::Brain;
|
||||||
|
|
||||||
/// Tries to find a phrase for address, given the number
|
/// Tries to find a phrase for address, given the number
|
||||||
/// of expected words and a partial phrase.
|
/// of expected words and a partial phrase.
|
||||||
@ -32,9 +33,7 @@ pub fn brain_recover(
|
|||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words);
|
let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words);
|
||||||
for phrase in it {
|
for phrase in it {
|
||||||
let keypair = Brain::new(phrase.clone())
|
let keypair = Brain::new(phrase.clone()).generate();
|
||||||
.generate()
|
|
||||||
.expect("Brain wallets are infallible; qed");
|
|
||||||
trace!("Testing: {}, got: {:?}", phrase, keypair.address());
|
trace!("Testing: {}, got: {:?}", phrase, keypair.address());
|
||||||
if &keypair.address() == address {
|
if &keypair.address() == address {
|
||||||
return Some(phrase);
|
return Some(phrase);
|
||||||
|
@ -1,202 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#![allow(deprecated)]
|
|
||||||
|
|
||||||
use parity_crypto::error::SymmError;
|
|
||||||
use secp256k1;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
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 super::Error;
|
|
||||||
use secp256k1::{self, ecdh, key};
|
|
||||||
use Public;
|
|
||||||
use Secret;
|
|
||||||
use SECP256K1;
|
|
||||||
|
|
||||||
/// Agree on a shared secret
|
|
||||||
pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, Error> {
|
|
||||||
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 super::{ecdh, Error};
|
|
||||||
use ethereum_types::H128;
|
|
||||||
use parity_crypto::{aes, digest, hmac, is_equal};
|
|
||||||
use Generator;
|
|
||||||
use Public;
|
|
||||||
use Random;
|
|
||||||
use 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<Vec<u8>, 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<Vec<u8>, 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 Generator;
|
|
||||||
use Random;
|
|
||||||
|
|
||||||
#[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[..]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use std::{error, fmt};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// Crypto error
|
|
||||||
pub enum Error {
|
|
||||||
/// Invalid secret key
|
|
||||||
InvalidSecret,
|
|
||||||
/// Invalid public key
|
|
||||||
InvalidPublic,
|
|
||||||
/// Invalid address
|
|
||||||
InvalidAddress,
|
|
||||||
/// Invalid EC signature
|
|
||||||
InvalidSignature,
|
|
||||||
/// Invalid AES message
|
|
||||||
InvalidMessage,
|
|
||||||
/// IO Error
|
|
||||||
Io(::std::io::Error),
|
|
||||||
/// Custom
|
|
||||||
Custom(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let msg = match *self {
|
|
||||||
Error::InvalidSecret => "Invalid secret".into(),
|
|
||||||
Error::InvalidPublic => "Invalid public".into(),
|
|
||||||
Error::InvalidAddress => "Invalid address".into(),
|
|
||||||
Error::InvalidSignature => "Invalid EC signature".into(),
|
|
||||||
Error::InvalidMessage => "Invalid AES message".into(),
|
|
||||||
Error::Io(ref err) => format!("I/O error: {}", err),
|
|
||||||
Error::Custom(ref s) => s.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
f.write_fmt(format_args!("Crypto error ({})", msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
"Crypto error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<String> for Error {
|
|
||||||
fn into(self) -> String {
|
|
||||||
format!("{}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<::secp256k1::Error> for Error {
|
|
||||||
fn from(e: ::secp256k1::Error) -> Error {
|
|
||||||
match e {
|
|
||||||
::secp256k1::Error::InvalidMessage => Error::InvalidMessage,
|
|
||||||
::secp256k1::Error::InvalidPublicKey => Error::InvalidPublic,
|
|
||||||
::secp256k1::Error::InvalidSecretKey => Error::InvalidSecret,
|
|
||||||
_ => Error::InvalidSignature,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<::std::io::Error> for Error {
|
|
||||||
fn from(err: ::std::io::Error) -> Error {
|
|
||||||
Error::Io(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,589 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Extended keys
|
|
||||||
|
|
||||||
pub use self::derivation::Error as DerivationError;
|
|
||||||
use ethereum_types::H256;
|
|
||||||
use secret::Secret;
|
|
||||||
use Public;
|
|
||||||
|
|
||||||
/// Represents label that can be stored as a part of key derivation
|
|
||||||
pub trait Label {
|
|
||||||
/// Length of the data that label occupies
|
|
||||||
fn len() -> usize;
|
|
||||||
|
|
||||||
/// Store label data to the key derivation sequence
|
|
||||||
/// Must not use more than `len()` bytes from slice
|
|
||||||
fn store(&self, target: &mut [u8]);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Label for u32 {
|
|
||||||
fn len() -> usize {
|
|
||||||
4
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&self, target: &mut [u8]) {
|
|
||||||
let bytes = self.to_be_bytes();
|
|
||||||
target[0..4].copy_from_slice(&bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Key derivation over generic label `T`
|
|
||||||
pub enum Derivation<T: Label> {
|
|
||||||
/// Soft key derivation (allow proof of parent)
|
|
||||||
Soft(T),
|
|
||||||
/// Hard key derivation (does not allow proof of parent)
|
|
||||||
Hard(T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u32> for Derivation<u32> {
|
|
||||||
fn from(index: u32) -> Self {
|
|
||||||
if index < (2 << 30) {
|
|
||||||
Derivation::Soft(index)
|
|
||||||
} else {
|
|
||||||
Derivation::Hard(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Label for H256 {
|
|
||||||
fn len() -> usize {
|
|
||||||
32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&self, target: &mut [u8]) {
|
|
||||||
self.copy_to(&mut target[0..32]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extended secret key, allows deterministic derivation of subsequent keys.
|
|
||||||
pub struct ExtendedSecret {
|
|
||||||
secret: Secret,
|
|
||||||
chain_code: H256,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExtendedSecret {
|
|
||||||
/// New extended key from given secret and chain code.
|
|
||||||
pub fn with_code(secret: Secret, chain_code: H256) -> ExtendedSecret {
|
|
||||||
ExtendedSecret {
|
|
||||||
secret: secret,
|
|
||||||
chain_code: chain_code,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New extended key from given secret with the random chain code.
|
|
||||||
pub fn new_random(secret: Secret) -> ExtendedSecret {
|
|
||||||
ExtendedSecret::with_code(secret, H256::random())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New extended key from given secret.
|
|
||||||
/// Chain code will be derived from the secret itself (in a deterministic way).
|
|
||||||
pub fn new(secret: Secret) -> ExtendedSecret {
|
|
||||||
let chain_code = derivation::chain_code(*secret);
|
|
||||||
ExtendedSecret::with_code(secret, chain_code)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derive new private key
|
|
||||||
pub fn derive<T>(&self, index: Derivation<T>) -> ExtendedSecret
|
|
||||||
where
|
|
||||||
T: Label,
|
|
||||||
{
|
|
||||||
let (derived_key, next_chain_code) =
|
|
||||||
derivation::private(*self.secret, self.chain_code, index);
|
|
||||||
|
|
||||||
let derived_secret = Secret::from(derived_key.0);
|
|
||||||
|
|
||||||
ExtendedSecret::with_code(derived_secret, next_chain_code)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Private key component of the extended key.
|
|
||||||
pub fn as_raw(&self) -> &Secret {
|
|
||||||
&self.secret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extended public key, allows deterministic derivation of subsequent keys.
|
|
||||||
pub struct ExtendedPublic {
|
|
||||||
public: Public,
|
|
||||||
chain_code: H256,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExtendedPublic {
|
|
||||||
/// New extended public key from known parent and chain code
|
|
||||||
pub fn new(public: Public, chain_code: H256) -> Self {
|
|
||||||
ExtendedPublic {
|
|
||||||
public: public,
|
|
||||||
chain_code: chain_code,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create new extended public key from known secret
|
|
||||||
pub fn from_secret(secret: &ExtendedSecret) -> Result<Self, DerivationError> {
|
|
||||||
Ok(ExtendedPublic::new(
|
|
||||||
derivation::point(**secret.as_raw())?,
|
|
||||||
secret.chain_code.clone(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derive new public key
|
|
||||||
/// Operation is defined only for index belongs [0..2^31)
|
|
||||||
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
|
|
||||||
where
|
|
||||||
T: Label,
|
|
||||||
{
|
|
||||||
let (derived_key, next_chain_code) =
|
|
||||||
derivation::public(self.public, self.chain_code, index)?;
|
|
||||||
Ok(ExtendedPublic::new(derived_key, next_chain_code))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public(&self) -> &Public {
|
|
||||||
&self.public
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ExtendedKeyPair {
|
|
||||||
secret: ExtendedSecret,
|
|
||||||
public: ExtendedPublic,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExtendedKeyPair {
|
|
||||||
pub fn new(secret: Secret) -> Self {
|
|
||||||
let extended_secret = ExtendedSecret::new(secret);
|
|
||||||
let extended_public = ExtendedPublic::from_secret(&extended_secret)
|
|
||||||
.expect("Valid `Secret` always produces valid public; qed");
|
|
||||||
ExtendedKeyPair {
|
|
||||||
secret: extended_secret,
|
|
||||||
public: extended_public,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_code(secret: Secret, public: Public, chain_code: H256) -> Self {
|
|
||||||
ExtendedKeyPair {
|
|
||||||
secret: ExtendedSecret::with_code(secret, chain_code.clone()),
|
|
||||||
public: ExtendedPublic::new(public, chain_code),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_secret(secret: Secret, chain_code: H256) -> Self {
|
|
||||||
let extended_secret = ExtendedSecret::with_code(secret, chain_code);
|
|
||||||
let extended_public = ExtendedPublic::from_secret(&extended_secret)
|
|
||||||
.expect("Valid `Secret` always produces valid public; qed");
|
|
||||||
ExtendedKeyPair {
|
|
||||||
secret: extended_secret,
|
|
||||||
public: extended_public,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_seed(seed: &[u8]) -> Result<ExtendedKeyPair, DerivationError> {
|
|
||||||
let (master_key, chain_code) = derivation::seed_pair(seed);
|
|
||||||
Ok(ExtendedKeyPair::with_secret(
|
|
||||||
Secret::from_unsafe_slice(&*master_key).map_err(|_| DerivationError::InvalidSeed)?,
|
|
||||||
chain_code,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn secret(&self) -> &ExtendedSecret {
|
|
||||||
&self.secret
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public(&self) -> &ExtendedPublic {
|
|
||||||
&self.public
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
|
|
||||||
where
|
|
||||||
T: Label,
|
|
||||||
{
|
|
||||||
let derived = self.secret.derive(index);
|
|
||||||
|
|
||||||
Ok(ExtendedKeyPair {
|
|
||||||
public: ExtendedPublic::from_secret(&derived)?,
|
|
||||||
secret: derived,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Derivation functions for private and public keys
|
|
||||||
// Work is based on BIP0032
|
|
||||||
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
|
||||||
mod derivation {
|
|
||||||
use super::{Derivation, Label};
|
|
||||||
use ethereum_types::{H256, H512, U256, U512};
|
|
||||||
use keccak;
|
|
||||||
use math::curve_order;
|
|
||||||
use parity_crypto::hmac;
|
|
||||||
use secp256k1::key::{PublicKey, SecretKey};
|
|
||||||
use SECP256K1;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
InvalidHardenedUse,
|
|
||||||
InvalidPoint,
|
|
||||||
MissingIndex,
|
|
||||||
InvalidSeed,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic derivation of the key using secp256k1 elliptic curve.
|
|
||||||
// Derivation can be either hardened or not.
|
|
||||||
// For hardened derivation, pass u32 index at least 2^31 or custom Derivation::Hard(T) enum
|
|
||||||
//
|
|
||||||
// Can panic if passed `private_key` is not a valid secp256k1 private key
|
|
||||||
// (outside of (0..curve_order()]) field
|
|
||||||
pub fn private<T>(private_key: H256, chain_code: H256, index: Derivation<T>) -> (H256, H256)
|
|
||||||
where
|
|
||||||
T: Label,
|
|
||||||
{
|
|
||||||
match index {
|
|
||||||
Derivation::Soft(index) => private_soft(private_key, chain_code, index),
|
|
||||||
Derivation::Hard(index) => private_hard(private_key, chain_code, index),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hmac_pair(data: &[u8], private_key: H256, chain_code: H256) -> (H256, H256) {
|
|
||||||
let private: U256 = private_key.into();
|
|
||||||
|
|
||||||
// produces 512-bit derived hmac (I)
|
|
||||||
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();
|
|
||||||
// right most 256 bits are new chain code for later derivations
|
|
||||||
let next_chain_code = H256::from(&i_512[32..64]);
|
|
||||||
|
|
||||||
let child_key = private_add(hmac_key, private).into();
|
|
||||||
(child_key, next_chain_code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can panic if passed `private_key` is not a valid secp256k1 private key
|
|
||||||
// (outside of (0..curve_order()]) field
|
|
||||||
fn private_soft<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256)
|
|
||||||
where
|
|
||||||
T: Label,
|
|
||||||
{
|
|
||||||
let mut data = vec![0u8; 33 + T::len()];
|
|
||||||
|
|
||||||
let sec_private = SecretKey::from_slice(&SECP256K1, &*private_key)
|
|
||||||
.expect("Caller should provide valid private key");
|
|
||||||
let sec_public = PublicKey::from_secret_key(&SECP256K1, &sec_private)
|
|
||||||
.expect("Caller should provide valid private key");
|
|
||||||
let public_serialized = sec_public.serialize_vec(&SECP256K1, true);
|
|
||||||
|
|
||||||
// curve point (compressed public key) -- index
|
|
||||||
// 0.33 -- 33..end
|
|
||||||
data[0..33].copy_from_slice(&public_serialized);
|
|
||||||
index.store(&mut data[33..]);
|
|
||||||
|
|
||||||
hmac_pair(&data, private_key, chain_code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic derivation of the key using secp256k1 elliptic curve
|
|
||||||
// This is hardened derivation and does not allow to associate
|
|
||||||
// corresponding public keys of the original and derived private keys
|
|
||||||
fn private_hard<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256)
|
|
||||||
where
|
|
||||||
T: Label,
|
|
||||||
{
|
|
||||||
let mut data: Vec<u8> = vec![0u8; 33 + T::len()];
|
|
||||||
let private: U256 = private_key.into();
|
|
||||||
|
|
||||||
// 0x00 (padding) -- private_key -- index
|
|
||||||
// 0 -- 1..33 -- 33..end
|
|
||||||
private.to_big_endian(&mut data[1..33]);
|
|
||||||
index.store(&mut data[33..(33 + T::len())]);
|
|
||||||
|
|
||||||
hmac_pair(&data, private_key, chain_code)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn private_add(k1: U256, k2: U256) -> U256 {
|
|
||||||
let sum = U512::from(k1) + U512::from(k2);
|
|
||||||
modulo(sum, curve_order())
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: surely can be optimized
|
|
||||||
fn modulo(u1: U512, u2: U256) -> U256 {
|
|
||||||
let dv = u1 / U512::from(u2);
|
|
||||||
let md = u1 - (dv * U512::from(u2));
|
|
||||||
md.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public<T>(
|
|
||||||
public_key: H512,
|
|
||||||
chain_code: H256,
|
|
||||||
derivation: Derivation<T>,
|
|
||||||
) -> Result<(H512, H256), Error>
|
|
||||||
where
|
|
||||||
T: Label,
|
|
||||||
{
|
|
||||||
let index = match derivation {
|
|
||||||
Derivation::Soft(index) => index,
|
|
||||||
Derivation::Hard(_) => {
|
|
||||||
return Err(Error::InvalidHardenedUse);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut public_sec_raw = [0u8; 65];
|
|
||||||
public_sec_raw[0] = 4;
|
|
||||||
public_sec_raw[1..65].copy_from_slice(&*public_key);
|
|
||||||
let public_sec =
|
|
||||||
PublicKey::from_slice(&SECP256K1, &public_sec_raw).map_err(|_| Error::InvalidPoint)?;
|
|
||||||
let public_serialized = public_sec.serialize_vec(&SECP256K1, true);
|
|
||||||
|
|
||||||
let mut data = vec![0u8; 33 + T::len()];
|
|
||||||
// curve point (compressed public key) -- index
|
|
||||||
// 0.33 -- 33..end
|
|
||||||
data[0..33].copy_from_slice(&public_serialized);
|
|
||||||
index.store(&mut data[33..(33 + T::len())]);
|
|
||||||
|
|
||||||
// HMAC512SHA produces [derived private(256); new chain code(256)]
|
|
||||||
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]);
|
|
||||||
|
|
||||||
// Generated private key can (extremely rarely) be out of secp256k1 key field
|
|
||||||
if curve_order() <= new_private.clone().into() {
|
|
||||||
return Err(Error::MissingIndex);
|
|
||||||
}
|
|
||||||
let new_private_sec = SecretKey::from_slice(&SECP256K1, &*new_private)
|
|
||||||
.expect("Private key belongs to the field [0..CURVE_ORDER) (checked above); So initializing can never fail; qed");
|
|
||||||
let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec)
|
|
||||||
.expect("Valid private key produces valid public key");
|
|
||||||
|
|
||||||
// Adding two points on the elliptic curves (combining two public keys)
|
|
||||||
new_public
|
|
||||||
.add_assign(&SECP256K1, &public_sec)
|
|
||||||
.expect("Addition of two valid points produce valid point");
|
|
||||||
|
|
||||||
let serialized = new_public.serialize_vec(&SECP256K1, false);
|
|
||||||
|
|
||||||
Ok((H512::from(&serialized[1..65]), new_chain_code))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sha3(slc: &[u8]) -> H256 {
|
|
||||||
keccak::Keccak256::keccak256(slc).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn chain_code(secret: H256) -> H256 {
|
|
||||||
// 10,000 rounds of sha3
|
|
||||||
let mut running_sha3 = sha3(&*secret);
|
|
||||||
for _ in 0..99999 {
|
|
||||||
running_sha3 = sha3(&*running_sha3);
|
|
||||||
}
|
|
||||||
running_sha3
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn point(secret: H256) -> Result<H512, Error> {
|
|
||||||
let sec = SecretKey::from_slice(&SECP256K1, &*secret).map_err(|_| Error::InvalidPoint)?;
|
|
||||||
let public_sec =
|
|
||||||
PublicKey::from_secret_key(&SECP256K1, &sec).map_err(|_| Error::InvalidPoint)?;
|
|
||||||
let serialized = public_sec.serialize_vec(&SECP256K1, false);
|
|
||||||
Ok(H512::from(&serialized[1..65]))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
|
|
||||||
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]);
|
|
||||||
|
|
||||||
(master_key, chain_code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{derivation, Derivation, ExtendedKeyPair, ExtendedPublic, ExtendedSecret};
|
|
||||||
use ethereum_types::{H128, H256};
|
|
||||||
use secret::Secret;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
fn master_chain_basic() -> (H256, H256) {
|
|
||||||
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
|
|
||||||
.expect("Seed should be valid H128")
|
|
||||||
.to_vec();
|
|
||||||
|
|
||||||
derivation::seed_pair(&*seed)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_extended<F>(f: F, test_private: H256)
|
|
||||||
where
|
|
||||||
F: Fn(ExtendedSecret) -> ExtendedSecret,
|
|
||||||
{
|
|
||||||
let (private_seed, chain_code) = master_chain_basic();
|
|
||||||
let extended_secret = ExtendedSecret::with_code(Secret::from(private_seed.0), chain_code);
|
|
||||||
let derived = f(extended_secret);
|
|
||||||
assert_eq!(**derived.as_raw(), test_private);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smoky() {
|
|
||||||
let secret =
|
|
||||||
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
|
|
||||||
.unwrap();
|
|
||||||
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
|
|
||||||
|
|
||||||
// hardened
|
|
||||||
assert_eq!(&**extended_secret.as_raw(), &*secret);
|
|
||||||
assert_eq!(
|
|
||||||
&**extended_secret.derive(2147483648.into()).as_raw(),
|
|
||||||
&"0927453daed47839608e414a3738dfad10aed17c459bbd9ab53f89b026c834b6".into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&**extended_secret.derive(2147483649.into()).as_raw(),
|
|
||||||
&"44238b6a29c6dcbe9b401364141ba11e2198c289a5fed243a1c11af35c19dc0f".into()
|
|
||||||
);
|
|
||||||
|
|
||||||
// normal
|
|
||||||
assert_eq!(
|
|
||||||
&**extended_secret.derive(0.into()).as_raw(),
|
|
||||||
&"bf6a74e3f7b36fc4c96a1e12f31abc817f9f5904f5a8fc27713163d1f0b713f6".into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&**extended_secret.derive(1.into()).as_raw(),
|
|
||||||
&"bd4fca9eb1f9c201e9448c1eecd66e302d68d4d313ce895b8c134f512205c1bc".into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&**extended_secret.derive(2.into()).as_raw(),
|
|
||||||
&"86932b542d6cab4d9c65490c7ef502d89ecc0e2a5f4852157649e3251e2a3268".into()
|
|
||||||
);
|
|
||||||
|
|
||||||
let extended_public = ExtendedPublic::from_secret(&extended_secret)
|
|
||||||
.expect("Extended public should be created");
|
|
||||||
let derived_public = extended_public
|
|
||||||
.derive(0.into())
|
|
||||||
.expect("First derivation of public should succeed");
|
|
||||||
assert_eq!(&*derived_public.public(), &"f7b3244c96688f92372bfd4def26dc4151529747bab9f188a4ad34e141d47bd66522ff048bc6f19a0a4429b04318b1a8796c000265b4fa200dae5f6dda92dd94".into());
|
|
||||||
|
|
||||||
let keypair = ExtendedKeyPair::with_secret(
|
|
||||||
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
|
|
||||||
.unwrap(),
|
|
||||||
064.into(),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&**keypair
|
|
||||||
.derive(2147483648u32.into())
|
|
||||||
.expect("Derivation of keypair should succeed")
|
|
||||||
.secret()
|
|
||||||
.as_raw(),
|
|
||||||
&"edef54414c03196557cf73774bc97a645c9a1df2164ed34f0c2a78d1375a930c".into()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn h256_soft_match() {
|
|
||||||
let secret =
|
|
||||||
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
|
|
||||||
.unwrap();
|
|
||||||
let derivation_secret =
|
|
||||||
H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
|
|
||||||
let extended_public = ExtendedPublic::from_secret(&extended_secret)
|
|
||||||
.expect("Extended public should be created");
|
|
||||||
|
|
||||||
let derived_secret0 = extended_secret.derive(Derivation::Soft(derivation_secret));
|
|
||||||
let derived_public0 = extended_public
|
|
||||||
.derive(Derivation::Soft(derivation_secret))
|
|
||||||
.expect("First derivation of public should succeed");
|
|
||||||
|
|
||||||
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
|
|
||||||
.expect("Extended public should be created");
|
|
||||||
|
|
||||||
assert_eq!(public_from_secret0.public(), derived_public0.public());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn h256_hard() {
|
|
||||||
let secret =
|
|
||||||
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
|
|
||||||
.unwrap();
|
|
||||||
let derivation_secret =
|
|
||||||
H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015")
|
|
||||||
.unwrap();
|
|
||||||
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1u64.into());
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
&**extended_secret
|
|
||||||
.derive(Derivation::Hard(derivation_secret))
|
|
||||||
.as_raw(),
|
|
||||||
&"2bc2d696fb744d77ff813b4a1ef0ad64e1e5188b622c54ba917acc5ebc7c5486".into()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn match_() {
|
|
||||||
let secret =
|
|
||||||
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
|
|
||||||
.unwrap();
|
|
||||||
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1.into());
|
|
||||||
let extended_public = ExtendedPublic::from_secret(&extended_secret)
|
|
||||||
.expect("Extended public should be created");
|
|
||||||
|
|
||||||
let derived_secret0 = extended_secret.derive(0.into());
|
|
||||||
let derived_public0 = extended_public
|
|
||||||
.derive(0.into())
|
|
||||||
.expect("First derivation of public should succeed");
|
|
||||||
|
|
||||||
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
|
|
||||||
.expect("Extended public should be created");
|
|
||||||
|
|
||||||
assert_eq!(public_from_secret0.public(), derived_public0.public());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_seeds() {
|
|
||||||
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
|
|
||||||
.expect("Seed should be valid H128")
|
|
||||||
.to_vec();
|
|
||||||
|
|
||||||
// private key from bitcoin test vector
|
|
||||||
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
|
|
||||||
let test_private =
|
|
||||||
H256::from_str("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35")
|
|
||||||
.expect("Private should be decoded ok");
|
|
||||||
|
|
||||||
let (private_seed, _) = derivation::seed_pair(&*seed);
|
|
||||||
|
|
||||||
assert_eq!(private_seed, test_private);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_vector_1() {
|
|
||||||
// xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7
|
|
||||||
// H(0)
|
|
||||||
test_extended(
|
|
||||||
|secret| secret.derive(2147483648.into()),
|
|
||||||
H256::from_str("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea")
|
|
||||||
.expect("Private should be decoded ok"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_vector_2() {
|
|
||||||
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
|
|
||||||
// H(0)/1
|
|
||||||
test_extended(
|
|
||||||
|secret| secret.derive(2147483648.into()).derive(1.into()),
|
|
||||||
H256::from_str("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368")
|
|
||||||
.expect("Private should be decoded ok"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use tiny_keccak::Keccak;
|
|
||||||
|
|
||||||
pub trait Keccak256<T> {
|
|
||||||
fn keccak256(&self) -> T
|
|
||||||
where
|
|
||||||
T: Sized;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Keccak256<[u8; 32]> for [u8] {
|
|
||||||
fn keccak256(&self) -> [u8; 32] {
|
|
||||||
let mut keccak = Keccak::new_keccak256();
|
|
||||||
let mut result = [0u8; 32];
|
|
||||||
keccak.update(self);
|
|
||||||
keccak.finalize(&mut result);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use super::{Address, Error, Public, Secret, SECP256K1};
|
|
||||||
use keccak::Keccak256;
|
|
||||||
use rustc_hex::ToHex;
|
|
||||||
use secp256k1::key;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
pub fn public_to_address(public: &Public) -> Address {
|
|
||||||
let hash = public.keccak256();
|
|
||||||
let mut result = Address::default();
|
|
||||||
result.copy_from_slice(&hash[12..]);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
/// secp256k1 key pair
|
|
||||||
pub struct KeyPair {
|
|
||||||
secret: Secret,
|
|
||||||
public: Public,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for KeyPair {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
writeln!(f, "secret: {}", self.secret.to_hex())?;
|
|
||||||
writeln!(f, "public: {}", self.public.to_hex())?;
|
|
||||||
write!(f, "address: {}", self.address().to_hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyPair {
|
|
||||||
/// Create a pair from secret key
|
|
||||||
pub fn from_secret(secret: Secret) -> Result<KeyPair, Error> {
|
|
||||||
let context = &SECP256K1;
|
|
||||||
let s: key::SecretKey = key::SecretKey::from_slice(context, &secret[..])?;
|
|
||||||
let pub_key = key::PublicKey::from_secret_key(context, &s)?;
|
|
||||||
let serialized = pub_key.serialize_vec(context, false);
|
|
||||||
|
|
||||||
let mut public = Public::default();
|
|
||||||
public.copy_from_slice(&serialized[1..65]);
|
|
||||||
|
|
||||||
let keypair = KeyPair {
|
|
||||||
secret: secret,
|
|
||||||
public: public,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(keypair)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_secret_slice(slice: &[u8]) -> Result<KeyPair, Error> {
|
|
||||||
Self::from_secret(Secret::from_unsafe_slice(slice)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
|
|
||||||
let context = &SECP256K1;
|
|
||||||
let serialized = publ.serialize_vec(context, false);
|
|
||||||
let secret = Secret::from(sec);
|
|
||||||
let mut public = Public::default();
|
|
||||||
public.copy_from_slice(&serialized[1..65]);
|
|
||||||
|
|
||||||
KeyPair {
|
|
||||||
secret: secret,
|
|
||||||
public: public,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn secret(&self) -> &Secret {
|
|
||||||
&self.secret
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public(&self) -> &Public {
|
|
||||||
&self.public
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn address(&self) -> Address {
|
|
||||||
public_to_address(&self.public)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use std::str::FromStr;
|
|
||||||
use KeyPair;
|
|
||||||
use Secret;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn from_secret() {
|
|
||||||
let secret =
|
|
||||||
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
|
|
||||||
.unwrap();
|
|
||||||
let _ = KeyPair::from_secret(secret).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn keypair_display() {
|
|
||||||
let expected =
|
|
||||||
"secret: a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65
|
|
||||||
public: 8ce0db0b0359ffc5866ba61903cc2518c3675ef2cf380a7e54bde7ea20e6fa1ab45b7617346cd11b7610001ee6ae5b0155c41cad9527cbcdff44ec67848943a4
|
|
||||||
address: 5b073e9233944b5e729e46d618f0d8edf3d9c34a".to_owned();
|
|
||||||
let secret =
|
|
||||||
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
|
|
||||||
.unwrap();
|
|
||||||
let kp = KeyPair::from_secret(secret).unwrap();
|
|
||||||
assert_eq!(format!("{}", kp), expected);
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,20 +17,10 @@
|
|||||||
// #![warn(missing_docs)]
|
// #![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate edit_distance;
|
extern crate edit_distance;
|
||||||
extern crate ethereum_types;
|
|
||||||
extern crate memzero;
|
|
||||||
extern crate parity_crypto;
|
extern crate parity_crypto;
|
||||||
extern crate parity_wordlist;
|
extern crate parity_wordlist;
|
||||||
#[macro_use]
|
|
||||||
extern crate quick_error;
|
|
||||||
extern crate rand;
|
|
||||||
extern crate rustc_hex;
|
|
||||||
extern crate secp256k1;
|
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate tiny_keccak;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -38,52 +28,12 @@ extern crate serde_derive;
|
|||||||
|
|
||||||
mod brain;
|
mod brain;
|
||||||
mod brain_prefix;
|
mod brain_prefix;
|
||||||
mod error;
|
|
||||||
mod extended;
|
|
||||||
mod keccak;
|
|
||||||
mod keypair;
|
|
||||||
mod password;
|
mod password;
|
||||||
mod prefix;
|
mod prefix;
|
||||||
mod random;
|
|
||||||
mod secret;
|
|
||||||
mod signature;
|
|
||||||
|
|
||||||
pub mod brain_recover;
|
pub mod brain_recover;
|
||||||
pub mod crypto;
|
|
||||||
pub mod math;
|
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
brain::Brain,
|
brain::Brain, brain_prefix::BrainPrefix, parity_wordlist::Error as WordlistError,
|
||||||
brain_prefix::BrainPrefix,
|
password::Password, prefix::Prefix,
|
||||||
error::Error,
|
|
||||||
extended::{Derivation, DerivationError, ExtendedKeyPair, ExtendedPublic, ExtendedSecret},
|
|
||||||
keypair::{public_to_address, KeyPair},
|
|
||||||
math::public_is_valid,
|
|
||||||
parity_wordlist::Error as WordlistError,
|
|
||||||
password::Password,
|
|
||||||
prefix::Prefix,
|
|
||||||
random::Random,
|
|
||||||
secret::Secret,
|
|
||||||
signature::{recover, sign, verify_address, verify_public, Signature},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethereum_types::H256;
|
|
||||||
|
|
||||||
pub use ethereum_types::{Address, Public};
|
|
||||||
pub type Message = H256;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Uninstantiatable error type for infallible generators.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Void {}
|
|
||||||
|
|
||||||
/// Generates new keypair.
|
|
||||||
pub trait Generator {
|
|
||||||
type Error;
|
|
||||||
|
|
||||||
/// Should be called to generate new keypair.
|
|
||||||
fn generate(&mut self) -> Result<KeyPair, Self::Error>;
|
|
||||||
}
|
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use super::{Error, Public, Secret, SECP256K1};
|
|
||||||
use ethereum_types::{H256, U256};
|
|
||||||
use secp256k1::{
|
|
||||||
constants::{CURVE_ORDER, GENERATOR_X, GENERATOR_Y},
|
|
||||||
key,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Whether the public key is valid.
|
|
||||||
pub fn public_is_valid(public: &Public) -> bool {
|
|
||||||
to_secp256k1_public(public)
|
|
||||||
.ok()
|
|
||||||
.map_or(false, |p| p.is_valid())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace multiply public key by secret key (EC point * scalar)
|
|
||||||
pub fn public_mul_secret(public: &mut Public, secret: &Secret) -> Result<(), Error> {
|
|
||||||
let key_secret = secret.to_secp256k1_secret()?;
|
|
||||||
let mut key_public = to_secp256k1_public(public)?;
|
|
||||||
key_public.mul_assign(&SECP256K1, &key_secret)?;
|
|
||||||
set_public(public, &key_public);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace add one public key to another (EC point + EC point)
|
|
||||||
pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> {
|
|
||||||
let mut key_public = to_secp256k1_public(public)?;
|
|
||||||
let other_public = to_secp256k1_public(other)?;
|
|
||||||
key_public.add_assign(&SECP256K1, &other_public)?;
|
|
||||||
set_public(public, &key_public);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace sub one public key from another (EC point - EC point)
|
|
||||||
pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> {
|
|
||||||
let mut key_neg_other = to_secp256k1_public(other)?;
|
|
||||||
key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
|
|
||||||
|
|
||||||
let mut key_public = to_secp256k1_public(public)?;
|
|
||||||
key_public.add_assign(&SECP256K1, &key_neg_other)?;
|
|
||||||
set_public(public, &key_public);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Replace public key with its negation (EC point = - EC point)
|
|
||||||
pub fn public_negate(public: &mut Public) -> Result<(), Error> {
|
|
||||||
let mut key_public = to_secp256k1_public(public)?;
|
|
||||||
key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
|
|
||||||
set_public(public, &key_public);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return base point of secp256k1
|
|
||||||
pub fn generation_point() -> Public {
|
|
||||||
let mut public_sec_raw = [0u8; 65];
|
|
||||||
public_sec_raw[0] = 4;
|
|
||||||
public_sec_raw[1..33].copy_from_slice(&GENERATOR_X);
|
|
||||||
public_sec_raw[33..65].copy_from_slice(&GENERATOR_Y);
|
|
||||||
|
|
||||||
let public_key = key::PublicKey::from_slice(&SECP256K1, &public_sec_raw)
|
|
||||||
.expect("constructing using predefined constants; qed");
|
|
||||||
let mut public = Public::default();
|
|
||||||
set_public(&mut public, &public_key);
|
|
||||||
public
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return secp256k1 elliptic curve order
|
|
||||||
pub fn curve_order() -> U256 {
|
|
||||||
H256::from_slice(&CURVE_ORDER).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
|
|
||||||
let public_data = {
|
|
||||||
let mut temp = [4u8; 65];
|
|
||||||
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
|
|
||||||
temp
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(key::PublicKey::from_slice(&SECP256K1, &public_data)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_public(public: &mut Public, key_public: &key::PublicKey) {
|
|
||||||
let key_public_serialized = key_public.serialize_vec(&SECP256K1, false);
|
|
||||||
public.copy_from_slice(&key_public_serialized[1..65]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{
|
|
||||||
super::{Generator, Random},
|
|
||||||
public_add, public_sub,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn public_addition_is_commutative() {
|
|
||||||
let public1 = Random.generate().unwrap().public().clone();
|
|
||||||
let public2 = Random.generate().unwrap().public().clone();
|
|
||||||
|
|
||||||
let mut left = public1.clone();
|
|
||||||
public_add(&mut left, &public2).unwrap();
|
|
||||||
|
|
||||||
let mut right = public2.clone();
|
|
||||||
public_add(&mut right, &public1).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(left, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn public_addition_is_reversible_with_subtraction() {
|
|
||||||
let public1 = Random.generate().unwrap().public().clone();
|
|
||||||
let public2 = Random.generate().unwrap().public().clone();
|
|
||||||
|
|
||||||
let mut sum = public1.clone();
|
|
||||||
public_add(&mut sum, &public2).unwrap();
|
|
||||||
public_sub(&mut sum, &public2).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(sum, public1);
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::{Error, Generator, KeyPair, Random};
|
use parity_crypto::publickey::{Error, Generator, KeyPair, Random};
|
||||||
|
|
||||||
/// Tries to find keypair with address starting with given prefix.
|
/// Tries to find keypair with address starting with given prefix.
|
||||||
pub struct Prefix {
|
pub struct Prefix {
|
||||||
@ -24,20 +24,13 @@ pub struct Prefix {
|
|||||||
|
|
||||||
impl Prefix {
|
impl Prefix {
|
||||||
pub fn new(prefix: Vec<u8>, iterations: usize) -> Self {
|
pub fn new(prefix: Vec<u8>, iterations: usize) -> Self {
|
||||||
Prefix {
|
Prefix { prefix, iterations }
|
||||||
prefix: prefix,
|
|
||||||
iterations: iterations,
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Generator for Prefix {
|
pub fn generate(&mut self) -> Result<KeyPair, Error> {
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn generate(&mut self) -> Result<KeyPair, Error> {
|
|
||||||
for _ in 0..self.iterations {
|
for _ in 0..self.iterations {
|
||||||
let keypair = Random.generate()?;
|
let keypair = Random.generate();
|
||||||
if keypair.address().starts_with(&self.prefix) {
|
if keypair.address().as_ref().starts_with(&self.prefix) {
|
||||||
return Ok(keypair);
|
return Ok(keypair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,7 +41,6 @@ impl Generator for Prefix {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use Generator;
|
|
||||||
use Prefix;
|
use Prefix;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -57,6 +49,6 @@ mod tests {
|
|||||||
let keypair = Prefix::new(prefix.clone(), usize::max_value())
|
let keypair = Prefix::new(prefix.clone(), usize::max_value())
|
||||||
.generate()
|
.generate()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(keypair.address().starts_with(&prefix));
|
assert!(keypair.address().as_bytes().starts_with(&prefix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use super::{Generator, KeyPair, SECP256K1};
|
|
||||||
use rand::os::OsRng;
|
|
||||||
|
|
||||||
/// Randomly generates new keypair, instantiating the RNG each time.
|
|
||||||
pub struct Random;
|
|
||||||
|
|
||||||
impl Generator for Random {
|
|
||||||
type Error = ::std::io::Error;
|
|
||||||
|
|
||||||
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
|
|
||||||
let mut rng = OsRng::new()?;
|
|
||||||
rng.generate().or_else(|void| match void {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Generator for OsRng {
|
|
||||||
type Error = ::Void;
|
|
||||||
|
|
||||||
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
|
|
||||||
let (sec, publ) = SECP256K1
|
|
||||||
.generate_keypair(self)
|
|
||||||
.expect("context always created with full capabilities; qed");
|
|
||||||
|
|
||||||
Ok(KeyPair::from_keypair(sec, publ))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,322 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use ethereum_types::H256;
|
|
||||||
use memzero::Memzero;
|
|
||||||
use rustc_hex::ToHex;
|
|
||||||
use secp256k1::{constants::SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE, key};
|
|
||||||
use std::{fmt, ops::Deref, str::FromStr};
|
|
||||||
use Error;
|
|
||||||
use SECP256K1;
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
|
||||||
pub struct Secret {
|
|
||||||
inner: Memzero<H256>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToHex for Secret {
|
|
||||||
fn to_hex(&self) -> String {
|
|
||||||
format!("{:x}", *self.inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::LowerHex for Secret {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.inner.fmt(fmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Secret {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.inner.fmt(fmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Secret {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
fmt,
|
|
||||||
"Secret: 0x{:x}{:x}..{:x}{:x}",
|
|
||||||
self.inner[0], self.inner[1], self.inner[30], self.inner[31]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Secret {
|
|
||||||
/// Creates a `Secret` from the given slice, returning `None` if the slice length != 32.
|
|
||||||
pub fn from_slice(key: &[u8]) -> Option<Self> {
|
|
||||||
if key.len() != 32 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let mut h = H256::default();
|
|
||||||
h.copy_from_slice(&key[0..32]);
|
|
||||||
Some(Secret {
|
|
||||||
inner: Memzero::from(h),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates zero key, which is invalid for crypto operations, but valid for math operation.
|
|
||||||
pub fn zero() -> Self {
|
|
||||||
Secret {
|
|
||||||
inner: Memzero::from(H256::default()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Imports and validates the key.
|
|
||||||
pub fn from_unsafe_slice(key: &[u8]) -> Result<Self, Error> {
|
|
||||||
let secret = key::SecretKey::from_slice(&super::SECP256K1, key)?;
|
|
||||||
Ok(secret.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks validity of this key.
|
|
||||||
pub fn check_validity(&self) -> Result<(), Error> {
|
|
||||||
self.to_secp256k1_secret().map(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace add one secret key to another (scalar + scalar)
|
|
||||||
pub fn add(&mut self, other: &Secret) -> Result<(), Error> {
|
|
||||||
match (self.is_zero(), other.is_zero()) {
|
|
||||||
(true, true) | (false, true) => Ok(()),
|
|
||||||
(true, false) => {
|
|
||||||
*self = other.clone();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(false, false) => {
|
|
||||||
let mut key_secret = self.to_secp256k1_secret()?;
|
|
||||||
let other_secret = other.to_secp256k1_secret()?;
|
|
||||||
key_secret.add_assign(&SECP256K1, &other_secret)?;
|
|
||||||
|
|
||||||
*self = key_secret.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace subtract one secret key from another (scalar - scalar)
|
|
||||||
pub fn sub(&mut self, other: &Secret) -> Result<(), Error> {
|
|
||||||
match (self.is_zero(), other.is_zero()) {
|
|
||||||
(true, true) | (false, true) => Ok(()),
|
|
||||||
(true, false) => {
|
|
||||||
*self = other.clone();
|
|
||||||
self.neg()
|
|
||||||
}
|
|
||||||
(false, false) => {
|
|
||||||
let mut key_secret = self.to_secp256k1_secret()?;
|
|
||||||
let mut other_secret = other.to_secp256k1_secret()?;
|
|
||||||
other_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
|
|
||||||
key_secret.add_assign(&SECP256K1, &other_secret)?;
|
|
||||||
|
|
||||||
*self = key_secret.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace decrease secret key (scalar - 1)
|
|
||||||
pub fn dec(&mut self) -> Result<(), Error> {
|
|
||||||
match self.is_zero() {
|
|
||||||
true => {
|
|
||||||
*self = key::MINUS_ONE_KEY.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
false => {
|
|
||||||
let mut key_secret = self.to_secp256k1_secret()?;
|
|
||||||
key_secret.add_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
|
|
||||||
|
|
||||||
*self = key_secret.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace multiply one secret key to another (scalar * scalar)
|
|
||||||
pub fn mul(&mut self, other: &Secret) -> Result<(), Error> {
|
|
||||||
match (self.is_zero(), other.is_zero()) {
|
|
||||||
(true, true) | (true, false) => Ok(()),
|
|
||||||
(false, true) => {
|
|
||||||
*self = Self::zero();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(false, false) => {
|
|
||||||
let mut key_secret = self.to_secp256k1_secret()?;
|
|
||||||
let other_secret = other.to_secp256k1_secret()?;
|
|
||||||
key_secret.mul_assign(&SECP256K1, &other_secret)?;
|
|
||||||
|
|
||||||
*self = key_secret.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace negate secret key (-scalar)
|
|
||||||
pub fn neg(&mut self) -> Result<(), Error> {
|
|
||||||
match self.is_zero() {
|
|
||||||
true => Ok(()),
|
|
||||||
false => {
|
|
||||||
let mut key_secret = self.to_secp256k1_secret()?;
|
|
||||||
key_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
|
|
||||||
|
|
||||||
*self = key_secret.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inplace inverse secret key (1 / scalar)
|
|
||||||
pub fn inv(&mut self) -> Result<(), Error> {
|
|
||||||
let mut key_secret = self.to_secp256k1_secret()?;
|
|
||||||
key_secret.inv_assign(&SECP256K1)?;
|
|
||||||
|
|
||||||
*self = key_secret.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute power of secret key inplace (secret ^ pow).
|
|
||||||
/// This function is not intended to be used with large powers.
|
|
||||||
pub fn pow(&mut self, pow: usize) -> Result<(), Error> {
|
|
||||||
if self.is_zero() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
match pow {
|
|
||||||
0 => *self = key::ONE_KEY.into(),
|
|
||||||
1 => (),
|
|
||||||
_ => {
|
|
||||||
let c = self.clone();
|
|
||||||
for _ in 1..pow {
|
|
||||||
self.mul(&c)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create `secp256k1::key::SecretKey` based on this secret
|
|
||||||
pub fn to_secp256k1_secret(&self) -> Result<key::SecretKey, Error> {
|
|
||||||
Ok(key::SecretKey::from_slice(&SECP256K1, &self[..])?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Secret {
|
|
||||||
type Err = Error;
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Ok(H256::from_str(s)
|
|
||||||
.map_err(|e| Error::Custom(format!("{:?}", e)))?
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<[u8; 32]> for Secret {
|
|
||||||
fn from(k: [u8; 32]) -> Self {
|
|
||||||
Secret {
|
|
||||||
inner: Memzero::from(H256(k)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<H256> for Secret {
|
|
||||||
fn from(s: H256) -> Self {
|
|
||||||
s.0.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&'static str> for Secret {
|
|
||||||
fn from(s: &'static str) -> Self {
|
|
||||||
s.parse().expect(&format!(
|
|
||||||
"invalid string literal for {}: '{}'",
|
|
||||||
stringify!(Self),
|
|
||||||
s
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<key::SecretKey> for Secret {
|
|
||||||
fn from(key: key::SecretKey) -> Self {
|
|
||||||
let mut a = [0; SECP256K1_SECRET_KEY_SIZE];
|
|
||||||
a.copy_from_slice(&key[0..SECP256K1_SECRET_KEY_SIZE]);
|
|
||||||
a.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Secret {
|
|
||||||
type Target = H256;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{
|
|
||||||
super::{Generator, Random},
|
|
||||||
Secret,
|
|
||||||
};
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multiplicating_secret_inversion_with_secret_gives_one() {
|
|
||||||
let secret = Random.generate().unwrap().secret().clone();
|
|
||||||
let mut inversion = secret.clone();
|
|
||||||
inversion.inv().unwrap();
|
|
||||||
inversion.mul(&secret).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
inversion,
|
|
||||||
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
|
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn secret_inversion_is_reversible_with_inversion() {
|
|
||||||
let secret = Random.generate().unwrap().secret().clone();
|
|
||||||
let mut inversion = secret.clone();
|
|
||||||
inversion.inv().unwrap();
|
|
||||||
inversion.inv().unwrap();
|
|
||||||
assert_eq!(inversion, secret);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn secret_pow() {
|
|
||||||
let secret = Random.generate().unwrap().secret().clone();
|
|
||||||
|
|
||||||
let mut pow0 = secret.clone();
|
|
||||||
pow0.pow(0).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
pow0,
|
|
||||||
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
|
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut pow1 = secret.clone();
|
|
||||||
pow1.pow(1).unwrap();
|
|
||||||
assert_eq!(pow1, secret);
|
|
||||||
|
|
||||||
let mut pow2 = secret.clone();
|
|
||||||
pow2.pow(2).unwrap();
|
|
||||||
let mut pow2_expected = secret.clone();
|
|
||||||
pow2_expected.mul(&secret).unwrap();
|
|
||||||
assert_eq!(pow2, pow2_expected);
|
|
||||||
|
|
||||||
let mut pow3 = secret.clone();
|
|
||||||
pow3.pow(3).unwrap();
|
|
||||||
let mut pow3_expected = secret.clone();
|
|
||||||
pow3_expected.mul(&secret).unwrap();
|
|
||||||
pow3_expected.mul(&secret).unwrap();
|
|
||||||
assert_eq!(pow3, pow3_expected);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,325 +0,0 @@
|
|||||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of OpenEthereum.
|
|
||||||
|
|
||||||
// OpenEthereum 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.
|
|
||||||
|
|
||||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use ethereum_types::{H256, H520};
|
|
||||||
use public_to_address;
|
|
||||||
use rustc_hex::{FromHex, ToHex};
|
|
||||||
use secp256k1::{
|
|
||||||
key::{PublicKey, SecretKey},
|
|
||||||
Error as SecpError, Message as SecpMessage, RecoverableSignature, RecoveryId,
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
cmp::PartialEq,
|
|
||||||
fmt,
|
|
||||||
hash::{Hash, Hasher},
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
use Address;
|
|
||||||
use Error;
|
|
||||||
use Message;
|
|
||||||
use Public;
|
|
||||||
use Secret;
|
|
||||||
use SECP256K1;
|
|
||||||
|
|
||||||
/// Signature encoded as RSV components
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Signature([u8; 65]);
|
|
||||||
|
|
||||||
impl Signature {
|
|
||||||
/// Get a slice into the 'r' portion of the data.
|
|
||||||
pub fn r(&self) -> &[u8] {
|
|
||||||
&self.0[0..32]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a slice into the 's' portion of the data.
|
|
||||||
pub fn s(&self) -> &[u8] {
|
|
||||||
&self.0[32..64]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the recovery byte.
|
|
||||||
pub fn v(&self) -> u8 {
|
|
||||||
self.0[64]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode the signature into RSV array (V altered to be in "Electrum" notation).
|
|
||||||
pub fn into_electrum(mut self) -> [u8; 65] {
|
|
||||||
self.0[64] += 27;
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse bytes as a signature encoded as RSV (V in "Electrum" notation).
|
|
||||||
/// May return empty (invalid) signature if given data has invalid length.
|
|
||||||
pub fn from_electrum(data: &[u8]) -> Self {
|
|
||||||
if data.len() != 65 || data[64] < 27 {
|
|
||||||
// fallback to empty (invalid) signature
|
|
||||||
return Signature::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sig = [0u8; 65];
|
|
||||||
sig.copy_from_slice(data);
|
|
||||||
sig[64] -= 27;
|
|
||||||
Signature(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a signature object from the sig.
|
|
||||||
pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Self {
|
|
||||||
let mut sig = [0u8; 65];
|
|
||||||
sig[0..32].copy_from_slice(&r);
|
|
||||||
sig[32..64].copy_from_slice(&s);
|
|
||||||
sig[64] = v;
|
|
||||||
Signature(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if this is a "low" signature.
|
|
||||||
pub fn is_low_s(&self) -> bool {
|
|
||||||
H256::from_slice(self.s())
|
|
||||||
<= "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0".into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if each component of the signature is in range.
|
|
||||||
pub fn is_valid(&self) -> bool {
|
|
||||||
self.v() <= 1
|
|
||||||
&& H256::from_slice(self.r())
|
|
||||||
< "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into()
|
|
||||||
&& H256::from_slice(self.r()) >= 1.into()
|
|
||||||
&& H256::from_slice(self.s())
|
|
||||||
< "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into()
|
|
||||||
&& H256::from_slice(self.s()) >= 1.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// manual implementation large arrays don't have trait impls by default.
|
|
||||||
// remove when integer generics exist
|
|
||||||
impl PartialEq for Signature {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
&self.0[..] == &other.0[..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// manual implementation required in Rust 1.13+, see `std::cmp::AssertParamIsEq`.
|
|
||||||
impl Eq for Signature {}
|
|
||||||
|
|
||||||
// also manual for the same reason, but the pretty printing might be useful.
|
|
||||||
impl fmt::Debug for Signature {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
f.debug_struct("Signature")
|
|
||||||
.field("r", &self.0[0..32].to_hex())
|
|
||||||
.field("s", &self.0[32..64].to_hex())
|
|
||||||
.field("v", &self.0[64..65].to_hex())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Signature {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
write!(f, "{}", self.to_hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Signature {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
match s.from_hex() {
|
|
||||||
Ok(ref hex) if hex.len() == 65 => {
|
|
||||||
let mut data = [0; 65];
|
|
||||||
data.copy_from_slice(&hex[0..65]);
|
|
||||||
Ok(Signature(data))
|
|
||||||
}
|
|
||||||
_ => Err(Error::InvalidSignature),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Signature {
|
|
||||||
fn default() -> Self {
|
|
||||||
Signature([0; 65])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for Signature {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
H520::from(self.0).hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for Signature {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Signature(self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<[u8; 65]> for Signature {
|
|
||||||
fn from(s: [u8; 65]) -> Self {
|
|
||||||
Signature(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<[u8; 65]> for Signature {
|
|
||||||
fn into(self) -> [u8; 65] {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Signature> for H520 {
|
|
||||||
fn from(s: Signature) -> Self {
|
|
||||||
H520::from(s.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<H520> for Signature {
|
|
||||||
fn from(bytes: H520) -> Self {
|
|
||||||
Signature(bytes.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Signature {
|
|
||||||
type Target = [u8; 65];
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Signature {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
|
|
||||||
let context = &SECP256K1;
|
|
||||||
let sec = SecretKey::from_slice(context, &secret)?;
|
|
||||||
let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec)?;
|
|
||||||
let (rec_id, data) = s.serialize_compact(context);
|
|
||||||
let mut data_arr = [0; 65];
|
|
||||||
|
|
||||||
// no need to check if s is low, it always is
|
|
||||||
data_arr[0..64].copy_from_slice(&data[0..64]);
|
|
||||||
data_arr[64] = rec_id.to_i32() as u8;
|
|
||||||
Ok(Signature(data_arr))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn verify_public(
|
|
||||||
public: &Public,
|
|
||||||
signature: &Signature,
|
|
||||||
message: &Message,
|
|
||||||
) -> Result<bool, Error> {
|
|
||||||
let context = &SECP256K1;
|
|
||||||
let rsig = RecoverableSignature::from_compact(
|
|
||||||
context,
|
|
||||||
&signature[0..64],
|
|
||||||
RecoveryId::from_i32(signature[64] as i32)?,
|
|
||||||
)?;
|
|
||||||
let sig = rsig.to_standard(context);
|
|
||||||
|
|
||||||
let pdata: [u8; 65] = {
|
|
||||||
let mut temp = [4u8; 65];
|
|
||||||
temp[1..65].copy_from_slice(&**public);
|
|
||||||
temp
|
|
||||||
};
|
|
||||||
|
|
||||||
let publ = PublicKey::from_slice(context, &pdata)?;
|
|
||||||
match context.verify(&SecpMessage::from_slice(&message[..])?, &sig, &publ) {
|
|
||||||
Ok(_) => Ok(true),
|
|
||||||
Err(SecpError::IncorrectSignature) => Ok(false),
|
|
||||||
Err(x) => Err(Error::from(x)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn verify_address(
|
|
||||||
address: &Address,
|
|
||||||
signature: &Signature,
|
|
||||||
message: &Message,
|
|
||||||
) -> Result<bool, Error> {
|
|
||||||
let public = recover(signature, message)?;
|
|
||||||
let recovered_address = public_to_address(&public);
|
|
||||||
Ok(address == &recovered_address)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recover(signature: &Signature, message: &Message) -> Result<Public, Error> {
|
|
||||||
let context = &SECP256K1;
|
|
||||||
let rsig = RecoverableSignature::from_compact(
|
|
||||||
context,
|
|
||||||
&signature[0..64],
|
|
||||||
RecoveryId::from_i32(signature[64] as i32)?,
|
|
||||||
)?;
|
|
||||||
let pubkey = context.recover(&SecpMessage::from_slice(&message[..])?, &rsig)?;
|
|
||||||
let serialized = pubkey.serialize_vec(context, false);
|
|
||||||
|
|
||||||
let mut public = Public::default();
|
|
||||||
public.copy_from_slice(&serialized[1..65]);
|
|
||||||
Ok(public)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{recover, sign, verify_address, verify_public, Signature};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use Generator;
|
|
||||||
use Message;
|
|
||||||
use Random;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn vrs_conversion() {
|
|
||||||
// given
|
|
||||||
let keypair = Random.generate().unwrap();
|
|
||||||
let message = Message::default();
|
|
||||||
let signature = sign(keypair.secret(), &message).unwrap();
|
|
||||||
|
|
||||||
// when
|
|
||||||
let vrs = signature.clone().into_electrum();
|
|
||||||
let from_vrs = Signature::from_electrum(&vrs);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(signature, from_vrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn signature_to_and_from_str() {
|
|
||||||
let keypair = Random.generate().unwrap();
|
|
||||||
let message = Message::default();
|
|
||||||
let signature = sign(keypair.secret(), &message).unwrap();
|
|
||||||
let string = format!("{}", signature);
|
|
||||||
let deserialized = Signature::from_str(&string).unwrap();
|
|
||||||
assert_eq!(signature, deserialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sign_and_recover_public() {
|
|
||||||
let keypair = Random.generate().unwrap();
|
|
||||||
let message = Message::default();
|
|
||||||
let signature = sign(keypair.secret(), &message).unwrap();
|
|
||||||
assert_eq!(keypair.public(), &recover(&signature, &message).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sign_and_verify_public() {
|
|
||||||
let keypair = Random.generate().unwrap();
|
|
||||||
let message = Message::default();
|
|
||||||
let signature = sign(keypair.secret(), &message).unwrap();
|
|
||||||
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sign_and_verify_address() {
|
|
||||||
let keypair = Random.generate().unwrap();
|
|
||||||
let message = Message::default();
|
|
||||||
let signature = sign(keypair.secret(), &message).unwrap();
|
|
||||||
assert!(verify_address(&keypair.address(), &signature, &message).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
rand = "0.4"
|
rand = "0.7.3"
|
||||||
ethkey = { path = "../ethkey" }
|
ethkey = { path = "../ethkey" }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
@ -16,8 +16,8 @@ rustc-hex = "1.0"
|
|||||||
time = "0.1.34"
|
time = "0.1.34"
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
parity-crypto = "0.3.0"
|
parity-crypto = { version = "0.6.2", features = [ "publickey"] }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
smallvec = "0.6"
|
smallvec = "0.6"
|
||||||
parity-wordlist = "1.3"
|
parity-wordlist = "1.3"
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use account::{Aes128Ctr, Cipher, Kdf, Pbkdf2, Prf};
|
use account::{Aes128Ctr, Cipher, Kdf, Pbkdf2, Prf};
|
||||||
use crypto::{self, Keccak256};
|
use crypto::{self, publickey::Secret, Keccak256};
|
||||||
use ethkey::{Password, Secret};
|
use ethkey::Password;
|
||||||
use json;
|
use json;
|
||||||
use random::Random;
|
use random::Random;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -79,7 +79,7 @@ impl Crypto {
|
|||||||
password: &Password,
|
password: &Password,
|
||||||
iterations: NonZeroU32,
|
iterations: NonZeroU32,
|
||||||
) -> Result<Self, crypto::Error> {
|
) -> Result<Self, crypto::Error> {
|
||||||
Crypto::with_plain(&*secret, password, iterations)
|
Crypto::with_plain(secret.as_bytes(), password, iterations)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypt custom plain data
|
/// Encrypt custom plain data
|
||||||
@ -94,7 +94,7 @@ impl Crypto {
|
|||||||
// two parts of derived key
|
// two parts of derived key
|
||||||
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
|
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
|
||||||
let (derived_left_bits, derived_right_bits) =
|
let (derived_left_bits, derived_right_bits) =
|
||||||
crypto::derive_key_iterations(password.as_bytes(), &salt, iterations);
|
crypto::derive_key_iterations(password.as_bytes(), &salt, iterations.get());
|
||||||
|
|
||||||
// preallocated (on-stack in case of `Secret`) buffer to hold cipher
|
// preallocated (on-stack in case of `Secret`) buffer to hold cipher
|
||||||
// length = length(plain) as we are using CTR-approach
|
// length = length(plain) as we are using CTR-approach
|
||||||
@ -127,7 +127,7 @@ impl Crypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let secret = self.do_decrypt(password, 32)?;
|
let secret = self.do_decrypt(password, 32)?;
|
||||||
Ok(Secret::from_unsafe_slice(&secret)?)
|
Ok(Secret::import_key(&secret)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to decrypt and return result as is
|
/// Try to decrypt and return result as is
|
||||||
@ -139,7 +139,7 @@ impl Crypto {
|
|||||||
fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result<Vec<u8>, Error> {
|
fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result<Vec<u8>, Error> {
|
||||||
let (derived_left_bits, derived_right_bits) = match self.kdf {
|
let (derived_left_bits, derived_right_bits) = match self.kdf {
|
||||||
Kdf::Pbkdf2(ref params) => {
|
Kdf::Pbkdf2(ref params) => {
|
||||||
crypto::derive_key_iterations(password.as_bytes(), ¶ms.salt, params.c)
|
crypto::derive_key_iterations(password.as_bytes(), ¶ms.salt, params.c.get())
|
||||||
}
|
}
|
||||||
Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(
|
Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(
|
||||||
password.as_bytes(),
|
password.as_bytes(),
|
||||||
@ -179,7 +179,7 @@ impl Crypto {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Crypto, Error, NonZeroU32};
|
use super::{Crypto, Error, NonZeroU32};
|
||||||
use ethkey::{Generator, Random};
|
use crypto::publickey::{Generator, Random};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
|
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
|
||||||
@ -187,7 +187,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_secret_create() {
|
fn crypto_with_secret_create() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let passwd = "this is sparta".into();
|
let passwd = "this is sparta".into();
|
||||||
let crypto = Crypto::with_secret(keypair.secret(), &passwd, *ITERATIONS).unwrap();
|
let crypto = Crypto::with_secret(keypair.secret(), &passwd, *ITERATIONS).unwrap();
|
||||||
let secret = crypto.secret(&passwd).unwrap();
|
let secret = crypto.secret(&passwd).unwrap();
|
||||||
@ -196,7 +196,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_secret_invalid_password() {
|
fn crypto_with_secret_invalid_password() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let crypto =
|
let crypto =
|
||||||
Crypto::with_secret(keypair.secret(), &"this is sparta".into(), *ITERATIONS).unwrap();
|
Crypto::with_secret(keypair.secret(), &"this is sparta".into(), *ITERATIONS).unwrap();
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
|
@ -16,10 +16,11 @@
|
|||||||
|
|
||||||
use super::crypto::Crypto;
|
use super::crypto::Crypto;
|
||||||
use account::Version;
|
use account::Version;
|
||||||
use crypto;
|
use crypto::{
|
||||||
use ethkey::{
|
self,
|
||||||
self, crypto::ecdh::agree, sign, Address, KeyPair, Message, Password, Public, Secret, Signature,
|
publickey::{ecdh::agree, sign, Address, KeyPair, Message, Public, Secret, Signature},
|
||||||
};
|
};
|
||||||
|
use ethkey::Password;
|
||||||
use json;
|
use json;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use Error;
|
use Error;
|
||||||
@ -193,7 +194,7 @@ impl SafeAccount {
|
|||||||
message: &[u8],
|
message: &[u8],
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
let secret = self.crypto.secret(password)?;
|
let secret = self.crypto.secret(password)?;
|
||||||
ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
|
crypto::publickey::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Agree on shared key.
|
/// Agree on shared key.
|
||||||
@ -237,7 +238,7 @@ impl SafeAccount {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{NonZeroU32, SafeAccount};
|
use super::{NonZeroU32, SafeAccount};
|
||||||
use ethkey::{verify_public, Generator, Message, Random};
|
use crypto::publickey::{verify_public, Generator, Random};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
|
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
|
||||||
@ -245,9 +246,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sign_and_verify_public() {
|
fn sign_and_verify_public() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let password = "hello world".into();
|
let password = "hello world".into();
|
||||||
let message = Message::default();
|
let message = [1u8; 32].into();
|
||||||
let account = SafeAccount::create(
|
let account = SafeAccount::create(
|
||||||
&keypair,
|
&keypair,
|
||||||
[0u8; 16],
|
[0u8; 16],
|
||||||
@ -262,10 +263,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_password() {
|
fn change_password() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let first_password = "hello world".into();
|
let first_password = "hello world".into();
|
||||||
let sec_password = "this is sparta".into();
|
let sec_password = "this is sparta".into();
|
||||||
let message = Message::default();
|
let message = [1u8; 32].into();
|
||||||
let account = SafeAccount::create(
|
let account = SafeAccount::create(
|
||||||
&keypair,
|
&keypair,
|
||||||
[0u8; 16],
|
[0u8; 16],
|
||||||
|
@ -420,7 +420,7 @@ mod test {
|
|||||||
use self::tempdir::TempDir;
|
use self::tempdir::TempDir;
|
||||||
use super::{KeyDirectory, RootDiskDirectory, VaultKey};
|
use super::{KeyDirectory, RootDiskDirectory, VaultKey};
|
||||||
use account::SafeAccount;
|
use account::SafeAccount;
|
||||||
use ethkey::{Generator, Random};
|
use crypto::publickey::{Generator, Random};
|
||||||
use std::{env, fs, num::NonZeroU32};
|
use std::{env, fs, num::NonZeroU32};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -432,7 +432,7 @@ mod test {
|
|||||||
// given
|
// given
|
||||||
let mut dir = env::temp_dir();
|
let mut dir = env::temp_dir();
|
||||||
dir.push("ethstore_should_create_new_account");
|
dir.push("ethstore_should_create_new_account");
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let password = "hello world".into();
|
let password = "hello world".into();
|
||||||
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
||||||
|
|
||||||
@ -463,7 +463,7 @@ mod test {
|
|||||||
// given
|
// given
|
||||||
let mut dir = env::temp_dir();
|
let mut dir = env::temp_dir();
|
||||||
dir.push("ethstore_should_handle_duplicate_filenames");
|
dir.push("ethstore_should_handle_duplicate_filenames");
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let password = "hello world".into();
|
let password = "hello world".into();
|
||||||
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
||||||
|
|
||||||
@ -582,7 +582,7 @@ mod test {
|
|||||||
.expect("Files hash should be calculated ok");
|
.expect("Files hash should be calculated ok");
|
||||||
assert_eq!(hash, 15130871412783076140);
|
assert_eq!(hash, 15130871412783076140);
|
||||||
|
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let password = "test pass".into();
|
let password = "test pass".into();
|
||||||
let account = SafeAccount::create(
|
let account = SafeAccount::create(
|
||||||
&keypair,
|
&keypair,
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethkey::Address;
|
use crypto::publickey::Address;
|
||||||
use itertools;
|
use itertools;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -70,7 +70,7 @@ impl KeyDirectory for MemoryDirectory {
|
|||||||
let mut val = 0u64;
|
let mut val = 0u64;
|
||||||
let accounts = self.accounts.read();
|
let accounts = self.accounts.read();
|
||||||
for acc in accounts.keys() {
|
for acc in accounts.keys() {
|
||||||
val = val ^ acc.low_u64()
|
val = val ^ acc.to_low_u64_be()
|
||||||
}
|
}
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crypto::{self, Error as EthCryptoError};
|
use crypto::publickey::DerivationError;
|
||||||
use ethkey::{self, DerivationError, Error as EthKeyError};
|
|
||||||
use std::{fmt, io::Error as IoError};
|
use std::{fmt, io::Error as IoError};
|
||||||
|
|
||||||
/// Account-related errors.
|
/// Account-related errors.
|
||||||
@ -45,12 +44,10 @@ pub enum Error {
|
|||||||
VaultNotFound,
|
VaultNotFound,
|
||||||
/// Account creation failed.
|
/// Account creation failed.
|
||||||
CreationFailed,
|
CreationFailed,
|
||||||
/// `EthKey` error
|
/// `crypto::publickey::Error`
|
||||||
EthKey(EthKeyError),
|
EthCrypto(crypto::Error),
|
||||||
/// `ethkey::crypto::Error`
|
|
||||||
EthKeyCrypto(ethkey::crypto::Error),
|
|
||||||
/// `EthCrypto` error
|
/// `EthCrypto` error
|
||||||
EthCrypto(EthCryptoError),
|
EthCryptoPublicKey(crypto::publickey::Error),
|
||||||
/// Derivation error
|
/// Derivation error
|
||||||
Derivation(DerivationError),
|
Derivation(DerivationError),
|
||||||
/// Custom error
|
/// Custom error
|
||||||
@ -72,9 +69,8 @@ impl fmt::Display for Error {
|
|||||||
Error::InvalidVaultName => "Invalid vault name".into(),
|
Error::InvalidVaultName => "Invalid vault name".into(),
|
||||||
Error::VaultNotFound => "Vault not found".into(),
|
Error::VaultNotFound => "Vault not found".into(),
|
||||||
Error::CreationFailed => "Account creation failed".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::EthCrypto(ref err) => err.to_string(),
|
||||||
|
Error::EthCryptoPublicKey(ref err) => err.to_string(),
|
||||||
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
|
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
|
||||||
Error::Custom(ref s) => s.clone(),
|
Error::Custom(ref s) => s.clone(),
|
||||||
};
|
};
|
||||||
@ -89,20 +85,14 @@ impl From<IoError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EthKeyError> for Error {
|
impl From<crypto::publickey::Error> for Error {
|
||||||
fn from(err: EthKeyError) -> Self {
|
fn from(err: crypto::publickey::Error) -> Self {
|
||||||
Error::EthKey(err)
|
Error::EthCryptoPublicKey(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethkey::crypto::Error> for Error {
|
impl From<crypto::Error> for Error {
|
||||||
fn from(err: ethkey::crypto::Error) -> Self {
|
fn from(err: crypto::Error) -> Self {
|
||||||
Error::EthKeyCrypto(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EthCryptoError> for Error {
|
|
||||||
fn from(err: EthCryptoError) -> Self {
|
|
||||||
Error::EthCrypto(err)
|
Error::EthCrypto(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
//! ethkey reexport to make documentation look pretty.
|
//! ethkey reexport to make documentation look pretty.
|
||||||
pub use _ethkey::*;
|
pub use _ethkey::*;
|
||||||
|
pub use crypto::publickey::Address;
|
||||||
use json;
|
use json;
|
||||||
|
|
||||||
impl Into<json::H160> for Address {
|
impl Into<json::H160> for Address {
|
||||||
|
@ -24,9 +24,10 @@ use std::{
|
|||||||
|
|
||||||
use account::SafeAccount;
|
use account::SafeAccount;
|
||||||
use accounts_dir::{KeyDirectory, SetKeyError, VaultKey, VaultKeyDirectory};
|
use accounts_dir::{KeyDirectory, SetKeyError, VaultKey, VaultKeyDirectory};
|
||||||
use ethkey::{
|
use crypto::publickey::{
|
||||||
self, Address, ExtendedKeyPair, KeyPair, Message, Password, Public, Secret, Signature,
|
self, Address, ExtendedKeyPair, KeyPair, Message, Public, Secret, Signature,
|
||||||
};
|
};
|
||||||
|
use ethkey::Password;
|
||||||
use json::{self, OpaqueKeyFile, Uuid};
|
use json::{self, OpaqueKeyFile, Uuid};
|
||||||
use presale::PresaleWallet;
|
use presale::PresaleWallet;
|
||||||
use random::Random;
|
use random::Random;
|
||||||
@ -554,17 +555,17 @@ impl EthMultiStore {
|
|||||||
Derivation::Hierarchical(path) => {
|
Derivation::Hierarchical(path) => {
|
||||||
for path_item in path {
|
for path_item in path {
|
||||||
extended = extended.derive(if path_item.soft {
|
extended = extended.derive(if path_item.soft {
|
||||||
ethkey::Derivation::Soft(path_item.index)
|
publickey::Derivation::Soft(path_item.index)
|
||||||
} else {
|
} else {
|
||||||
ethkey::Derivation::Hard(path_item.index)
|
publickey::Derivation::Hard(path_item.index)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Derivation::SoftHash(h256) => {
|
Derivation::SoftHash(h256) => {
|
||||||
extended = extended.derive(ethkey::Derivation::Soft(h256))?;
|
extended = extended.derive(publickey::Derivation::Soft(h256))?;
|
||||||
}
|
}
|
||||||
Derivation::HardHash(h256) => {
|
Derivation::HardHash(h256) => {
|
||||||
extended = extended.derive(ethkey::Derivation::Hard(h256))?;
|
extended = extended.derive(publickey::Derivation::Hard(h256))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(extended)
|
Ok(extended)
|
||||||
@ -615,7 +616,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
let accounts = self.get_matching(&account_ref, password)?;
|
let accounts = self.get_matching(&account_ref, password)?;
|
||||||
for account in accounts {
|
for account in accounts {
|
||||||
let extended = self.generate(account.crypto.secret(password)?, derivation)?;
|
let extended = self.generate(account.crypto.secret(password)?, derivation)?;
|
||||||
return Ok(ethkey::public_to_address(extended.public().public()));
|
return Ok(publickey::public_to_address(extended.public().public()));
|
||||||
}
|
}
|
||||||
Err(Error::InvalidPassword)
|
Err(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
@ -631,7 +632,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
for account in accounts {
|
for account in accounts {
|
||||||
let extended = self.generate(account.crypto.secret(password)?, derivation)?;
|
let extended = self.generate(account.crypto.secret(password)?, derivation)?;
|
||||||
let secret = extended.secret().as_raw();
|
let secret = extended.secret().as_raw();
|
||||||
return Ok(ethkey::sign(&secret, message)?);
|
return Ok(publickey::sign(&secret, message)?);
|
||||||
}
|
}
|
||||||
Err(Error::InvalidPassword)
|
Err(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
@ -898,14 +899,14 @@ mod tests {
|
|||||||
use self::tempdir::TempDir;
|
use self::tempdir::TempDir;
|
||||||
use super::{EthMultiStore, EthStore};
|
use super::{EthMultiStore, EthStore};
|
||||||
use accounts_dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory};
|
use accounts_dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory};
|
||||||
|
use crypto::publickey::{Generator, KeyPair, Random};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use ethkey::{Generator, KeyPair, Random};
|
|
||||||
use secret_store::{
|
use secret_store::{
|
||||||
Derivation, SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
|
Derivation, SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn keypair() -> KeyPair {
|
fn keypair() -> KeyPair {
|
||||||
Random.generate().unwrap()
|
Random.generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store() -> EthStore {
|
fn store() -> EthStore {
|
||||||
@ -1051,6 +1052,7 @@ mod tests {
|
|||||||
let passwd2 = "xzy".into();
|
let passwd2 = "xzy".into();
|
||||||
let multi_store = multi_store();
|
let multi_store = multi_store();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
|
let message = [1u8; 32].into();
|
||||||
let address = store
|
let address = store
|
||||||
.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1)
|
.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1073,9 +1075,7 @@ mod tests {
|
|||||||
"First password should work for store."
|
"First password should work for store."
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
multi_store
|
multi_store.sign(&address, &passwd2, &message).is_ok(),
|
||||||
.sign(&address, &passwd2, &Default::default())
|
|
||||||
.is_ok(),
|
|
||||||
"Second password should work for second store."
|
"Second password should work for second store."
|
||||||
);
|
);
|
||||||
assert_eq!(multi_store.accounts().unwrap().len(), 1);
|
assert_eq!(multi_store.accounts().unwrap().len(), 1);
|
||||||
@ -1462,7 +1462,7 @@ mod tests {
|
|||||||
SecretVaultRef::Root,
|
SecretVaultRef::Root,
|
||||||
&address,
|
&address,
|
||||||
&"test".into(),
|
&"test".into(),
|
||||||
Derivation::HardHash(H256::from(0)),
|
Derivation::HardHash(H256::zero()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -1470,11 +1470,10 @@ mod tests {
|
|||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
assert_eq!(accounts.len(), 2);
|
assert_eq!(accounts.len(), 2);
|
||||||
|
|
||||||
|
let message = [1u8; 32].into();
|
||||||
// and we can sign with the derived contract
|
// and we can sign with the derived contract
|
||||||
assert!(
|
assert!(
|
||||||
store
|
store.sign(&derived, &"test".into(), &message).is_ok(),
|
||||||
.sign(&derived, &"test".into(), &Default::default())
|
|
||||||
.is_ok(),
|
|
||||||
"Second password should work for second store."
|
"Second password should work for second store."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
use std::{collections::HashSet, fs, path::Path};
|
use std::{collections::HashSet, fs, path::Path};
|
||||||
|
|
||||||
use accounts_dir::{DiskKeyFileManager, KeyDirectory, KeyFileManager};
|
use accounts_dir::{DiskKeyFileManager, KeyDirectory, KeyFileManager};
|
||||||
use ethkey::Address;
|
use crypto::publickey::Address;
|
||||||
use Error;
|
use Error;
|
||||||
|
|
||||||
/// Import an account from a file.
|
/// Import an account from a file.
|
||||||
|
@ -74,4 +74,4 @@ pub use self::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// An opaque wrapper for secret.
|
/// An opaque wrapper for secret.
|
||||||
pub struct OpaqueSecret(::ethkey::Secret);
|
pub struct OpaqueSecret(crypto::publickey::Secret);
|
||||||
|
@ -14,8 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crypto::{self, pbkdf2, Keccak256};
|
use crypto::{
|
||||||
use ethkey::{Address, KeyPair, Password, Secret};
|
self, pbkdf2,
|
||||||
|
publickey::{Address, KeyPair, Secret},
|
||||||
|
Keccak256,
|
||||||
|
};
|
||||||
|
use ethkey::Password;
|
||||||
use json;
|
use json;
|
||||||
use std::{fs, num::NonZeroU32, path::Path};
|
use std::{fs, num::NonZeroU32, path::Path};
|
||||||
use Error;
|
use Error;
|
||||||
@ -61,7 +65,7 @@ impl PresaleWallet {
|
|||||||
let salt = pbkdf2::Salt(password.as_bytes());
|
let salt = pbkdf2::Salt(password.as_bytes());
|
||||||
let sec = pbkdf2::Secret(password.as_bytes());
|
let sec = pbkdf2::Secret(password.as_bytes());
|
||||||
let iter = NonZeroU32::new(2000).expect("2000 > 0; qed");
|
let iter = NonZeroU32::new(2000).expect("2000 > 0; qed");
|
||||||
pbkdf2::sha256(iter, salt, sec, &mut derived_key);
|
pbkdf2::sha256(iter.get(), salt, sec, &mut derived_key);
|
||||||
|
|
||||||
let mut key = vec![0; self.ciphertext.len()];
|
let mut key = vec![0; self.ciphertext.len()];
|
||||||
let len =
|
let len =
|
||||||
@ -69,7 +73,7 @@ impl PresaleWallet {
|
|||||||
.map_err(|_| Error::InvalidPassword)?;
|
.map_err(|_| Error::InvalidPassword)?;
|
||||||
let unpadded = &key[..len];
|
let unpadded = &key[..len];
|
||||||
|
|
||||||
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?;
|
let secret = Secret::import_key(&unpadded.keccak256())?;
|
||||||
if let Ok(kp) = KeyPair::from_secret(secret) {
|
if let Ok(kp) = KeyPair::from_secret(secret) {
|
||||||
if kp.address() == self.address {
|
if kp.address() == self.address {
|
||||||
return Ok(kp);
|
return Ok(kp);
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use rand::{OsRng, Rng};
|
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng, RngCore};
|
||||||
|
|
||||||
pub trait Random {
|
pub trait Random {
|
||||||
fn random() -> Self
|
fn random() -> Self
|
||||||
@ -25,7 +25,7 @@ pub trait Random {
|
|||||||
impl Random for [u8; 16] {
|
impl Random for [u8; 16] {
|
||||||
fn random() -> Self {
|
fn random() -> Self {
|
||||||
let mut result = [0u8; 16];
|
let mut result = [0u8; 16];
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng;
|
||||||
rng.fill_bytes(&mut result);
|
rng.fill_bytes(&mut result);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ impl Random for [u8; 16] {
|
|||||||
impl Random for [u8; 32] {
|
impl Random for [u8; 32] {
|
||||||
fn random() -> Self {
|
fn random() -> Self {
|
||||||
let mut result = [0u8; 32];
|
let mut result = [0u8; 32];
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng;
|
||||||
rng.fill_bytes(&mut result);
|
rng.fill_bytes(&mut result);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -42,6 +42,6 @@ impl Random for [u8; 32] {
|
|||||||
|
|
||||||
/// Generate a random string of given length.
|
/// Generate a random string of given length.
|
||||||
pub fn random_string(length: usize) -> String {
|
pub fn random_string(length: usize) -> String {
|
||||||
let mut rng = OsRng::new().expect("Not able to operate without random source.");
|
let rng = OsRng;
|
||||||
rng.gen_ascii_chars().take(length).collect()
|
rng.sample_iter(&Alphanumeric).take(length).collect()
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crypto::publickey::{Address, Message, Public, Secret, Signature};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use ethkey::{Address, Message, Password, Public, Secret, Signature};
|
use ethkey::Password;
|
||||||
use json::{OpaqueKeyFile, Uuid};
|
use json::{OpaqueKeyFile, Uuid};
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
@ -174,7 +175,7 @@ pub trait SecretStore: SimpleSecretStore {
|
|||||||
secret: &OpaqueSecret,
|
secret: &OpaqueSecret,
|
||||||
message: &Message,
|
message: &Message,
|
||||||
) -> Result<Signature, Error> {
|
) -> Result<Signature, Error> {
|
||||||
Ok(::ethkey::sign(&secret.0, message)?)
|
Ok(crypto::publickey::sign(&secret.0, message)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Imports presale wallet
|
/// Imports presale wallet
|
||||||
|
@ -14,15 +14,19 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
extern crate ethereum_types;
|
||||||
extern crate ethstore;
|
extern crate ethstore;
|
||||||
|
extern crate parity_crypto as crypto;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crypto::publickey::{verify_address, Generator, KeyPair, Random, Secret};
|
||||||
|
use ethereum_types::H160;
|
||||||
use ethstore::{
|
use ethstore::{
|
||||||
accounts_dir::RootDiskDirectory,
|
accounts_dir::RootDiskDirectory, EthStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
|
||||||
ethkey::{verify_address, Generator, KeyPair, Random, Secret},
|
|
||||||
EthStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
|
|
||||||
};
|
};
|
||||||
use util::TransientDir;
|
use util::TransientDir;
|
||||||
|
|
||||||
@ -40,7 +44,7 @@ fn secret_store_open_not_existing() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn random_secret() -> Secret {
|
fn random_secret() -> Secret {
|
||||||
Random.generate().unwrap().secret().clone()
|
Random.generate().secret().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -66,13 +70,10 @@ fn secret_store_sign() {
|
|||||||
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
|
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
|
let message = [1u8; 32].into();
|
||||||
assert_eq!(accounts.len(), 1);
|
assert_eq!(accounts.len(), 1);
|
||||||
assert!(store
|
assert!(store.sign(&accounts[0], &"".into(), &message).is_ok());
|
||||||
.sign(&accounts[0], &"".into(), &Default::default())
|
assert!(store.sign(&accounts[0], &"1".into(), &message).is_err());
|
||||||
.is_ok());
|
|
||||||
assert!(store
|
|
||||||
.sign(&accounts[0], &"1".into(), &Default::default())
|
|
||||||
.is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -83,19 +84,14 @@ fn secret_store_change_password() {
|
|||||||
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
|
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
|
let message = [1u8; 32].into();
|
||||||
assert_eq!(accounts.len(), 1);
|
assert_eq!(accounts.len(), 1);
|
||||||
assert!(store
|
assert!(store.sign(&accounts[0], &"".into(), &message).is_ok());
|
||||||
.sign(&accounts[0], &"".into(), &Default::default())
|
|
||||||
.is_ok());
|
|
||||||
assert!(store
|
assert!(store
|
||||||
.change_password(&accounts[0], &"".into(), &"1".into())
|
.change_password(&accounts[0], &"".into(), &"1".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(store
|
assert!(store.sign(&accounts[0], &"".into(), &message).is_err());
|
||||||
.sign(&accounts[0], &"".into(), &Default::default())
|
assert!(store.sign(&accounts[0], &"1".into(), &message).is_ok());
|
||||||
.is_err());
|
|
||||||
assert!(store
|
|
||||||
.sign(&accounts[0], &"1".into(), &Default::default())
|
|
||||||
.is_ok());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -140,9 +136,15 @@ fn secret_store_laod_geth_files() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.accounts().unwrap(),
|
store.accounts().unwrap(),
|
||||||
vec![
|
vec![
|
||||||
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
|
StoreAccountRef::root(
|
||||||
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
|
H160::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()
|
||||||
StoreAccountRef::root("63121b431a52f8043c16fcf0d1df9cb7b5f66649".into()),
|
),
|
||||||
|
StoreAccountRef::root(
|
||||||
|
H160::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()
|
||||||
|
),
|
||||||
|
StoreAccountRef::root(
|
||||||
|
H160::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap()
|
||||||
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -154,8 +156,12 @@ fn secret_store_load_pat_files() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.accounts().unwrap(),
|
store.accounts().unwrap(),
|
||||||
vec![
|
vec![
|
||||||
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
|
StoreAccountRef::root(
|
||||||
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
|
H160::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()
|
||||||
|
),
|
||||||
|
StoreAccountRef::root(
|
||||||
|
H160::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()
|
||||||
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -182,12 +188,16 @@ fn test_decrypting_files_with_short_ciphertext() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
accounts,
|
accounts,
|
||||||
vec![
|
vec![
|
||||||
StoreAccountRef::root("31e9d1e6d844bd3a536800ef8d8be6a9975db509".into()),
|
StoreAccountRef::root(
|
||||||
StoreAccountRef::root("d1e64e5480bfaf733ba7d48712decb8227797a4e".into()),
|
H160::from_str("31e9d1e6d844bd3a536800ef8d8be6a9975db509").unwrap()
|
||||||
|
),
|
||||||
|
StoreAccountRef::root(
|
||||||
|
H160::from_str("d1e64e5480bfaf733ba7d48712decb8227797a4e").unwrap()
|
||||||
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
let message = Default::default();
|
let message = [1u8; 32].into();
|
||||||
|
|
||||||
let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap();
|
let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap();
|
||||||
let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap();
|
let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap();
|
||||||
|
@ -18,11 +18,11 @@ use ethstore::{
|
|||||||
accounts_dir::{KeyDirectory, RootDiskDirectory},
|
accounts_dir::{KeyDirectory, RootDiskDirectory},
|
||||||
Error, SafeAccount,
|
Error, SafeAccount,
|
||||||
};
|
};
|
||||||
use rand::{OsRng, Rng};
|
use rand::{rngs::OsRng, RngCore};
|
||||||
use std::{env, fs, path::PathBuf};
|
use std::{env, fs, path::PathBuf};
|
||||||
|
|
||||||
pub fn random_dir() -> PathBuf {
|
pub fn random_dir() -> PathBuf {
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng;
|
||||||
let mut dir = env::temp_dir();
|
let mut dir = env::temp_dir();
|
||||||
dir.push(format!("{:x}-{:x}", rng.next_u64(), rng.next_u64()));
|
dir.push(format!("{:x}-{:x}", rng.next_u64(), rng.next_u64()));
|
||||||
dir
|
dir
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
use std::{collections::HashMap, time::Instant};
|
use std::{collections::HashMap, time::Instant};
|
||||||
|
|
||||||
use ethkey::{Address, Password};
|
use crypto::publickey::Address;
|
||||||
|
use ethkey::Password;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
//! Account management.
|
//! Account management.
|
||||||
|
|
||||||
|
extern crate parity_crypto as crypto;
|
||||||
|
|
||||||
mod account_data;
|
mod account_data;
|
||||||
mod error;
|
mod error;
|
||||||
mod stores;
|
mod stores;
|
||||||
@ -32,7 +34,8 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethkey::{Address, Generator, Message, Password, Public, Random, Secret};
|
use crypto::publickey::{Address, Generator, Message, Public, Random, Secret};
|
||||||
|
use ethkey::Password;
|
||||||
use ethstore::{
|
use ethstore::{
|
||||||
accounts_dir::MemoryDirectory, random_string, EthMultiStore, EthStore, OpaqueSecret,
|
accounts_dir::MemoryDirectory, random_string, EthMultiStore, EthStore, OpaqueSecret,
|
||||||
SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
|
SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
|
||||||
@ -40,7 +43,7 @@ use ethstore::{
|
|||||||
use log::*;
|
use log::*;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
pub use ethkey::Signature;
|
pub use crypto::publickey::Signature;
|
||||||
pub use ethstore::{Derivation, Error, IndexDerivation, KeyFile};
|
pub use ethstore::{Derivation, Error, IndexDerivation, KeyFile};
|
||||||
|
|
||||||
pub use self::{account_data::AccountMeta, error::SignError};
|
pub use self::{account_data::AccountMeta, error::SignError};
|
||||||
@ -134,9 +137,7 @@ impl AccountProvider {
|
|||||||
|
|
||||||
/// Creates new random account and returns address and public key
|
/// Creates new random account and returns address and public key
|
||||||
pub fn new_account_and_public(&self, password: &Password) -> Result<(Address, Public), Error> {
|
pub fn new_account_and_public(&self, password: &Password) -> Result<(Address, Public), Error> {
|
||||||
let acc = Random
|
let acc = Random.generate();
|
||||||
.generate()
|
|
||||||
.expect("secp context has generation capabilities; qed");
|
|
||||||
let public = acc.public().clone();
|
let public = acc.public().clone();
|
||||||
let secret = acc.secret().clone();
|
let secret = acc.secret().clone();
|
||||||
let account = self
|
let account = self
|
||||||
@ -355,7 +356,8 @@ impl AccountProvider {
|
|||||||
} else {
|
} else {
|
||||||
// verify password by signing dump message
|
// verify password by signing dump message
|
||||||
// result may be discarded
|
// result may be discarded
|
||||||
let _ = self.sstore.sign(&account, &password, &Default::default())?;
|
let dummy_msg = [1u8; 32].into();
|
||||||
|
let _ = self.sstore.sign(&account, &password, &dummy_msg)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = AccountData {
|
let data = AccountData {
|
||||||
@ -632,15 +634,16 @@ impl AccountProvider {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{AccountProvider, Unlock};
|
use super::{AccountProvider, Unlock};
|
||||||
|
use crypto::publickey::{Address, Generator, Random};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use ethkey::{Address, Generator, Random};
|
|
||||||
use ethstore::{Derivation, StoreAccountRef};
|
use ethstore::{Derivation, StoreAccountRef};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unlock_account_temp() {
|
fn unlock_account_temp() {
|
||||||
let kp = Random.generate().unwrap();
|
let kp = Random.generate();
|
||||||
let ap = AccountProvider::transient_provider();
|
let ap = AccountProvider::transient_provider();
|
||||||
|
let dummy_msg = [1u8; 32].into();
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.insert_account(kp.secret().clone(), &"test".into())
|
.insert_account(kp.secret().clone(), &"test".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
@ -650,13 +653,13 @@ mod tests {
|
|||||||
assert!(ap
|
assert!(ap
|
||||||
.unlock_account_temporarily(kp.address(), "test".into())
|
.unlock_account_temporarily(kp.address(), "test".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_err());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn derived_account_nosave() {
|
fn derived_account_nosave() {
|
||||||
let kp = Random.generate().unwrap();
|
let kp = Random.generate();
|
||||||
let ap = AccountProvider::transient_provider();
|
let ap = AccountProvider::transient_provider();
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.insert_account(kp.secret().clone(), &"base".into())
|
.insert_account(kp.secret().clone(), &"base".into())
|
||||||
@ -669,7 +672,7 @@ mod tests {
|
|||||||
.derive_account(
|
.derive_account(
|
||||||
&kp.address(),
|
&kp.address(),
|
||||||
None,
|
None,
|
||||||
Derivation::SoftHash(H256::from(999)),
|
Derivation::SoftHash(H256::from_low_u64_be(999)),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.expect("Derivation should not fail");
|
.expect("Derivation should not fail");
|
||||||
@ -683,7 +686,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn derived_account_save() {
|
fn derived_account_save() {
|
||||||
let kp = Random.generate().unwrap();
|
let kp = Random.generate();
|
||||||
let ap = AccountProvider::transient_provider();
|
let ap = AccountProvider::transient_provider();
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.insert_account(kp.secret().clone(), &"base".into())
|
.insert_account(kp.secret().clone(), &"base".into())
|
||||||
@ -696,7 +699,7 @@ mod tests {
|
|||||||
.derive_account(
|
.derive_account(
|
||||||
&kp.address(),
|
&kp.address(),
|
||||||
None,
|
None,
|
||||||
Derivation::SoftHash(H256::from(999)),
|
Derivation::SoftHash(H256::from_low_u64_be(999)),
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
.expect("Derivation should not fail");
|
.expect("Derivation should not fail");
|
||||||
@ -716,7 +719,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn derived_account_sign() {
|
fn derived_account_sign() {
|
||||||
let kp = Random.generate().unwrap();
|
let kp = Random.generate();
|
||||||
let ap = AccountProvider::transient_provider();
|
let ap = AccountProvider::transient_provider();
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.insert_account(kp.secret().clone(), &"base".into())
|
.insert_account(kp.secret().clone(), &"base".into())
|
||||||
@ -729,14 +732,14 @@ mod tests {
|
|||||||
.derive_account(
|
.derive_account(
|
||||||
&kp.address(),
|
&kp.address(),
|
||||||
None,
|
None,
|
||||||
Derivation::SoftHash(H256::from(1999)),
|
Derivation::SoftHash(H256::from_low_u64_be(1999)),
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
.expect("Derivation should not fail");
|
.expect("Derivation should not fail");
|
||||||
ap.unlock_account_permanently(derived_addr, "base".into())
|
ap.unlock_account_permanently(derived_addr, "base".into())
|
||||||
.expect("Should be ok because account is saved and password is valid");
|
.expect("Should be ok because account is saved and password is valid");
|
||||||
|
|
||||||
let msg = Default::default();
|
let msg = [2u8; 32].into();
|
||||||
let signed_msg1 = ap
|
let signed_msg1 = ap
|
||||||
.sign(derived_addr, None, msg)
|
.sign(derived_addr, None, msg)
|
||||||
.expect("Signing with existing unlocked account should not fail");
|
.expect("Signing with existing unlocked account should not fail");
|
||||||
@ -744,7 +747,7 @@ mod tests {
|
|||||||
.sign_derived(
|
.sign_derived(
|
||||||
&kp.address(),
|
&kp.address(),
|
||||||
None,
|
None,
|
||||||
Derivation::SoftHash(H256::from(1999)),
|
Derivation::SoftHash(H256::from_low_u64_be(1999)),
|
||||||
msg,
|
msg,
|
||||||
)
|
)
|
||||||
.expect("Derived signing with existing unlocked account should not fail");
|
.expect("Derived signing with existing unlocked account should not fail");
|
||||||
@ -754,8 +757,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unlock_account_perm() {
|
fn unlock_account_perm() {
|
||||||
let kp = Random.generate().unwrap();
|
let kp = Random.generate();
|
||||||
let ap = AccountProvider::transient_provider();
|
let ap = AccountProvider::transient_provider();
|
||||||
|
let dummy_msg = [1u8; 32].into();
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.insert_account(kp.secret().clone(), &"test".into())
|
.insert_account(kp.secret().clone(), &"test".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
@ -765,19 +769,20 @@ mod tests {
|
|||||||
assert!(ap
|
assert!(ap
|
||||||
.unlock_account_permanently(kp.address(), "test".into())
|
.unlock_account_permanently(kp.address(), "test".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.unlock_account_temporarily(kp.address(), "test".into())
|
.unlock_account_temporarily(kp.address(), "test".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unlock_account_timer() {
|
fn unlock_account_timer() {
|
||||||
let kp = Random.generate().unwrap();
|
let kp = Random.generate();
|
||||||
let ap = AccountProvider::transient_provider();
|
let ap = AccountProvider::transient_provider();
|
||||||
|
let dummy_msg = [1u8; 32].into();
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.insert_account(kp.secret().clone(), &"test".into())
|
.insert_account(kp.secret().clone(), &"test".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
@ -787,35 +792,35 @@ mod tests {
|
|||||||
assert!(ap
|
assert!(ap
|
||||||
.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60))
|
.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60))
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
|
||||||
ap.unlocked
|
ap.unlocked
|
||||||
.write()
|
.write()
|
||||||
.get_mut(&StoreAccountRef::root(kp.address()))
|
.get_mut(&StoreAccountRef::root(kp.address()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unlock = Unlock::Timed(Instant::now());
|
.unlock = Unlock::Timed(Instant::now());
|
||||||
assert!(ap.sign(kp.address(), None, Default::default()).is_err());
|
assert!(ap.sign(kp.address(), None, dummy_msg).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_sign_and_return_token() {
|
fn should_sign_and_return_token() {
|
||||||
// given
|
// given
|
||||||
let kp = Random.generate().unwrap();
|
let kp = Random.generate();
|
||||||
let ap = AccountProvider::transient_provider();
|
let ap = AccountProvider::transient_provider();
|
||||||
|
let dummy_msg = [1u8; 32].into();
|
||||||
assert!(ap
|
assert!(ap
|
||||||
.insert_account(kp.secret().clone(), &"test".into())
|
.insert_account(kp.secret().clone(), &"test".into())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let (_signature, token) = ap
|
let (_signature, token) = ap
|
||||||
.sign_with_token(kp.address(), "test".into(), Default::default())
|
.sign_with_token(kp.address(), "test".into(), dummy_msg)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
ap.sign_with_token(kp.address(), token.clone(), Default::default())
|
ap.sign_with_token(kp.address(), token.clone(), dummy_msg)
|
||||||
.expect("First usage of token should be correct.");
|
.expect("First usage of token should be correct.");
|
||||||
assert!(
|
assert!(
|
||||||
ap.sign_with_token(kp.address(), token, Default::default())
|
ap.sign_with_token(kp.address(), token, dummy_msg).is_err(),
|
||||||
.is_err(),
|
|
||||||
"Second usage of the same token should fail."
|
"Second usage of the same token should fail."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use std::{
|
|||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethkey::Address;
|
use crypto::publickey::Address;
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
|
|
||||||
use crate::AccountMeta;
|
use crate::AccountMeta;
|
||||||
@ -172,6 +172,7 @@ impl<K: hash::Hash + Eq, V> DiskMap<K, V> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::AddressBook;
|
use super::AddressBook;
|
||||||
use crate::account_data::AccountMeta;
|
use crate::account_data::AccountMeta;
|
||||||
|
use ethereum_types::H160;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
|
|
||||||
@ -179,8 +180,8 @@ mod tests {
|
|||||||
fn should_save_and_reload_address_book() {
|
fn should_save_and_reload_address_book() {
|
||||||
let tempdir = TempDir::new("").unwrap();
|
let tempdir = TempDir::new("").unwrap();
|
||||||
let mut b = AddressBook::new(tempdir.path());
|
let mut b = AddressBook::new(tempdir.path());
|
||||||
b.set_name(1.into(), "One".to_owned());
|
b.set_name(H160::from_low_u64_be(1), "One".to_owned());
|
||||||
b.set_meta(1.into(), "{1:1}".to_owned());
|
b.set_meta(H160::from_low_u64_be(1), "{1:1}".to_owned());
|
||||||
let b = AddressBook::new(tempdir.path());
|
let b = AddressBook::new(tempdir.path());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
b.get(),
|
b.get(),
|
||||||
@ -193,7 +194,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(a, b)| (a.into(), b))
|
.map(|(a, b)| (H160::from_low_u64_be(a), b))
|
||||||
.collect::<HashMap<_, _>>()
|
.collect::<HashMap<_, _>>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -203,10 +204,10 @@ mod tests {
|
|||||||
let tempdir = TempDir::new("").unwrap();
|
let tempdir = TempDir::new("").unwrap();
|
||||||
let mut b = AddressBook::new(tempdir.path());
|
let mut b = AddressBook::new(tempdir.path());
|
||||||
|
|
||||||
b.set_name(1.into(), "One".to_owned());
|
b.set_name(H160::from_low_u64_be(1), "One".to_owned());
|
||||||
b.set_name(2.into(), "Two".to_owned());
|
b.set_name(H160::from_low_u64_be(2), "Two".to_owned());
|
||||||
b.set_name(3.into(), "Three".to_owned());
|
b.set_name(H160::from_low_u64_be(3), "Three".to_owned());
|
||||||
b.remove(2.into());
|
b.remove(H160::from_low_u64_be(2));
|
||||||
|
|
||||||
let b = AddressBook::new(tempdir.path());
|
let b = AddressBook::new(tempdir.path());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -230,7 +231,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(a, b)| (a.into(), b))
|
.map(|(a, b)| (H160::from_low_u64_be(a), b))
|
||||||
.collect::<HashMap<_, _>>()
|
.collect::<HashMap<_, _>>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
crunchy = "0.1.0"
|
crunchy = "0.1.0"
|
||||||
either = "1.0.0"
|
either = "1.0.0"
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
keccak-hash = "0.1"
|
keccak-hash = "0.5.0"
|
||||||
|
tiny-keccak = "2.0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
memmap = "0.6"
|
memmap = "0.6"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
|
@ -21,7 +21,7 @@ use memmap::MmapMut;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use seed_compute::SeedHashCompute;
|
use seed_compute::SeedHashCompute;
|
||||||
|
|
||||||
use shared::{epoch, get_cache_size, to_hex, Node, ETHASH_CACHE_ROUNDS, NODE_BYTES, NODE_DWORDS};
|
use shared::{epoch, get_cache_size, to_hex, Node, ETHASH_CACHE_ROUNDS, NODE_BYTES};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
@ -318,27 +318,22 @@ impl AsRef<[Node]> for NodeCache {
|
|||||||
// out. It counts as a read and causes all writes afterwards to be elided. Yes, really. I know, I
|
// out. It counts as a read and causes all writes afterwards to be elided. Yes, really. I know, I
|
||||||
// want to refactor this to use less `unsafe` as much as the next rustacean.
|
// want to refactor this to use less `unsafe` as much as the next rustacean.
|
||||||
unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) {
|
unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) {
|
||||||
let dst = memory as *mut u8;
|
// We use raw pointers here, see above
|
||||||
|
let dst = slice::from_raw_parts_mut(memory as *mut u8, NODE_BYTES);
|
||||||
|
|
||||||
debug_assert_eq!(ident.len(), 32);
|
debug_assert_eq!(ident.len(), 32);
|
||||||
keccak_512::unchecked(dst, NODE_BYTES, ident.as_ptr(), ident.len());
|
keccak_512::write(&ident[..], dst);
|
||||||
|
|
||||||
for i in 1..num_nodes {
|
for i in 1..num_nodes {
|
||||||
// We use raw pointers here, see above
|
// We use raw pointers here, see above
|
||||||
let dst = memory.offset(i as _) as *mut u8;
|
let dst = slice::from_raw_parts_mut(memory.offset(i as _) as *mut u8, NODE_BYTES);
|
||||||
let src = memory.offset(i as isize - 1) as *mut u8;
|
let src = slice::from_raw_parts(memory.offset(i as isize - 1) as *mut u8, NODE_BYTES);
|
||||||
|
keccak_512::write(src, dst);
|
||||||
keccak_512::unchecked(dst, NODE_BYTES, src, NODE_BYTES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now this is initialized, we can treat it as a slice.
|
// Now this is initialized, we can treat it as a slice.
|
||||||
let nodes: &mut [Node] = slice::from_raw_parts_mut(memory, num_nodes);
|
let nodes: &mut [Node] = slice::from_raw_parts_mut(memory, num_nodes);
|
||||||
|
|
||||||
// For `unroll!`, see below. If the literal in `unroll!` is not the same as the RHS here then
|
|
||||||
// these have got out of sync! Don't let this happen!
|
|
||||||
debug_assert_eq!(NODE_DWORDS, 8);
|
|
||||||
|
|
||||||
// This _should_ get unrolled by the compiler, since it's not using the loop variable.
|
|
||||||
for _ in 0..ETHASH_CACHE_ROUNDS {
|
for _ in 0..ETHASH_CACHE_ROUNDS {
|
||||||
for i in 0..num_nodes {
|
for i in 0..num_nodes {
|
||||||
let data_idx = (num_nodes - 1 + i) % num_nodes;
|
let data_idx = (num_nodes - 1 + i) % num_nodes;
|
||||||
@ -348,11 +343,8 @@ unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) {
|
|||||||
let mut data: Node = nodes.get_unchecked(data_idx).clone();
|
let mut data: Node = nodes.get_unchecked(data_idx).clone();
|
||||||
let rhs: &Node = nodes.get_unchecked(idx);
|
let rhs: &Node = nodes.get_unchecked(idx);
|
||||||
|
|
||||||
unroll! {
|
for (a, b) in data.as_dwords_mut().iter_mut().zip(rhs.as_dwords()) {
|
||||||
for w in 0..8 {
|
*a ^= *b;
|
||||||
*data.as_dwords_mut().get_unchecked_mut(w) ^=
|
|
||||||
*rhs.as_dwords().get_unchecked(w);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data
|
data
|
||||||
|
@ -26,7 +26,7 @@ use seed_compute::SeedHashCompute;
|
|||||||
use shared::*;
|
use shared::*;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use std::{mem, path::Path, ptr};
|
use std::{mem, path::Path};
|
||||||
|
|
||||||
const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4;
|
const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4;
|
||||||
const MIX_NODES: usize = MIX_WORDS / NODE_WORDS;
|
const MIX_NODES: usize = MIX_WORDS / NODE_WORDS;
|
||||||
@ -141,32 +141,25 @@ pub fn quick_get_difficulty(
|
|||||||
mix_hash: &H256,
|
mix_hash: &H256,
|
||||||
progpow: bool,
|
progpow: bool,
|
||||||
) -> H256 {
|
) -> H256 {
|
||||||
unsafe {
|
|
||||||
if progpow {
|
if progpow {
|
||||||
let seed = keccak_f800_short(*header_hash, nonce, [0u32; 8]);
|
let seed = keccak_f800_short(*header_hash, nonce, [0u32; 8]);
|
||||||
keccak_f800_long(*header_hash, seed, mem::transmute(*mix_hash))
|
keccak_f800_long(*header_hash, seed, unsafe { mem::transmute(*mix_hash) })
|
||||||
} else {
|
} else {
|
||||||
// This is safe - the `keccak_512` call below reads the first 40 bytes (which we explicitly set
|
let mut buf = [0u8; 64 + 32];
|
||||||
// with two `copy_nonoverlapping` calls) but writes the first 64, and then we explicitly write
|
|
||||||
// the next 32 bytes before we read the whole thing with `keccak_256`.
|
|
||||||
//
|
|
||||||
// This cannot be elided by the compiler as it doesn't know the implementation of
|
|
||||||
// `keccak_512`.
|
|
||||||
let mut buf: [u8; 64 + 32] = ::mem::MaybeUninit::uninit().assume_init();
|
|
||||||
|
|
||||||
ptr::copy_nonoverlapping(header_hash.as_ptr(), buf.as_mut_ptr(), 32);
|
let hash_len = header_hash.len();
|
||||||
ptr::copy_nonoverlapping(&nonce as *const u64 as *const u8, buf[32..].as_mut_ptr(), 8);
|
buf[..hash_len].copy_from_slice(header_hash);
|
||||||
|
let end = hash_len + mem::size_of::<u64>();
|
||||||
|
buf[hash_len..end].copy_from_slice(&nonce.to_ne_bytes());
|
||||||
|
|
||||||
keccak_512::unchecked(buf.as_mut_ptr(), 64, buf.as_ptr(), 40);
|
keccak_512::inplace_range(&mut buf, 0..end);
|
||||||
ptr::copy_nonoverlapping(mix_hash.as_ptr(), buf[64..].as_mut_ptr(), 32);
|
buf[64..].copy_from_slice(mix_hash);
|
||||||
|
|
||||||
// This is initialized in `keccak_256`
|
let mut hash = [0u8; 32];
|
||||||
let mut hash: [u8; 32] = ::mem::MaybeUninit::uninit().assume_init();
|
keccak_256::write(&buf, &mut hash);
|
||||||
keccak_256::unchecked(hash.as_mut_ptr(), hash.len(), buf.as_ptr(), buf.len());
|
|
||||||
|
|
||||||
hash
|
hash
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the light client data
|
/// Calculate the light client data
|
||||||
@ -214,32 +207,21 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
|
|||||||
// improvements, since I can't imagine that 3-5% of our runtime is taken up by catting two
|
// improvements, since I can't imagine that 3-5% of our runtime is taken up by catting two
|
||||||
// arrays together.
|
// arrays together.
|
||||||
let mut buf: MixBuf = MixBuf {
|
let mut buf: MixBuf = MixBuf {
|
||||||
half_mix: unsafe {
|
half_mix: {
|
||||||
// Pack `header_hash` and `nonce` together
|
// Pack `header_hash` and `nonce` together
|
||||||
// We explicitly write the first 40 bytes, leaving the last 24 as uninitialized. Then
|
let mut out = [0u8; NODE_BYTES];
|
||||||
// `keccak_512` reads the first 40 bytes (4th parameter) and overwrites the entire array,
|
|
||||||
// leaving it fully initialized.
|
|
||||||
let mut out: [u8; NODE_BYTES] = ::mem::MaybeUninit::uninit().assume_init();
|
|
||||||
|
|
||||||
ptr::copy_nonoverlapping(header_hash.as_ptr(), out.as_mut_ptr(), header_hash.len());
|
let hash_len = header_hash.len();
|
||||||
ptr::copy_nonoverlapping(
|
out[..hash_len].copy_from_slice(header_hash);
|
||||||
&nonce as *const u64 as *const u8,
|
let end = hash_len + mem::size_of::<u64>();
|
||||||
out[header_hash.len()..].as_mut_ptr(),
|
out[hash_len..end].copy_from_slice(&nonce.to_ne_bytes());
|
||||||
mem::size_of::<u64>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// compute keccak-512 hash and replicate across mix
|
// compute keccak-512 hash and replicate across mix
|
||||||
keccak_512::unchecked(
|
keccak_512::inplace_range(&mut out, 0..end);
|
||||||
out.as_mut_ptr(),
|
|
||||||
NODE_BYTES,
|
|
||||||
out.as_ptr(),
|
|
||||||
header_hash.len() + mem::size_of::<u64>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Node { bytes: out }
|
Node { bytes: out }
|
||||||
},
|
},
|
||||||
// This is fully initialized before being read, see `let mut compress = ...` below
|
compress_bytes: [0u8; MIX_WORDS],
|
||||||
compress_bytes: unsafe { ::mem::MaybeUninit::uninit().assume_init() },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut mix: [_; MIX_NODES] = [buf.half_mix.clone(), buf.half_mix.clone()];
|
let mut mix: [_; MIX_NODES] = [buf.half_mix.clone(), buf.half_mix.clone()];
|
||||||
@ -263,24 +245,13 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
|
|||||||
fnv_hash(first_val ^ i, mix_words[i as usize % MIX_WORDS]) % num_full_pages
|
fnv_hash(first_val ^ i, mix_words[i as usize % MIX_WORDS]) % num_full_pages
|
||||||
};
|
};
|
||||||
|
|
||||||
unroll! {
|
|
||||||
// MIX_NODES
|
// MIX_NODES
|
||||||
for n in 0..2 {
|
for n in 0..2 {
|
||||||
let tmp_node = calculate_dag_item(
|
let tmp_node = calculate_dag_item(index * MIX_NODES as u32 + n as u32, cache);
|
||||||
index * MIX_NODES as u32 + n as u32,
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
|
|
||||||
unroll! {
|
|
||||||
// NODE_WORDS
|
// NODE_WORDS
|
||||||
for w in 0..16 {
|
for (a, b) in mix[n].as_words_mut().iter_mut().zip(tmp_node.as_words()) {
|
||||||
mix[n].as_words_mut()[w] =
|
*a = fnv_hash(*a, *b);
|
||||||
fnv_hash(
|
|
||||||
mix[n].as_words()[w],
|
|
||||||
tmp_node.as_words()[w],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,16 +259,19 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
|
|||||||
let mix_words: [u32; MIX_WORDS] = unsafe { mem::transmute(mix) };
|
let mix_words: [u32; MIX_WORDS] = unsafe { mem::transmute(mix) };
|
||||||
|
|
||||||
{
|
{
|
||||||
// This is an uninitialized buffer to begin with, but we iterate precisely `compress.len()`
|
// We iterate precisely `compress.len()` times and set each index,
|
||||||
// times and set each index, leaving the array fully initialized. THIS ONLY WORKS ON LITTLE-
|
// leaving the array fully initialized. THIS ONLY WORKS ON LITTLE-ENDIAN MACHINES.
|
||||||
// ENDIAN MACHINES. See a future PR to make this and the rest of the code work correctly on
|
// See a future PR to make this and the rest of the code work correctly on
|
||||||
// big-endian arches like mips.
|
// big-endian arches like mips.
|
||||||
let compress: &mut [u32; MIX_WORDS / 4] =
|
let compress: &mut [u32; MIX_WORDS / 4] =
|
||||||
unsafe { make_const_array!(MIX_WORDS / 4, &mut buf.compress_bytes) };
|
unsafe { make_const_array!(MIX_WORDS / 4, &mut buf.compress_bytes) };
|
||||||
|
#[cfg(target_endian = "big")]
|
||||||
|
{
|
||||||
|
compile_error!("OpenEthereum currently only supports little-endian targets");
|
||||||
|
}
|
||||||
|
|
||||||
// Compress mix
|
// Compress mix
|
||||||
debug_assert_eq!(MIX_WORDS / 4, 8);
|
debug_assert_eq!(MIX_WORDS / 4, 8);
|
||||||
unroll! {
|
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
let w = i * 4;
|
let w = i * 4;
|
||||||
|
|
||||||
@ -308,31 +282,26 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
|
|||||||
compress[i] = reduction;
|
compress[i] = reduction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mix_hash = buf.compress_bytes;
|
let mix_hash = buf.compress_bytes;
|
||||||
|
|
||||||
let value: H256 = {
|
let value: H256 = {
|
||||||
// We can interpret the buffer as an array of `u8`s, since it's `repr(C)`.
|
// We can interpret the buffer as an array of `u8`s, since it's `repr(C)`.
|
||||||
let read_ptr: *const u8 = &buf as *const MixBuf as *const u8;
|
let read_ptr: *const u8 = &buf as *const MixBuf as *const u8;
|
||||||
// We overwrite the second half since `keccak_256` has an internal buffer and so allows
|
let buffer = unsafe {
|
||||||
// overlapping arrays as input.
|
core::slice::from_raw_parts(
|
||||||
let write_ptr: *mut u8 = &mut buf.compress_bytes as *mut [u8; 32] as *mut u8;
|
|
||||||
unsafe {
|
|
||||||
keccak_256::unchecked(
|
|
||||||
write_ptr,
|
|
||||||
buf.compress_bytes.len(),
|
|
||||||
read_ptr,
|
read_ptr,
|
||||||
buf.half_mix.bytes.len() + buf.compress_bytes.len(),
|
buf.half_mix.bytes.len() + buf.compress_bytes.len(),
|
||||||
);
|
)
|
||||||
}
|
};
|
||||||
|
// We overwrite the buf.compress_bytes since `keccak_256` has an internal buffer and so allows
|
||||||
|
// overlapping arrays as input.
|
||||||
|
keccak_256::write(buffer, &mut buf.compress_bytes);
|
||||||
|
|
||||||
buf.compress_bytes
|
buf.compress_bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
ProofOfWork {
|
ProofOfWork { mix_hash, value }
|
||||||
mix_hash: mix_hash,
|
|
||||||
value: value,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use the `simd` crate
|
// TODO: Use the `simd` crate
|
||||||
|
@ -21,46 +21,15 @@ pub type H256 = [u8; 32];
|
|||||||
pub mod keccak_512 {
|
pub mod keccak_512 {
|
||||||
use super::hash;
|
use super::hash;
|
||||||
|
|
||||||
pub use self::hash::keccak_512_unchecked as unchecked;
|
pub use self::hash::{
|
||||||
|
keccak512 as inplace, keccak512_range as inplace_range, keccak_512 as write,
|
||||||
pub fn write(input: &[u8], output: &mut [u8]) {
|
};
|
||||||
hash::keccak_512(input, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inplace(input: &mut [u8]) {
|
|
||||||
// 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_unchecked(
|
|
||||||
input.as_mut_ptr(),
|
|
||||||
input.len(),
|
|
||||||
input.as_ptr(),
|
|
||||||
input.len(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod keccak_256 {
|
pub mod keccak_256 {
|
||||||
use super::hash;
|
use super::hash;
|
||||||
|
|
||||||
pub use self::hash::keccak_256_unchecked as unchecked;
|
pub use self::hash::{
|
||||||
|
keccak256 as inplace, keccak256_range as inplace_range, keccak_256 as write,
|
||||||
#[allow(dead_code)]
|
};
|
||||||
pub fn write(input: &[u8], output: &mut [u8]) {
|
|
||||||
hash::keccak_256(input, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inplace(input: &mut [u8]) {
|
|
||||||
// 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_unchecked(
|
|
||||||
input.as_mut_ptr(),
|
|
||||||
input.len(),
|
|
||||||
input.as_ptr(),
|
|
||||||
input.len(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ extern crate ethereum_types;
|
|||||||
extern crate memmap;
|
extern crate memmap;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
extern crate primal;
|
extern crate primal;
|
||||||
|
extern crate tiny_keccak;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate crunchy;
|
extern crate crunchy;
|
||||||
@ -52,12 +53,13 @@ mod progpow;
|
|||||||
pub use cache::{NodeCacheBuilder, OptimizeFor};
|
pub use cache::{NodeCacheBuilder, OptimizeFor};
|
||||||
use compute::Light;
|
use compute::Light;
|
||||||
pub use compute::{quick_get_difficulty, slow_hash_block_number, ProofOfWork};
|
pub use compute::{quick_get_difficulty, slow_hash_block_number, ProofOfWork};
|
||||||
use ethereum_types::{U256, U512};
|
use ethereum_types::{BigEndianHash, U256, U512};
|
||||||
use keccak::H256;
|
use keccak::H256;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
pub use seed_compute::SeedHashCompute;
|
pub use seed_compute::SeedHashCompute;
|
||||||
pub use shared::ETHASH_EPOCH_LENGTH;
|
pub use shared::ETHASH_EPOCH_LENGTH;
|
||||||
use std::{
|
use std::{
|
||||||
|
convert::TryFrom,
|
||||||
mem,
|
mem,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
@ -168,12 +170,12 @@ impl EthashManager {
|
|||||||
|
|
||||||
/// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`.
|
/// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`.
|
||||||
pub fn boundary_to_difficulty(boundary: ðereum_types::H256) -> U256 {
|
pub fn boundary_to_difficulty(boundary: ðereum_types::H256) -> U256 {
|
||||||
difficulty_to_boundary_aux(&**boundary)
|
difficulty_to_boundary_aux(&boundary.into_uint())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`.
|
/// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`.
|
||||||
pub fn difficulty_to_boundary(difficulty: &U256) -> ethereum_types::H256 {
|
pub fn difficulty_to_boundary(difficulty: &U256) -> ethereum_types::H256 {
|
||||||
difficulty_to_boundary_aux(difficulty).into()
|
BigEndianHash::from_uint(&difficulty_to_boundary_aux(difficulty))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U256 {
|
fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U256 {
|
||||||
@ -184,8 +186,8 @@ fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U
|
|||||||
if difficulty == U512::one() {
|
if difficulty == U512::one() {
|
||||||
U256::max_value()
|
U256::max_value()
|
||||||
} else {
|
} else {
|
||||||
// difficulty > 1, so result should never overflow 256 bits
|
const PROOF: &str = "difficulty > 1, so result never overflows 256 bits; qed";
|
||||||
U256::from((U512::one() << 256) / difficulty)
|
U256::try_from((U512::one() << 256) / difficulty).expect(PROOF)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,12 +212,12 @@ fn test_lru() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_difficulty_to_boundary() {
|
fn test_difficulty_to_boundary() {
|
||||||
use ethereum_types::H256;
|
use ethereum_types::{BigEndianHash, H256};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
difficulty_to_boundary(&U256::from(1)),
|
difficulty_to_boundary(&U256::from(1)),
|
||||||
H256::from(U256::max_value())
|
BigEndianHash::from_uint(&U256::max_value())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
difficulty_to_boundary(&U256::from(2)),
|
difficulty_to_boundary(&U256::from(2)),
|
||||||
@ -243,16 +245,18 @@ fn test_difficulty_to_boundary_regression() {
|
|||||||
boundary_to_difficulty(&difficulty_to_boundary(&difficulty.into()))
|
boundary_to_difficulty(&difficulty_to_boundary(&difficulty.into()))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
H256::from(difficulty),
|
H256::from_low_u64_be(difficulty),
|
||||||
difficulty_to_boundary(&boundary_to_difficulty(&difficulty.into()))
|
difficulty_to_boundary(&boundary_to_difficulty(&H256::from_low_u64_be(difficulty)))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U256::from(difficulty),
|
U256::from(difficulty),
|
||||||
boundary_to_difficulty(&boundary_to_difficulty(&difficulty.into()).into())
|
boundary_to_difficulty(&BigEndianHash::from_uint(&boundary_to_difficulty(
|
||||||
|
&H256::from_low_u64_be(difficulty)
|
||||||
|
))),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
H256::from(difficulty),
|
H256::from_low_u64_be(difficulty),
|
||||||
difficulty_to_boundary(&difficulty_to_boundary(&difficulty.into()).into())
|
difficulty_to_boundary(&difficulty_to_boundary(&difficulty.into()).into_uint())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,5 +270,5 @@ fn test_difficulty_to_boundary_panics_on_zero() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_boundary_to_difficulty_panics_on_zero() {
|
fn test_boundary_to_difficulty_panics_on_zero() {
|
||||||
boundary_to_difficulty(ðereum_types::H256::from(0));
|
boundary_to_difficulty(ðereum_types::H256::zero());
|
||||||
}
|
}
|
||||||
|
@ -17,20 +17,21 @@ url = { version = "2", optional = true }
|
|||||||
ansi_term = "0.10"
|
ansi_term = "0.10"
|
||||||
common-types = { path = "../../ethcore/types" }
|
common-types = { path = "../../ethcore/types" }
|
||||||
error-chain = "0.12"
|
error-chain = "0.12"
|
||||||
ethabi = "6.0"
|
ethabi = "12.0.0"
|
||||||
ethabi-derive = "6.0"
|
ethabi-derive = "12.0.0"
|
||||||
ethabi-contract = "6.0"
|
ethabi-contract = "11.0.0"
|
||||||
ethcore-call-contract = { path = "../../vm/call-contract" }
|
ethcore-call-contract = { path = "../../vm/call-contract" }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
heapsize = "0.4"
|
keccak-hash = "0.5.0"
|
||||||
keccak-hash = "0.1"
|
|
||||||
linked-hash-map = "0.5"
|
linked-hash-map = "0.5"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
|
||||||
parity-runtime = { path = "../../runtime/runtime" }
|
parity-runtime = { path = "../../runtime/runtime" }
|
||||||
|
parity-util-mem = "0.7"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
price-info = { path = "./price-info", optional = true }
|
price-info = { path = "./price-info", optional = true }
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
rlp = { version = "0.4.6" }
|
||||||
trace-time = "0.1"
|
trace-time = "0.1"
|
||||||
transaction-pool = "2.0.1"
|
transaction-pool = "2.0.1"
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ ethcore-io = { path = "../../../runtime/io" }
|
|||||||
ethcore-db = { path = "../../../db/db"}
|
ethcore-db = { path = "../../../db/db"}
|
||||||
kvdb = "0.1"
|
kvdb = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
|
||||||
|
rlp = { version = "0.4.6" }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
@ -29,6 +29,7 @@ extern crate common_types as types;
|
|||||||
extern crate ethcore_db;
|
extern crate ethcore_db;
|
||||||
extern crate ethcore_io as io;
|
extern crate ethcore_io as io;
|
||||||
extern crate kvdb;
|
extern crate kvdb;
|
||||||
|
extern crate parity_crypto as crypto;
|
||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
@ -238,7 +239,7 @@ impl<T: NodeInfo> Drop for LocalDataStore<T> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::NodeInfo;
|
use super::NodeInfo;
|
||||||
|
|
||||||
use ethkey::{Brain, Generator};
|
use ethkey::Brain;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::transaction::{Condition, PendingTransaction, Transaction, TypedTransaction};
|
use types::transaction::{Condition, PendingTransaction, Transaction, TypedTransaction};
|
||||||
|
|
||||||
@ -269,7 +270,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn with_condition() {
|
fn with_condition() {
|
||||||
let keypair = Brain::new("abcd".into()).generate().unwrap();
|
let keypair = Brain::new("abcd".into()).generate();
|
||||||
let transactions: Vec<_> = (0..10u64)
|
let transactions: Vec<_> = (0..10u64)
|
||||||
.map(|nonce| {
|
.map(|nonce| {
|
||||||
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
@ -306,7 +307,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn skips_bad_transactions() {
|
fn skips_bad_transactions() {
|
||||||
let keypair = Brain::new("abcd".into()).generate().unwrap();
|
let keypair = Brain::new("abcd".into()).generate();
|
||||||
let mut transactions: Vec<_> = (0..10u64)
|
let mut transactions: Vec<_> = (0..10u64)
|
||||||
.map(|nonce| {
|
.map(|nonce| {
|
||||||
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
|
@ -92,7 +92,7 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let m = miner();
|
let m = miner();
|
||||||
assert_eq!(m.hashrate(), U256::from(0));
|
assert_eq!(m.hashrate(), U256::from(0));
|
||||||
m.submit_hashrate(U256::from(10), H256::from(1));
|
m.submit_hashrate(U256::from(10), H256::from_low_u64_be(1));
|
||||||
assert_eq!(m.hashrate(), U256::from(10));
|
assert_eq!(m.hashrate(), U256::from(10));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -107,12 +107,12 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let m = miner();
|
let m = miner();
|
||||||
assert_eq!(m.hashrate(), U256::from(0));
|
assert_eq!(m.hashrate(), U256::from(0));
|
||||||
m.submit_hashrate(U256::from(10), H256::from(1));
|
m.submit_hashrate(U256::from(10), H256::from_low_u64_be(1));
|
||||||
assert_eq!(m.hashrate(), U256::from(10));
|
assert_eq!(m.hashrate(), U256::from(10));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
m.submit_hashrate(U256::from(15), H256::from(1));
|
m.submit_hashrate(U256::from(15), H256::from_low_u64_be(1));
|
||||||
m.submit_hashrate(U256::from(20), H256::from(2));
|
m.submit_hashrate(U256::from(20), H256::from_low_u64_be(2));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(m.hashrate(), U256::from(35));
|
assert_eq!(m.hashrate(), U256::from(35));
|
||||||
|
@ -22,13 +22,15 @@
|
|||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
extern crate common_types as types;
|
extern crate common_types as types;
|
||||||
extern crate ethabi;
|
extern crate ethabi;
|
||||||
|
extern crate ethabi_derive;
|
||||||
extern crate ethcore_call_contract as call_contract;
|
extern crate ethcore_call_contract as call_contract;
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate heapsize;
|
|
||||||
extern crate keccak_hash as hash;
|
extern crate keccak_hash as hash;
|
||||||
extern crate linked_hash_map;
|
extern crate linked_hash_map;
|
||||||
|
extern crate parity_crypto as crypto;
|
||||||
extern crate parity_runtime;
|
extern crate parity_runtime;
|
||||||
|
extern crate parity_util_mem;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
#[cfg(feature = "price-info")]
|
#[cfg(feature = "price-info")]
|
||||||
extern crate price_info;
|
extern crate price_info;
|
||||||
@ -38,8 +40,6 @@ extern crate transaction_pool as txpool;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate ethabi_contract;
|
extern crate ethabi_contract;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate ethabi_derive;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate error_chain;
|
extern crate error_chain;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
@ -124,6 +124,7 @@ impl txpool::Listener<Transaction> for Logger {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use ethereum_types::H160;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use txpool::Listener;
|
use txpool::Listener;
|
||||||
use types::transaction;
|
use types::transaction;
|
||||||
@ -166,7 +167,7 @@ mod tests {
|
|||||||
gas_price: 5.into(),
|
gas_price: 5.into(),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
})
|
})
|
||||||
.fake_sign(5.into());
|
.fake_sign(H160::from_low_u64_be(5));
|
||||||
|
|
||||||
Arc::new(Transaction::from_pending_block_transaction(signed))
|
Arc::new(Transaction::from_pending_block_transaction(signed))
|
||||||
}
|
}
|
||||||
|
@ -254,8 +254,8 @@ impl txpool::Listener<Transaction> for LocalTransactionsList {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crypto::publickey::{Generator, Random};
|
||||||
use ethereum_types::U256;
|
use ethereum_types::U256;
|
||||||
use ethkey::{Generator, Random};
|
|
||||||
use txpool::Listener;
|
use txpool::Listener;
|
||||||
use types::transaction;
|
use types::transaction;
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_tx<T: Into<U256>>(nonce: T) -> Arc<Transaction> {
|
fn new_tx<T: Into<U256>>(nonce: T) -> Arc<Transaction> {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let signed = transaction::TypedTransaction::Legacy(transaction::Transaction {
|
let signed = transaction::TypedTransaction::Legacy(transaction::Transaction {
|
||||||
action: transaction::Action::Create,
|
action: transaction::Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Transaction Pool
|
//! Transaction Pool
|
||||||
|
|
||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use heapsize::HeapSizeOf;
|
use parity_util_mem::MallocSizeOfExt;
|
||||||
use txpool;
|
use txpool;
|
||||||
use types::transaction;
|
use types::transaction;
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ impl txpool::VerifiedTransaction for VerifiedTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mem_usage(&self) -> usize {
|
fn mem_usage(&self) -> usize {
|
||||||
self.transaction.heap_size_of_children()
|
self.transaction.malloc_size_of()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sender(&self) -> &Address {
|
fn sender(&self) -> &Address {
|
||||||
|
@ -117,7 +117,7 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use ethkey::{Generator, KeyPair, Random};
|
use crypto::publickey::{Generator, KeyPair, Random};
|
||||||
use pool::{
|
use pool::{
|
||||||
scoring::*,
|
scoring::*,
|
||||||
tests::{
|
tests::{
|
||||||
@ -160,7 +160,7 @@ mod tests {
|
|||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||||
|
|
||||||
// same sender txs
|
// same sender txs
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
|
|
||||||
let same_sender_tx1 = local_tx_verified(
|
let same_sender_tx1 = local_tx_verified(
|
||||||
Tx {
|
Tx {
|
||||||
@ -190,7 +190,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// different sender txs
|
// different sender txs
|
||||||
let sender1 = Random.generate().unwrap();
|
let sender1 = Random.generate();
|
||||||
let different_sender_tx1 = local_tx_verified(
|
let different_sender_tx1 = local_tx_verified(
|
||||||
Tx {
|
Tx {
|
||||||
nonce: 2,
|
nonce: 2,
|
||||||
@ -200,7 +200,7 @@ mod tests {
|
|||||||
&sender1,
|
&sender1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let sender2 = Random.generate().unwrap();
|
let sender2 = Random.generate();
|
||||||
let different_sender_tx2 = local_tx_verified(
|
let different_sender_tx2 = local_tx_verified(
|
||||||
Tx {
|
Tx {
|
||||||
nonce: 1,
|
nonce: 1,
|
||||||
@ -274,7 +274,7 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let txs = vec![tx1, tx2, tx3, tx4]
|
let txs = vec![tx1, tx2, tx3, tx4]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tx| tx.unsigned().sign(keypair.secret(), None).verified())
|
.map(|tx| tx.unsigned().sign(keypair.secret(), None).verified())
|
||||||
@ -440,7 +440,7 @@ mod tests {
|
|||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||||
|
|
||||||
let old_sender = Random.generate().unwrap();
|
let old_sender = Random.generate();
|
||||||
let tx_old_ready_1 = {
|
let tx_old_ready_1 = {
|
||||||
let tx = Tx {
|
let tx = Tx {
|
||||||
nonce: 1,
|
nonce: 1,
|
||||||
@ -518,7 +518,7 @@ mod tests {
|
|||||||
tx.signed().verified()
|
tx.signed().verified()
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_sender = Random.generate().unwrap();
|
let new_sender = Random.generate();
|
||||||
let tx_new_ready_1 = {
|
let tx_new_ready_1 = {
|
||||||
let tx = Tx {
|
let tx = Tx {
|
||||||
nonce: 1,
|
nonce: 1,
|
||||||
@ -586,7 +586,7 @@ mod tests {
|
|||||||
tx.signed().verified()
|
tx.signed().verified()
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_sender = Random.generate().unwrap();
|
let new_sender = Random.generate();
|
||||||
let tx_new_ready_1 = local_tx_verified(
|
let tx_new_ready_1 = local_tx_verified(
|
||||||
Tx {
|
Tx {
|
||||||
nonce: 1,
|
nonce: 1,
|
||||||
@ -641,7 +641,7 @@ mod tests {
|
|||||||
tx.signed().verified()
|
tx.signed().verified()
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_sender = Random.generate().unwrap();
|
let new_sender = Random.generate();
|
||||||
let tx_new_ready_1 = local_tx_verified(
|
let tx_new_ready_1 = local_tx_verified(
|
||||||
Tx {
|
Tx {
|
||||||
nonce: 1,
|
nonce: 1,
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crypto::publickey::{Generator, Random};
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{H256, U256};
|
||||||
use ethkey::{Generator, Random};
|
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use types::transaction::{
|
use types::transaction::{
|
||||||
self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction,
|
self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction,
|
||||||
@ -49,7 +49,7 @@ impl Tx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn signed(self) -> SignedTransaction {
|
pub fn signed(self) -> SignedTransaction {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
self.unsigned().sign(keypair.secret(), None)
|
self.unsigned().sign(keypair.secret(), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ impl Tx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn signed_triple(mut self) -> (SignedTransaction, SignedTransaction, SignedTransaction) {
|
pub fn signed_triple(mut self) -> (SignedTransaction, SignedTransaction, SignedTransaction) {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let tx1 = self.clone().unsigned().sign(keypair.secret(), None);
|
let tx1 = self.clone().unsigned().sign(keypair.secret(), None);
|
||||||
self.nonce += 1;
|
self.nonce += 1;
|
||||||
let tx2 = self.clone().unsigned().sign(keypair.secret(), None);
|
let tx2 = self.clone().unsigned().sign(keypair.secret(), None);
|
||||||
@ -70,7 +70,7 @@ impl Tx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn signed_replacement(mut self) -> (SignedTransaction, SignedTransaction) {
|
pub fn signed_replacement(mut self) -> (SignedTransaction, SignedTransaction) {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let tx1 = self.clone().unsigned().sign(keypair.secret(), None);
|
let tx1 = self.clone().unsigned().sign(keypair.secret(), None);
|
||||||
self.gas_price += 1;
|
self.gas_price += 1;
|
||||||
let tx2 = self.unsigned().sign(keypair.secret(), None);
|
let tx2 = self.unsigned().sign(keypair.secret(), None);
|
||||||
@ -90,7 +90,7 @@ impl Tx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn big_one(self) -> SignedTransaction {
|
pub fn big_one(self) -> SignedTransaction {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let tx = TypedTransaction::Legacy(Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
action: transaction::Action::Create,
|
action: transaction::Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
|
@ -6,8 +6,8 @@ license = "GPL-3.0"
|
|||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
keccak-hash = "0.1"
|
keccak-hash = "0.5.0"
|
||||||
jsonrpc-core = "15.0.0"
|
jsonrpc-core = "15.0.0"
|
||||||
jsonrpc-tcp-server = "15.0.0"
|
jsonrpc-tcp-server = "15.0.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -6,7 +6,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.2"
|
byteorder = "1.2"
|
||||||
ethbloom = "=0.5.0"
|
ethbloom = "0.9.1"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
tiny-keccak = "1.4"
|
tiny-keccak = "1.4"
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ fn bench_blooms_filter_1_million_ok(c: &mut Criterion) {
|
|||||||
database
|
database
|
||||||
.insert_blooms(999_999, iter::once(&Bloom::zero()))
|
.insert_blooms(999_999, iter::once(&Bloom::zero()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let bloom = Bloom::from(0x001);
|
let bloom = Bloom::from_low_u64_be(0x001);
|
||||||
database.insert_blooms(200_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(200_000, iter::once(&bloom)).unwrap();
|
||||||
database.insert_blooms(400_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(400_000, iter::once(&bloom)).unwrap();
|
||||||
database.insert_blooms(600_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(600_000, iter::once(&bloom)).unwrap();
|
||||||
@ -60,8 +60,8 @@ fn bench_blooms_filter_1_million_miss(c: &mut Criterion) {
|
|||||||
database
|
database
|
||||||
.insert_blooms(999_999, iter::once(&Bloom::zero()))
|
.insert_blooms(999_999, iter::once(&Bloom::zero()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let bloom = Bloom::from(0x001);
|
let bloom = Bloom::from_low_u64_be(0x001);
|
||||||
let bad_bloom = Bloom::from(0x0001);
|
let bad_bloom = Bloom::from_low_u64_be(0x0001);
|
||||||
database.insert_blooms(200_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(200_000, iter::once(&bloom)).unwrap();
|
||||||
database.insert_blooms(400_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(400_000, iter::once(&bloom)).unwrap();
|
||||||
database.insert_blooms(600_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(600_000, iter::once(&bloom)).unwrap();
|
||||||
@ -81,8 +81,8 @@ fn bench_blooms_filter_1_million_miss_and_ok(c: &mut Criterion) {
|
|||||||
database
|
database
|
||||||
.insert_blooms(999_999, iter::once(&Bloom::zero()))
|
.insert_blooms(999_999, iter::once(&Bloom::zero()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let bloom = Bloom::from(0x001);
|
let bloom = Bloom::from_low_u64_be(0x001);
|
||||||
let bad_bloom = Bloom::from(0x0001);
|
let bad_bloom = Bloom::from_low_u64_be(0x0001);
|
||||||
database.insert_blooms(200_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(200_000, iter::once(&bloom)).unwrap();
|
||||||
database.insert_blooms(400_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(400_000, iter::once(&bloom)).unwrap();
|
||||||
database.insert_blooms(600_000, iter::once(&bloom)).unwrap();
|
database.insert_blooms(600_000, iter::once(&bloom)).unwrap();
|
||||||
|
@ -346,59 +346,59 @@ mod tests {
|
|||||||
.insert_blooms(
|
.insert_blooms(
|
||||||
0,
|
0,
|
||||||
vec![
|
vec![
|
||||||
Bloom::from(0),
|
Bloom::zero(),
|
||||||
Bloom::from(0x01),
|
Bloom::from_low_u64_be(0x01),
|
||||||
Bloom::from(0x10),
|
Bloom::from_low_u64_be(0x10),
|
||||||
Bloom::from(0x11),
|
Bloom::from_low_u64_be(0x11),
|
||||||
]
|
]
|
||||||
.iter(),
|
.iter(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(0, 3, Some(&Bloom::from(0)))
|
.iterate_matching(0, 3, Some(&Bloom::zero()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![0, 1, 2, 3]);
|
assert_eq!(matches, vec![0, 1, 2, 3]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(0, 4, Some(&Bloom::from(0)))
|
.iterate_matching(0, 4, Some(&Bloom::zero()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![0, 1, 2, 3]);
|
assert_eq!(matches, vec![0, 1, 2, 3]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(1, 3, Some(&Bloom::from(0)))
|
.iterate_matching(1, 3, Some(&Bloom::zero()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![1, 2, 3]);
|
assert_eq!(matches, vec![1, 2, 3]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(1, 2, Some(&Bloom::from(0)))
|
.iterate_matching(1, 2, Some(&Bloom::zero()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![1, 2]);
|
assert_eq!(matches, vec![1, 2]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(0, 3, Some(&Bloom::from(0x01)))
|
.iterate_matching(0, 3, Some(&Bloom::from_low_u64_be(0x01)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![1, 3]);
|
assert_eq!(matches, vec![1, 3]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(0, 3, Some(&Bloom::from(0x10)))
|
.iterate_matching(0, 3, Some(&Bloom::from_low_u64_be(0x10)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![2, 3]);
|
assert_eq!(matches, vec![2, 3]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(2, 2, Some(&Bloom::from(0x10)))
|
.iterate_matching(2, 2, Some(&Bloom::from_low_u64_be(0x10)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -413,52 +413,52 @@ mod tests {
|
|||||||
.insert_blooms(
|
.insert_blooms(
|
||||||
254,
|
254,
|
||||||
vec![
|
vec![
|
||||||
Bloom::from(0x100),
|
Bloom::from_low_u64_be(0x100),
|
||||||
Bloom::from(0x01),
|
Bloom::from_low_u64_be(0x01),
|
||||||
Bloom::from(0x10),
|
Bloom::from_low_u64_be(0x10),
|
||||||
Bloom::from(0x11),
|
Bloom::from_low_u64_be(0x11),
|
||||||
]
|
]
|
||||||
.iter(),
|
.iter(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(0, 257, Some(&Bloom::from(0x01)))
|
.iterate_matching(0, 257, Some(&Bloom::from_low_u64_be(0x01)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![255, 257]);
|
assert_eq!(matches, vec![255, 257]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(0, 258, Some(&Bloom::from(0x100)))
|
.iterate_matching(0, 258, Some(&Bloom::from_low_u64_be(0x100)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![254]);
|
assert_eq!(matches, vec![254]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(0, 256, Some(&Bloom::from(0x01)))
|
.iterate_matching(0, 256, Some(&Bloom::from_low_u64_be(0x01)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![255]);
|
assert_eq!(matches, vec![255]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(255, 255, Some(&Bloom::from(0x01)))
|
.iterate_matching(255, 255, Some(&Bloom::from_low_u64_be(0x01)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![255]);
|
assert_eq!(matches, vec![255]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(256, 256, Some(&Bloom::from(0x10)))
|
.iterate_matching(256, 256, Some(&Bloom::from_low_u64_be(0x10)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(matches, vec![256]);
|
assert_eq!(matches, vec![256]);
|
||||||
|
|
||||||
let matches = database
|
let matches = database
|
||||||
.iterate_matching(256, 257, Some(&Bloom::from(0x10)))
|
.iterate_matching(256, 257, Some(&Bloom::from_low_u64_be(0x10)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -469,10 +469,10 @@ mod tests {
|
|||||||
fn test_db_close() {
|
fn test_db_close() {
|
||||||
let tempdir = TempDir::new("").unwrap();
|
let tempdir = TempDir::new("").unwrap();
|
||||||
let blooms = vec![
|
let blooms = vec![
|
||||||
Bloom::from(0x100),
|
Bloom::from_low_u64_be(0x100),
|
||||||
Bloom::from(0x01),
|
Bloom::from_low_u64_be(0x01),
|
||||||
Bloom::from(0x10),
|
Bloom::from_low_u64_be(0x10),
|
||||||
Bloom::from(0x11),
|
Bloom::from_low_u64_be(0x11),
|
||||||
];
|
];
|
||||||
let mut database = Database::open(tempdir.path()).unwrap();
|
let mut database = Database::open(tempdir.path()).unwrap();
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ impl File {
|
|||||||
let mut file_ref = &self.file;
|
let mut file_ref = &self.file;
|
||||||
file_ref.seek(SeekFrom::Start(pos * 256))?;
|
file_ref.seek(SeekFrom::Start(pos * 256))?;
|
||||||
let mut bloom = ethbloom::Bloom::default();
|
let mut bloom = ethbloom::Bloom::default();
|
||||||
file_ref.read_exact(&mut bloom)?;
|
file_ref.read_exact(bloom.as_bytes_mut())?;
|
||||||
Ok(bloom)
|
Ok(bloom)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ impl File {
|
|||||||
old_bloom.accrue_bloom(bloom);
|
old_bloom.accrue_bloom(bloom);
|
||||||
let mut file_ref = &self.file;
|
let mut file_ref = &self.file;
|
||||||
file_ref.seek(SeekFrom::Start(pos * 256))?;
|
file_ref.seek(SeekFrom::Start(pos * 256))?;
|
||||||
file_ref.write_all(&old_bloom)
|
file_ref.write_all(old_bloom.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace bloom at given position with a new one.
|
/// Replace bloom at given position with a new one.
|
||||||
@ -133,7 +133,7 @@ impl<'a> Iterator for FileIterator<'a> {
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let mut bloom = ethbloom::Bloom::default();
|
let mut bloom = ethbloom::Bloom::default();
|
||||||
match self.file.read_exact(&mut bloom) {
|
match self.file.read_exact(bloom.as_bytes_mut()) {
|
||||||
Ok(_) => Some(Ok(bloom)),
|
Ok(_) => Some(Ok(bloom)),
|
||||||
Err(ref err) if err.kind() == io::ErrorKind::UnexpectedEof => None,
|
Err(ref err) if err.kind() == io::ErrorKind::UnexpectedEof => None,
|
||||||
Err(err) => Some(Err(err)),
|
Err(err) => Some(Err(err)),
|
||||||
@ -151,8 +151,8 @@ mod tests {
|
|||||||
fn test_file() {
|
fn test_file() {
|
||||||
let tempdir = TempDir::new("").unwrap();
|
let tempdir = TempDir::new("").unwrap();
|
||||||
let mut file = File::open(tempdir.path().join("file")).unwrap();
|
let mut file = File::open(tempdir.path().join("file")).unwrap();
|
||||||
file.accrue_bloom(0, &Bloom::from(1)).unwrap();
|
file.accrue_bloom(0, &Bloom::from_low_u64_be(1)).unwrap();
|
||||||
file.flush().unwrap();
|
file.flush().unwrap();
|
||||||
assert_eq!(file.read_bloom(0).unwrap(), Bloom::from(1));
|
assert_eq!(file.read_bloom(0).unwrap(), Bloom::from_low_u64_be(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,12 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
common-types = { path = "../../ethcore/types" }
|
common-types = { path = "../../ethcore/types" }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
heapsize = "0.4"
|
|
||||||
kvdb = "0.1"
|
kvdb = "0.1"
|
||||||
kvdb-rocksdb = "0.1.3"
|
kvdb-rocksdb = "0.1.3"
|
||||||
kvdb-memorydb = "0.1"
|
kvdb-memorydb = "0.1"
|
||||||
|
parity-util-mem = "0.7"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
rlp = { version = "0.4.6" }
|
||||||
rlp_derive = { path = "../../util/rlp-derive" }
|
rlp_derive = { path = "../../util/rlp-derive" }
|
||||||
stats = { path = "../../util/stats" }
|
stats = { path = "../../util/stats" }
|
@ -20,7 +20,7 @@ use kvdb::DBTransaction;
|
|||||||
use kvdb_rocksdb::Database;
|
use kvdb_rocksdb::Database;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use stats::{PrometheusMetrics, PrometheusRegistry};
|
use stats::{PrometheusMetrics, PrometheusRegistry};
|
||||||
use std::{collections::HashMap, hash::Hash, io::Read, ops::Deref};
|
use std::{collections::HashMap, hash::Hash, io::Read};
|
||||||
|
|
||||||
use rlp;
|
use rlp;
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ where
|
|||||||
/// Should be used to get database key associated with given value.
|
/// Should be used to get database key associated with given value.
|
||||||
pub trait Key<T> {
|
pub trait Key<T> {
|
||||||
/// The db key associated with this value.
|
/// The db key associated with this value.
|
||||||
type Target: Deref<Target = [u8]>;
|
type Target: AsRef<[u8]>;
|
||||||
|
|
||||||
/// Returns db key.
|
/// Returns db key.
|
||||||
fn key(&self) -> Self::Target;
|
fn key(&self) -> Self::Target;
|
||||||
@ -96,13 +96,13 @@ pub trait Writable {
|
|||||||
fn write<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>, value: &T)
|
fn write<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>, value: &T)
|
||||||
where
|
where
|
||||||
T: rlp::Encodable,
|
T: rlp::Encodable,
|
||||||
R: Deref<Target = [u8]>;
|
R: AsRef<[u8]>;
|
||||||
|
|
||||||
/// Deletes key from the databse.
|
/// Deletes key from the databse.
|
||||||
fn delete<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>)
|
fn delete<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>)
|
||||||
where
|
where
|
||||||
T: rlp::Encodable,
|
T: rlp::Encodable,
|
||||||
R: Deref<Target = [u8]>;
|
R: AsRef<[u8]>;
|
||||||
|
|
||||||
/// Writes the value into the database and updates the cache.
|
/// Writes the value into the database and updates the cache.
|
||||||
fn write_with_cache<K, T, R>(
|
fn write_with_cache<K, T, R>(
|
||||||
@ -115,7 +115,7 @@ pub trait Writable {
|
|||||||
) where
|
) where
|
||||||
K: Key<T, Target = R> + Hash + Eq,
|
K: Key<T, Target = R> + Hash + Eq,
|
||||||
T: rlp::Encodable,
|
T: rlp::Encodable,
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
self.write(col, &key, &value);
|
self.write(col, &key, &value);
|
||||||
match policy {
|
match policy {
|
||||||
@ -138,7 +138,7 @@ pub trait Writable {
|
|||||||
) where
|
) where
|
||||||
K: Key<T, Target = R> + Hash + Eq,
|
K: Key<T, Target = R> + Hash + Eq,
|
||||||
T: rlp::Encodable,
|
T: rlp::Encodable,
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
match policy {
|
match policy {
|
||||||
CacheUpdatePolicy::Overwrite => {
|
CacheUpdatePolicy::Overwrite => {
|
||||||
@ -166,7 +166,7 @@ pub trait Writable {
|
|||||||
) where
|
) where
|
||||||
K: Key<T, Target = R> + Hash + Eq,
|
K: Key<T, Target = R> + Hash + Eq,
|
||||||
T: rlp::Encodable,
|
T: rlp::Encodable,
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
match policy {
|
match policy {
|
||||||
CacheUpdatePolicy::Overwrite => {
|
CacheUpdatePolicy::Overwrite => {
|
||||||
@ -197,7 +197,7 @@ pub trait Readable {
|
|||||||
fn read<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> Option<T>
|
fn read<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> Option<T>
|
||||||
where
|
where
|
||||||
T: rlp::Decodable,
|
T: rlp::Decodable,
|
||||||
R: Deref<Target = [u8]>;
|
R: AsRef<[u8]>;
|
||||||
|
|
||||||
/// Returns value for given key either in cache or in database.
|
/// Returns value for given key either in cache or in database.
|
||||||
fn read_with_cache<K, T, C>(&self, col: Option<u32>, cache: &RwLock<C>, key: &K) -> Option<T>
|
fn read_with_cache<K, T, C>(&self, col: Option<u32>, cache: &RwLock<C>, key: &K) -> Option<T>
|
||||||
@ -246,13 +246,13 @@ pub trait Readable {
|
|||||||
/// Returns true if given value exists.
|
/// Returns true if given value exists.
|
||||||
fn exists<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> bool
|
fn exists<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> bool
|
||||||
where
|
where
|
||||||
R: Deref<Target = [u8]>;
|
R: AsRef<[u8]>;
|
||||||
|
|
||||||
/// Returns true if given value exists either in cache or in database.
|
/// Returns true if given value exists either in cache or in database.
|
||||||
fn exists_with_cache<K, T, R, C>(&self, col: Option<u32>, cache: &RwLock<C>, key: &K) -> bool
|
fn exists_with_cache<K, T, R, C>(&self, col: Option<u32>, cache: &RwLock<C>, key: &K) -> bool
|
||||||
where
|
where
|
||||||
K: Eq + Hash + Key<T, Target = R>,
|
K: Eq + Hash + Key<T, Target = R>,
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
C: Cache<K, T>,
|
C: Cache<K, T>,
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -270,17 +270,17 @@ impl Writable for DBTransaction {
|
|||||||
fn write<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>, value: &T)
|
fn write<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>, value: &T)
|
||||||
where
|
where
|
||||||
T: rlp::Encodable,
|
T: rlp::Encodable,
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
self.put(col, &key.key(), &rlp::encode(value));
|
self.put(col, key.key().as_ref(), &rlp::encode(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>)
|
fn delete<T, R>(&mut self, col: Option<u32>, key: &dyn Key<T, Target = R>)
|
||||||
where
|
where
|
||||||
T: rlp::Encodable,
|
T: rlp::Encodable,
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
self.delete(col, &key.key());
|
self.delete(col, key.key().as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,25 +288,25 @@ impl<KVDB: kvdb::KeyValueDB + ?Sized> Readable for KVDB {
|
|||||||
fn read<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> Option<T>
|
fn read<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> Option<T>
|
||||||
where
|
where
|
||||||
T: rlp::Decodable,
|
T: rlp::Decodable,
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
self.get(col, &key.key())
|
self.get(col, key.key().as_ref())
|
||||||
.expect(&format!("db get failed, key: {:?}", &key.key() as &[u8]))
|
.expect(&format!("db get failed, key: {:?}", key.key().as_ref()))
|
||||||
.map(|v| rlp::decode(&v).expect("decode db value failed"))
|
.map(|v| rlp::decode(&v).expect("decode db value failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> bool
|
fn exists<T, R>(&self, col: Option<u32>, key: &dyn Key<T, Target = R>) -> bool
|
||||||
where
|
where
|
||||||
R: Deref<Target = [u8]>,
|
R: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
let result = self.get(col, &key.key());
|
let result = self.get(col, key.key().as_ref());
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(v) => v.is_some(),
|
Ok(v) => v.is_some(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
panic!(
|
panic!(
|
||||||
"db get failed, key: {:?}, err: {:?}",
|
"db get failed, key: {:?}, err: {:?}",
|
||||||
&key.key() as &[u8],
|
key.key().as_ref(),
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
//! Blockchain DB extras.
|
//! Blockchain DB extras.
|
||||||
|
|
||||||
use std::{io::Write, ops};
|
use std::io::Write;
|
||||||
|
|
||||||
use common_types::{
|
use common_types::{
|
||||||
engines::epoch::Transition as EpochTransition, receipt::TypedReceipt, BlockNumber,
|
engines::epoch::Transition as EpochTransition, receipt::TypedReceipt, BlockNumber,
|
||||||
};
|
};
|
||||||
use ethereum_types::{H256, H264, U256};
|
use ethereum_types::{H256, H264, U256};
|
||||||
use heapsize::HeapSizeOf;
|
|
||||||
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
|
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
|
||||||
|
use parity_util_mem::MallocSizeOf;
|
||||||
use rlp;
|
use rlp;
|
||||||
use rlp_derive::{RlpDecodable, RlpEncodable};
|
use rlp_derive::{RlpDecodable, RlpEncodable};
|
||||||
|
|
||||||
@ -48,19 +48,17 @@ pub enum ExtrasIndex {
|
|||||||
|
|
||||||
fn with_index(hash: &H256, i: ExtrasIndex) -> H264 {
|
fn with_index(hash: &H256, i: ExtrasIndex) -> H264 {
|
||||||
let mut result = H264::default();
|
let mut result = H264::default();
|
||||||
result[0] = i as u8;
|
result.as_bytes_mut()[0] = i as u8;
|
||||||
(*result)[1..].clone_from_slice(hash);
|
result.as_bytes_mut()[1..].clone_from_slice(hash.as_bytes());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for block number used as a DB key.
|
/// Wrapper for block number used as a DB key.
|
||||||
pub struct BlockNumberKey([u8; 5]);
|
pub struct BlockNumberKey([u8; 5]);
|
||||||
|
|
||||||
impl ops::Deref for BlockNumberKey {
|
impl AsRef<[u8]> for BlockNumberKey {
|
||||||
type Target = [u8];
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
&self.0[..]
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,10 +131,8 @@ pub const EPOCH_KEY_PREFIX: &'static [u8; DB_PREFIX_LEN] = &[
|
|||||||
/// Epoch transitions key
|
/// Epoch transitions key
|
||||||
pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
|
pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
|
||||||
|
|
||||||
impl ops::Deref for EpochTransitionsKey {
|
impl AsRef<[u8]> for EpochTransitionsKey {
|
||||||
type Target = [u8];
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
&self.0[..]
|
&self.0[..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +152,7 @@ impl Key<EpochTransitions> for u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Familial details concerning a block
|
/// Familial details concerning a block
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, MallocSizeOf)]
|
||||||
pub struct BlockDetails {
|
pub struct BlockDetails {
|
||||||
/// Block number
|
/// Block number
|
||||||
pub number: BlockNumber,
|
pub number: BlockNumber,
|
||||||
@ -215,14 +211,8 @@ impl rlp::Decodable for BlockDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapSizeOf for BlockDetails {
|
|
||||||
fn heap_size_of_children(&self) -> usize {
|
|
||||||
self.children.heap_size_of_children()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents address of certain transaction within block
|
/// Represents address of certain transaction within block
|
||||||
#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)]
|
#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable, MallocSizeOf)]
|
||||||
pub struct TransactionAddress {
|
pub struct TransactionAddress {
|
||||||
/// Block hash
|
/// Block hash
|
||||||
pub block_hash: H256,
|
pub block_hash: H256,
|
||||||
@ -230,14 +220,8 @@ pub struct TransactionAddress {
|
|||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapSizeOf for TransactionAddress {
|
|
||||||
fn heap_size_of_children(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contains all block receipts.
|
/// Contains all block receipts.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, MallocSizeOf)]
|
||||||
pub struct BlockReceipts {
|
pub struct BlockReceipts {
|
||||||
/// Block receipts
|
/// Block receipts
|
||||||
pub receipts: Vec<TypedReceipt>,
|
pub receipts: Vec<TypedReceipt>,
|
||||||
@ -262,12 +246,6 @@ impl BlockReceipts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapSizeOf for BlockReceipts {
|
|
||||||
fn heap_size_of_children(&self) -> usize {
|
|
||||||
self.receipts.heap_size_of_children()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Candidate transitions to an epoch with specific number.
|
/// Candidate transitions to an epoch with specific number.
|
||||||
#[derive(Clone, RlpEncodable, RlpDecodable)]
|
#[derive(Clone, RlpEncodable, RlpDecodable)]
|
||||||
pub struct EpochTransitions {
|
pub struct EpochTransitions {
|
||||||
|
@ -7,19 +7,19 @@ license = "GPL3"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-bytes = "0.1"
|
parity-bytes = "0.1"
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
hash-db = "0.11.0"
|
hash-db = "0.11.0"
|
||||||
heapsize = "0.4"
|
|
||||||
keccak-hasher = { path = "../../util/keccak-hasher" }
|
keccak-hasher = { path = "../../util/keccak-hasher" }
|
||||||
ethcore-db = { path = "../../db/db"}
|
ethcore-db = { path = "../../db/db"}
|
||||||
kvdb = "0.1"
|
kvdb = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
memory-db = { path = "../memory-db" }
|
memory-db = { path = "../memory-db" }
|
||||||
|
parity-util-mem = "0.7"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
fastmap = { path = "../../util/fastmap" }
|
fastmap = { path = "../../util/fastmap" }
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
rlp = { version = "0.4.6" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
keccak-hash = "0.1"
|
keccak-hash = "0.5.0"
|
||||||
kvdb-memorydb = "=0.1.0"
|
kvdb-memorydb = "=0.1.0"
|
||||||
|
@ -63,7 +63,7 @@ impl ArchiveDB {
|
|||||||
|
|
||||||
fn payload(&self, key: &H256) -> Option<DBValue> {
|
fn payload(&self, key: &H256) -> Option<DBValue> {
|
||||||
self.backing
|
self.backing
|
||||||
.get(self.column, key)
|
.get(self.column, key.as_bytes())
|
||||||
.expect("Low-level database error. Some issue with your hard disk?")
|
.expect("Low-level database error. Some issue with your hard disk?")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ impl JournalDB for ArchiveDB {
|
|||||||
for i in self.overlay.drain() {
|
for i in self.overlay.drain() {
|
||||||
let (key, (value, rc)) = i;
|
let (key, (value, rc)) = i;
|
||||||
if rc > 0 {
|
if rc > 0 {
|
||||||
batch.put(self.column, &key, &value);
|
batch.put(self.column, key.as_bytes(), &value);
|
||||||
inserts += 1;
|
inserts += 1;
|
||||||
}
|
}
|
||||||
if rc < 0 {
|
if rc < 0 {
|
||||||
@ -180,18 +180,18 @@ impl JournalDB for ArchiveDB {
|
|||||||
for i in self.overlay.drain() {
|
for i in self.overlay.drain() {
|
||||||
let (key, (value, rc)) = i;
|
let (key, (value, rc)) = i;
|
||||||
if rc > 0 {
|
if rc > 0 {
|
||||||
if self.backing.get(self.column, &key)?.is_some() {
|
if self.backing.get(self.column, key.as_bytes())?.is_some() {
|
||||||
return Err(error_key_already_exists(&key));
|
return Err(error_key_already_exists(&key));
|
||||||
}
|
}
|
||||||
batch.put(self.column, &key, &value);
|
batch.put(self.column, key.as_bytes(), &value);
|
||||||
inserts += 1;
|
inserts += 1;
|
||||||
}
|
}
|
||||||
if rc < 0 {
|
if rc < 0 {
|
||||||
assert!(rc == -1);
|
assert!(rc == -1);
|
||||||
if self.backing.get(self.column, &key)?.is_none() {
|
if self.backing.get(self.column, key.as_bytes())?.is_none() {
|
||||||
return Err(error_negatively_reference_hash(&key));
|
return Err(error_negatively_reference_hash(&key));
|
||||||
}
|
}
|
||||||
batch.delete(self.column, &key);
|
batch.delete(self.column, key.as_bytes());
|
||||||
deletes += 1;
|
deletes += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,25 +29,19 @@ use bytes::Bytes;
|
|||||||
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
|
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use hash_db::HashDB;
|
use hash_db::HashDB;
|
||||||
use heapsize::HeapSizeOf;
|
|
||||||
use keccak_hasher::KeccakHasher;
|
use keccak_hasher::KeccakHasher;
|
||||||
use memory_db::*;
|
use memory_db::*;
|
||||||
|
use parity_util_mem::MallocSizeOf;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use rlp::{decode, encode};
|
use rlp::{decode, encode};
|
||||||
use util::{DatabaseKey, DatabaseValueRef, DatabaseValueView};
|
use util::{DatabaseKey, DatabaseValueRef, DatabaseValueView};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, MallocSizeOf)]
|
||||||
struct RefInfo {
|
struct RefInfo {
|
||||||
queue_refs: usize,
|
queue_refs: usize,
|
||||||
in_archive: bool,
|
in_archive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapSizeOf for RefInfo {
|
|
||||||
fn heap_size_of_children(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
enum RemoveFrom {
|
enum RemoveFrom {
|
||||||
Queue,
|
Queue,
|
||||||
@ -133,7 +127,7 @@ impl EarlyMergeDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn morph_key(key: &H256, index: u8) -> Bytes {
|
fn morph_key(key: &H256, index: u8) -> Bytes {
|
||||||
let mut ret = (&**key).to_owned();
|
let mut ret = key.as_bytes().to_owned();
|
||||||
ret.push(index);
|
ret.push(index);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
@ -170,7 +164,7 @@ impl EarlyMergeDB {
|
|||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
// this is the first entry for this node in the journal.
|
// this is the first entry for this node in the journal.
|
||||||
let in_archive = backing
|
let in_archive = backing
|
||||||
.get(col, h)
|
.get(col, h.as_bytes())
|
||||||
.expect("Low-level database error. Some issue with your hard disk?")
|
.expect("Low-level database error. Some issue with your hard disk?")
|
||||||
.is_some();
|
.is_some();
|
||||||
if in_archive {
|
if in_archive {
|
||||||
@ -182,7 +176,7 @@ impl EarlyMergeDB {
|
|||||||
//Self::reset_already_in(&h);
|
//Self::reset_already_in(&h);
|
||||||
assert!(!Self::is_already_in(backing, col, h));
|
assert!(!Self::is_already_in(backing, col, h));
|
||||||
trace!(target: "jdb.fine", " insert({}): New to queue, not in DB: Inserting into queue and DB", h);
|
trace!(target: "jdb.fine", " insert({}): New to queue, not in DB: Inserting into queue and DB", h);
|
||||||
batch.put(col, h, d);
|
batch.put(col, h.as_bytes(), d);
|
||||||
}
|
}
|
||||||
entry.insert(RefInfo {
|
entry.insert(RefInfo {
|
||||||
queue_refs: 1,
|
queue_refs: 1,
|
||||||
@ -258,7 +252,7 @@ impl EarlyMergeDB {
|
|||||||
}
|
}
|
||||||
(1, false) => {
|
(1, false) => {
|
||||||
entry.remove();
|
entry.remove();
|
||||||
batch.delete(col, h);
|
batch.delete(col, h.as_bytes());
|
||||||
trace!(target: "jdb.fine", " remove({}): Not in archive, only 1 ref in queue: Removing from queue and DB", h);
|
trace!(target: "jdb.fine", " remove({}): Not in archive, only 1 ref in queue: Removing from queue and DB", h);
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid value in refs: {:?}", entry.get()),
|
_ => panic!("Invalid value in refs: {:?}", entry.get()),
|
||||||
@ -267,7 +261,7 @@ impl EarlyMergeDB {
|
|||||||
Entry::Vacant(_entry) => {
|
Entry::Vacant(_entry) => {
|
||||||
// Gets removed when moving from 1 to 0 additional refs. Should never be here at 0 additional refs.
|
// Gets removed when moving from 1 to 0 additional refs. Should never be here at 0 additional refs.
|
||||||
//assert!(!Self::is_already_in(db, &h));
|
//assert!(!Self::is_already_in(db, &h));
|
||||||
batch.delete(col, h);
|
batch.delete(col, h.as_bytes());
|
||||||
trace!(target: "jdb.fine", " remove({}): Not in queue - MUST BE IN ARCHIVE: Removing from DB", h);
|
trace!(target: "jdb.fine", " remove({}): Not in queue - MUST BE IN ARCHIVE: Removing from DB", h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,7 +302,7 @@ impl EarlyMergeDB {
|
|||||||
|
|
||||||
fn payload(&self, key: &H256) -> Option<DBValue> {
|
fn payload(&self, key: &H256) -> Option<DBValue> {
|
||||||
self.backing
|
self.backing
|
||||||
.get(self.column, key)
|
.get(self.column, key.as_bytes())
|
||||||
.expect("Low-level database error. Some issue with your hard disk?")
|
.expect("Low-level database error. Some issue with your hard disk?")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,16 +587,16 @@ impl JournalDB for EarlyMergeDB {
|
|||||||
match rc {
|
match rc {
|
||||||
0 => {}
|
0 => {}
|
||||||
1 => {
|
1 => {
|
||||||
if self.backing.get(self.column, &key)?.is_some() {
|
if self.backing.get(self.column, key.as_bytes())?.is_some() {
|
||||||
return Err(error_key_already_exists(&key));
|
return Err(error_key_already_exists(&key));
|
||||||
}
|
}
|
||||||
batch.put(self.column, &key, &value)
|
batch.put(self.column, key.as_bytes(), &value)
|
||||||
}
|
}
|
||||||
-1 => {
|
-1 => {
|
||||||
if self.backing.get(self.column, &key)?.is_none() {
|
if self.backing.get(self.column, key.as_bytes())?.is_none() {
|
||||||
return Err(error_negatively_reference_hash(&key));
|
return Err(error_negatively_reference_hash(&key));
|
||||||
}
|
}
|
||||||
batch.delete(self.column, &key)
|
batch.delete(self.column, key.as_bytes())
|
||||||
}
|
}
|
||||||
_ => panic!("Attempted to inject invalid state."),
|
_ => panic!("Attempted to inject invalid state."),
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
//! `JournalDB` interface and implementation.
|
//! `JournalDB` interface and implementation.
|
||||||
|
|
||||||
extern crate heapsize;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
@ -28,6 +27,7 @@ extern crate keccak_hasher;
|
|||||||
extern crate kvdb;
|
extern crate kvdb;
|
||||||
extern crate memory_db;
|
extern crate memory_db;
|
||||||
extern crate parity_bytes as bytes;
|
extern crate parity_bytes as bytes;
|
||||||
|
extern crate parity_util_mem;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ impl OverlayDB {
|
|||||||
/// Get the refs and value of the given key.
|
/// Get the refs and value of the given key.
|
||||||
fn payload(&self, key: &H256) -> Option<Payload> {
|
fn payload(&self, key: &H256) -> Option<Payload> {
|
||||||
self.backing
|
self.backing
|
||||||
.get(self.column, key)
|
.get(self.column, key.as_bytes())
|
||||||
.expect("Low-level database error. Some issue with your hard disk?")
|
.expect("Low-level database error. Some issue with your hard disk?")
|
||||||
.map(|ref d| decode(d).expect("decoding db value failed"))
|
.map(|ref d| decode(d).expect("decoding db value failed"))
|
||||||
}
|
}
|
||||||
@ -162,10 +162,10 @@ impl OverlayDB {
|
|||||||
payload: &Payload,
|
payload: &Payload,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if payload.count > 0 {
|
if payload.count > 0 {
|
||||||
batch.put(self.column, key, &encode(payload));
|
batch.put(self.column, key.as_bytes(), &encode(payload));
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
batch.delete(self.column, key);
|
batch.delete(self.column, key.as_bytes());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
|
|||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use fastmap::H256FastMap;
|
use fastmap::H256FastMap;
|
||||||
use hash_db::HashDB;
|
use hash_db::HashDB;
|
||||||
use heapsize::HeapSizeOf;
|
|
||||||
use keccak_hasher::KeccakHasher;
|
use keccak_hasher::KeccakHasher;
|
||||||
use memory_db::*;
|
use memory_db::*;
|
||||||
|
use parity_util_mem::MallocSizeOf;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use rlp::{decode, encode, Decodable, DecoderError, Encodable, Rlp, RlpStream};
|
use rlp::{decode, encode, Decodable, DecoderError, Encodable, Rlp, RlpStream};
|
||||||
use util::DatabaseKey;
|
use util::DatabaseKey;
|
||||||
@ -132,19 +132,13 @@ struct JournalOverlay {
|
|||||||
cumulative_size: usize, // cumulative size of all entries.
|
cumulative_size: usize, // cumulative size of all entries.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, MallocSizeOf)]
|
||||||
struct JournalEntry {
|
struct JournalEntry {
|
||||||
id: H256,
|
id: H256,
|
||||||
insertions: Vec<H256>,
|
insertions: Vec<H256>,
|
||||||
deletions: Vec<H256>,
|
deletions: Vec<H256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapSizeOf for JournalEntry {
|
|
||||||
fn heap_size_of_children(&self) -> usize {
|
|
||||||
self.insertions.heap_size_of_children() + self.deletions.heap_size_of_children()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for OverlayRecentDB {
|
impl Clone for OverlayRecentDB {
|
||||||
fn clone(&self) -> OverlayRecentDB {
|
fn clone(&self) -> OverlayRecentDB {
|
||||||
OverlayRecentDB {
|
OverlayRecentDB {
|
||||||
@ -181,7 +175,7 @@ impl OverlayRecentDB {
|
|||||||
|
|
||||||
fn payload(&self, key: &H256) -> Option<DBValue> {
|
fn payload(&self, key: &H256) -> Option<DBValue> {
|
||||||
self.backing
|
self.backing
|
||||||
.get(self.column, key)
|
.get(self.column, key.as_bytes())
|
||||||
.expect("Low-level database error. Some issue with your hard disk?")
|
.expect("Low-level database error. Some issue with your hard disk?")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +250,7 @@ impl OverlayRecentDB {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_short_key(key: &H256) -> H256 {
|
fn to_short_key(key: &H256) -> H256 {
|
||||||
let mut k = H256::new();
|
let mut k = H256::zero();
|
||||||
k[0..DB_PREFIX_LEN].copy_from_slice(&key[0..DB_PREFIX_LEN]);
|
k[0..DB_PREFIX_LEN].copy_from_slice(&key[0..DB_PREFIX_LEN]);
|
||||||
k
|
k
|
||||||
}
|
}
|
||||||
@ -453,7 +447,7 @@ impl JournalDB for OverlayRecentDB {
|
|||||||
|
|
||||||
// apply canon inserts first
|
// apply canon inserts first
|
||||||
for (k, v) in canon_insertions {
|
for (k, v) in canon_insertions {
|
||||||
batch.put(self.column, &k, &v);
|
batch.put(self.column, k.as_bytes(), &v);
|
||||||
journal_overlay.pending_overlay.insert(to_short_key(&k), v);
|
journal_overlay.pending_overlay.insert(to_short_key(&k), v);
|
||||||
}
|
}
|
||||||
// update the overlay
|
// update the overlay
|
||||||
@ -468,7 +462,7 @@ impl JournalDB for OverlayRecentDB {
|
|||||||
// apply canon deletions
|
// apply canon deletions
|
||||||
for k in canon_deletions {
|
for k in canon_deletions {
|
||||||
if !journal_overlay.backing_overlay.contains(&to_short_key(&k)) {
|
if !journal_overlay.backing_overlay.contains(&to_short_key(&k)) {
|
||||||
batch.delete(self.column, &k);
|
batch.delete(self.column, k.as_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -496,12 +490,14 @@ impl JournalDB for OverlayRecentDB {
|
|||||||
|
|
||||||
match rc {
|
match rc {
|
||||||
0 => {}
|
0 => {}
|
||||||
_ if rc > 0 => batch.put(self.column, &key, &value),
|
_ if rc > 0 => batch.put(self.column, key.as_bytes(), &value),
|
||||||
-1 => {
|
-1 => {
|
||||||
if cfg!(debug_assertions) && self.backing.get(self.column, &key)?.is_none() {
|
if cfg!(debug_assertions)
|
||||||
|
&& self.backing.get(self.column, key.as_bytes())?.is_none()
|
||||||
|
{
|
||||||
return Err(error_negatively_reference_hash(&key));
|
return Err(error_negatively_reference_hash(&key));
|
||||||
}
|
}
|
||||||
batch.delete(self.column, &key)
|
batch.delete(self.column, key.as_bytes())
|
||||||
}
|
}
|
||||||
_ => panic!("Attempted to inject invalid state ({})", rc),
|
_ => panic!("Attempted to inject invalid state ({})", rc),
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,10 @@ use super::{traits::JournalDB, LATEST_ERA_KEY};
|
|||||||
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
|
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use hash_db::HashDB;
|
use hash_db::HashDB;
|
||||||
use heapsize::HeapSizeOf;
|
|
||||||
use keccak_hasher::KeccakHasher;
|
use keccak_hasher::KeccakHasher;
|
||||||
use memory_db::MemoryDB;
|
use memory_db::MemoryDB;
|
||||||
use overlaydb::OverlayDB;
|
use overlaydb::OverlayDB;
|
||||||
|
use parity_util_mem::{allocators::new_malloc_size_ops, MallocSizeOf};
|
||||||
use rlp::{decode, encode};
|
use rlp::{decode, encode};
|
||||||
use util::{DatabaseKey, DatabaseValueRef, DatabaseValueView};
|
use util::{DatabaseKey, DatabaseValueRef, DatabaseValueView};
|
||||||
|
|
||||||
@ -121,13 +121,14 @@ impl JournalDB for RefCountedDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_sizes(&self, sizes: &mut BTreeMap<String, usize>) {
|
fn get_sizes(&self, sizes: &mut BTreeMap<String, usize>) {
|
||||||
|
let mut ops = new_malloc_size_ops();
|
||||||
sizes.insert(
|
sizes.insert(
|
||||||
String::from("db_ref_counted_inserts"),
|
String::from("db_ref_counted_inserts"),
|
||||||
self.inserts.heap_size_of_children(),
|
self.inserts.size_of(&mut ops),
|
||||||
);
|
);
|
||||||
sizes.insert(
|
sizes.insert(
|
||||||
String::from("db_ref_counted_removes"),
|
String::from("db_ref_counted_removes"),
|
||||||
self.removes.heap_size_of_children(),
|
self.removes.size_of(&mut ops),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,13 +21,15 @@ repository = "https://github.com/paritytech/parity-common"
|
|||||||
[[bench]]
|
[[bench]]
|
||||||
name = "bench"
|
name = "bench"
|
||||||
harness = false
|
harness = false
|
||||||
[dependencies.hash-db]
|
|
||||||
version = "0.11.0"
|
|
||||||
|
|
||||||
[dependencies.heapsize]
|
[dependencies]
|
||||||
version = "0.4"
|
hash-db = "0.11.0"
|
||||||
|
|
||||||
[dev-dependencies.criterion]
|
[dev-dependencies.criterion]
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
|
||||||
[dev-dependencies.keccak-hasher]
|
[dev-dependencies.keccak-hasher]
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
||||||
|
[dependencies.parity-util-mem]
|
||||||
|
version = "0.7"
|
||||||
|
@ -15,12 +15,13 @@
|
|||||||
//! Reference-counted memory-based `HashDB` implementation.
|
//! Reference-counted memory-based `HashDB` implementation.
|
||||||
|
|
||||||
extern crate hash_db;
|
extern crate hash_db;
|
||||||
extern crate heapsize;
|
extern crate parity_util_mem;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate keccak_hasher;
|
extern crate keccak_hasher;
|
||||||
|
|
||||||
use hash_db::{AsHashDB, AsPlainDB, HashDB, HashDBRef, Hasher as KeyHasher, PlainDB, PlainDBRef};
|
use hash_db::{AsHashDB, AsPlainDB, HashDB, HashDBRef, Hasher as KeyHasher, PlainDB, PlainDBRef};
|
||||||
use heapsize::HeapSizeOf;
|
use parity_util_mem::MallocSizeOf;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::Entry, HashMap},
|
collections::{hash_map::Entry, HashMap},
|
||||||
hash, mem,
|
hash, mem,
|
||||||
@ -233,12 +234,15 @@ where
|
|||||||
impl<H, T> MemoryDB<H, T>
|
impl<H, T> MemoryDB<H, T>
|
||||||
where
|
where
|
||||||
H: KeyHasher,
|
H: KeyHasher,
|
||||||
T: HeapSizeOf,
|
T: MallocSizeOf,
|
||||||
{
|
{
|
||||||
/// Returns the size of allocated heap memory
|
/// Returns the size of allocated heap memory
|
||||||
pub fn mem_used(&self) -> usize {
|
pub fn mem_used(&self) -> usize {
|
||||||
0 //self.data.heap_size_of_children()
|
// TODO: figure out how to call malloc_size_of()
|
||||||
// TODO Reenable above when HeapSizeOf supports arrays.
|
//let mut ops = new_malloc_size_ops();
|
||||||
|
//self.data.size_of(&mut ops)
|
||||||
|
//self.data.malloc_size_of()
|
||||||
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,12 +9,12 @@ license = "GPL-3.0"
|
|||||||
trie-db = "0.11.0"
|
trie-db = "0.11.0"
|
||||||
keccak-hasher = { version = "0.1.1", path = "../../util/keccak-hasher" }
|
keccak-hasher = { version = "0.1.1", path = "../../util/keccak-hasher" }
|
||||||
hash-db = "0.11.0"
|
hash-db = "0.11.0"
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
rlp = { version = "0.4.6" }
|
||||||
parity-bytes = "0.1"
|
parity-bytes = "0.1"
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
elastic-array = "0.10"
|
elastic-array = "0.10"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
memory-db = "0.11.0"
|
memory-db = "0.11.0"
|
||||||
keccak-hash = "0.1.2"
|
keccak-hash = "0.5.0"
|
||||||
journaldb = { path = "../journaldb" }
|
journaldb = { path = "../journaldb" }
|
||||||
|
@ -63,7 +63,7 @@ pub type RlpCodec = RlpNodeCodec<KeccakHasher>;
|
|||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let mut memdb = journaldb::new_memory_db();
|
/// let mut memdb = journaldb::new_memory_db();
|
||||||
/// let mut root = H256::new();
|
/// let mut root = H256::default();
|
||||||
/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap();
|
/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap();
|
||||||
/// let t = TrieDB::new(&memdb, &root).unwrap();
|
/// let t = TrieDB::new(&memdb, &root).unwrap();
|
||||||
/// assert!(t.contains(b"foo").unwrap());
|
/// assert!(t.contains(b"foo").unwrap());
|
||||||
@ -107,7 +107,7 @@ pub type FatDB<'db> = trie::FatDB<'db, KeccakHasher, RlpCodec>;
|
|||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let mut memdb = journaldb::new_memory_db();
|
/// let mut memdb = journaldb::new_memory_db();
|
||||||
/// let mut root = H256::new();
|
/// let mut root = H256::default();
|
||||||
/// let mut t = TrieDBMut::new(&mut memdb, &mut root);
|
/// let mut t = TrieDBMut::new(&mut memdb, &mut root);
|
||||||
/// assert!(t.is_empty());
|
/// assert!(t.is_empty());
|
||||||
/// assert_eq!(*t.root(), KECCAK_NULL_RLP);
|
/// assert_eq!(*t.root(), KECCAK_NULL_RLP);
|
||||||
|
@ -14,9 +14,9 @@ crossbeam-utils = "0.6"
|
|||||||
eip-152 = { version = "0.1", path = "../util/EIP-152" }
|
eip-152 = { version = "0.1", path = "../util/EIP-152" }
|
||||||
env_logger = { version = "0.5", optional = true }
|
env_logger = { version = "0.5", optional = true }
|
||||||
error-chain = { version = "0.12", default-features = false }
|
error-chain = { version = "0.12", default-features = false }
|
||||||
ethabi = "6.0"
|
ethabi = "12.0.0"
|
||||||
ethabi-contract = "6.0"
|
ethabi-contract = "11.0.0"
|
||||||
ethabi-derive = "6.0"
|
ethabi-derive = "12.0.0"
|
||||||
ethash = { path = "../concensus/ethash" }
|
ethash = { path = "../concensus/ethash" }
|
||||||
ethcore-blockchain = { path = "./blockchain" }
|
ethcore-blockchain = { path = "./blockchain" }
|
||||||
ethcore-bloom-journal = { path = "../db/bloom" }
|
ethcore-bloom-journal = { path = "../db/bloom" }
|
||||||
@ -26,16 +26,15 @@ ethcore-db = { path = "../db/db" }
|
|||||||
ethcore-io = { path = "../runtime/io" }
|
ethcore-io = { path = "../runtime/io" }
|
||||||
ethcore-miner = { path = "../concensus/miner" }
|
ethcore-miner = { path = "../concensus/miner" }
|
||||||
ethcore-stratum = { path = "../concensus/miner/stratum", optional = true }
|
ethcore-stratum = { path = "../concensus/miner/stratum", optional = true }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
ethjson = { path = "../ethjson" }
|
ethjson = { path = "../ethjson" }
|
||||||
ethkey = { path = "../accounts/ethkey" }
|
ethkey = { path = "../accounts/ethkey" }
|
||||||
evm = { path = "../vm/evm" }
|
evm = { path = "../vm/evm" }
|
||||||
globset = "0.4"
|
globset = "0.4"
|
||||||
hash-db = "0.11.0"
|
hash-db = "0.11.0"
|
||||||
heapsize = "0.4"
|
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
journaldb = { path = "../db/journaldb" }
|
journaldb = { path = "../db/journaldb" }
|
||||||
keccak-hash = "0.1"
|
keccak-hash = "0.5.0"
|
||||||
keccak-hasher = { path = "../util/keccak-hasher" }
|
keccak-hasher = { path = "../util/keccak-hasher" }
|
||||||
kvdb = "0.1"
|
kvdb = "0.1"
|
||||||
kvdb-memorydb = "0.1"
|
kvdb-memorydb = "0.1"
|
||||||
@ -50,14 +49,17 @@ memory-cache = { path = "../util/memory-cache" }
|
|||||||
memory-db = { path = "../db/memory-db" }
|
memory-db = { path = "../db/memory-db" }
|
||||||
num_cpus = "1.2"
|
num_cpus = "1.2"
|
||||||
parity-bytes = "0.1"
|
parity-bytes = "0.1"
|
||||||
|
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
|
||||||
parity-snappy = "0.1"
|
parity-snappy = "0.1"
|
||||||
|
parity-util-mem = "0.7"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
trie-db = "0.11.0"
|
trie-db = "0.11.0"
|
||||||
patricia-trie-ethereum = { path = "../db/patricia-trie-ethereum" }
|
patricia-trie-ethereum = { path = "../db/patricia-trie-ethereum" }
|
||||||
rand = "0.4"
|
rand = "0.7.3"
|
||||||
|
rand_xorshift = "0.2.0"
|
||||||
rayon = "1.1"
|
rayon = "1.1"
|
||||||
regex = "1.3.9"
|
regex = "1.3.9"
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
rlp = { version = "0.4.6" }
|
||||||
rlp_derive = { path = "../util/rlp-derive" }
|
rlp_derive = { path = "../util/rlp-derive" }
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
@ -87,7 +89,7 @@ kvdb-rocksdb = "0.1.3"
|
|||||||
parity-runtime = { path = "../runtime/runtime" }
|
parity-runtime = { path = "../runtime/runtime" }
|
||||||
rlp_compress = { path = "../util/rlp-compress" }
|
rlp_compress = { path = "../util/rlp-compress" }
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
trie-standardmap = "0.1"
|
trie-standardmap = "0.15.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
parity = ["work-notify", "price-info", "stratum"]
|
parity = ["work-notify", "price-info", "stratum"]
|
||||||
|
@ -25,10 +25,13 @@ extern crate ethereum_types;
|
|||||||
extern crate parity_bytes as bytes;
|
extern crate parity_bytes as bytes;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use bytes::BytesRef;
|
use bytes::BytesRef;
|
||||||
use criterion::{Bencher, Criterion};
|
use criterion::{Bencher, Criterion};
|
||||||
use ethcore::{ethereum::new_byzantium_test_machine, machine::EthereumMachine};
|
use ethcore::{ethereum::new_byzantium_test_machine, machine::EthereumMachine};
|
||||||
use ethcore_builtin::Builtin;
|
use ethcore_builtin::Builtin;
|
||||||
|
use ethereum_types::H160;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -45,7 +48,10 @@ impl<'a> BuiltinBenchmark<'a> {
|
|||||||
fn new(builtin_address: &'static str, input: &str, expected: &str) -> BuiltinBenchmark<'a> {
|
fn new(builtin_address: &'static str, input: &str, expected: &str) -> BuiltinBenchmark<'a> {
|
||||||
let builtins = BYZANTIUM_MACHINE.builtins();
|
let builtins = BYZANTIUM_MACHINE.builtins();
|
||||||
|
|
||||||
let builtin = builtins.get(&builtin_address.into()).unwrap().clone();
|
let builtin = builtins
|
||||||
|
.get(&H160::from_str(builtin_address).unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
let input = FromHex::from_hex(input).unwrap();
|
let input = FromHex::from_hex(input).unwrap();
|
||||||
let expected = FromHex::from_hex(expected).unwrap();
|
let expected = FromHex::from_hex(expected).unwrap();
|
||||||
|
|
||||||
|
@ -12,17 +12,18 @@ ansi_term = "0.11"
|
|||||||
blooms-db = { path = "../../db/blooms-db" }
|
blooms-db = { path = "../../db/blooms-db" }
|
||||||
common-types = { path = "../types" }
|
common-types = { path = "../types" }
|
||||||
ethcore-db = { path = "../../db/db" }
|
ethcore-db = { path = "../../db/db" }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
heapsize = "0.4"
|
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
keccak-hash = "0.1"
|
keccak-hash = "0.5.0"
|
||||||
kvdb = "0.1"
|
kvdb = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
parity-bytes = "0.1"
|
parity-bytes = "0.1"
|
||||||
|
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
|
||||||
|
parity-util-mem = "0.7"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
rand = "0.6"
|
rand = "0.7.3"
|
||||||
rayon = "1.1"
|
rayon = "1.1"
|
||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
rlp = { version = "0.4.6" }
|
||||||
rlp_compress = { path = "../../util/rlp-compress" }
|
rlp_compress = { path = "../../util/rlp-compress" }
|
||||||
rlp_derive = { path = "../../util/rlp-derive" }
|
rlp_derive = { path = "../../util/rlp-derive" }
|
||||||
triehash-ethereum = { version = "0.2", path = "../../util/triehash-ethereum" }
|
triehash-ethereum = { version = "0.2", path = "../../util/triehash-ethereum" }
|
||||||
|
@ -49,10 +49,10 @@ use ethcore_db::{
|
|||||||
CacheUpdatePolicy, Readable, Writable,
|
CacheUpdatePolicy, Readable, Writable,
|
||||||
};
|
};
|
||||||
use ethereum_types::{Bloom, BloomRef, H256, U256};
|
use ethereum_types::{Bloom, BloomRef, H256, U256};
|
||||||
use heapsize::HeapSizeOf;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::{info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
use parity_bytes::Bytes;
|
use parity_bytes::Bytes;
|
||||||
|
use parity_util_mem::{allocators::new_malloc_size_ops, MallocSizeOf};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use rlp::RlpStream;
|
use rlp::RlpStream;
|
||||||
@ -324,7 +324,11 @@ impl BlockProvider for BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read from DB and populate cache
|
// Read from DB and populate cache
|
||||||
let b = self.db.key_value().get(db::COL_HEADERS, hash).expect(
|
let b = self
|
||||||
|
.db
|
||||||
|
.key_value()
|
||||||
|
.get(db::COL_HEADERS, hash.as_bytes())
|
||||||
|
.expect(
|
||||||
"Low level database error when fetching block header data. Some issue with disk?",
|
"Low level database error when fetching block header data. Some issue with disk?",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -357,7 +361,11 @@ impl BlockProvider for BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read from DB and populate cache
|
// Read from DB and populate cache
|
||||||
let b = self.db.key_value().get(db::COL_BODIES, hash).expect(
|
let b = self
|
||||||
|
.db
|
||||||
|
.key_value()
|
||||||
|
.get(db::COL_BODIES, hash.as_bytes())
|
||||||
|
.expect(
|
||||||
"Low level database error when fetching block body data. Some issue with disk?",
|
"Low level database error when fetching block body data. Some issue with disk?",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -672,13 +680,21 @@ impl BlockChain {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut batch = DBTransaction::new();
|
let mut batch = DBTransaction::new();
|
||||||
batch.put(db::COL_HEADERS, &hash, block.header_rlp().as_raw());
|
batch.put(
|
||||||
batch.put(db::COL_BODIES, &hash, &Self::block_to_body(genesis));
|
db::COL_HEADERS,
|
||||||
|
hash.as_bytes(),
|
||||||
|
block.header_rlp().as_raw(),
|
||||||
|
);
|
||||||
|
batch.put(
|
||||||
|
db::COL_BODIES,
|
||||||
|
hash.as_bytes(),
|
||||||
|
&Self::block_to_body(genesis),
|
||||||
|
);
|
||||||
|
|
||||||
batch.write(db::COL_EXTRA, &hash, &details);
|
batch.write(db::COL_EXTRA, &hash, &details);
|
||||||
batch.write(db::COL_EXTRA, &header.number(), &hash);
|
batch.write(db::COL_EXTRA, &header.number(), &hash);
|
||||||
|
|
||||||
batch.put(db::COL_EXTRA, b"best", &hash);
|
batch.put(db::COL_EXTRA, b"best", hash.as_bytes());
|
||||||
bc.db.key_value().write(batch).expect(
|
bc.db.key_value().write(batch).expect(
|
||||||
"Low level database error when fetching 'best' block. Some issue with disk?",
|
"Low level database error when fetching 'best' block. Some issue with disk?",
|
||||||
);
|
);
|
||||||
@ -752,7 +768,7 @@ impl BlockChain {
|
|||||||
if hash != bc.genesis_hash() {
|
if hash != bc.genesis_hash() {
|
||||||
info!("First new block calculated: {:?}", hash);
|
info!("First new block calculated: {:?}", hash);
|
||||||
let mut batch = db.key_value().transaction();
|
let mut batch = db.key_value().transaction();
|
||||||
batch.put(db::COL_EXTRA, b"first", &hash);
|
batch.put(db::COL_EXTRA, b"first", hash.as_bytes());
|
||||||
db.key_value().write(batch).expect("Low level database error when writing 'first' block. Some issue with disk?");
|
db.key_value().write(batch).expect("Low level database error when writing 'first' block. Some issue with disk?");
|
||||||
bc.first_block = Some(hash);
|
bc.first_block = Some(hash);
|
||||||
}
|
}
|
||||||
@ -916,8 +932,8 @@ impl BlockChain {
|
|||||||
let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper());
|
let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper());
|
||||||
|
|
||||||
// store block in db
|
// store block in db
|
||||||
batch.put(db::COL_HEADERS, &hash, &compressed_header);
|
batch.put(db::COL_HEADERS, hash.as_bytes(), &compressed_header);
|
||||||
batch.put(db::COL_BODIES, &hash, &compressed_body);
|
batch.put(db::COL_BODIES, hash.as_bytes(), &compressed_body);
|
||||||
|
|
||||||
let maybe_parent = self.uncommitted_block_details(&block_parent_hash);
|
let maybe_parent = self.uncommitted_block_details(&block_parent_hash);
|
||||||
|
|
||||||
@ -1115,7 +1131,7 @@ impl BlockChain {
|
|||||||
*pending_best_ancient_block = Some(None);
|
*pending_best_ancient_block = Some(None);
|
||||||
} else if block_number > ancient_number {
|
} else if block_number > ancient_number {
|
||||||
trace!(target: "blockchain", "Updating the best ancient block to {}.", block_number);
|
trace!(target: "blockchain", "Updating the best ancient block to {}.", block_number);
|
||||||
batch.put(db::COL_EXTRA, b"ancient", &block_hash);
|
batch.put(db::COL_EXTRA, b"ancient", block_hash.as_bytes());
|
||||||
*pending_best_ancient_block = Some(Some(BestAncientBlock {
|
*pending_best_ancient_block = Some(Some(BestAncientBlock {
|
||||||
hash: *block_hash,
|
hash: *block_hash,
|
||||||
number: block_number,
|
number: block_number,
|
||||||
@ -1301,8 +1317,8 @@ impl BlockChain {
|
|||||||
let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper());
|
let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper());
|
||||||
|
|
||||||
// store block in db
|
// store block in db
|
||||||
batch.put(db::COL_HEADERS, &hash, &compressed_header);
|
batch.put(db::COL_HEADERS, hash.as_bytes(), &compressed_header);
|
||||||
batch.put(db::COL_BODIES, &hash, &compressed_body);
|
batch.put(db::COL_BODIES, hash.as_bytes(), &compressed_body);
|
||||||
|
|
||||||
let info = self.block_info(&block.header_view(), route, &extras);
|
let info = self.block_info(&block.header_view(), route, &extras);
|
||||||
|
|
||||||
@ -1444,7 +1460,7 @@ impl BlockChain {
|
|||||||
{
|
{
|
||||||
let mut best_block = self.pending_best_block.write();
|
let mut best_block = self.pending_best_block.write();
|
||||||
if is_best && update.info.location != BlockLocation::Branch {
|
if is_best && update.info.location != BlockLocation::Branch {
|
||||||
batch.put(db::COL_EXTRA, b"best", &update.info.hash);
|
batch.put(db::COL_EXTRA, b"best", update.info.hash.as_bytes());
|
||||||
*best_block = Some(BestBlock {
|
*best_block = Some(BestBlock {
|
||||||
total_difficulty: update.info.total_difficulty,
|
total_difficulty: update.info.total_difficulty,
|
||||||
header: update.block.decode_header(),
|
header: update.block.decode_header(),
|
||||||
@ -1818,12 +1834,13 @@ impl BlockChain {
|
|||||||
|
|
||||||
/// Get current cache size.
|
/// Get current cache size.
|
||||||
pub fn cache_size(&self) -> CacheSize {
|
pub fn cache_size(&self) -> CacheSize {
|
||||||
|
let mut ops = new_malloc_size_ops();
|
||||||
CacheSize {
|
CacheSize {
|
||||||
blocks: self.block_headers.read().heap_size_of_children()
|
blocks: self.block_headers.read().size_of(&mut ops)
|
||||||
+ self.block_bodies.read().heap_size_of_children(),
|
+ self.block_bodies.read().size_of(&mut ops),
|
||||||
block_details: self.block_details.read().heap_size_of_children(),
|
block_details: self.block_details.read().size_of(&mut ops),
|
||||||
transaction_addresses: self.transaction_addresses.read().heap_size_of_children(),
|
transaction_addresses: self.transaction_addresses.read().size_of(&mut ops),
|
||||||
block_receipts: self.block_receipts.read().heap_size_of_children(),
|
block_receipts: self.block_receipts.read().size_of(&mut ops),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1870,12 +1887,13 @@ impl BlockChain {
|
|||||||
transaction_addresses.shrink_to_fit();
|
transaction_addresses.shrink_to_fit();
|
||||||
block_receipts.shrink_to_fit();
|
block_receipts.shrink_to_fit();
|
||||||
|
|
||||||
block_headers.heap_size_of_children()
|
let mut ops = new_malloc_size_ops();
|
||||||
+ block_bodies.heap_size_of_children()
|
block_headers.size_of(&mut ops)
|
||||||
+ block_details.heap_size_of_children()
|
+ block_bodies.size_of(&mut ops)
|
||||||
+ block_hashes.heap_size_of_children()
|
+ block_details.size_of(&mut ops)
|
||||||
+ transaction_addresses.heap_size_of_children()
|
+ block_hashes.size_of(&mut ops)
|
||||||
+ block_receipts.heap_size_of_children()
|
+ transaction_addresses.size_of(&mut ops)
|
||||||
|
+ block_receipts.size_of(&mut ops)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1918,14 +1936,14 @@ impl BlockChain {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::iter;
|
use std::{iter, str::FromStr};
|
||||||
|
|
||||||
use crate::generator::{BlockBuilder, BlockGenerator, BlockOptions};
|
use crate::generator::{BlockBuilder, BlockGenerator, BlockOptions};
|
||||||
use common_types::{
|
use common_types::{
|
||||||
receipt::{LegacyReceipt, TransactionOutcome, TypedReceipt},
|
receipt::{LegacyReceipt, TransactionOutcome, TypedReceipt},
|
||||||
transaction::{Action, Transaction, TypedTransaction},
|
transaction::{Action, Transaction, TypedTransaction},
|
||||||
};
|
};
|
||||||
use ethkey::Secret;
|
use crypto::publickey::Secret;
|
||||||
use keccak_hash::keccak;
|
use keccak_hash::keccak;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
@ -2492,8 +2510,9 @@ mod tests {
|
|||||||
fn find_transaction_by_hash() {
|
fn find_transaction_by_hash() {
|
||||||
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap();
|
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap();
|
||||||
let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap();
|
let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap();
|
||||||
let b1_hash: H256 =
|
let b1_hash =
|
||||||
"f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3".into();
|
H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let db = new_db();
|
let db = new_db();
|
||||||
let bc = new_chain(encoded::Block::new(genesis), db.clone());
|
let bc = new_chain(encoded::Block::new(genesis), db.clone());
|
||||||
@ -2745,11 +2764,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bloom_filter_simple() {
|
fn test_bloom_filter_simple() {
|
||||||
let bloom_b1: Bloom = "00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000".into();
|
let bloom_b1 = Bloom::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap();
|
||||||
|
|
||||||
let bloom_b2: Bloom = "00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
|
let bloom_b2 = Bloom::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
|
|
||||||
let bloom_ba: Bloom = "00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
|
let bloom_ba = Bloom::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
|
|
||||||
let genesis = BlockBuilder::genesis();
|
let genesis = BlockBuilder::genesis();
|
||||||
let b1 = genesis.add_block_with(|| BlockOptions {
|
let b1 = genesis.add_block_with(|| BlockOptions {
|
||||||
@ -2813,11 +2832,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_insert_unordered() {
|
fn test_insert_unordered() {
|
||||||
let bloom_b1: Bloom = "00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000".into();
|
let bloom_b1 = Bloom::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap();
|
||||||
|
|
||||||
let bloom_b2: Bloom = "00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
|
let bloom_b2 = Bloom::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
|
|
||||||
let bloom_b3: Bloom = "00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
|
let bloom_b3 = Bloom::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
|
|
||||||
let genesis = BlockBuilder::genesis();
|
let genesis = BlockBuilder::genesis();
|
||||||
let b1 = genesis.add_block_with_bloom(bloom_b1);
|
let b1 = genesis.add_block_with_bloom(bloom_b1);
|
||||||
|
@ -70,7 +70,7 @@ impl From<BlockInfo> for ImportRoute {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::ImportRoute;
|
use super::ImportRoute;
|
||||||
use crate::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
|
use crate::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{BigEndianHash, U256};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn import_route_none() {
|
fn import_route_none() {
|
||||||
@ -87,7 +87,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn import_route_branch() {
|
fn import_route_branch() {
|
||||||
let info = BlockInfo {
|
let info = BlockInfo {
|
||||||
hash: H256::from(U256::from(1)),
|
hash: BigEndianHash::from_uint(&U256::from(1)),
|
||||||
number: 0,
|
number: 0,
|
||||||
total_difficulty: U256::from(0),
|
total_difficulty: U256::from(0),
|
||||||
location: BlockLocation::Branch,
|
location: BlockLocation::Branch,
|
||||||
@ -98,7 +98,7 @@ mod tests {
|
|||||||
ImportRoute {
|
ImportRoute {
|
||||||
retracted: vec![],
|
retracted: vec![],
|
||||||
enacted: vec![],
|
enacted: vec![],
|
||||||
omitted: vec![H256::from(U256::from(1))],
|
omitted: vec![BigEndianHash::from_uint(&U256::from(1))],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn import_route_canon_chain() {
|
fn import_route_canon_chain() {
|
||||||
let info = BlockInfo {
|
let info = BlockInfo {
|
||||||
hash: H256::from(U256::from(1)),
|
hash: BigEndianHash::from_uint(&U256::from(1)),
|
||||||
number: 0,
|
number: 0,
|
||||||
total_difficulty: U256::from(0),
|
total_difficulty: U256::from(0),
|
||||||
location: BlockLocation::CanonChain,
|
location: BlockLocation::CanonChain,
|
||||||
@ -116,7 +116,7 @@ mod tests {
|
|||||||
ImportRoute::from(info),
|
ImportRoute::from(info),
|
||||||
ImportRoute {
|
ImportRoute {
|
||||||
retracted: vec![],
|
retracted: vec![],
|
||||||
enacted: vec![H256::from(U256::from(1))],
|
enacted: vec![BigEndianHash::from_uint(&U256::from(1))],
|
||||||
omitted: vec![],
|
omitted: vec![],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -125,21 +125,30 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn import_route_branch_becoming_canon_chain() {
|
fn import_route_branch_becoming_canon_chain() {
|
||||||
let info = BlockInfo {
|
let info = BlockInfo {
|
||||||
hash: H256::from(U256::from(2)),
|
hash: BigEndianHash::from_uint(&U256::from(2)),
|
||||||
number: 0,
|
number: 0,
|
||||||
total_difficulty: U256::from(0),
|
total_difficulty: U256::from(0),
|
||||||
location: BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData {
|
location: BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData {
|
||||||
ancestor: H256::from(U256::from(0)),
|
ancestor: BigEndianHash::from_uint(&U256::from(0)),
|
||||||
enacted: vec![H256::from(U256::from(1))],
|
enacted: vec![BigEndianHash::from_uint(&U256::from(1))],
|
||||||
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
|
retracted: vec![
|
||||||
|
BigEndianHash::from_uint(&U256::from(3)),
|
||||||
|
BigEndianHash::from_uint(&U256::from(4)),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ImportRoute::from(info),
|
ImportRoute::from(info),
|
||||||
ImportRoute {
|
ImportRoute {
|
||||||
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
|
retracted: vec![
|
||||||
enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))],
|
BigEndianHash::from_uint(&U256::from(3)),
|
||||||
|
BigEndianHash::from_uint(&U256::from(4))
|
||||||
|
],
|
||||||
|
enacted: vec![
|
||||||
|
BigEndianHash::from_uint(&U256::from(1)),
|
||||||
|
BigEndianHash::from_uint(&U256::from(2))
|
||||||
|
],
|
||||||
omitted: vec![],
|
omitted: vec![],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
extern crate parity_crypto as crypto;
|
||||||
|
|
||||||
mod best_block;
|
mod best_block;
|
||||||
mod block_info;
|
mod block_info;
|
||||||
mod blockchain;
|
mod blockchain;
|
||||||
|
@ -11,7 +11,7 @@ ethcore = { path = ".." }
|
|||||||
ethcore-blockchain = { path = "../blockchain" }
|
ethcore-blockchain = { path = "../blockchain" }
|
||||||
ethcore-io = { path = "../../runtime/io" }
|
ethcore-io = { path = "../../runtime/io" }
|
||||||
ethcore-sync = { path = "../sync" }
|
ethcore-sync = { path = "../sync" }
|
||||||
ethereum-types = "0.4"
|
ethereum-types = "0.9.2"
|
||||||
kvdb = "0.1"
|
kvdb = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
trace-time = "0.1"
|
trace-time = "0.1"
|
||||||
|
@ -31,8 +31,8 @@ use ethereum_types::Address;
|
|||||||
fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 {
|
fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 {
|
||||||
let mut dst = key.clone();
|
let mut dst = key.clone();
|
||||||
{
|
{
|
||||||
let last_src: &[u8] = &*address_hash;
|
let last_src: &[u8] = address_hash.as_bytes();
|
||||||
let last_dst: &mut [u8] = &mut *dst;
|
let last_dst: &mut [u8] = dst.as_bytes_mut();
|
||||||
for (k, a) in last_dst[12..].iter_mut().zip(&last_src[12..]) {
|
for (k, a) in last_dst[12..].iter_mut().zip(&last_src[12..]) {
|
||||||
*k ^= *a
|
*k ^= *a
|
||||||
}
|
}
|
||||||
|
@ -662,7 +662,7 @@ mod tests {
|
|||||||
db,
|
db,
|
||||||
parent,
|
parent,
|
||||||
last_hashes,
|
last_hashes,
|
||||||
Address::new(),
|
Address::default(),
|
||||||
(3141562.into(), 31415620.into()),
|
(3141562.into(), 31415620.into()),
|
||||||
vec![],
|
vec![],
|
||||||
false,
|
false,
|
||||||
|
@ -40,7 +40,7 @@ use ethereum_types::{Address, H256, H264, U256};
|
|||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use rand::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rlp::{PayloadInfo, Rlp};
|
use rlp::{PayloadInfo, Rlp};
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use trie::{Trie, TrieFactory, TrieSpec};
|
use trie::{Trie, TrieFactory, TrieSpec};
|
||||||
@ -541,7 +541,7 @@ impl Importer {
|
|||||||
{
|
{
|
||||||
trace_time!("import_old_block");
|
trace_time!("import_old_block");
|
||||||
// verify the block, passing the chain for updating the epoch verifier.
|
// verify the block, passing the chain for updating the epoch verifier.
|
||||||
let mut rng = OsRng::new()?;
|
let mut rng = OsRng;
|
||||||
self.ancient_verifier
|
self.ancient_verifier
|
||||||
.verify(&mut rng, &unverified.header, &chain)?;
|
.verify(&mut rng, &unverified.header, &chain)?;
|
||||||
|
|
||||||
@ -1641,8 +1641,8 @@ impl BlockChainReset for Client {
|
|||||||
best_block_hash = current_header.parent_hash();
|
best_block_hash = current_header.parent_hash();
|
||||||
|
|
||||||
let (number, hash) = (current_header.number(), current_header.hash());
|
let (number, hash) = (current_header.number(), current_header.hash());
|
||||||
batch.delete(::db::COL_HEADERS, &hash);
|
batch.delete(::db::COL_HEADERS, hash.as_bytes());
|
||||||
batch.delete(::db::COL_BODIES, &hash);
|
batch.delete(::db::COL_BODIES, hash.as_bytes());
|
||||||
Writable::delete::<BlockDetails, H264>(&mut batch, ::db::COL_EXTRA, &hash);
|
Writable::delete::<BlockDetails, H264>(&mut batch, ::db::COL_EXTRA, &hash);
|
||||||
Writable::delete::<H256, BlockNumberKey>(&mut batch, ::db::COL_EXTRA, &number);
|
Writable::delete::<H256, BlockNumberKey>(&mut batch, ::db::COL_EXTRA, &number);
|
||||||
|
|
||||||
@ -1673,7 +1673,7 @@ impl BlockChainReset for Client {
|
|||||||
best_block_details.children.retain(|h| *h != *last_hash);
|
best_block_details.children.retain(|h| *h != *last_hash);
|
||||||
batch.write(::db::COL_EXTRA, &best_block_hash, &best_block_details);
|
batch.write(::db::COL_EXTRA, &best_block_hash, &best_block_details);
|
||||||
// update the new best block hash
|
// update the new best block hash
|
||||||
batch.put(::db::COL_EXTRA, b"best", &best_block_hash);
|
batch.put(::db::COL_EXTRA, b"best", best_block_hash.as_bytes());
|
||||||
|
|
||||||
self.db
|
self.db
|
||||||
.read()
|
.read()
|
||||||
@ -2203,7 +2203,7 @@ impl BlockChainClient for Client {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(after) = after {
|
if let Some(after) = after {
|
||||||
if let Err(e) = iter.seek(after) {
|
if let Err(e) = iter.seek(after.as_bytes()) {
|
||||||
trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e);
|
trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e);
|
||||||
} else {
|
} else {
|
||||||
// Position the iterator after the `after` element
|
// Position the iterator after the `after` element
|
||||||
@ -2261,7 +2261,7 @@ impl BlockChainClient for Client {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(after) = after {
|
if let Some(after) = after {
|
||||||
if let Err(e) = iter.seek(after) {
|
if let Err(e) = iter.seek(after.as_bytes()) {
|
||||||
trace!(target: "fatdb", "list_storage: Couldn't seek the DB: {:?}", e);
|
trace!(target: "fatdb", "list_storage: Couldn't seek the DB: {:?}", e);
|
||||||
} else {
|
} else {
|
||||||
// Position the iterator after the `after` element
|
// Position the iterator after the `after` element
|
||||||
@ -3404,6 +3404,7 @@ impl PrometheusMetrics for Client {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use blockchain::{BlockProvider, ExtrasInsert};
|
use blockchain::{BlockProvider, ExtrasInsert};
|
||||||
|
use ethereum_types::{H160, H256};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use test_helpers::generate_dummy_client_with_spec_and_data;
|
use test_helpers::generate_dummy_client_with_spec_and_data;
|
||||||
|
|
||||||
@ -3484,7 +3485,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_correct_log_index() {
|
fn should_return_correct_log_index() {
|
||||||
use super::transaction_receipt;
|
use super::transaction_receipt;
|
||||||
use ethkey::KeyPair;
|
use crypto::publickey::KeyPair;
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use types::{
|
use types::{
|
||||||
log_entry::{LocalizedLogEntry, LogEntry},
|
log_entry::{LocalizedLogEntry, LogEntry},
|
||||||
@ -3493,19 +3494,19 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// given
|
// given
|
||||||
let key = KeyPair::from_secret_slice(&keccak("test")).unwrap();
|
let key = KeyPair::from_secret_slice(keccak("test").as_bytes()).unwrap();
|
||||||
let secret = key.secret();
|
let secret = key.secret();
|
||||||
let machine = ::ethereum::new_frontier_test_machine();
|
let machine = ::ethereum::new_frontier_test_machine();
|
||||||
|
|
||||||
let block_number = 1;
|
let block_number = 1;
|
||||||
let block_hash = 5.into();
|
let block_hash = H256::from_low_u64_be(5);
|
||||||
let state_root = 99.into();
|
let state_root = H256::from_low_u64_be(99);
|
||||||
let gas_used = 10.into();
|
let gas_used = 10.into();
|
||||||
let raw_tx = TypedTransaction::Legacy(Transaction {
|
let raw_tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 21000.into(),
|
gas: 21000.into(),
|
||||||
action: Action::Call(10.into()),
|
action: Action::Call(H160::from_low_u64_be(10)),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
});
|
});
|
||||||
@ -3519,12 +3520,12 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let logs = vec![
|
let logs = vec![
|
||||||
LogEntry {
|
LogEntry {
|
||||||
address: 5.into(),
|
address: H160::from_low_u64_be(5),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![],
|
data: vec![],
|
||||||
},
|
},
|
||||||
LogEntry {
|
LogEntry {
|
||||||
address: 15.into(),
|
address: H160::from_low_u64_be(15),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![],
|
data: vec![],
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap},
|
||||||
|
str::FromStr,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrder},
|
atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrder},
|
||||||
Arc,
|
Arc,
|
||||||
@ -26,10 +27,10 @@ use std::{
|
|||||||
|
|
||||||
use blockchain::{BlockReceipts, TreeRoute};
|
use blockchain::{BlockReceipts, TreeRoute};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
use crypto::publickey::{Generator, Random};
|
||||||
use db::{COL_STATE, NUM_COLUMNS};
|
use db::{COL_STATE, NUM_COLUMNS};
|
||||||
use ethcore_miner::pool::VerifiedTransaction;
|
use ethcore_miner::pool::VerifiedTransaction;
|
||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use ethkey::{Generator, Random};
|
|
||||||
use ethtrie;
|
use ethtrie;
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -174,9 +175,9 @@ impl TestBlockChainClient {
|
|||||||
let mut client = TestBlockChainClient {
|
let mut client = TestBlockChainClient {
|
||||||
blocks: RwLock::new(HashMap::new()),
|
blocks: RwLock::new(HashMap::new()),
|
||||||
numbers: RwLock::new(HashMap::new()),
|
numbers: RwLock::new(HashMap::new()),
|
||||||
genesis_hash: H256::new(),
|
genesis_hash: H256::default(),
|
||||||
extra_data: extra_data,
|
extra_data: extra_data,
|
||||||
last_hash: RwLock::new(H256::new()),
|
last_hash: RwLock::new(H256::default()),
|
||||||
difficulty: RwLock::new(spec.genesis_header().difficulty().clone()),
|
difficulty: RwLock::new(spec.genesis_header().difficulty().clone()),
|
||||||
balances: RwLock::new(HashMap::new()),
|
balances: RwLock::new(HashMap::new()),
|
||||||
nonces: RwLock::new(HashMap::new()),
|
nonces: RwLock::new(HashMap::new()),
|
||||||
@ -293,7 +294,7 @@ impl TestBlockChainClient {
|
|||||||
_ => 1,
|
_ => 1,
|
||||||
};
|
};
|
||||||
let mut txs = RlpStream::new_list(num_transactions);
|
let mut txs = RlpStream::new_list(num_transactions);
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let mut nonce = U256::zero();
|
let mut nonce = U256::zero();
|
||||||
|
|
||||||
for _ in 0..num_transactions {
|
for _ in 0..num_transactions {
|
||||||
@ -340,7 +341,7 @@ impl TestBlockChainClient {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.decode()
|
.decode()
|
||||||
.expect("decoding failed");
|
.expect("decoding failed");
|
||||||
header.set_parent_hash(H256::from(42));
|
header.set_parent_hash(H256::from_low_u64_be(42));
|
||||||
let mut rlp = RlpStream::new_list(3);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
rlp.append(&header);
|
rlp.append(&header);
|
||||||
rlp.append_raw(&::rlp::NULL_RLP, 1);
|
rlp.append_raw(&::rlp::NULL_RLP, 1);
|
||||||
@ -370,7 +371,7 @@ impl TestBlockChainClient {
|
|||||||
|
|
||||||
/// Inserts a transaction with given gas price to miners transactions queue.
|
/// Inserts a transaction with given gas price to miners transactions queue.
|
||||||
pub fn insert_transaction_with_gas_price_to_queue(&self, gas_price: U256) -> H256 {
|
pub fn insert_transaction_with_gas_price_to_queue(&self, gas_price: U256) -> H256 {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate();
|
||||||
let tx = TypedTransaction::Legacy(Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
@ -753,7 +754,7 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
.clone()
|
.clone()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|t| t.transaction_hash.unwrap_or(H256::new()))
|
.map(|t| t.transaction_hash.unwrap_or(H256::default()))
|
||||||
.zip(self.execution_result.read().clone().unwrap().into_iter()),
|
.zip(self.execution_result.read().clone().unwrap().into_iter()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -784,7 +785,7 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
.read()
|
.read()
|
||||||
.get(&(address.clone(), position.clone()))
|
.get(&(address.clone(), position.clone()))
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(H256::new),
|
.unwrap_or_else(H256::default),
|
||||||
),
|
),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -902,7 +903,7 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
// works only if blocks are one after another 1 -> 2 -> 3
|
// works only if blocks are one after another 1 -> 2 -> 3
|
||||||
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
|
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
|
||||||
Some(TreeRoute {
|
Some(TreeRoute {
|
||||||
ancestor: H256::new(),
|
ancestor: H256::default(),
|
||||||
index: 0,
|
index: 0,
|
||||||
blocks: {
|
blocks: {
|
||||||
let numbers_read = self.numbers.read();
|
let numbers_read = self.numbers.read();
|
||||||
@ -943,7 +944,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
|
|
||||||
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
|
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
|
||||||
// starts with 'f' ?
|
// starts with 'f' ?
|
||||||
if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") {
|
if *hash
|
||||||
|
> H256::from_str("f000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
let receipt = BlockReceipts::new(vec![TypedReceipt::new(
|
let receipt = BlockReceipts::new(vec![TypedReceipt::new(
|
||||||
TypedTxId::Legacy,
|
TypedTxId::Legacy,
|
||||||
LegacyReceipt::new(
|
LegacyReceipt::new(
|
||||||
|
@ -36,6 +36,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use block::*;
|
use block::*;
|
||||||
use client::{traits::ForceUpdateSealing, EngineClient};
|
use client::{traits::ForceUpdateSealing, EngineClient};
|
||||||
|
use crypto::publickey::{self, Signature};
|
||||||
use engines::{
|
use engines::{
|
||||||
block_reward,
|
block_reward,
|
||||||
block_reward::{BlockRewardContract, RewardKind},
|
block_reward::{BlockRewardContract, RewardKind},
|
||||||
@ -43,8 +44,8 @@ use engines::{
|
|||||||
};
|
};
|
||||||
use error::{BlockError, Error, ErrorKind};
|
use error::{BlockError, Error, ErrorKind};
|
||||||
use ethereum_types::{Address, H256, H520, U128, U256};
|
use ethereum_types::{Address, H256, H520, U128, U256};
|
||||||
|
|
||||||
use ethjson::{self, uint::Uint};
|
use ethjson::{self, uint::Uint};
|
||||||
use ethkey::{self, Signature};
|
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use io::{IoContext, IoHandler, IoService, TimerToken};
|
use io::{IoContext, IoHandler, IoService, TimerToken};
|
||||||
use itertools::{self, Itertools};
|
use itertools::{self, Itertools};
|
||||||
@ -378,14 +379,14 @@ impl EmptyStep {
|
|||||||
let message = keccak(empty_step_rlp(self.step, &self.parent_hash));
|
let message = keccak(empty_step_rlp(self.step, &self.parent_hash));
|
||||||
let correct_proposer = step_proposer(validators, &self.parent_hash, self.step);
|
let correct_proposer = step_proposer(validators, &self.parent_hash, self.step);
|
||||||
|
|
||||||
ethkey::verify_address(&correct_proposer, &self.signature.into(), &message)
|
publickey::verify_address(&correct_proposer, &self.signature.into(), &message)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn author(&self) -> Result<Address, Error> {
|
fn author(&self) -> Result<Address, Error> {
|
||||||
let message = keccak(empty_step_rlp(self.step, &self.parent_hash));
|
let message = keccak(empty_step_rlp(self.step, &self.parent_hash));
|
||||||
let public = ethkey::recover(&self.signature.into(), &message)?;
|
let public = publickey::recover(&self.signature.into(), &message)?;
|
||||||
Ok(ethkey::public_to_address(&public))
|
Ok(publickey::public_to_address(&public))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sealed(&self) -> SealedEmptyStep {
|
fn sealed(&self) -> SealedEmptyStep {
|
||||||
@ -583,7 +584,7 @@ impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
|||||||
fn header_seal_hash(header: &Header, empty_steps_rlp: Option<&[u8]>) -> H256 {
|
fn header_seal_hash(header: &Header, empty_steps_rlp: Option<&[u8]>) -> H256 {
|
||||||
match empty_steps_rlp {
|
match empty_steps_rlp {
|
||||||
Some(empty_steps_rlp) => {
|
Some(empty_steps_rlp) => {
|
||||||
let mut message = header.bare_hash().to_vec();
|
let mut message = header.bare_hash().as_bytes().to_vec();
|
||||||
message.extend_from_slice(empty_steps_rlp);
|
message.extend_from_slice(empty_steps_rlp);
|
||||||
keccak(message)
|
keccak(message)
|
||||||
}
|
}
|
||||||
@ -717,7 +718,7 @@ fn verify_external(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let header_seal_hash = header_seal_hash(header, empty_steps_rlp);
|
let header_seal_hash = header_seal_hash(header, empty_steps_rlp);
|
||||||
!ethkey::verify_address(&correct_proposer, &proposer_signature, &header_seal_hash)?
|
!publickey::verify_address(&correct_proposer, &proposer_signature, &header_seal_hash)?
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_invalid_proposer {
|
if is_invalid_proposer {
|
||||||
@ -1312,7 +1313,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut fields =
|
let mut fields =
|
||||||
vec![encode(&step), encode(&(&H520::from(signature) as &[u8]))];
|
vec![encode(&step), encode(&(H520::from(signature).as_bytes()))];
|
||||||
|
|
||||||
if let Some(empty_steps_rlp) = empty_steps_rlp {
|
if let Some(empty_steps_rlp) = empty_steps_rlp {
|
||||||
fields.push(empty_steps_rlp);
|
fields.push(empty_steps_rlp);
|
||||||
@ -1738,7 +1739,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
.signer
|
.signer
|
||||||
.read()
|
.read()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(ethkey::Error::InvalidAddress)?
|
.ok_or(publickey::Error::InvalidAddress)?
|
||||||
.sign(hash)?)
|
.sign(hash)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1782,13 +1783,13 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use accounts::AccountProvider;
|
use accounts::AccountProvider;
|
||||||
use block::*;
|
use block::*;
|
||||||
|
use crypto::publickey::Signature;
|
||||||
use engines::{
|
use engines::{
|
||||||
validator_set::{SimpleList, TestSet},
|
validator_set::{SimpleList, TestSet},
|
||||||
Engine, EngineError, EthEngine, Seal,
|
Engine, EngineError, EthEngine, Seal,
|
||||||
};
|
};
|
||||||
use error::{Error, ErrorKind};
|
use error::{Error, ErrorKind};
|
||||||
use ethereum_types::{Address, H256, H520, U256};
|
use ethereum_types::{Address, H256, H520, U256};
|
||||||
use ethkey::Signature;
|
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use rlp::encode;
|
use rlp::encode;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
@ -2187,7 +2188,7 @@ mod tests {
|
|||||||
fn set_empty_steps_seal(
|
fn set_empty_steps_seal(
|
||||||
header: &mut Header,
|
header: &mut Header,
|
||||||
step: u64,
|
step: u64,
|
||||||
block_signature: ðkey::Signature,
|
block_signature: &crypto::publickey::Signature,
|
||||||
empty_steps: &[SealedEmptyStep],
|
empty_steps: &[SealedEmptyStep],
|
||||||
) {
|
) {
|
||||||
header.set_seal(vec![
|
header.set_seal(vec![
|
||||||
@ -2539,7 +2540,7 @@ mod tests {
|
|||||||
|
|
||||||
// empty step with invalid step
|
// empty step with invalid step
|
||||||
let empty_steps = vec![SealedEmptyStep {
|
let empty_steps = vec![SealedEmptyStep {
|
||||||
signature: 0.into(),
|
signature: H520::zero(),
|
||||||
step: 2,
|
step: 2,
|
||||||
}];
|
}];
|
||||||
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
||||||
@ -2551,7 +2552,7 @@ mod tests {
|
|||||||
|
|
||||||
// empty step with invalid signature
|
// empty step with invalid signature
|
||||||
let empty_steps = vec![SealedEmptyStep {
|
let empty_steps = vec![SealedEmptyStep {
|
||||||
signature: 0.into(),
|
signature: H520::zero(),
|
||||||
step: 1,
|
step: 1,
|
||||||
}];
|
}];
|
||||||
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
||||||
@ -2703,7 +2704,7 @@ mod tests {
|
|||||||
p.maximum_empty_steps = 0;
|
p.maximum_empty_steps = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
let parent_hash: H256 = 1.into();
|
let parent_hash = H256::from_low_u64_be(1);
|
||||||
let signature = H520::default();
|
let signature = H520::default();
|
||||||
let step = |step: u64| EmptyStep {
|
let step = |step: u64| EmptyStep {
|
||||||
step,
|
step,
|
||||||
|
@ -19,11 +19,11 @@
|
|||||||
use super::validator_set::{new_validator_set, SimpleList, ValidatorSet};
|
use super::validator_set::{new_validator_set, SimpleList, ValidatorSet};
|
||||||
use block::*;
|
use block::*;
|
||||||
use client::EngineClient;
|
use client::EngineClient;
|
||||||
|
use crypto::publickey::{self, Signature};
|
||||||
use engines::{signer::EngineSigner, ConstructedVerifier, Engine, EngineError, Seal};
|
use engines::{signer::EngineSigner, ConstructedVerifier, Engine, EngineError, Seal};
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
use ethereum_types::{H256, H520};
|
use ethereum_types::{H256, H520};
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use ethkey::{self, Signature};
|
|
||||||
use machine::{AuxiliaryData, Call, EthereumMachine};
|
use machine::{AuxiliaryData, Call, EthereumMachine};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
@ -59,7 +59,8 @@ fn verify_external(header: &Header, validators: &dyn ValidatorSet) -> Result<(),
|
|||||||
|
|
||||||
// Check if the signature belongs to a validator, can depend on parent state.
|
// Check if the signature belongs to a validator, can depend on parent state.
|
||||||
let sig = Rlp::new(&header.seal()[0]).as_val::<H520>()?;
|
let sig = Rlp::new(&header.seal()[0]).as_val::<H520>()?;
|
||||||
let signer = ethkey::public_to_address(ðkey::recover(&sig.into(), &header.bare_hash())?);
|
let signer =
|
||||||
|
publickey::public_to_address(&publickey::recover(&sig.into(), &header.bare_hash())?);
|
||||||
|
|
||||||
if *header.author() != signer {
|
if *header.author() != signer {
|
||||||
return Err(EngineError::NotAuthorized(*header.author()).into());
|
return Err(EngineError::NotAuthorized(*header.author()).into());
|
||||||
@ -114,7 +115,7 @@ impl Engine<EthereumMachine> for BasicAuthority {
|
|||||||
if self.validators.contains(header.parent_hash(), author) {
|
if self.validators.contains(header.parent_hash(), author) {
|
||||||
// account should be pernamently unlocked, otherwise sealing will fail
|
// account should be pernamently unlocked, otherwise sealing will fail
|
||||||
if let Ok(signature) = self.sign(header.bare_hash()) {
|
if let Ok(signature) = self.sign(header.bare_hash()) {
|
||||||
return Seal::Regular(vec![::rlp::encode(&(&H520::from(signature) as &[u8]))]);
|
return Seal::Regular(vec![::rlp::encode(&(H520::from(signature).as_bytes()))]);
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable");
|
trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable");
|
||||||
}
|
}
|
||||||
@ -205,7 +206,7 @@ impl Engine<EthereumMachine> for BasicAuthority {
|
|||||||
.signer
|
.signer
|
||||||
.read()
|
.read()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| ethkey::Error::InvalidAddress)?
|
.ok_or_else(|| publickey::Error::InvalidAddress)?
|
||||||
.sign(hash)?)
|
.sign(hash)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,12 +196,13 @@ pub fn apply_block_rewards<M: Machine>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use client::PrepareOpenBlock;
|
use client::PrepareOpenBlock;
|
||||||
use ethereum_types::U256;
|
use ethereum_types::{H160, U256};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use test_helpers::generate_dummy_client_with_spec;
|
use test_helpers::generate_dummy_client_with_spec;
|
||||||
|
|
||||||
use super::{BlockRewardContract, RewardKind};
|
use super::{BlockRewardContract, RewardKind};
|
||||||
use engines::SystemOrCodeCallKind;
|
use engines::SystemOrCodeCallKind;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_reward_contract() {
|
fn block_reward_contract() {
|
||||||
@ -211,13 +212,13 @@ mod test {
|
|||||||
|
|
||||||
// the spec has a block reward contract defined at the given address
|
// the spec has a block reward contract defined at the given address
|
||||||
let block_reward_contract = BlockRewardContract::new_from_address(
|
let block_reward_contract = BlockRewardContract::new_from_address(
|
||||||
"0000000000000000000000000000000000000042".into(),
|
H160::from_str("0000000000000000000000000000000000000042").unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut call = |to, data| {
|
let mut call = |to, data| {
|
||||||
let mut block = client
|
let mut block = client
|
||||||
.prepare_open_block(
|
.prepare_open_block(
|
||||||
"0000000000000000000000000000000000000001".into(),
|
H160::from_str("0000000000000000000000000000000000000001").unwrap(),
|
||||||
(3141562.into(), 31415620.into()),
|
(3141562.into(), 31415620.into()),
|
||||||
vec![],
|
vec![],
|
||||||
)
|
)
|
||||||
@ -244,15 +245,15 @@ mod test {
|
|||||||
// the contract rewards (1000 + kind) for each benefactor
|
// the contract rewards (1000 + kind) for each benefactor
|
||||||
let beneficiaries = vec![
|
let beneficiaries = vec![
|
||||||
(
|
(
|
||||||
"0000000000000000000000000000000000000033".into(),
|
H160::from_str("0000000000000000000000000000000000000033").unwrap(),
|
||||||
RewardKind::Author,
|
RewardKind::Author,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"0000000000000000000000000000000000000034".into(),
|
H160::from_str("0000000000000000000000000000000000000034").unwrap(),
|
||||||
RewardKind::Uncle(1),
|
RewardKind::Uncle(1),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"0000000000000000000000000000000000000035".into(),
|
H160::from_str("0000000000000000000000000000000000000035").unwrap(),
|
||||||
RewardKind::EmptyStep,
|
RewardKind::EmptyStep,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@ -262,15 +263,15 @@ mod test {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
(
|
(
|
||||||
"0000000000000000000000000000000000000033".into(),
|
H160::from_str("0000000000000000000000000000000000000033").unwrap(),
|
||||||
U256::from(1000),
|
U256::from(1000),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"0000000000000000000000000000000000000034".into(),
|
H160::from_str("0000000000000000000000000000000000000034").unwrap(),
|
||||||
U256::from(1000 + 101),
|
U256::from(1000 + 101),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"0000000000000000000000000000000000000035".into(),
|
H160::from_str("0000000000000000000000000000000000000035").unwrap(),
|
||||||
U256::from(1000 + 2),
|
U256::from(1000 + 2),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@ -221,7 +221,7 @@ impl CliqueBlockState {
|
|||||||
}))?
|
}))?
|
||||||
}
|
}
|
||||||
|
|
||||||
let nonce: H64 = decoded_seal[1].into();
|
let nonce = H64::from_slice(decoded_seal[1]);
|
||||||
self.update_signers_on_vote(
|
self.update_signers_on_vote(
|
||||||
VoteType::from_nonce(nonce)?,
|
VoteType::from_nonce(nonce)?,
|
||||||
creator,
|
creator,
|
||||||
|
@ -68,13 +68,13 @@ use std::{
|
|||||||
use super::signer::EngineSigner;
|
use super::signer::EngineSigner;
|
||||||
use block::ExecutedBlock;
|
use block::ExecutedBlock;
|
||||||
use client::{traits::ForceUpdateSealing, BlockId, EngineClient};
|
use client::{traits::ForceUpdateSealing, BlockId, EngineClient};
|
||||||
|
use crypto::publickey::Signature;
|
||||||
use engines::{
|
use engines::{
|
||||||
clique::util::{extract_signers, recover_creator},
|
clique::util::{extract_signers, recover_creator},
|
||||||
Engine, EngineError, Seal,
|
Engine, EngineError, Seal,
|
||||||
};
|
};
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
use ethereum_types::{Address, H160, H256, H64, U256};
|
use ethereum_types::{Address, H160, H256, H64, U256};
|
||||||
use ethkey::Signature;
|
|
||||||
use hash::KECCAK_EMPTY_LIST_RLP;
|
use hash::KECCAK_EMPTY_LIST_RLP;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lru_cache::LruCache;
|
use lru_cache::LruCache;
|
||||||
@ -590,7 +590,7 @@ impl Engine<EthereumMachine> for Clique {
|
|||||||
|
|
||||||
if is_checkpoint && *header.author() != NULL_AUTHOR {
|
if is_checkpoint && *header.author() != NULL_AUTHOR {
|
||||||
return Err(EngineError::CliqueWrongAuthorCheckpoint(Mismatch {
|
return Err(EngineError::CliqueWrongAuthorCheckpoint(Mismatch {
|
||||||
expected: 0.into(),
|
expected: H160::zero(),
|
||||||
found: *header.author(),
|
found: *header.author(),
|
||||||
}))?;
|
}))?;
|
||||||
}
|
}
|
||||||
@ -603,8 +603,8 @@ impl Engine<EthereumMachine> for Clique {
|
|||||||
}))?
|
}))?
|
||||||
}
|
}
|
||||||
|
|
||||||
let mixhash: H256 = seal_fields[0].into();
|
let mixhash = H256::from_slice(seal_fields[0]);
|
||||||
let nonce: H64 = seal_fields[1].into();
|
let nonce = H64::from_slice(seal_fields[1]);
|
||||||
|
|
||||||
// Nonce must be 0x00..0 or 0xff..f
|
// Nonce must be 0x00..0 or 0xff..f
|
||||||
if nonce != NONCE_DROP_VOTE && nonce != NONCE_AUTH_VOTE {
|
if nonce != NONCE_DROP_VOTE && nonce != NONCE_AUTH_VOTE {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user