Merge branch 'master' into ui-2
This commit is contained in:
commit
073564b508
@ -254,7 +254,7 @@ linux-armv7:
|
||||
- cat .cargo/config
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/parity
|
||||
- export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
|
||||
- export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh armhf
|
||||
- cp target/$PLATFORM/release/parity deb/usr/bin/parity
|
||||
@ -300,7 +300,7 @@ linux-arm:
|
||||
- cat .cargo/config
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/parity
|
||||
- export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
|
||||
- export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh armhf
|
||||
- cp target/$PLATFORM/release/parity deb/usr/bin/parity
|
||||
@ -346,7 +346,7 @@ linux-armv6:
|
||||
- cat .cargo/config
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- arm-linux-gnueabi-strip target/$PLATFORM/release/parity
|
||||
- export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
|
||||
- export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- aws configure set aws_access_key_id $s3_key
|
||||
- aws configure set aws_secret_access_key $s3_secret
|
||||
@ -385,7 +385,7 @@ linux-aarch64:
|
||||
- cat .cargo/config
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- aarch64-linux-gnu-strip target/$PLATFORM/release/parity
|
||||
- export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
|
||||
- export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh arm64
|
||||
- cp target/$PLATFORM/release/parity deb/usr/bin/parity
|
||||
|
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -1705,6 +1705,7 @@ dependencies = [
|
||||
"jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||
"jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||
"jsonrpc-minihttp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||
"jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||
"jsonrpc-ws-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"multihash 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1712,6 +1713,7 @@ dependencies = [
|
||||
"parity-reactor 0.1.0",
|
||||
"parity-updater 1.7.0",
|
||||
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rlp 0.1.0",
|
||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1721,6 +1723,7 @@ dependencies = [
|
||||
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stats 0.1.0",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1778,7 +1781,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "parity-ui-precompiled"
|
||||
version = "1.4.0"
|
||||
source = "git+https://github.com/paritytech/js-precompiled.git#4ad25201e9bc25a3873fd1e7a6d8a7b49861c946"
|
||||
source = "git+https://github.com/paritytech/js-precompiled.git#b6fbfc59f044546ccd3b928fb17daa3812ae856e"
|
||||
dependencies = [
|
||||
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -2553,6 +2556,15 @@ dependencies = [
|
||||
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-timer"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-uds"
|
||||
version = "0.1.4"
|
||||
@ -2986,6 +2998,7 @@ dependencies = [
|
||||
"checksum tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)" = "<none>"
|
||||
"checksum tokio-proto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c0d6031f94d78d7b4d509d4a7c5e1cdf524a17e7b08d1c188a83cf720e69808"
|
||||
"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
|
||||
"checksum tokio-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f33def658c14724fc13ec6289b3875a8152ee8ae767a5b1ccbded363b03db8"
|
||||
"checksum tokio-uds 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bd209039933255ea77c6d7a1d18abc20b997d161acb900acca6eb74cdd049f31"
|
||||
"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6"
|
||||
"checksum toml 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a442dfc13508e603c3f763274361db7f79d7469a0e95c411cde53662ab30fc72"
|
||||
|
@ -377,7 +377,7 @@ impl Client {
|
||||
let chain = self.chain.read();
|
||||
// Check the block isn't so old we won't be able to enact it.
|
||||
let best_block_number = chain.best_block_number();
|
||||
if best_block_number >= self.history && header.number() <= best_block_number - self.history {
|
||||
if self.pruning_info().earliest_state > header.number() {
|
||||
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
|
||||
return Err(());
|
||||
}
|
||||
@ -770,7 +770,7 @@ impl Client {
|
||||
let db = self.state_db.lock().boxed_clone();
|
||||
|
||||
// early exit for pruned blocks
|
||||
if db.is_pruned() && self.chain.read().best_block_number() >= block_number + self.history {
|
||||
if db.is_pruned() && self.pruning_info().earliest_state > block_number {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -871,7 +871,7 @@ impl Client {
|
||||
let best_block_number = self.chain_info().best_block_number;
|
||||
let block_number = self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at))?;
|
||||
|
||||
if best_block_number > self.history + block_number && db.is_pruned() {
|
||||
if db.is_pruned() && self.pruning_info().earliest_state > block_number {
|
||||
return Err(snapshot::Error::OldBlockPrunedDB.into());
|
||||
}
|
||||
|
||||
@ -1354,8 +1354,7 @@ impl BlockChainClient for Client {
|
||||
.collect();
|
||||
match (transaction, previous_receipts) {
|
||||
(Some(transaction), Some(previous_receipts)) => {
|
||||
let schedule = self.engine().schedule(block_number);
|
||||
Some(transaction_receipt(&schedule, transaction, previous_receipts))
|
||||
Some(transaction_receipt(self.engine(), transaction, previous_receipts))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -1748,7 +1747,7 @@ impl Drop for Client {
|
||||
|
||||
/// Returns `LocalizedReceipt` given `LocalizedTransaction`
|
||||
/// and a vector of receipts from given block up to transaction index.
|
||||
fn transaction_receipt(schedule: &Schedule, mut tx: LocalizedTransaction, mut receipts: Vec<Receipt>) -> LocalizedReceipt {
|
||||
fn transaction_receipt(engine: &Engine, mut tx: LocalizedTransaction, mut receipts: Vec<Receipt>) -> LocalizedReceipt {
|
||||
assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided.");
|
||||
|
||||
let sender = tx.sender();
|
||||
@ -1772,7 +1771,7 @@ fn transaction_receipt(schedule: &Schedule, mut tx: LocalizedTransaction, mut re
|
||||
gas_used: receipt.gas_used - prior_gas_used,
|
||||
contract_address: match tx.action {
|
||||
Action::Call(_) => None,
|
||||
Action::Create => Some(contract_address(schedule.create_address, &sender, &tx.nonce, &tx.data.sha3()))
|
||||
Action::Create => Some(contract_address(engine.create_address_scheme(block_number), &sender, &tx.nonce, &tx.data.sha3()))
|
||||
},
|
||||
logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry {
|
||||
entry: log,
|
||||
@ -1827,17 +1826,17 @@ mod tests {
|
||||
#[test]
|
||||
fn should_return_correct_log_index() {
|
||||
use super::transaction_receipt;
|
||||
use evm::schedule::Schedule;
|
||||
use ethkey::KeyPair;
|
||||
use log_entry::{LogEntry, LocalizedLogEntry};
|
||||
use receipt::{Receipt, LocalizedReceipt};
|
||||
use transaction::{Transaction, LocalizedTransaction, Action};
|
||||
use util::Hashable;
|
||||
use tests::helpers::TestEngine;
|
||||
|
||||
// given
|
||||
let key = KeyPair::from_secret_slice(&"test".sha3()).unwrap();
|
||||
let secret = key.secret();
|
||||
let schedule = Schedule::new_homestead();
|
||||
let engine = TestEngine::new(0);
|
||||
|
||||
let block_number = 1;
|
||||
let block_hash = 5.into();
|
||||
@ -1881,7 +1880,7 @@ mod tests {
|
||||
}];
|
||||
|
||||
// when
|
||||
let receipt = transaction_receipt(&schedule, transaction, receipts);
|
||||
let receipt = transaction_receipt(&engine, transaction, receipts);
|
||||
|
||||
// then
|
||||
assert_eq!(receipt, LocalizedReceipt {
|
||||
|
@ -48,6 +48,7 @@ use receipt::Receipt;
|
||||
use snapshot::SnapshotComponents;
|
||||
use spec::CommonParams;
|
||||
use transaction::{UnverifiedTransaction, SignedTransaction};
|
||||
use evm::CreateContractAddress;
|
||||
|
||||
use ethkey::Signature;
|
||||
use util::*;
|
||||
@ -294,4 +295,9 @@ pub trait Engine : Sync + Send {
|
||||
fn snapshot_components(&self) -> Option<Box<SnapshotComponents>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns new contract address generation scheme at given block number.
|
||||
fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
|
||||
if number >= self.params().eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ lazy_static! {
|
||||
arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero);
|
||||
arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special);
|
||||
arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special);
|
||||
arr[CREATE_P2SH as usize] = InstructionInfo::new("CREATE_P2SH", 0, 3, 1, true, GasPriceTier::Special);
|
||||
arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 0, 3, 1, true, GasPriceTier::Special);
|
||||
arr
|
||||
};
|
||||
}
|
||||
@ -555,7 +555,7 @@ pub const RETURN: Instruction = 0xf3;
|
||||
/// like CALLCODE but keeps caller's value and sender
|
||||
pub const DELEGATECALL: Instruction = 0xf4;
|
||||
/// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160
|
||||
pub const CREATE_P2SH: Instruction = 0xfb;
|
||||
pub const CREATE2: Instruction = 0xfb;
|
||||
/// halt execution and register account for later deletion
|
||||
pub const SUICIDE: Instruction = 0xff;
|
||||
|
||||
|
@ -223,7 +223,7 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
|
||||
Request::GasMemProvide(gas, mem, Some(requested))
|
||||
},
|
||||
instructions::CREATE | instructions::CREATE_P2SH => {
|
||||
instructions::CREATE | instructions::CREATE2 => {
|
||||
let gas = Gas::from(schedule.create_gas);
|
||||
let mem = mem_needed(stack.peek(1), stack.peek(2))?;
|
||||
|
||||
|
@ -183,7 +183,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let schedule = ext.schedule();
|
||||
|
||||
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
|
||||
(instruction == instructions::CREATE_P2SH && !schedule.have_create_p2sh) {
|
||||
(instruction == instructions::CREATE2 && !schedule.have_create2) {
|
||||
|
||||
return Err(evm::Error::BadInstruction {
|
||||
instruction: instruction
|
||||
@ -268,12 +268,12 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
instructions::JUMPDEST => {
|
||||
// ignore
|
||||
},
|
||||
instructions::CREATE | instructions::CREATE_P2SH => {
|
||||
instructions::CREATE | instructions::CREATE2 => {
|
||||
let endowment = stack.pop_back();
|
||||
let init_off = stack.pop_back();
|
||||
let init_size = stack.pop_back();
|
||||
|
||||
let address_scheme = if instruction == instructions::CREATE { ext.schedule().create_address } else { CreateContractAddress::FromSenderAndCodeHash };
|
||||
let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };
|
||||
let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed");
|
||||
|
||||
let contract_code = self.mem.read_slice(init_off, init_size);
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Cost schedule and other parameterisations for the EVM.
|
||||
use evm::CreateContractAddress;
|
||||
|
||||
/// Definition of the cost schedule and other parameterisations for the EVM.
|
||||
pub struct Schedule {
|
||||
@ -24,7 +23,7 @@ pub struct Schedule {
|
||||
/// Does it have a delegate cal
|
||||
pub have_delegate_call: bool,
|
||||
/// Does it have a CREATE_P2SH instruction
|
||||
pub have_create_p2sh: bool,
|
||||
pub have_create2: bool,
|
||||
/// VM stack limit
|
||||
pub stack_limit: usize,
|
||||
/// Max number of nested calls/creates
|
||||
@ -102,8 +101,6 @@ pub struct Schedule {
|
||||
pub no_empty: bool,
|
||||
/// Kill empty accounts if touched.
|
||||
pub kill_empty: bool,
|
||||
/// Contract address generation scheme
|
||||
pub create_address: CreateContractAddress,
|
||||
}
|
||||
|
||||
impl Schedule {
|
||||
@ -118,11 +115,11 @@ impl Schedule {
|
||||
}
|
||||
|
||||
/// Schedule for the post-EIP-150-era of the Ethereum main net.
|
||||
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, have_create_p2sh: bool) -> Schedule {
|
||||
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, have_metropolis_instructions: bool) -> Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: true,
|
||||
have_delegate_call: true,
|
||||
have_create_p2sh: have_create_p2sh,
|
||||
have_create2: have_metropolis_instructions,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
@ -161,7 +158,6 @@ impl Schedule {
|
||||
sub_gas_cap_divisor: Some(64),
|
||||
no_empty: no_empty,
|
||||
kill_empty: kill_empty,
|
||||
create_address: if have_create_p2sh { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce },
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +170,7 @@ impl Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: efcd,
|
||||
have_delegate_call: hdc,
|
||||
have_create_p2sh: false,
|
||||
have_create2: false,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
@ -213,7 +209,6 @@ impl Schedule {
|
||||
sub_gas_cap_divisor: None,
|
||||
no_empty: false,
|
||||
kill_empty: false,
|
||||
create_address: CreateContractAddress::FromSenderAndNonce,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let (gas_left, output) = match t.action {
|
||||
Action::Create => {
|
||||
let code_hash = t.data.sha3();
|
||||
let new_address = contract_address(schedule.create_address, &sender, &nonce, &code_hash);
|
||||
let new_address = contract_address(self.engine.create_address_scheme(self.info.number), &sender, &nonce, &code_hash);
|
||||
let params = ActionParams {
|
||||
code_address: new_address.clone(),
|
||||
code_hash: code_hash,
|
||||
@ -386,8 +386,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
vm_tracer: &mut V,
|
||||
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
||||
|
||||
let schedule = self.engine.schedule(self.info.number);
|
||||
if schedule.create_address != CreateContractAddress::FromSenderAndNonce && self.state.exists(¶ms.address)? {
|
||||
let scheme = self.engine.create_address_scheme(self.info.number);
|
||||
if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? {
|
||||
return Err(evm::Error::OutOfGas);
|
||||
}
|
||||
|
||||
@ -398,6 +398,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let mut unconfirmed_substate = Substate::new();
|
||||
|
||||
// create contract and transfer value to it if necessary
|
||||
let schedule = self.engine.schedule(self.info.number);
|
||||
let nonce_offset = if schedule.no_empty {1} else {0}.into();
|
||||
let prev_bal = self.state.balance(¶ms.address)?;
|
||||
if let ActionValue::Transfer(val) = params.value {
|
||||
|
@ -1048,7 +1048,7 @@ impl MinerService for Miner {
|
||||
Action::Call(_) => None,
|
||||
Action::Create => {
|
||||
let sender = tx.sender();
|
||||
Some(contract_address(self.engine.schedule(pending.header().number()).create_address, &sender, &tx.nonce, &tx.data.sha3()))
|
||||
Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data.sha3()))
|
||||
}
|
||||
},
|
||||
logs: receipt.logs.clone(),
|
||||
|
@ -238,7 +238,7 @@ pub fn check_proof(
|
||||
/// Reverting a checkpoint with `revert_to_checkpoint` involves copying
|
||||
/// original values from the latest checkpoint back into `cache`. The code
|
||||
/// takes care not to overwrite cached storage while doing that.
|
||||
/// checkpoint can be discateded with `discard_checkpoint`. All of the orignal
|
||||
/// checkpoint can be discarded with `discard_checkpoint`. All of the orignal
|
||||
/// backed-up values are moved into a parent checkpoint (if any).
|
||||
///
|
||||
pub struct State<B: Backend> {
|
||||
@ -433,6 +433,11 @@ impl<B: Backend> State<B> {
|
||||
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
|
||||
}
|
||||
|
||||
/// Determine whether an account exists and has code.
|
||||
pub fn exists_and_has_code(&self, a: &Address) -> trie::Result<bool> {
|
||||
self.ensure_cached(a, RequireCache::CodeSize, false, |a| a.map_or(false, |a| a.code_size().map_or(false, |size| size != 0)))
|
||||
}
|
||||
|
||||
/// Get the balance of account `a`.
|
||||
pub fn balance(&self, a: &Address) -> trie::Result<U256> {
|
||||
self.ensure_cached(a, RequireCache::None, true,
|
||||
|
@ -34,6 +34,9 @@ pub const KEY_LENGTH: usize = 32;
|
||||
pub const KEY_ITERATIONS: usize = 10240;
|
||||
pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2;
|
||||
|
||||
/// Default MAC to use (in RPC).
|
||||
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum ScryptError {
|
||||
// log(N) < r / 16
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "parity.js",
|
||||
"version": "1.7.66",
|
||||
"version": "1.7.68",
|
||||
"main": "release/index.js",
|
||||
"jsnext:main": "src/index.js",
|
||||
"author": "Parity Team <admin@parity.io>",
|
||||
|
@ -50,7 +50,7 @@ disable = false
|
||||
port = 8545
|
||||
interface = "local"
|
||||
cors = "null"
|
||||
apis = ["web3", "eth", "net", "parity", "traces", "rpc"]
|
||||
apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"]
|
||||
hosts = ["none"]
|
||||
|
||||
[websockets]
|
||||
@ -58,13 +58,13 @@ disable = false
|
||||
port = 8546
|
||||
interface = "local"
|
||||
origins = ["none"]
|
||||
apis = ["web3", "eth", "net", "parity", "traces", "rpc"]
|
||||
apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"]
|
||||
hosts = ["none"]
|
||||
|
||||
[ipc]
|
||||
disable = false
|
||||
path = "$HOME/.parity/jsonrpc.ipc"
|
||||
apis = ["web3", "eth", "net", "parity", "parity_accounts", "personal", "traces", "rpc"]
|
||||
apis = ["web3", "eth", "net", "parity", "parity_accounts", "personal", "traces", "rpc", "secretstore"]
|
||||
|
||||
[dapps]
|
||||
disable = false
|
||||
|
@ -165,7 +165,7 @@ usage! {
|
||||
or |c: &Config| otry!(c.rpc).interface.clone(),
|
||||
flag_jsonrpc_cors: Option<String> = None,
|
||||
or |c: &Config| otry!(c.rpc).cors.clone().map(Some),
|
||||
flag_jsonrpc_apis: String = "web3,eth,net,parity,traces,rpc",
|
||||
flag_jsonrpc_apis: String = "web3,eth,net,parity,traces,rpc,secretstore",
|
||||
or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
|
||||
flag_jsonrpc_hosts: String = "none",
|
||||
or |c: &Config| otry!(c.rpc).hosts.as_ref().map(|vec| vec.join(",")),
|
||||
@ -179,7 +179,7 @@ usage! {
|
||||
or |c: &Config| otry!(c.websockets).port.clone(),
|
||||
flag_ws_interface: String = "local",
|
||||
or |c: &Config| otry!(c.websockets).interface.clone(),
|
||||
flag_ws_apis: String = "web3,eth,net,parity,traces,rpc",
|
||||
flag_ws_apis: String = "web3,eth,net,parity,traces,rpc,secretstore",
|
||||
or |c: &Config| otry!(c.websockets).apis.as_ref().map(|vec| vec.join(",")),
|
||||
flag_ws_origins: String = "none",
|
||||
or |c: &Config| otry!(c.websockets).origins.as_ref().map(|vec| vec.join(",")),
|
||||
@ -191,7 +191,7 @@ usage! {
|
||||
or |c: &Config| otry!(c.ipc).disable.clone(),
|
||||
flag_ipc_path: String = "$BASE/jsonrpc.ipc",
|
||||
or |c: &Config| otry!(c.ipc).path.clone(),
|
||||
flag_ipc_apis: String = "web3,eth,net,parity,parity_accounts,traces,rpc",
|
||||
flag_ipc_apis: String = "web3,eth,net,parity,parity_accounts,traces,rpc,secretstore",
|
||||
or |c: &Config| otry!(c.ipc).apis.as_ref().map(|vec| vec.join(",")),
|
||||
|
||||
// DAPPS
|
||||
@ -723,7 +723,7 @@ mod tests {
|
||||
flag_jsonrpc_port: 8545u16,
|
||||
flag_jsonrpc_interface: "local".into(),
|
||||
flag_jsonrpc_cors: Some("null".into()),
|
||||
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc".into(),
|
||||
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(),
|
||||
flag_jsonrpc_hosts: "none".into(),
|
||||
flag_jsonrpc_threads: None,
|
||||
|
||||
@ -731,14 +731,14 @@ mod tests {
|
||||
flag_no_ws: false,
|
||||
flag_ws_port: 8546u16,
|
||||
flag_ws_interface: "local".into(),
|
||||
flag_ws_apis: "web3,eth,net,parity,traces,rpc".into(),
|
||||
flag_ws_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(),
|
||||
flag_ws_origins: "none".into(),
|
||||
flag_ws_hosts: "none".into(),
|
||||
|
||||
// IPC
|
||||
flag_no_ipc: false,
|
||||
flag_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(),
|
||||
flag_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc".into(),
|
||||
flag_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc,secretstore".into(),
|
||||
|
||||
// DAPPS
|
||||
flag_dapps_path: "$HOME/.parity/dapps".into(),
|
||||
|
@ -22,7 +22,7 @@ use dir::default_data_path;
|
||||
use parity_rpc::informant::{RpcStats, Middleware};
|
||||
use parity_rpc::{self as rpc, HttpServerError, Metadata, Origin, DomainsValidation};
|
||||
use helpers::parity_ipc_path;
|
||||
use jsonrpc_core::MetaIoHandler;
|
||||
use jsonrpc_core::{futures, MetaIoHandler};
|
||||
use parity_reactor::TokioRemote;
|
||||
use rpc_apis::{self, ApiSet};
|
||||
|
||||
@ -126,11 +126,53 @@ impl rpc::IpcMetaExtractor<Metadata> for RpcExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
impl rpc::ws::MetaExtractor<Metadata> for RpcExtractor {
|
||||
struct Sender(rpc::ws::ws::Sender, futures::sync::mpsc::Receiver<String>);
|
||||
|
||||
impl futures::Future for Sender {
|
||||
type Item = ();
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
|
||||
use self::futures::Stream;
|
||||
|
||||
let item = self.1.poll()?;
|
||||
match item {
|
||||
futures::Async::NotReady => {
|
||||
Ok(futures::Async::NotReady)
|
||||
},
|
||||
futures::Async::Ready(None) => {
|
||||
Ok(futures::Async::Ready(()))
|
||||
},
|
||||
futures::Async::Ready(Some(val)) => {
|
||||
if let Err(e) = self.0.send(val) {
|
||||
warn!("Error sending a subscription update: {:?}", e);
|
||||
}
|
||||
self.poll()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WsRpcExtractor {
|
||||
remote: TokioRemote,
|
||||
}
|
||||
|
||||
impl WsRpcExtractor {
|
||||
fn wrap_out(&self, out: rpc::ws::ws::Sender) -> futures::sync::mpsc::Sender<String> {
|
||||
let (sender, receiver) = futures::sync::mpsc::channel(8);
|
||||
self.remote.spawn(move |_| Sender(out, receiver));
|
||||
sender
|
||||
}
|
||||
}
|
||||
|
||||
impl rpc::ws::MetaExtractor<Metadata> for WsRpcExtractor {
|
||||
fn extract(&self, req: &rpc::ws::RequestContext) -> Metadata {
|
||||
let mut metadata = Metadata::default();
|
||||
let id = req.session_id as u64;
|
||||
metadata.origin = Origin::Ws(id.into());
|
||||
metadata.session = Some(Arc::new(rpc::PubSubSession::new(
|
||||
self.wrap_out(req.out.clone())
|
||||
)));
|
||||
metadata
|
||||
}
|
||||
}
|
||||
@ -173,10 +215,12 @@ pub fn new_ws<D: rpc_apis::Dependencies>(
|
||||
let start_result = rpc::start_ws(
|
||||
&addr,
|
||||
handler,
|
||||
remote,
|
||||
remote.clone(),
|
||||
allowed_origins,
|
||||
allowed_hosts,
|
||||
RpcExtractor,
|
||||
WsRpcExtractor {
|
||||
remote: remote,
|
||||
},
|
||||
WsStats {
|
||||
stats: deps.stats.clone(),
|
||||
},
|
||||
@ -247,7 +291,14 @@ pub fn new_ipc<D: rpc_apis::Dependencies>(
|
||||
|
||||
let handler = setup_apis(conf.apis, dependencies);
|
||||
let remote = dependencies.remote.clone();
|
||||
match rpc::start_ipc(&conf.socket_addr, handler, remote, RpcExtractor) {
|
||||
let ipc = rpc::start_ipc(
|
||||
&conf.socket_addr,
|
||||
handler,
|
||||
remote,
|
||||
RpcExtractor,
|
||||
);
|
||||
|
||||
match ipc {
|
||||
Ok(server) => Ok(Some(server)),
|
||||
Err(io_error) => Err(format!("IPC error: {}", io_error)),
|
||||
}
|
||||
|
@ -31,11 +31,12 @@ use parity_rpc::informant::{ActivityNotifier, Middleware, RpcStats, ClientNotifi
|
||||
use parity_rpc::dispatch::{FullDispatcher, LightDispatcher};
|
||||
use ethsync::{ManageNetwork, SyncProvider, LightSync};
|
||||
use hash_fetch::fetch::Client as FetchClient;
|
||||
use jsonrpc_core::{MetaIoHandler};
|
||||
use jsonrpc_core::{self as core, MetaIoHandler};
|
||||
use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache};
|
||||
use updater::Updater;
|
||||
use util::{Mutex, RwLock};
|
||||
use ethcore_logger::RotatingLogger;
|
||||
use parity_reactor;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
|
||||
pub enum Api {
|
||||
@ -59,6 +60,8 @@ pub enum Api {
|
||||
Traces,
|
||||
/// Rpc (Safe)
|
||||
Rpc,
|
||||
/// SecretStore (Safe)
|
||||
SecretStore,
|
||||
}
|
||||
|
||||
impl FromStr for Api {
|
||||
@ -78,6 +81,7 @@ impl FromStr for Api {
|
||||
"parity_set" => Ok(ParitySet),
|
||||
"traces" => Ok(Traces),
|
||||
"rpc" => Ok(Rpc),
|
||||
"secretstore" => Ok(SecretStore),
|
||||
api => Err(format!("Unknown api: {}", api))
|
||||
}
|
||||
}
|
||||
@ -156,6 +160,7 @@ fn to_modules(apis: &[Api]) -> BTreeMap<String, String> {
|
||||
Api::ParitySet => ("parity_set", "1.0"),
|
||||
Api::Traces => ("traces", "1.0"),
|
||||
Api::Rpc => ("rpc", "1.0"),
|
||||
Api::SecretStore => ("secretstore", "1.0"),
|
||||
};
|
||||
modules.insert(name.into(), version.into());
|
||||
}
|
||||
@ -191,18 +196,16 @@ pub struct FullDependencies {
|
||||
pub dapps_interface: Option<String>,
|
||||
pub dapps_port: Option<u16>,
|
||||
pub fetch: FetchClient,
|
||||
pub remote: parity_reactor::Remote,
|
||||
}
|
||||
|
||||
impl Dependencies for FullDependencies {
|
||||
type Notifier = ClientNotifier;
|
||||
|
||||
fn activity_notifier(&self) -> ClientNotifier {
|
||||
ClientNotifier {
|
||||
client: self.client.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_with_set(&self, handler: &mut MetaIoHandler<Metadata, Middleware>, apis: &[Api]) {
|
||||
impl FullDependencies {
|
||||
fn extend_api<T: core::Middleware<Metadata>>(
|
||||
&self,
|
||||
handler: &mut MetaIoHandler<Metadata, T>,
|
||||
apis: &[Api],
|
||||
for_generic_pubsub: bool,
|
||||
) {
|
||||
use parity_rpc::v1::*;
|
||||
|
||||
macro_rules! add_signing_methods {
|
||||
@ -244,10 +247,12 @@ impl Dependencies for FullDependencies {
|
||||
);
|
||||
handler.extend_with(client.to_delegate());
|
||||
|
||||
let filter_client = EthFilterClient::new(self.client.clone(), self.miner.clone());
|
||||
handler.extend_with(filter_client.to_delegate());
|
||||
if !for_generic_pubsub {
|
||||
let filter_client = EthFilterClient::new(self.client.clone(), self.miner.clone());
|
||||
handler.extend_with(filter_client.to_delegate());
|
||||
|
||||
add_signing_methods!(EthSigning, handler, self);
|
||||
add_signing_methods!(EthSigning, handler, self);
|
||||
}
|
||||
},
|
||||
Api::Personal => {
|
||||
handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility).to_delegate());
|
||||
@ -274,8 +279,14 @@ impl Dependencies for FullDependencies {
|
||||
self.dapps_port,
|
||||
).to_delegate());
|
||||
|
||||
add_signing_methods!(EthSigning, handler, self);
|
||||
add_signing_methods!(ParitySigning, handler, self);
|
||||
if !for_generic_pubsub {
|
||||
let mut rpc = MetaIoHandler::default();
|
||||
self.extend_api(&mut rpc, apis, true);
|
||||
handler.extend_with(PubSubClient::new(rpc, self.remote.clone()).to_delegate());
|
||||
|
||||
add_signing_methods!(EthSigning, handler, self);
|
||||
add_signing_methods!(ParitySigning, handler, self);
|
||||
}
|
||||
},
|
||||
Api::ParityAccounts => {
|
||||
handler.extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate());
|
||||
@ -295,12 +306,29 @@ impl Dependencies for FullDependencies {
|
||||
Api::Rpc => {
|
||||
let modules = to_modules(&apis);
|
||||
handler.extend_with(RpcClient::new(modules).to_delegate());
|
||||
}
|
||||
},
|
||||
Api::SecretStore => {
|
||||
handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate());
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dependencies for FullDependencies {
|
||||
type Notifier = ClientNotifier;
|
||||
|
||||
fn activity_notifier(&self) -> ClientNotifier {
|
||||
ClientNotifier {
|
||||
client: self.client.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_with_set(&self, handler: &mut MetaIoHandler<Metadata, Middleware<Self::Notifier>>, apis: &[Api]) {
|
||||
self.extend_api(handler, apis, false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Light client notifier. Doesn't do anything yet, but might in the future.
|
||||
pub struct LightClientNotifier;
|
||||
|
||||
@ -424,7 +452,11 @@ impl Dependencies for LightDependencies {
|
||||
Api::Rpc => {
|
||||
let modules = to_modules(&apis);
|
||||
handler.extend_with(RpcClient::new(modules).to_delegate());
|
||||
}
|
||||
},
|
||||
Api::SecretStore => {
|
||||
let secret_store = Some(self.secret_store.clone());
|
||||
handler.extend_with(SecretStoreClient::new(&secret_store).to_delegate());
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -438,7 +470,7 @@ impl ApiSet {
|
||||
|
||||
pub fn list_apis(&self) -> HashSet<Api> {
|
||||
let mut public_list = vec![
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Rpc,
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Rpc, Api::SecretStore,
|
||||
].into_iter().collect();
|
||||
match *self {
|
||||
ApiSet::List(ref apis) => apis.clone(),
|
||||
@ -496,6 +528,7 @@ mod test {
|
||||
assert_eq!(Api::ParitySet, "parity_set".parse().unwrap());
|
||||
assert_eq!(Api::Traces, "traces".parse().unwrap());
|
||||
assert_eq!(Api::Rpc, "rpc".parse().unwrap());
|
||||
assert_eq!(Api::SecretStore, "secretstore".parse().unwrap());
|
||||
assert!("rp".parse::<Api>().is_err());
|
||||
}
|
||||
|
||||
@ -513,7 +546,7 @@ mod test {
|
||||
fn test_api_set_unsafe_context() {
|
||||
let expected = vec![
|
||||
// make sure this list contains only SAFE methods
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc, Api::SecretStore
|
||||
].into_iter().collect();
|
||||
assert_eq!(ApiSet::UnsafeContext.list_apis(), expected);
|
||||
}
|
||||
@ -522,7 +555,7 @@ mod test {
|
||||
fn test_api_set_ipc_context() {
|
||||
let expected = vec![
|
||||
// safe
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc, Api::SecretStore,
|
||||
// semi-safe
|
||||
Api::ParityAccounts
|
||||
].into_iter().collect();
|
||||
@ -533,7 +566,7 @@ mod test {
|
||||
fn test_api_set_safe_context() {
|
||||
let expected = vec![
|
||||
// safe
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc, Api::SecretStore,
|
||||
// semi-safe
|
||||
Api::ParityAccounts,
|
||||
// Unsafe
|
||||
@ -545,7 +578,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_all_apis() {
|
||||
assert_eq!("all".parse::<ApiSet>().unwrap(), ApiSet::List(vec![
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc, Api::SecretStore,
|
||||
Api::ParityAccounts,
|
||||
Api::ParitySet, Api::Signer,
|
||||
Api::Personal
|
||||
@ -555,7 +588,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_all_without_personal_apis() {
|
||||
assert_eq!("personal,all,-personal".parse::<ApiSet>().unwrap(), ApiSet::List(vec![
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc, Api::SecretStore,
|
||||
Api::ParityAccounts,
|
||||
Api::ParitySet, Api::Signer,
|
||||
].into_iter().collect()));
|
||||
@ -564,7 +597,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_safe_parsing() {
|
||||
assert_eq!("safe".parse::<ApiSet>().unwrap(), ApiSet::List(vec![
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
|
||||
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc, Api::SecretStore,
|
||||
].into_iter().collect()));
|
||||
}
|
||||
}
|
||||
|
@ -631,6 +631,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
false => None,
|
||||
},
|
||||
fetch: fetch.clone(),
|
||||
remote: event_loop.remote(),
|
||||
});
|
||||
|
||||
let dependencies = rpc::Dependencies {
|
||||
|
@ -17,10 +17,12 @@ serde = "0.9"
|
||||
serde_derive = "0.9"
|
||||
serde_json = "0.9"
|
||||
time = "0.1"
|
||||
tokio-timer = "0.1"
|
||||
transient-hashmap = "0.4"
|
||||
cid = "0.2.1"
|
||||
multihash = "0.5"
|
||||
rust-crypto = "0.2.36"
|
||||
rand = "0.3"
|
||||
|
||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
@ -28,6 +30,7 @@ jsonrpc-minihttp-server = { git = "https://github.com/paritytech/jsonrpc.git", b
|
||||
jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
jsonrpc-ipc-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
|
||||
ethcore-io = { path = "../util/io" }
|
||||
ethcore-ipc = { path = "../ipc/rpc" }
|
||||
|
@ -26,15 +26,18 @@ extern crate semver;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate time;
|
||||
extern crate tokio_timer;
|
||||
extern crate transient_hashmap;
|
||||
extern crate cid;
|
||||
extern crate multihash;
|
||||
extern crate crypto as rust_crypto;
|
||||
extern crate rand;
|
||||
|
||||
extern crate jsonrpc_core;
|
||||
extern crate jsonrpc_http_server as http;
|
||||
extern crate jsonrpc_minihttp_server as minihttp;
|
||||
extern crate jsonrpc_ipc_server as ipc;
|
||||
extern crate jsonrpc_minihttp_server as minihttp;
|
||||
extern crate jsonrpc_pubsub;
|
||||
|
||||
extern crate ethash;
|
||||
extern crate ethcore;
|
||||
@ -75,6 +78,7 @@ pub extern crate jsonrpc_ws_server as ws;
|
||||
mod metadata;
|
||||
pub mod v1;
|
||||
|
||||
pub use jsonrpc_pubsub::Session as PubSubSession;
|
||||
pub use ipc::{Server as IpcServer, MetaExtractor as IpcMetaExtractor, RequestContext as IpcRequestContext};
|
||||
pub use http::{
|
||||
hyper,
|
||||
|
@ -37,6 +37,7 @@ use ethcore::miner::MinerService;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
use ethcore::transaction::{Action, SignedTransaction, PendingTransaction, Transaction};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use crypto::DEFAULT_MAC;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use v1::helpers::{errors, TransactionRequest, FilledTransactionRequest, ConfirmationPayload};
|
||||
@ -400,9 +401,6 @@ impl Dispatcher for LightDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/// default MAC to use.
|
||||
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
|
||||
|
||||
/// Single-use account token.
|
||||
pub type AccountToken = String;
|
||||
|
||||
|
@ -25,6 +25,7 @@ pub mod light_fetch;
|
||||
pub mod informant;
|
||||
pub mod oneshot;
|
||||
pub mod ipfs;
|
||||
pub mod secretstore;
|
||||
|
||||
mod network_settings;
|
||||
mod poll_manager;
|
||||
@ -32,6 +33,7 @@ mod poll_filter;
|
||||
mod requests;
|
||||
mod signer;
|
||||
mod signing_queue;
|
||||
mod subscription_manager;
|
||||
|
||||
pub use self::dispatch::{Dispatcher, FullDispatcher};
|
||||
pub use self::network_settings::NetworkSettings;
|
||||
@ -45,3 +47,4 @@ pub use self::signing_queue::{
|
||||
QUEUE_LIMIT as SIGNING_QUEUE_LIMIT,
|
||||
};
|
||||
pub use self::signer::SignerService;
|
||||
pub use self::subscription_manager::GenericPollManager;
|
||||
|
127
rpc/src/v1/helpers/secretstore.rs
Normal file
127
rpc/src/v1/helpers/secretstore.rs
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::iter::repeat;
|
||||
use rand::{Rng, OsRng};
|
||||
use ethkey::{Public, Secret, math};
|
||||
use crypto;
|
||||
use util::Bytes;
|
||||
use jsonrpc_core::Error;
|
||||
use v1::helpers::errors;
|
||||
|
||||
/// Initialization vector length.
|
||||
const INIT_VEC_LEN: usize = 16;
|
||||
|
||||
/// Encrypt document with distributely generated key.
|
||||
pub fn encrypt_document(key: Bytes, document: Bytes) -> Result<Bytes, Error> {
|
||||
// make document key
|
||||
let key = into_document_key(key)?;
|
||||
|
||||
// use symmetric encryption to encrypt document
|
||||
let iv = initialization_vector();
|
||||
let mut encrypted_document = Vec::with_capacity(document.len() + iv.len());
|
||||
encrypted_document.extend(repeat(0).take(document.len()));
|
||||
crypto::aes::encrypt(&key, &iv, &document, &mut encrypted_document);
|
||||
encrypted_document.extend_from_slice(&iv);
|
||||
|
||||
Ok(encrypted_document)
|
||||
}
|
||||
|
||||
/// Decrypt document with distributely generated key.
|
||||
pub fn decrypt_document(key: Bytes, mut encrypted_document: Bytes) -> Result<Bytes, Error> {
|
||||
// initialization vector takes INIT_VEC_LEN bytes
|
||||
let encrypted_document_len = encrypted_document.len();
|
||||
if encrypted_document_len < INIT_VEC_LEN {
|
||||
return Err(errors::invalid_params("encrypted_document", "invalid encrypted data"));
|
||||
}
|
||||
|
||||
// make document key
|
||||
let key = into_document_key(key)?;
|
||||
|
||||
// use symmetric decryption to decrypt document
|
||||
let iv = encrypted_document.split_off(encrypted_document_len - INIT_VEC_LEN);
|
||||
let mut document = Vec::with_capacity(encrypted_document_len - INIT_VEC_LEN);
|
||||
document.extend(repeat(0).take(encrypted_document_len - INIT_VEC_LEN));
|
||||
crypto::aes::decrypt(&key, &iv, &encrypted_document, &mut document);
|
||||
|
||||
Ok(document)
|
||||
}
|
||||
|
||||
pub fn decrypt_document_with_shadow(decrypted_secret: Public, common_point: Public, shadows: Vec<Secret>, encrypted_document: Bytes) -> Result<Bytes, Error> {
|
||||
let key = decrypt_with_shadow_coefficients(decrypted_secret, common_point, shadows)?;
|
||||
decrypt_document(key.to_vec(), encrypted_document)
|
||||
}
|
||||
|
||||
fn into_document_key(key: Bytes) -> Result<Bytes, Error> {
|
||||
// key is a previously distributely generated Public
|
||||
if key.len() != 64 {
|
||||
return Err(errors::invalid_params("key", "invalid public key length"));
|
||||
}
|
||||
|
||||
// use x coordinate of distributely generated point as encryption key
|
||||
Ok(key[..INIT_VEC_LEN].into())
|
||||
}
|
||||
|
||||
fn initialization_vector() -> [u8; INIT_VEC_LEN] {
|
||||
let mut result = [0u8; INIT_VEC_LEN];
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
rng.fill_bytes(&mut result);
|
||||
result
|
||||
}
|
||||
|
||||
fn decrypt_with_shadow_coefficients(mut decrypted_shadow: Public, mut common_shadow_point: Public, shadow_coefficients: Vec<Secret>) -> Result<Public, Error> {
|
||||
let mut shadow_coefficients_sum = shadow_coefficients[0].clone();
|
||||
for shadow_coefficient in shadow_coefficients.iter().skip(1) {
|
||||
shadow_coefficients_sum.add(shadow_coefficient)
|
||||
.map_err(errors::encryption_error)?;
|
||||
}
|
||||
|
||||
math::public_mul_secret(&mut common_shadow_point, &shadow_coefficients_sum)
|
||||
.map_err(errors::encryption_error)?;
|
||||
math::public_add(&mut decrypted_shadow, &common_shadow_point)
|
||||
.map_err(errors::encryption_error)?;
|
||||
Ok(decrypted_shadow)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use util::Bytes;
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use super::{encrypt_document, decrypt_document, decrypt_document_with_shadow};
|
||||
|
||||
#[test]
|
||||
fn encrypt_and_decrypt_document() {
|
||||
let document_key: Bytes = "cac6c205eb06c8308d65156ff6c862c62b000b8ead121a4455a8ddeff7248128d895692136f240d5d1614dc7cc4147b1bd584bd617e30560bb872064d09ea325".from_hex().unwrap();
|
||||
let document: Bytes = b"Hello, world!!!"[..].into();
|
||||
|
||||
let encrypted_document = encrypt_document(document_key.clone(), document.clone()).unwrap();
|
||||
assert!(document != encrypted_document);
|
||||
|
||||
let decrypted_document = decrypt_document(document_key.clone(), encrypted_document).unwrap();
|
||||
assert_eq!(decrypted_document, document);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_and_shadow_decrypt_document() {
|
||||
let document: Bytes = "deadbeef".from_hex().unwrap();
|
||||
let encrypted_document = "2ddec1f96229efa2916988d8b2a82a47ef36f71c".from_hex().unwrap();
|
||||
let decrypted_secret = "843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91".parse().unwrap();
|
||||
let common_point = "07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3".parse().unwrap();
|
||||
let shadows = vec!["46f542416216f66a7d7881f5a283d2a1ab7a87b381cbc5f29d0b093c7c89ee31".parse().unwrap()];
|
||||
let decrypted_document = decrypt_document_with_shadow(decrypted_secret, common_point, shadows, encrypted_document).unwrap();
|
||||
assert_eq!(decrypted_document, document);
|
||||
}
|
||||
}
|
175
rpc/src/v1/helpers/subscription_manager.rs
Normal file
175
rpc/src/v1/helpers/subscription_manager.rs
Normal file
@ -0,0 +1,175 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Generic poll manager for Pub-Sub.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use util::Mutex;
|
||||
|
||||
use jsonrpc_core::futures::future::{self, Either};
|
||||
use jsonrpc_core::futures::sync::mpsc;
|
||||
use jsonrpc_core::futures::{Sink, Future, BoxFuture};
|
||||
use jsonrpc_core::{self as core, MetaIoHandler};
|
||||
|
||||
use v1::metadata::Metadata;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Subscription {
|
||||
metadata: Metadata,
|
||||
method: String,
|
||||
params: core::Params,
|
||||
sink: mpsc::Sender<Result<core::Value, core::Error>>,
|
||||
last_result: Arc<Mutex<Option<core::Output>>>,
|
||||
}
|
||||
|
||||
/// A struct managing all subscriptions.
|
||||
/// TODO [ToDr] Depending on the method decide on poll interval.
|
||||
/// For most of the methods it will be enough to poll on new block instead of time-interval.
|
||||
pub struct GenericPollManager<S: core::Middleware<Metadata>> {
|
||||
next_id: usize,
|
||||
poll_subscriptions: HashMap<usize, Subscription>,
|
||||
rpc: MetaIoHandler<Metadata, S>,
|
||||
}
|
||||
|
||||
impl<S: core::Middleware<Metadata>> GenericPollManager<S> {
|
||||
/// Creates new poll manager
|
||||
pub fn new(rpc: MetaIoHandler<Metadata, S>) -> Self {
|
||||
GenericPollManager {
|
||||
next_id: 1,
|
||||
poll_subscriptions: Default::default(),
|
||||
rpc: rpc,
|
||||
}
|
||||
}
|
||||
|
||||
/// Subscribes to update from polling given method.
|
||||
pub fn subscribe(&mut self, metadata: Metadata, method: String, params: core::Params)
|
||||
-> (usize, mpsc::Receiver<Result<core::Value, core::Error>>)
|
||||
{
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
let (sink, stream) = mpsc::channel(1);
|
||||
|
||||
let subscription = Subscription {
|
||||
metadata: metadata,
|
||||
method: method,
|
||||
params: params,
|
||||
sink: sink,
|
||||
last_result: Default::default(),
|
||||
};
|
||||
|
||||
debug!(target: "pubsub", "Adding subscription id={:?}, {:?}", id, subscription);
|
||||
self.poll_subscriptions.insert(id, subscription);
|
||||
(id, stream)
|
||||
}
|
||||
|
||||
pub fn unsubscribe(&mut self, id: usize) -> bool {
|
||||
debug!(target: "pubsub", "Removing subscription: {:?}", id);
|
||||
self.poll_subscriptions.remove(&id).is_some()
|
||||
}
|
||||
|
||||
pub fn tick(&self) -> BoxFuture<(), ()> {
|
||||
let mut futures = Vec::new();
|
||||
// poll all subscriptions
|
||||
for (id, subscription) in self.poll_subscriptions.iter() {
|
||||
let call = core::MethodCall {
|
||||
jsonrpc: Some(core::Version::V2),
|
||||
id: core::Id::Num(*id as u64),
|
||||
method: subscription.method.clone(),
|
||||
params: Some(subscription.params.clone()),
|
||||
};
|
||||
trace!(target: "pubsub", "Polling method: {:?}", call);
|
||||
let result = self.rpc.handle_call(call.into(), subscription.metadata.clone());
|
||||
|
||||
let last_result = subscription.last_result.clone();
|
||||
let sender = subscription.sink.clone();
|
||||
|
||||
let result = result.and_then(move |response| {
|
||||
let mut last_result = last_result.lock();
|
||||
if *last_result != response && response.is_some() {
|
||||
let output = response.expect("Existence proved by the condition.");
|
||||
debug!(target: "pubsub", "Got new response, sending: {:?}", output);
|
||||
*last_result = Some(output.clone());
|
||||
|
||||
let send = match output {
|
||||
core::Output::Success(core::Success { result, .. }) => Ok(result),
|
||||
core::Output::Failure(core::Failure { error, .. }) => Err(error),
|
||||
};
|
||||
Either::A(sender.send(send).map(|_| ()).map_err(|_| ()))
|
||||
} else {
|
||||
trace!(target: "pubsub", "Response was not changed: {:?}", response);
|
||||
Either::B(future::ok(()))
|
||||
}
|
||||
});
|
||||
|
||||
futures.push(result)
|
||||
}
|
||||
|
||||
// return a future represeting all the polls
|
||||
future::join_all(futures).map(|_| ()).boxed()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
|
||||
use jsonrpc_core::{MetaIoHandler, NoopMiddleware, Value, Params};
|
||||
use jsonrpc_core::futures::{Future, Stream};
|
||||
use http::tokio_core::reactor;
|
||||
|
||||
use super::GenericPollManager;
|
||||
|
||||
fn poll_manager() -> GenericPollManager<NoopMiddleware> {
|
||||
let mut io = MetaIoHandler::default();
|
||||
let called = AtomicBool::new(false);
|
||||
io.add_method("hello", move |_| {
|
||||
if !called.load(atomic::Ordering::SeqCst) {
|
||||
called.store(true, atomic::Ordering::SeqCst);
|
||||
Ok(Value::String("hello".into()))
|
||||
} else {
|
||||
Ok(Value::String("world".into()))
|
||||
}
|
||||
});
|
||||
GenericPollManager::new(io)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_poll_subscribed_method() {
|
||||
// given
|
||||
let mut el = reactor::Core::new().unwrap();
|
||||
let mut poll_manager = poll_manager();
|
||||
let (id, rx) = poll_manager.subscribe(Default::default(), "hello".into(), Params::None);
|
||||
assert_eq!(id, 1);
|
||||
|
||||
// then
|
||||
poll_manager.tick().wait().unwrap();
|
||||
let (res, rx) = el.run(rx.into_future()).unwrap();
|
||||
assert_eq!(res, Some(Ok(Value::String("hello".into()))));
|
||||
|
||||
// retrieve second item
|
||||
poll_manager.tick().wait().unwrap();
|
||||
let (res, rx) = el.run(rx.into_future()).unwrap();
|
||||
assert_eq!(res, Some(Ok(Value::String("world".into()))));
|
||||
|
||||
// and no more notifications
|
||||
poll_manager.tick().wait().unwrap();
|
||||
// we need to unsubscribe otherwise the future will never finish.
|
||||
poll_manager.unsubscribe(1);
|
||||
assert_eq!(el.run(rx.into_future()).unwrap().0, None);
|
||||
}
|
||||
}
|
@ -27,13 +27,14 @@ use ethkey::{Brain, Generator};
|
||||
use ethstore::random_phrase;
|
||||
use ethsync::LightSyncProvider;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use crypto::DEFAULT_MAC;
|
||||
|
||||
use light::client::LightChainClient;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::helpers::{errors, ipfs, SigningQueue, SignerService, NetworkSettings};
|
||||
use v1::helpers::dispatch::{LightDispatcher, DEFAULT_MAC};
|
||||
use v1::helpers::dispatch::LightDispatcher;
|
||||
use v1::helpers::light_fetch::LightFetch;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::Parity;
|
||||
|
@ -23,16 +23,17 @@ mod parity;
|
||||
mod parity_accounts;
|
||||
mod parity_set;
|
||||
mod personal;
|
||||
mod pubsub;
|
||||
mod signer;
|
||||
mod signing;
|
||||
mod signing_unsafe;
|
||||
mod rpc;
|
||||
mod secretstore;
|
||||
mod traces;
|
||||
mod web3;
|
||||
|
||||
pub mod light;
|
||||
|
||||
pub use self::web3::Web3Client;
|
||||
pub use self::eth::{EthClient, EthClientOptions};
|
||||
pub use self::eth_filter::EthFilterClient;
|
||||
pub use self::net::NetClient;
|
||||
@ -40,8 +41,11 @@ pub use self::parity::ParityClient;
|
||||
pub use self::parity_accounts::ParityAccountsClient;
|
||||
pub use self::parity_set::ParitySetClient;
|
||||
pub use self::personal::PersonalClient;
|
||||
pub use self::pubsub::PubSubClient;
|
||||
pub use self::signer::SignerClient;
|
||||
pub use self::signing::SigningQueueClient;
|
||||
pub use self::signing_unsafe::SigningUnsafeClient;
|
||||
pub use self::traces::TracesClient;
|
||||
pub use self::web3::Web3Client;
|
||||
pub use self::rpc::RpcClient;
|
||||
pub use self::secretstore::SecretStoreClient;
|
||||
|
@ -34,12 +34,12 @@ use ethcore::client::{MiningBlockChainClient};
|
||||
use ethcore::mode::Mode;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use updater::{Service as UpdateService};
|
||||
use crypto::DEFAULT_MAC;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::helpers::{errors, ipfs, SigningQueue, SignerService, NetworkSettings};
|
||||
use v1::helpers::accounts::unwrap_provider;
|
||||
use v1::helpers::dispatch::DEFAULT_MAC;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::Parity;
|
||||
use v1::types::{
|
||||
|
100
rpc/src/v1/impls/pubsub.rs
Normal file
100
rpc/src/v1/impls/pubsub.rs
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Parity-specific PUB-SUB rpc implementation.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use util::RwLock;
|
||||
|
||||
use futures::{self, BoxFuture, Future, Stream, Sink};
|
||||
use jsonrpc_core::{self as core, Error, MetaIoHandler};
|
||||
use jsonrpc_macros::pubsub::Subscriber;
|
||||
use jsonrpc_pubsub::SubscriptionId;
|
||||
use tokio_timer;
|
||||
|
||||
use parity_reactor::Remote;
|
||||
use v1::helpers::GenericPollManager;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::PubSub;
|
||||
|
||||
/// Parity PubSub implementation.
|
||||
pub struct PubSubClient<S: core::Middleware<Metadata>> {
|
||||
poll_manager: Arc<RwLock<GenericPollManager<S>>>,
|
||||
remote: Remote,
|
||||
}
|
||||
|
||||
impl<S: core::Middleware<Metadata>> PubSubClient<S> {
|
||||
/// Creates new `PubSubClient`.
|
||||
pub fn new(rpc: MetaIoHandler<Metadata, S>, remote: Remote) -> Self {
|
||||
let poll_manager = Arc::new(RwLock::new(GenericPollManager::new(rpc)));
|
||||
let pm2 = poll_manager.clone();
|
||||
|
||||
let timer = tokio_timer::wheel()
|
||||
.tick_duration(Duration::from_millis(500))
|
||||
.build();
|
||||
|
||||
// Start ticking
|
||||
let interval = timer.interval(Duration::from_millis(1000));
|
||||
remote.spawn(interval
|
||||
.map_err(|e| warn!("Polling timer error: {:?}", e))
|
||||
.for_each(move |_| pm2.read().tick())
|
||||
);
|
||||
|
||||
PubSubClient {
|
||||
poll_manager: poll_manager,
|
||||
remote: remote,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: core::Middleware<Metadata>> PubSub for PubSubClient<S> {
|
||||
type Metadata = Metadata;
|
||||
|
||||
fn parity_subscribe(&self, mut meta: Metadata, subscriber: Subscriber<core::Value>, method: String, params: core::Params) {
|
||||
// Make sure to get rid of PubSub session otherwise it will never be dropped.
|
||||
meta.session = None;
|
||||
|
||||
let mut poll_manager = self.poll_manager.write();
|
||||
let (id, receiver) = poll_manager.subscribe(meta, method, params);
|
||||
match subscriber.assign_id(SubscriptionId::Number(id as u64)) {
|
||||
Ok(sink) => {
|
||||
self.remote.spawn(receiver.map(|res| match res {
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
warn!(target: "pubsub", "Subscription error: {:?}", error);
|
||||
core::Value::Null
|
||||
},
|
||||
}).forward(sink.sink_map_err(|e| {
|
||||
warn!("Cannot send notification: {:?}", e);
|
||||
})).map(|_| ()));
|
||||
},
|
||||
Err(_) => {
|
||||
poll_manager.unsubscribe(id);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn parity_unsubscribe(&self, id: SubscriptionId) -> BoxFuture<bool, Error> {
|
||||
let res = if let SubscriptionId::Number(id) = id {
|
||||
self.poll_manager.write().unsubscribe(id as usize)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
futures::future::ok(res).boxed()
|
||||
}
|
||||
}
|
85
rpc/src/v1/impls/secretstore.rs
Normal file
85
rpc/src/v1/impls/secretstore.rs
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! SecretStore-specific rpc implementation.
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crypto::DEFAULT_MAC;
|
||||
use ethkey::Secret;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use v1::helpers::errors;
|
||||
use v1::helpers::accounts::unwrap_provider;
|
||||
use v1::helpers::secretstore::{encrypt_document, decrypt_document, decrypt_document_with_shadow};
|
||||
use v1::traits::SecretStore;
|
||||
use v1::types::{H160, H512, Bytes};
|
||||
|
||||
/// Parity implementation.
|
||||
pub struct SecretStoreClient {
|
||||
accounts: Option<Weak<AccountProvider>>,
|
||||
}
|
||||
|
||||
impl SecretStoreClient {
|
||||
/// Creates new SecretStoreClient
|
||||
pub fn new(store: &Option<Arc<AccountProvider>>) -> Self {
|
||||
SecretStoreClient {
|
||||
accounts: store.as_ref().map(Arc::downgrade),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to get the `Arc<AccountProvider>`, errors if provider was not
|
||||
/// set, or if upgrading the weak reference failed.
|
||||
fn account_provider(&self) -> Result<Arc<AccountProvider>, Error> {
|
||||
unwrap_provider(&self.accounts)
|
||||
}
|
||||
|
||||
/// Decrypt public key using account' private key
|
||||
fn decrypt_key(&self, address: H160, password: String, key: Bytes) -> Result<Vec<u8>, Error> {
|
||||
let store = self.account_provider()?;
|
||||
store.decrypt(address.into(), Some(password), &DEFAULT_MAC, &key.0)
|
||||
.map_err(|e| errors::account("Could not decrypt key.", e))
|
||||
}
|
||||
|
||||
/// Decrypt secret key using account' private key
|
||||
fn decrypt_secret(&self, address: H160, password: String, key: Bytes) -> Result<Secret, Error> {
|
||||
self.decrypt_key(address, password, key)
|
||||
.and_then(|s| Secret::from_slice(&s).map_err(|e| errors::account("invalid secret", e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretStore for SecretStoreClient {
|
||||
fn encrypt(&self, address: H160, password: String, key: Bytes, data: Bytes) -> Result<Bytes, Error> {
|
||||
encrypt_document(self.decrypt_key(address, password, key)?, data.0)
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn decrypt(&self, address: H160, password: String, key: Bytes, data: Bytes) -> Result<Bytes, Error> {
|
||||
decrypt_document(self.decrypt_key(address, password, key)?, data.0)
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn shadow_decrypt(&self, address: H160, password: String, decrypted_secret: H512, common_point: H512, decrypt_shadows: Vec<Bytes>, data: Bytes) -> Result<Bytes, Error> {
|
||||
let mut shadows = Vec::with_capacity(decrypt_shadows.len());
|
||||
for decrypt_shadow in decrypt_shadows {
|
||||
shadows.push(self.decrypt_secret(address.clone(), password.clone(), decrypt_shadow)?);
|
||||
}
|
||||
|
||||
decrypt_document_with_shadow(decrypted_secret.into(), common_point.into(), shadows, data.0)
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
@ -14,20 +14,26 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use jsonrpc_core;
|
||||
use jsonrpc_pubsub::{Session, PubSubMetadata};
|
||||
|
||||
use v1::types::{DappId, Origin};
|
||||
|
||||
/// RPC methods metadata.
|
||||
#[derive(Clone, Default, Debug, PartialEq)]
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct Metadata {
|
||||
/// Request origin
|
||||
pub origin: Origin,
|
||||
/// Request PubSub Session
|
||||
pub session: Option<Arc<Session>>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
/// Get
|
||||
/// Returns dapp id if this request is coming from a Dapp or default `DappId` otherwise.
|
||||
pub fn dapp_id(&self) -> DappId {
|
||||
// TODO [ToDr] Extract dapp info from Ws connections.
|
||||
match self.origin {
|
||||
Origin::Dapps(ref dapp_id) => dapp_id.clone(),
|
||||
_ => DappId::default(),
|
||||
@ -36,4 +42,8 @@ impl Metadata {
|
||||
}
|
||||
|
||||
impl jsonrpc_core::Metadata for Metadata {}
|
||||
|
||||
impl PubSubMetadata for Metadata {
|
||||
fn session(&self) -> Option<Arc<Session>> {
|
||||
self.session.clone()
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ pub mod traits;
|
||||
pub mod tests;
|
||||
pub mod types;
|
||||
|
||||
pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, Signer, Personal, Traces, Rpc};
|
||||
pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, PubSub, Signer, Personal, Traces, Rpc, SecretStore};
|
||||
pub use self::impls::*;
|
||||
pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, block_import, informant, dispatch};
|
||||
pub use self::metadata::Metadata;
|
||||
|
@ -24,7 +24,9 @@ mod parity;
|
||||
mod parity_accounts;
|
||||
mod parity_set;
|
||||
mod personal;
|
||||
mod pubsub;
|
||||
mod rpc;
|
||||
mod secretstore;
|
||||
mod signer;
|
||||
mod signing;
|
||||
mod traces;
|
||||
|
76
rpc/src/v1/tests/mocked/pubsub.rs
Normal file
76
rpc/src/v1/tests/mocked/pubsub.rs
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::{atomic, Arc};
|
||||
|
||||
use jsonrpc_core::{self as core, MetaIoHandler};
|
||||
use jsonrpc_core::futures::{self, Stream, Future};
|
||||
use jsonrpc_pubsub::Session;
|
||||
|
||||
use parity_reactor::EventLoop;
|
||||
use v1::{PubSub, PubSubClient, Metadata};
|
||||
|
||||
fn rpc() -> MetaIoHandler<Metadata, core::NoopMiddleware> {
|
||||
let mut io = MetaIoHandler::default();
|
||||
let called = atomic::AtomicBool::new(false);
|
||||
io.add_method("hello", move |_| {
|
||||
if !called.load(atomic::Ordering::SeqCst) {
|
||||
called.store(true, atomic::Ordering::SeqCst);
|
||||
Ok(core::Value::String("hello".into()))
|
||||
} else {
|
||||
Ok(core::Value::String("world".into()))
|
||||
}
|
||||
});
|
||||
io
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_subscribe_to_a_method() {
|
||||
// given
|
||||
let el = EventLoop::spawn();
|
||||
let rpc = rpc();
|
||||
let pubsub = PubSubClient::new(rpc, el.remote()).to_delegate();
|
||||
|
||||
let mut io = MetaIoHandler::default();
|
||||
io.extend_with(pubsub);
|
||||
|
||||
let mut metadata = Metadata::default();
|
||||
let (sender, receiver) = futures::sync::mpsc::channel(8);
|
||||
metadata.session = Some(Arc::new(Session::new(sender)));
|
||||
|
||||
// Subscribe
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "parity_subscribe", "params": ["hello", []], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":1,"id":1}"#;
|
||||
assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned()));
|
||||
|
||||
// Check notifications
|
||||
let (res, receiver) = receiver.into_future().wait().unwrap();
|
||||
let response = r#"{"jsonrpc":"2.0","method":"parity_subscription","params":{"result":"hello","subscription":1}}"#;
|
||||
assert_eq!(res, Some(response.into()));
|
||||
|
||||
let (res, receiver) = receiver.into_future().wait().unwrap();
|
||||
let response = r#"{"jsonrpc":"2.0","method":"parity_subscription","params":{"result":"world","subscription":1}}"#;
|
||||
assert_eq!(res, Some(response.into()));
|
||||
|
||||
// And unsubscribe
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "parity_unsubscribe", "params": [1], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
|
||||
assert_eq!(io.handle_request_sync(request, metadata), Some(response.to_owned()));
|
||||
|
||||
let (res, _receiver) = receiver.into_future().wait().unwrap();
|
||||
assert_eq!(res, None);
|
||||
}
|
||||
|
98
rpc/src/v1/tests/mocked/secretstore.rs
Normal file
98
rpc/src/v1/tests/mocked/secretstore.rs
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
|
||||
use serde_json;
|
||||
use jsonrpc_core::{IoHandler, Success};
|
||||
use v1::metadata::Metadata;
|
||||
use v1::SecretStoreClient;
|
||||
use v1::traits::secretstore::SecretStore;
|
||||
|
||||
struct Dependencies {
|
||||
pub accounts: Arc<AccountProvider>,
|
||||
}
|
||||
|
||||
impl Dependencies {
|
||||
pub fn new() -> Self {
|
||||
Dependencies {
|
||||
accounts: Arc::new(AccountProvider::transient_provider()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client(&self) -> SecretStoreClient {
|
||||
SecretStoreClient::new(&Some(self.accounts.clone()))
|
||||
}
|
||||
|
||||
fn default_client(&self) -> IoHandler<Metadata> {
|
||||
let mut io = IoHandler::default();
|
||||
io.extend_with(self.client().to_delegate());
|
||||
io
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_secretstore_encrypt_and_decrypt() {
|
||||
let deps = Dependencies::new();
|
||||
let io = deps.default_client();
|
||||
|
||||
// insert new account && unlock it
|
||||
let secret = "c1f1cfe279a5c350d13795bce162941967340c8a228e6ba175489afc564a5bef".parse().unwrap();
|
||||
deps.accounts.insert_account(secret, "password").unwrap();
|
||||
|
||||
// execute encryption request
|
||||
let encryption_request = r#"{"jsonrpc": "2.0", "method": "secretstore_encrypt", "params":[
|
||||
"0x5c2f3b4ec0c2234f8358697edc8b82a62e3ac995", "password",
|
||||
"0x0440262acc06f1e13cb11b34e792cdf698673a16bb812163cb52689ac34c94ae47047b58f58d8b596d21ac7b03a55896132d07a7dc028b2dad88f6c5a90623fa5b30ff4b1ba385a98c970432d13417cf6d7facd62f86faaef15ca993735890da0cb3e417e2740fc72de7501eef083a12dd5a9ebe513b592b1740848576a936a1eb88fc553fc624b1cae41a0a4e074e34e2aaae686709f08d70e505c5acba12ef96017e89be675a2adb07c72c4e95814fbf",
|
||||
"0xdeadbeef"
|
||||
], "id": 1}"#;
|
||||
let encryption_response = io.handle_request_sync(encryption_request).unwrap();
|
||||
let encryption_response: Success = serde_json::from_str(&encryption_response).unwrap();
|
||||
|
||||
// execute decryption request
|
||||
let decryption_request_left = r#"{"jsonrpc": "2.0", "method": "secretstore_decrypt", "params":[
|
||||
"0x5c2f3b4ec0c2234f8358697edc8b82a62e3ac995", "password",
|
||||
"0x0440262acc06f1e13cb11b34e792cdf698673a16bb812163cb52689ac34c94ae47047b58f58d8b596d21ac7b03a55896132d07a7dc028b2dad88f6c5a90623fa5b30ff4b1ba385a98c970432d13417cf6d7facd62f86faaef15ca993735890da0cb3e417e2740fc72de7501eef083a12dd5a9ebe513b592b1740848576a936a1eb88fc553fc624b1cae41a0a4e074e34e2aaae686709f08d70e505c5acba12ef96017e89be675a2adb07c72c4e95814fbf",""#;
|
||||
let decryption_request_mid = encryption_response.result.as_str().unwrap();
|
||||
let decryption_request_right = r#""
|
||||
], "id": 2}"#;
|
||||
let decryption_request = decryption_request_left.to_owned() + decryption_request_mid + decryption_request_right;
|
||||
let decryption_response = io.handle_request_sync(&decryption_request).unwrap();
|
||||
assert_eq!(decryption_response, r#"{"jsonrpc":"2.0","result":"0xdeadbeef","id":2}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_secretstore_shadow_decrypt() {
|
||||
let deps = Dependencies::new();
|
||||
let io = deps.default_client();
|
||||
|
||||
// insert new account && unlock it
|
||||
let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap();
|
||||
deps.accounts.insert_account(secret, "password").unwrap();
|
||||
|
||||
// execute decryption request
|
||||
let decryption_request = r#"{"jsonrpc": "2.0", "method": "secretstore_shadowDecrypt", "params":[
|
||||
"0x00dfE63B22312ab4329aD0d28CaD8Af987A01932", "password",
|
||||
"0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91",
|
||||
"0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3",
|
||||
["0x049ce50bbadb6352574f2c59742f78df83333975cbd5cbb151c6e8628749a33dc1fa93bb6dffae5994e3eb98ae859ed55ee82937538e6adb054d780d1e89ff140f121529eeadb1161562af9d3342db0008919ca280a064305e5a4e518e93279de7a9396fe5136a9658e337e8e276221248c381c5384cd1ad28e5921f46ff058d5fbcf8a388fc881d0dd29421c218d51761"],
|
||||
"0x2ddec1f96229efa2916988d8b2a82a47ef36f71c"
|
||||
], "id": 1}"#;
|
||||
let decryption_response = io.handle_request_sync(&decryption_request).unwrap();
|
||||
assert_eq!(decryption_response, r#"{"jsonrpc":"2.0","result":"0xdeadbeef","id":1}"#);
|
||||
}
|
@ -25,9 +25,11 @@ pub mod parity_accounts;
|
||||
pub mod parity_set;
|
||||
pub mod parity_signing;
|
||||
pub mod personal;
|
||||
pub mod pubsub;
|
||||
pub mod signer;
|
||||
pub mod traces;
|
||||
pub mod rpc;
|
||||
pub mod secretstore;
|
||||
|
||||
pub use self::web3::Web3;
|
||||
pub use self::eth::{Eth, EthFilter};
|
||||
@ -38,7 +40,8 @@ pub use self::parity_accounts::ParityAccounts;
|
||||
pub use self::parity_set::ParitySet;
|
||||
pub use self::parity_signing::ParitySigning;
|
||||
pub use self::personal::Personal;
|
||||
pub use self::pubsub::PubSub;
|
||||
pub use self::signer::Signer;
|
||||
pub use self::traces::Traces;
|
||||
pub use self::rpc::Rpc;
|
||||
|
||||
pub use self::secretstore::SecretStore;
|
||||
|
39
rpc/src/v1/traits/pubsub.rs
Normal file
39
rpc/src/v1/traits/pubsub.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Parity-specific PUB-SUB rpc interface.
|
||||
|
||||
use jsonrpc_core::{Error, Value, Params};
|
||||
use jsonrpc_pubsub::SubscriptionId;
|
||||
use jsonrpc_macros::pubsub::Subscriber;
|
||||
use futures::BoxFuture;
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Parity-specific PUB-SUB rpc interface.
|
||||
pub trait PubSub {
|
||||
type Metadata;
|
||||
|
||||
#[pubsub(name = "parity_subscription")] {
|
||||
/// Subscribe to changes of any RPC method in Parity.
|
||||
#[rpc(name = "parity_subscribe")]
|
||||
fn parity_subscribe(&self, Self::Metadata, Subscriber<Value>, String, Params);
|
||||
|
||||
/// Unsubscribe from existing Parity subscription.
|
||||
#[rpc(name = "parity_unsubscribe")]
|
||||
fn parity_unsubscribe(&self, SubscriptionId) -> BoxFuture<bool, Error>;
|
||||
}
|
||||
}
|
||||
}
|
41
rpc/src/v1/traits/secretstore.rs
Normal file
41
rpc/src/v1/traits/secretstore.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! SecretStore-specific rpc interface.
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
|
||||
use v1::types::{H160, H512, Bytes};
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Parity-specific rpc interface.
|
||||
pub trait SecretStore {
|
||||
/// Encrypt data with key, received from secret store.
|
||||
/// Arguments: `account`, `password`, `key`, `data`.
|
||||
#[rpc(name = "secretstore_encrypt")]
|
||||
fn encrypt(&self, H160, String, Bytes, Bytes) -> Result<Bytes, Error>;
|
||||
|
||||
/// Decrypt data with key, received from secret store.
|
||||
/// Arguments: `account`, `password`, `key`, `data`.
|
||||
#[rpc(name = "secretstore_decrypt")]
|
||||
fn decrypt(&self, H160, String, Bytes, Bytes) -> Result<Bytes, Error>;
|
||||
|
||||
/// Decrypt data with shadow key, received from secret store.
|
||||
/// Arguments: `account`, `password`, `decrypted_secret`, `common_point`, `decrypt_shadows`, `data`.
|
||||
#[rpc(name = "secretstore_shadowDecrypt")]
|
||||
fn shadow_decrypt(&self, H160, String, H512, H512, Vec<Bytes>, Bytes) -> Result<Bytes, Error>;
|
||||
}
|
||||
}
|
@ -24,9 +24,8 @@ use hyper::server::{Server as HttpServer, Request as HttpRequest, Response as Ht
|
||||
use serde_json;
|
||||
use url::percent_encoding::percent_decode;
|
||||
|
||||
use util::ToPretty;
|
||||
use traits::KeyServer;
|
||||
use serialization::SerializableDocumentEncryptedKeyShadow;
|
||||
use serialization::{SerializableDocumentEncryptedKeyShadow, SerializableBytes};
|
||||
use types::all::{Error, NodeAddress, RequestSignature, DocumentAddress, DocumentEncryptedKey, DocumentEncryptedKeyShadow};
|
||||
|
||||
/// Key server http-requests listener
|
||||
@ -168,9 +167,10 @@ impl<T> HttpHandler for KeyServerHttpHandler<T> where T: KeyServer + 'static {
|
||||
}
|
||||
|
||||
fn return_document_key(req: HttpRequest, mut res: HttpResponse, document_key: Result<DocumentEncryptedKey, Error>) {
|
||||
let document_key = document_key.
|
||||
and_then(|k| serde_json::to_vec(&SerializableBytes(k)).map_err(|e| Error::Serde(e.to_string())));
|
||||
match document_key {
|
||||
Ok(document_key) => {
|
||||
let document_key = document_key.to_hex().into_bytes();
|
||||
res.headers_mut().set(header::ContentType::plaintext());
|
||||
if let Err(err) = res.send(&document_key) {
|
||||
// nothing to do, but to log an error
|
||||
@ -186,6 +186,7 @@ fn return_error(mut res: HttpResponse, err: Error) {
|
||||
Error::BadSignature => *res.status_mut() = HttpStatusCode::BadRequest,
|
||||
Error::AccessDenied => *res.status_mut() = HttpStatusCode::Forbidden,
|
||||
Error::DocumentNotFound => *res.status_mut() = HttpStatusCode::NotFound,
|
||||
Error::Serde(_) => *res.status_mut() = HttpStatusCode::BadRequest,
|
||||
Error::Database(_) => *res.status_mut() = HttpStatusCode::InternalServerError,
|
||||
Error::Internal(_) => *res.status_mut() = HttpStatusCode::InternalServerError,
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ impl KeyServer for KeyServerImpl {
|
||||
let document_key = encryption_session.wait(None)?;
|
||||
|
||||
// encrypt document key with requestor public key
|
||||
let document_key = ethcrypto::ecies::encrypt_single_message(&public, &document_key)
|
||||
let document_key = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &document_key)
|
||||
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
||||
Ok(document_key)
|
||||
}
|
||||
@ -83,13 +83,13 @@ impl KeyServer for KeyServerImpl {
|
||||
let document_key = decryption_session.wait()?.decrypted_secret;
|
||||
|
||||
// encrypt document key with requestor public key
|
||||
let document_key = ethcrypto::ecies::encrypt_single_message(&public, &document_key)
|
||||
let document_key = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &document_key)
|
||||
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
||||
Ok(document_key)
|
||||
}
|
||||
|
||||
fn document_key_shadow(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKeyShadow, Error> {
|
||||
let decryption_session = self.data.lock().cluster.new_decryption_session(document.clone(), signature.clone(), false)?;
|
||||
let decryption_session = self.data.lock().cluster.new_decryption_session(document.clone(), signature.clone(), true)?;
|
||||
decryption_session.wait().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
@ -118,7 +118,7 @@ impl KeyServerCore {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
let cluster = ClusterCore::new(el.handle(), config);
|
||||
let cluster_client = cluster.and_then(|c| c.run().map(|_| c.client()));
|
||||
tx.send(cluster_client.map_err(Into::into)).expect("Rx is blocking upper thread.");
|
||||
@ -229,12 +229,12 @@ pub mod tests {
|
||||
let secret = Random.generate().unwrap().secret().clone();
|
||||
let signature = ethkey::sign(&secret, &document).unwrap();
|
||||
let generated_key = key_servers[0].generate_document_key(&signature, &document, threshold).unwrap();
|
||||
let generated_key = ethcrypto::ecies::decrypt_single_message(&secret, &generated_key).unwrap();
|
||||
let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap();
|
||||
|
||||
// now let's try to retrieve key back
|
||||
for key_server in key_servers.iter() {
|
||||
let retrieved_key = key_server.document_key(&signature, &document).unwrap();
|
||||
let retrieved_key = ethcrypto::ecies::decrypt_single_message(&secret, &retrieved_key).unwrap();
|
||||
let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap();
|
||||
assert_eq!(retrieved_key, generated_key);
|
||||
}
|
||||
}
|
||||
@ -251,12 +251,12 @@ pub mod tests {
|
||||
let secret = Random.generate().unwrap().secret().clone();
|
||||
let signature = ethkey::sign(&secret, &document).unwrap();
|
||||
let generated_key = key_servers[0].generate_document_key(&signature, &document, *threshold).unwrap();
|
||||
let generated_key = ethcrypto::ecies::decrypt_single_message(&secret, &generated_key).unwrap();
|
||||
let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap();
|
||||
|
||||
// now let's try to retrieve key back
|
||||
for key_server in key_servers.iter() {
|
||||
let retrieved_key = key_server.document_key(&signature, &document).unwrap();
|
||||
let retrieved_key = ethcrypto::ecies::decrypt_single_message(&secret, &retrieved_key).unwrap();
|
||||
let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap();
|
||||
assert_eq!(retrieved_key, generated_key);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ use std::cmp::{Ord, PartialOrd, Ordering};
|
||||
use std::collections::{BTreeSet, BTreeMap};
|
||||
use std::sync::Arc;
|
||||
use parking_lot::{Mutex, Condvar};
|
||||
use ethcrypto::ecies::encrypt_single_message;
|
||||
use ethcrypto::ecies::encrypt;
|
||||
use ethcrypto::DEFAULT_MAC;
|
||||
use ethkey::{self, Secret, Public, Signature};
|
||||
use key_server_cluster::{Error, AclStorage, DocumentKeyShare, NodeId, SessionId, DocumentEncryptedKeyShadow};
|
||||
use key_server_cluster::cluster::Cluster;
|
||||
@ -688,7 +689,7 @@ fn do_partial_decryption(node: &NodeId, requestor_public: &Public, is_shadow_dec
|
||||
shadow_point: shadow_point,
|
||||
decrypt_shadow: match decrypt_shadow {
|
||||
None => None,
|
||||
Some(decrypt_shadow) => Some(encrypt_single_message(requestor_public, &**decrypt_shadow)?),
|
||||
Some(decrypt_shadow) => Some(encrypt(requestor_public, &DEFAULT_MAC, &**decrypt_shadow)?),
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -1085,9 +1086,10 @@ mod tests {
|
||||
assert!(decrypted_secret.common_point.is_some());
|
||||
assert!(decrypted_secret.decrypt_shadows.is_some());
|
||||
// check that KS client is able to restore original secret
|
||||
use ethcrypto::ecies::decrypt_single_message;
|
||||
use ethcrypto::DEFAULT_MAC;
|
||||
use ethcrypto::ecies::decrypt;
|
||||
let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter()
|
||||
.map(|c| Secret::from_slice(&decrypt_single_message(key_pair.secret(), &c).unwrap()).unwrap())
|
||||
.map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap())
|
||||
.collect();
|
||||
let decrypted_secret = math::decrypt_with_shadow_coefficients(decrypted_secret.decrypted_secret, decrypted_secret.common_point.unwrap(), decrypt_shadows).unwrap();
|
||||
assert_eq!(decrypted_secret, SECRET_PLAIN.into());
|
||||
|
@ -34,9 +34,9 @@ pub struct SerializableDocumentEncryptedKeyShadow {
|
||||
pub decrypt_shadows: Vec<SerializableBytes>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
/// Serializable Bytes.
|
||||
pub struct SerializableBytes(Bytes);
|
||||
pub struct SerializableBytes(pub Bytes);
|
||||
|
||||
impl<T> From<T> for SerializableBytes where Bytes: From<T> {
|
||||
fn from(s: T) -> SerializableBytes {
|
||||
@ -60,7 +60,9 @@ impl Deref for SerializableBytes {
|
||||
|
||||
impl Serialize for SerializableBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&(*self.0).to_hex())
|
||||
let mut serialized = "0x".to_owned();
|
||||
serialized.push_str(self.0.to_hex().as_ref());
|
||||
serializer.serialize_str(serialized.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,14 +71,18 @@ impl Deserialize for SerializableBytes {
|
||||
where D: Deserializer
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
let data = s.from_hex().map_err(SerdeError::custom)?;
|
||||
Ok(SerializableBytes(data))
|
||||
if s.len() >= 2 && &s[0..2] == "0x" && s.len() & 1 == 0 {
|
||||
let data = s[2..].from_hex().map_err(SerdeError::custom)?;
|
||||
Ok(SerializableBytes(data))
|
||||
} else {
|
||||
Err(SerdeError::custom("invalid format"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Serializable Signature.
|
||||
pub struct SerializableSignature(Signature);
|
||||
pub struct SerializableSignature(pub Signature);
|
||||
|
||||
impl<T> From<T> for SerializableSignature where Signature: From<T> {
|
||||
fn from(s: T) -> SerializableSignature {
|
||||
@ -100,7 +106,9 @@ impl Deref for SerializableSignature {
|
||||
|
||||
impl Serialize for SerializableSignature {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&(*self.0).to_hex())
|
||||
let mut serialized = "0x".to_owned();
|
||||
serialized.push_str(self.0.to_hex().as_ref());
|
||||
serializer.serialize_str(serialized.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +124,11 @@ impl Deserialize for SerializableSignature {
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
|
||||
value.parse().map(|s| SerializableSignature(s)).map_err(SerdeError::custom)
|
||||
if value.len() >= 2 && &value[0..2] == "0x" && value.len() & 1 == 0 {
|
||||
value[2..].parse().map(|s| SerializableSignature(s)).map_err(SerdeError::custom)
|
||||
} else {
|
||||
Err(SerdeError::custom("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
|
||||
@ -130,7 +142,7 @@ impl Deserialize for SerializableSignature {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Serializable H256.
|
||||
pub struct SerializableH256(H256);
|
||||
pub struct SerializableH256(pub H256);
|
||||
|
||||
impl<T> From<T> for SerializableH256 where H256: From<T> {
|
||||
fn from(s: T) -> SerializableH256 {
|
||||
@ -154,7 +166,9 @@ impl Deref for SerializableH256 {
|
||||
|
||||
impl Serialize for SerializableH256 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&(*self.0).to_hex())
|
||||
let mut serialized = "0x".to_owned();
|
||||
serialized.push_str(self.0.to_hex().as_ref());
|
||||
serializer.serialize_str(serialized.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +184,11 @@ impl Deserialize for SerializableH256 {
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
|
||||
value.parse().map(|s| SerializableH256(s)).map_err(SerdeError::custom)
|
||||
if value.len() >= 2 && &value[0..2] == "0x" && value.len() & 1 == 0 {
|
||||
value[2..].parse().map(|s| SerializableH256(s)).map_err(SerdeError::custom)
|
||||
} else {
|
||||
Err(SerdeError::custom("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
|
||||
@ -184,7 +202,7 @@ impl Deserialize for SerializableH256 {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Serializable EC scalar/secret key.
|
||||
pub struct SerializableSecret(Secret);
|
||||
pub struct SerializableSecret(pub Secret);
|
||||
|
||||
impl<T> From<T> for SerializableSecret where Secret: From<T> {
|
||||
fn from(s: T) -> SerializableSecret {
|
||||
@ -208,7 +226,9 @@ impl Deref for SerializableSecret {
|
||||
|
||||
impl Serialize for SerializableSecret {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&(*self.0).to_hex())
|
||||
let mut serialized = "0x".to_owned();
|
||||
serialized.push_str(self.0.to_hex().as_ref());
|
||||
serializer.serialize_str(serialized.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +244,11 @@ impl Deserialize for SerializableSecret {
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
|
||||
value.parse().map(|s| SerializableSecret(s)).map_err(SerdeError::custom)
|
||||
if value.len() >= 2 && &value[0..2] == "0x" && value.len() & 1 == 0 {
|
||||
value[2..].parse().map(|s| SerializableSecret(s)).map_err(SerdeError::custom)
|
||||
} else {
|
||||
Err(SerdeError::custom("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
|
||||
@ -238,7 +262,7 @@ impl Deserialize for SerializableSecret {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Serializable EC point/public key.
|
||||
pub struct SerializablePublic(Public);
|
||||
pub struct SerializablePublic(pub Public);
|
||||
|
||||
impl<T> From<T> for SerializablePublic where Public: From<T> {
|
||||
fn from(p: T) -> SerializablePublic {
|
||||
@ -282,7 +306,9 @@ impl PartialOrd for SerializablePublic {
|
||||
|
||||
impl Serialize for SerializablePublic {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&(*self.0).to_hex())
|
||||
let mut serialized = "0x".to_owned();
|
||||
serialized.push_str(self.0.to_hex().as_ref());
|
||||
serializer.serialize_str(serialized.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,7 +324,11 @@ impl Deserialize for SerializablePublic {
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
|
||||
value.parse().map(|s| SerializablePublic(s)).map_err(SerdeError::custom)
|
||||
if value.len() >= 2 && &value[0..2] == "0x" && value.len() & 1 == 0 {
|
||||
value[2..].parse().map(|s| SerializablePublic(s)).map_err(SerdeError::custom)
|
||||
} else {
|
||||
Err(SerdeError::custom("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
|
||||
@ -309,3 +339,27 @@ impl Deserialize for SerializablePublic {
|
||||
deserializer.deserialize(HashVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use super::{SerializableBytes, SerializablePublic};
|
||||
|
||||
#[test]
|
||||
fn serialize_and_deserialize_bytes() {
|
||||
let bytes = SerializableBytes(vec![1, 2, 3, 4]);
|
||||
let bytes_serialized = serde_json::to_string(&bytes).unwrap();
|
||||
assert_eq!(&bytes_serialized, r#""0x01020304""#);
|
||||
let bytes_deserialized: SerializableBytes = serde_json::from_str(&bytes_serialized).unwrap();
|
||||
assert_eq!(bytes_deserialized, bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_and_deserialize_public() {
|
||||
let public = SerializablePublic("cac6c205eb06c8308d65156ff6c862c62b000b8ead121a4455a8ddeff7248128d895692136f240d5d1614dc7cc4147b1bd584bd617e30560bb872064d09ea325".parse().unwrap());
|
||||
let public_serialized = serde_json::to_string(&public).unwrap();
|
||||
assert_eq!(&public_serialized, r#""0xcac6c205eb06c8308d65156ff6c862c62b000b8ead121a4455a8ddeff7248128d895692136f240d5d1614dc7cc4147b1bd584bd617e30560bb872064d09ea325""#);
|
||||
let public_deserialized: SerializablePublic = serde_json::from_str(&public_serialized).unwrap();
|
||||
assert_eq!(public_deserialized, public);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
use std::fmt;
|
||||
use std::collections::BTreeMap;
|
||||
use serde_json;
|
||||
|
||||
use ethkey;
|
||||
use util;
|
||||
@ -44,6 +45,8 @@ pub enum Error {
|
||||
AccessDenied,
|
||||
/// Requested document not found
|
||||
DocumentNotFound,
|
||||
/// Serialization/deserialization error
|
||||
Serde(String),
|
||||
/// Database-related error
|
||||
Database(String),
|
||||
/// Internal error
|
||||
@ -107,12 +110,19 @@ impl fmt::Display for Error {
|
||||
Error::BadSignature => write!(f, "Bad signature"),
|
||||
Error::AccessDenied => write!(f, "Access dened"),
|
||||
Error::DocumentNotFound => write!(f, "Document not found"),
|
||||
Error::Serde(ref msg) => write!(f, "Serialization error: {}", msg),
|
||||
Error::Database(ref msg) => write!(f, "Database error: {}", msg),
|
||||
Error::Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for Error {
|
||||
fn from(err: serde_json::Error) -> Self {
|
||||
Error::Serde(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethkey::Error> for Error {
|
||||
fn from(err: ethkey::Error) -> Self {
|
||||
Error::Internal(err.into())
|
||||
|
Loading…
Reference in New Issue
Block a user