From aedc473f64e72ded88077be3b9854a77ec071e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 10 Mar 2017 10:11:37 +0100 Subject: [PATCH 01/36] Lowering threshold for transactions above gas limit (#4831) --- ethcore/src/miner/transaction_queue.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index d686a3ff5..9a3e6af1a 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -485,7 +485,7 @@ pub struct AccountDetails { } /// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue. -const GAS_LIMIT_HYSTERESIS: usize = 10; // (100/GAS_LIMIT_HYSTERESIS) % +const GAS_LIMIT_HYSTERESIS: usize = 200; // (100/GAS_LIMIT_HYSTERESIS) % /// Describes the strategy used to prioritize transactions in the queue. #[cfg_attr(feature="dev", allow(enum_variant_names))] @@ -1867,7 +1867,7 @@ pub mod test { // then assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded { - limit: U256::from(55_000), // Should be 110% of set_gas_limit + limit: U256::from(50_250), // Should be 100.5% of set_gas_limit got: gas, }); let stats = txq.status(); From 608c0dc613ea6d1ec4c8ddb50a1100d1de008a85 Mon Sep 17 00:00:00 2001 From: "Denis S. Soldatov aka General-Beck" Date: Fri, 10 Mar 2017 12:12:16 +0300 Subject: [PATCH 02/36] CI: test coverage (for core) (#4832) * test coverage * update gitlab add `git submodule update --init --recursive` * test exec coverage in docker runner * tags kcov --- .gitlab-ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 32cb7e947..e71b99ec0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -503,6 +503,18 @@ docker-build: - sh scripts/docker-build.sh $DOCKER_TAG tags: - docker +test-coverage: + stage: test + only: + - coverage + script: + - git submodule update --init --recursive + - scripts/cov.sh + - COVERAGE=$(grep -Po 'covered":.*?[^\\]"' target/kcov/index.json | grep "[0-9]*\.[0-9]" -o) + - echo "Coverage:" $COVERAGE + tags: + - kcov + allow_failure: true test-darwin: stage: test only: From 0ab0cb1173f96c718cb1da4d2bbdad4f6547cc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 10 Mar 2017 10:25:13 +0100 Subject: [PATCH 03/36] Fix RPC errors. Implement geth-compatibility option to return correct pending nonce. (#4837) --- parity/rpc_apis.rs | 1 + rpc/src/v1/helpers/errors.rs | 12 ++++++ rpc/src/v1/impls/eth.rs | 48 ++++++++++++++++------- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 2 +- rpc/src/v1/impls/parity.rs | 2 +- rpc/src/v1/tests/helpers/miner_service.rs | 17 ++++++++ rpc/src/v1/tests/mocked/eth.rs | 33 ++++++++++++++-- 8 files changed, 96 insertions(+), 21 deletions(-) diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 548e84995..469245c19 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -215,6 +215,7 @@ pub fn setup_rpc(stats: Arc, deps: Arc, apis: ApiSet) -> &deps.miner, &deps.external_miner, EthClientOptions { + pending_nonce_from_queue: deps.geth_compatibility, allow_pending_receipt_query: !deps.geth_compatibility, send_block_number_in_get_work: !deps.geth_compatibility, } diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 0be3f7240..1f98b922d 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -37,6 +37,7 @@ mod codes { pub const TRANSACTION_ERROR: i64 = -32010; pub const EXECUTION_ERROR: i64 = -32015; pub const EXCEPTION_ERROR: i64 = -32016; + pub const DATABASE_ERROR: i64 = -32017; pub const ACCOUNT_LOCKED: i64 = -32020; pub const PASSWORD_INVALID: i64 = -32021; pub const ACCOUNT_ERROR: i64 = -32023; @@ -100,6 +101,9 @@ pub fn account(error: &str, details: T) -> Error { } } +/// Internal error signifying a logic error in code. +/// Should not be used when function can just fail +/// because of invalid parameters or incomplete node state. pub fn internal(error: &str, data: T) -> Error { Error { code: ErrorCode::InternalError, @@ -216,6 +220,14 @@ pub fn encryption_error(error: T) -> Error { } } +pub fn database_error(error: T) -> Error { + Error { + code: ErrorCode::ServerError(codes::DATABASE_ERROR), + message: "Database error.".into(), + data: Some(Value::String(format!("{:?}", error))), + } +} + pub fn from_fetch_error(error: T) -> Error { Error { code: ErrorCode::ServerError(codes::FETCH_ERROR), diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 6df8f5278..8da7063f4 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -58,15 +58,28 @@ const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched /// Eth RPC options pub struct EthClientOptions { + /// Return nonce from transaction queue when pending block not available. + pub pending_nonce_from_queue: bool, /// Returns receipt from pending blocks pub allow_pending_receipt_query: bool, /// Send additional block number when asking for work pub send_block_number_in_get_work: bool, } +impl EthClientOptions { + /// Creates new default `EthClientOptions` and allows alterations + /// by provided function. + pub fn with(fun: F) -> Self { + let mut options = Self::default(); + fun(&mut options); + options + } +} + impl Default for EthClientOptions { fn default() -> Self { EthClientOptions { + pending_nonce_from_queue: false, allow_pending_receipt_query: true, send_block_number_in_get_work: true, } @@ -227,7 +240,7 @@ impl EthClient where store .note_dapp_used(dapp.clone()) .and_then(|_| store.dapp_addresses(dapp)) - .map_err(|e| errors::internal("Could not fetch accounts.", e)) + .map_err(|e| errors::account("Could not fetch accounts.", e)) } } @@ -352,18 +365,16 @@ impl Eth for EthClient where fn balance(&self, address: RpcH160, num: Trailing) -> BoxFuture { let address = address.into(); + let client = take_weakf!(self.client); let res = match num.0.clone() { BlockNumber::Pending => { - let client = take_weakf!(self.client); match take_weakf!(self.miner).balance(&*client, &address) { Some(balance) => Ok(balance.into()), - None => Err(errors::internal("Unable to load balance from database", "")) + None => Err(errors::database_error("latest balance missing")) } } id => { - let client = take_weakf!(self.client); - try_bf!(check_known(&*client, id.clone())); match client.balance(&address, id.into()) { Some(balance) => Ok(balance.into()), @@ -384,7 +395,7 @@ impl Eth for EthClient where let client = take_weakf!(self.client); match take_weakf!(self.miner).storage_at(&*client, &address, &H256::from(position)) { Some(s) => Ok(s.into()), - None => Err(errors::internal("Unable to load storage from database", "")) + None => Err(errors::database_error("latest storage missing")) } } id => { @@ -403,17 +414,26 @@ impl Eth for EthClient where fn transaction_count(&self, address: RpcH160, num: Trailing) -> BoxFuture { let address: Address = RpcH160::into(address); + let client = take_weakf!(self.client); + let miner = take_weakf!(self.miner); + let res = match num.0.clone() { - BlockNumber::Pending => { - let client = take_weakf!(self.client); - match take_weakf!(self.miner).nonce(&*client, &address) { + BlockNumber::Pending if self.options.pending_nonce_from_queue => { + let nonce = miner.last_nonce(&address) + .map(|n| n + 1.into()) + .or_else(|| miner.nonce(&*client, &address)); + match nonce { Some(nonce) => Ok(nonce.into()), - None => Err(errors::internal("Unable to load nonce from database", "")) + None => Err(errors::database_error("latest nonce missing")) + } + } + BlockNumber::Pending => { + match miner.nonce(&*client, &address) { + Some(nonce) => Ok(nonce.into()), + None => Err(errors::database_error("latest nonce missing")) } } id => { - let client = take_weakf!(self.client); - try_bf!(check_known(&*client, id.clone())); match client.nonce(&address, id.into()) { Some(nonce) => Ok(nonce.into()), @@ -464,7 +484,7 @@ impl Eth for EthClient where let client = take_weakf!(self.client); match take_weakf!(self.miner).code(&*client, &address) { Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), - None => Err(errors::internal("Unable to load code from database", "")) + None => Err(errors::database_error("latest code missing")) } } id => { @@ -597,7 +617,7 @@ impl Eth for EthClient where number: None }) } - }).unwrap_or(Err(Error::internal_error())) // no work found. + }).unwrap_or(Err(errors::internal("No work found.", ""))) } fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index f889faf00..9b0c92e9c 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -263,7 +263,7 @@ impl Eth for EthClient { let accounts = self.accounts .note_dapp_used(dapp.clone()) .and_then(|_| self.accounts.dapp_addresses(dapp)) - .map_err(|e| errors::internal("Could not fetch accounts.", e)) + .map_err(|e| errors::account("Could not fetch accounts.", e)) .map(|accs| accs.into_iter().map(Into::::into).collect()); future::done(accounts).boxed() diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 332088dd6..1f056b89e 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -87,7 +87,7 @@ impl Parity for ParityClient { let dapp_accounts = store .note_dapp_used(dapp.clone().into()) .and_then(|_| store.dapp_addresses(dapp.into())) - .map_err(|e| errors::internal("Could not fetch accounts.", e))? + .map_err(|e| errors::account("Could not fetch accounts.", e))? .into_iter().collect::>(); let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 820aa6670..503dfcce6 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -119,7 +119,7 @@ impl Parity for ParityClient where let dapp_accounts = store .note_dapp_used(dapp.clone().into()) .and_then(|_| store.dapp_addresses(dapp.into())) - .map_err(|e| errors::internal("Could not fetch accounts.", e))? + .map_err(|e| errors::account("Could not fetch accounts.", e))? .into_iter().collect::>(); let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 01dd9edc7..c667e408b 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -16,6 +16,7 @@ //! Test implementation of miner service. +use std::collections::hash_map::Entry; use util::{Address, H256, Bytes, U256, FixedHash, Uint}; use util::standard::*; use ethcore::error::{Error, CallError}; @@ -72,6 +73,22 @@ impl Default for TestMinerService { } } +impl TestMinerService { + /// Increments last nonce for given address. + pub fn increment_last_nonce(&self, address: Address) { + let mut last_nonces = self.last_nonces.write(); + match last_nonces.entry(address) { + Entry::Occupied(mut occupied) => { + let val = *occupied.get(); + *occupied.get_mut() = val + 1.into(); + }, + Entry::Vacant(vacant) => { + vacant.insert(0.into()); + }, + } + } +} + impl MinerService for TestMinerService { /// Returns miner's status. diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 2432b55e7..6603bd722 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -468,6 +468,32 @@ fn rpc_eth_transaction_count() { assert_eq!(EthTester::default().io.handle_request_sync(request), Some(response.to_owned())); } +#[test] +fn rpc_eth_transaction_count_next_nonce() { + let tester = EthTester::new_with_options(EthClientOptions::with(|mut options| { + options.pending_nonce_from_queue = true; + })); + tester.miner.increment_last_nonce(1.into()); + + let request1 = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": ["0x0000000000000000000000000000000000000001", "pending"], + "id": 1 + }"#; + let response1 = r#"{"jsonrpc":"2.0","result":"0x1","id":1}"#; + assert_eq!(tester.io.handle_request_sync(request1), Some(response1.to_owned())); + + let request2 = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": ["0x0000000000000000000000000000000000000002", "pending"], + "id": 1 + }"#; + let response2 = r#"{"jsonrpc":"2.0","result":"0x0","id":1}"#; + assert_eq!(tester.io.handle_request_sync(request2), Some(response2.to_owned())); +} + #[test] fn rpc_eth_block_transaction_count_by_hash() { let request = r#"{ @@ -1076,10 +1102,9 @@ fn rpc_get_work_returns_correct_work_package() { #[test] fn rpc_get_work_should_not_return_block_number() { - let eth_tester = EthTester::new_with_options(EthClientOptions { - allow_pending_receipt_query: true, - send_block_number_in_get_work: false, - }); + let eth_tester = EthTester::new_with_options(EthClientOptions::with(|mut options| { + options.send_block_number_in_get_work = false; + })); eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; From 9047b4b487e5e67ac5fbaf20ba79ad6476a31456 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 10 Mar 2017 10:25:40 +0100 Subject: [PATCH 04/36] Supress USB error message (#4839) --- ethcore/src/account_provider/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 2f6d49e75..5bb183d0b 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -152,7 +152,7 @@ impl AccountProvider { manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum }); hardware_store = Some(manager) }, - Err(e) => warn!("Error initializing hardware wallets: {}", e), + Err(e) => debug!("Error initializing hardware wallets: {}", e), } } AccountProvider { From 6eefecf31e42d8af5da03e61cf948035f718588b Mon Sep 17 00:00:00 2001 From: "Denis S. Soldatov aka General-Beck" Date: Fri, 10 Mar 2017 13:23:34 +0300 Subject: [PATCH 05/36] build docker with custom branch or tag [ci -skip] --- docker/hub/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docker/hub/README.md diff --git a/docker/hub/README.md b/docker/hub/README.md new file mode 100644 index 000000000..072307a32 --- /dev/null +++ b/docker/hub/README.md @@ -0,0 +1,2 @@ +Usage +`docker build --build-arg BUILD_TAG=branch_or_tag_name --no-cache=true --tag ethcore/parity:branch_or_tag_name .` From ca963137e9550b89f4019ccd77fd0aa3409bb7f2 Mon Sep 17 00:00:00 2001 From: "Denis S. Soldatov aka General-Beck" Date: Fri, 10 Mar 2017 13:24:18 +0300 Subject: [PATCH 06/36] Update README.md [ci skip] --- docker/hub/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/hub/README.md b/docker/hub/README.md index 072307a32..6253f53f0 100644 --- a/docker/hub/README.md +++ b/docker/hub/README.md @@ -1,2 +1,3 @@ Usage -`docker build --build-arg BUILD_TAG=branch_or_tag_name --no-cache=true --tag ethcore/parity:branch_or_tag_name .` + +```docker build --build-arg BUILD_TAG=branch_or_tag_name --no-cache=true --tag ethcore/parity:branch_or_tag_name .``` From 8edee76f8b78a878833c1187926e10fa37bfa4a3 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 10 Mar 2017 11:38:27 +0100 Subject: [PATCH 07/36] Pull steps from actual available steps (#4848) --- js/src/modals/DeployContract/deployContract.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/js/src/modals/DeployContract/deployContract.js b/js/src/modals/DeployContract/deployContract.js index 14930d312..802de64fb 100644 --- a/js/src/modals/DeployContract/deployContract.js +++ b/js/src/modals/DeployContract/deployContract.js @@ -142,12 +142,13 @@ class DeployContract extends Component { render () { const { step, deployError, rejected, inputs } = this.state; - const realStep = Object.keys(STEPS).findIndex((k) => k === step); - const realSteps = deployError || rejected - ? null - : Object.keys(STEPS) - .filter((k) => k !== 'CONTRACT_PARAMETERS' || inputs.length > 0) - .map((k) => STEPS[k]); + const realStepKeys = deployError || rejected + ? [] + : Object.keys(STEPS).filter((k) => k !== 'CONTRACT_PARAMETERS' || inputs.length > 0); + const realStep = realStepKeys.findIndex((k) => k === step); + const realSteps = realStepKeys.length + ? realStepKeys.map((k) => STEPS[k]) + : null; const title = realSteps ? null From d98b7aab612d8d38e10dbd959f5ea67e74ca42c8 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 10 Mar 2017 11:52:27 +0100 Subject: [PATCH 08/36] Wait for the value to have changed in the input (#4844) --- js/src/ui/Form/Input/input.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/js/src/ui/Form/Input/input.js b/js/src/ui/Form/Input/input.js index 44906ad93..64ec544b9 100644 --- a/js/src/ui/Form/Input/input.js +++ b/js/src/ui/Form/Input/input.js @@ -214,6 +214,7 @@ export default class Input extends Component { onChange = (event, value) => { event.persist(); + this.setValue(value, () => { this.props.onChange && this.props.onChange(event, value); }); @@ -231,12 +232,10 @@ export default class Input extends Component { } onPaste = (event) => { - const { value } = event.target; - const pasted = event.clipboardData.getData('Text'); - + // Wait for the onChange handler to be called window.setTimeout(() => { - this.onSubmit(value + pasted); - }, 0); + this.onSubmit(this.state.value); + }, 200); } onKeyDown = (event) => { From 4e5fd92e67d7f5efecf2f00f1376a38583ce3600 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 10 Mar 2017 12:04:40 +0100 Subject: [PATCH 09/36] Extract i18n from shared UI components (#4834) * Actionbar i18n * ui Errors i18n * Features i18n * GapPriceSelector i18n * WIP * WIP #2 * Update methodDecoding * ModalBox -> functional * Signer pages i18n (missed previously) * Update ModalBox tests * Update variable --- js/src/ui/Actionbar/Export/export.js | 12 +- js/src/ui/Actionbar/Search/search.js | 12 +- js/src/ui/Errors/errors.js | 37 +- js/src/ui/Features/defaults.js | 31 +- .../CustomTooltip/customTooltip.js | 15 +- js/src/ui/Icons/index.js | 2 + js/src/ui/MethodDecoding/methodDecoding.js | 342 ++++++++++++------ js/src/ui/ModalBox/body.js | 35 ++ js/src/ui/ModalBox/modalBox.js | 68 +--- js/src/ui/ModalBox/modalBox.spec.js | 24 +- js/src/ui/ModalBox/summary.js | 37 ++ .../Signer/containers/Embedded/embedded.js | 6 +- .../containers/RequestsPage/requestsPage.js | 30 +- 13 files changed, 452 insertions(+), 199 deletions(-) create mode 100644 js/src/ui/ModalBox/body.js create mode 100644 js/src/ui/ModalBox/summary.js diff --git a/js/src/ui/Actionbar/Export/export.js b/js/src/ui/Actionbar/Export/export.js index b64ab8797..c5fd2f18a 100644 --- a/js/src/ui/Actionbar/Export/export.js +++ b/js/src/ui/Actionbar/Export/export.js @@ -15,11 +15,12 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; +import { FormattedMessage } from 'react-intl'; import FileSaver from 'file-saver'; -import FileDownloadIcon from 'material-ui/svg-icons/file/file-download'; import Button from '../../Button'; +import { FileDownloadIcon } from '../../Icons'; class ActionbarExport extends Component { static propTypes = { @@ -38,7 +39,12 @@ class ActionbarExport extends Component { ); } - onClick = (event) => { + handleClick = (event) => { if (this.props.disabled) { + event.preventDefault(); + event.stopPropagation(); return; } diff --git a/js/src/dapps/dappreg/ButtonBar/buttonBar.js b/js/src/dapps/dappreg/ButtonBar/buttonBar.js deleted file mode 100644 index cce4bb7aa..000000000 --- a/js/src/dapps/dappreg/ButtonBar/buttonBar.js +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -import React, { Component } from 'react'; -import { observer } from 'mobx-react'; - -import DappsStore from '../dappsStore'; -import ModalStore from '../modalStore'; - -import Button from '../Button'; -import styles from './buttonBar.css'; - -@observer -export default class ButtonBar extends Component { - dappsStore = DappsStore.instance(); - modalStore = ModalStore.instance(); - - render () { - let buttons = []; - - if (this.dappsStore.isEditing || this.dappsStore.isNew) { - buttons = [ - + ); + } + + renderButtons () { + const { contractBadgereg, contractDappreg, isBadgeDeploying, isContractDeploying, isDappDeploying, haveAllBadges, haveAllContracts, haveAllDapps, registry } = this.store; + const disableRegistry = registry.address || registry.isDeploying; + const disableContracts = !registry.address || isContractDeploying || haveAllContracts; + const disableDapps = !contractDappreg.address || isDappDeploying || haveAllDapps; + const disableBadges = !registry.address || !contractBadgereg.address || isBadgeDeploying || haveAllBadges; + + return ( +
+ { this.renderButton('registry', this.deployRegistry, disableRegistry) } + { this.renderButton('contracts', this.deployContracts, disableContracts) } + { this.renderButton('badges', this.deployBadges, disableBadges) } + { this.renderButton('apps', this.deployApps, disableDapps) } +
+ ); + } + + renderContracts (isBadges, isExternal) { + const { badges, contracts, contractBadgereg, registry } = this.store; + const regaddress = isBadges + ? contractBadgereg.address + : registry.address; + + return ( +
+

+ { + isExternal + ? 'External ' + : '' + }{ + isBadges + ? 'Badges ' + : 'Contracts ' + }(registry { regaddress || 'unknown' }) +

+
+ { + isExternal || isBadges + ? null + : ( + + ) + } + { + (isBadges ? badges : contracts) + .filter((contract) => contract.isExternal === isExternal) + .map((contract) => { + return ( + + ); + }) + } +
+
+ ); + } + + renderApps (isExternal) { + const { apps, contractDappreg, contractGithubhint } = this.store; + const isDisabled = !contractDappreg.isOnChain || !contractGithubhint.isOnChain; + + return ( +
+

+ { + isExternal + ? 'External ' + : '' + }Applications (registry { + contractDappreg.address + ? contractDappreg.address + : 'unknown' + }) +

+
+ { + apps + .filter((app) => app.isExternal === isExternal) + .map((app) => { + return ( + + ); + }) + } +
+
+ ); + } + + deployApps = () => { + return this.store.deployApps(); + } + + deployBadges = () => { + return this.store.deployBadges(); + } + + deployContracts = () => { + return this.store.deployContracts(); + } + + deployRegistry = () => { + return this.store.deployRegistry(); + } +} diff --git a/js/src/dapps/chaindeploy/Application/index.js b/js/src/dapps/chaindeploy/Application/index.js new file mode 100644 index 000000000..3d8d1ca3b --- /dev/null +++ b/js/src/dapps/chaindeploy/Application/index.js @@ -0,0 +1,17 @@ +// 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 . + +export default from './application'; diff --git a/js/src/dapps/chaindeploy/Contract/contract.js b/js/src/dapps/chaindeploy/Contract/contract.js new file mode 100644 index 000000000..1f0b158d2 --- /dev/null +++ b/js/src/dapps/chaindeploy/Contract/contract.js @@ -0,0 +1,132 @@ +// 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 . + +import React, { Component, PropTypes } from 'react'; + +import ListItem, { Header, Row } from '../ListItem'; + +export default class Contract extends Component { + static propTypes = { + contract: PropTypes.object.isRequired, + disabled: PropTypes.bool + } + + render () { + const { contract, disabled } = this.props; + const location = contract.id === 'registry' + ? 'chain' + : 'registry'; + + return ( + +
+ { contract.id } was { + contract.address + ? 'deployed' + : 'not found' + } +
+ + { + contract.address + ? contract.address + : 'no address' + } + + + { + contract.hasLatestCode + ? 'has latest available code' + : 'does not have latest code' + } + + + { + contract.isOnChain + ? `registered on ${location}` + : `not registered on ${location}` + } + + { this.renderBadgeInfo() } +
+ ); + } + + renderBadgeInfo () { + const { contract } = this.props; + + if (!contract.isBadge) { + return null; + } + + return [ + + { + contract.isBadgeRegistered + ? 'found in badgereg' + : 'not found in badgereg' + } + , + + { + contract.badgeImageHash + ? `badge imageHash ${contract.badgeImageHash}` + : 'has not registered a badge imageHash' + } + , + + { + contract.badgeImageMatch + ? 'has latest badge imageHash' + : 'does not have latest badge imageHash' + } + + ]; + } +} diff --git a/js/src/dapps/chaindeploy/Contract/index.js b/js/src/dapps/chaindeploy/Contract/index.js new file mode 100644 index 000000000..74c58e942 --- /dev/null +++ b/js/src/dapps/chaindeploy/Contract/index.js @@ -0,0 +1,17 @@ +// 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 . + +export default from './contract'; diff --git a/js/src/dapps/chaindeploy/Dapp/dapp.js b/js/src/dapps/chaindeploy/Dapp/dapp.js new file mode 100644 index 000000000..5a997c295 --- /dev/null +++ b/js/src/dapps/chaindeploy/Dapp/dapp.js @@ -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 . + +import React, { Component, PropTypes } from 'react'; + +import ListItem, { Header, Row } from '../ListItem'; + +export default class Dapp extends Component { + static propTypes = { + dapp: PropTypes.object.isRequired, + disabled: PropTypes.bool + } + + render () { + const { dapp, disabled } = this.props; + + return ( + +
+ { dapp.name } +
+ + { + dapp.isOnChain + ? 'found in dappreg' + : 'not found in dappreg' + } + + { this.renderHash(dapp, 'image') } + { this.renderHash(dapp, 'manifest') } + { this.renderHash(dapp, 'content') } +
+ ); + } + + renderHash (dapp, type) { + if (!dapp.source[`${type}Hash`]) { + return null; + } + + const isMatch = dapp[`${type}Match`]; + const hash = dapp[`${type}Hash`]; + + return [ + + { + hash + ? `${type}Hash ${hash}` + : `has not registered an ${type}Hash` + } + , + + { + isMatch + ? `has latest ${type}Hash` + : `does not have latest ${type}Hash` + } + + ]; + } +} diff --git a/js/src/dapps/chaindeploy/Dapp/index.js b/js/src/dapps/chaindeploy/Dapp/index.js new file mode 100644 index 000000000..3d3281389 --- /dev/null +++ b/js/src/dapps/chaindeploy/Dapp/index.js @@ -0,0 +1,17 @@ +// 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 . + +export default from './dapp'; diff --git a/js/src/dapps/chaindeploy/ListItem/Header/header.js b/js/src/dapps/chaindeploy/ListItem/Header/header.js new file mode 100644 index 000000000..e9be01eea --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/Header/header.js @@ -0,0 +1,45 @@ +// 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 . + +import React, { Component, PropTypes } from 'react'; + +import Icon from '../Icon'; + +import styles from '../listItem.css'; + +export default class Header extends Component { + static propTypes = { + children: PropTypes.node.isRequired, + isBusy: PropTypes.bool, + isOk: PropTypes.bool + } + + render () { + const { children, isBusy, isOk } = this.props; + + return ( +
+ +
+ { children } +
+
+ ); + } +} diff --git a/js/src/dapps/chaindeploy/ListItem/Header/index.js b/js/src/dapps/chaindeploy/ListItem/Header/index.js new file mode 100644 index 000000000..aef90266f --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/Header/index.js @@ -0,0 +1,17 @@ +// 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 . + +export default from './header'; diff --git a/js/src/dapps/chaindeploy/ListItem/Icon/icon.js b/js/src/dapps/chaindeploy/ListItem/Icon/icon.js new file mode 100644 index 000000000..1f32622e5 --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/Icon/icon.js @@ -0,0 +1,53 @@ +// 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 . + +import React, { Component, PropTypes } from 'react'; + +import styles from '../listItem.css'; + +export default class Icon extends Component { + static propTypes = { + isBusy: PropTypes.bool, + isOk: PropTypes.bool + } + + render () { + const { isBusy, isOk } = this.props; + + return ( +
+ { + isOk + ? '\u2714' + : ( + isBusy + ? '\u29d6' + : '\u2716' + ) + } +
+ ); + } +} diff --git a/js/src/dapps/chaindeploy/ListItem/Icon/index.js b/js/src/dapps/chaindeploy/ListItem/Icon/index.js new file mode 100644 index 000000000..f43e02c49 --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/Icon/index.js @@ -0,0 +1,17 @@ +// 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 . + +export default from './icon'; diff --git a/js/src/dapps/chaindeploy/ListItem/Row/index.js b/js/src/dapps/chaindeploy/ListItem/Row/index.js new file mode 100644 index 000000000..5f2c62dee --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/Row/index.js @@ -0,0 +1,17 @@ +// 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 . + +export default from './row'; diff --git a/js/src/dapps/chaindeploy/ListItem/Row/row.js b/js/src/dapps/chaindeploy/ListItem/Row/row.js new file mode 100644 index 000000000..0982e0321 --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/Row/row.js @@ -0,0 +1,54 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; + +import Icon from '../Icon'; + +import styles from '../listItem.css'; + +export default class Row extends Component { + static propTypes = { + children: PropTypes.node.isRequired, + disabled: PropTypes.bool, + isBusy: PropTypes.bool, + isOk: PropTypes.bool + } + + render () { + const { children, disabled, isBusy, isOk } = this.props; + + return ( +
+ +
+ { children } +
+
+ ); + } +} diff --git a/js/src/dapps/chaindeploy/ListItem/index.js b/js/src/dapps/chaindeploy/ListItem/index.js new file mode 100644 index 000000000..7c79e3241 --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/index.js @@ -0,0 +1,20 @@ +// 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 . + +export Header from './Header'; +export Row from './Row'; + +export default from './listItem'; diff --git a/js/src/dapps/chaindeploy/ListItem/listItem.css b/js/src/dapps/chaindeploy/ListItem/listItem.css new file mode 100644 index 000000000..47d6d481d --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/listItem.css @@ -0,0 +1,94 @@ +/* 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 . +*/ + +.listItem { + box-sizing: border-box; + flex: 0 1 33.33%; + max-width: 33.33%; + padding: 0.5em; + position: relative; + + .body { + background: rgba(0, 0, 0, 0.025); + border-radius: 0.25em; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + overflow: hidden; + padding: 0.75em; + } + + .status { + background: #f80; + border-radius: 0.25em; + color: white; + font-size: 0.75em; + line-height: 1em; + opacity: 0.9; + padding: 0.5em; + position: absolute; + right: 1em; + top: 1em; + } +} + +.header, +.details { + display: flex; + line-height: 1.5em; + padding: 0.125em 0; + position: relative; + white-space: nowrap; + + .title { + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: top; + } +} + +.details { + margin-left: 2em; +} + +.icon { + border-radius: 0.25em; + display: inline-block; + flex: 0 0 1.5em; + height: 1.5em; + margin-right: 0.5em; + opacity: 0.75; + text-align: center; + vertical-align: middle; + width: 1.5em; + + &.error { + box-shadow: inset 0 0 0 2px rgb(200, 0, 0); + color: rgb(200, 0, 0); + } + + &.ok { + box-shadow: inset 0 0 0 2px rgb(0, 200, 0); + color: rgb(0, 200, 0); + } +} + +.muted { + opacity: 0.25; +} diff --git a/js/src/dapps/chaindeploy/ListItem/listItem.js b/js/src/dapps/chaindeploy/ListItem/listItem.js new file mode 100644 index 000000000..c670123f9 --- /dev/null +++ b/js/src/dapps/chaindeploy/ListItem/listItem.js @@ -0,0 +1,63 @@ +// 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 . + +import React, { Component, PropTypes } from 'react'; + +import styles from './listItem.css'; + +export default class ListItem extends Component { + static propTypes = { + children: PropTypes.node.isRequired, + disabled: PropTypes.bool, + status: PropTypes.string + } + + render () { + const { children, disabled } = this.props; + + return ( +
+
+ { children } +
+ { this.renderStatus() } +
+ ); + } + + renderStatus () { + const { status } = this.props; + + if (!status) { + return null; + } + + return ( +
+ { status } +
+ ); + } +} diff --git a/js/src/dapps/chaindeploy/_dapps.js b/js/src/dapps/chaindeploy/_dapps.js new file mode 100644 index 000000000..b2ce1d4be --- /dev/null +++ b/js/src/dapps/chaindeploy/_dapps.js @@ -0,0 +1,43 @@ +// 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 . + +import builtinsJson from '~/views/Dapps/builtin.json'; + +const REGISTER_URLS = { + console: 'https://raw.githubusercontent.com/ethcore/console/3ea0dbfefded359ccdbea37bc4cf350c0aa16948/console.jpeg', + dappreg: 'https://raw.githubusercontent.com/ethcore/dapp-assets/cdd6ac4f1e2f11619bed72a53ae71217dffe19ad/dapps/legos-64x64.png', + githubhint: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/link-64x64.jpg', + localtx: 'https://raw.githubusercontent.com/ethcore/dapp-assets/cdd6ac4f1e2f11619bed72a53ae71217dffe19ad/dapps/stack-64x64.png', + registry: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/register-64x64.jpg', + signaturereg: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/hex-64x64.jpg', + tokendeploy: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/interlock-64x64.png', + tokenreg: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/coins-64x64.jpg', + web: 'https://raw.githubusercontent.com/ethcore/dapp-assets/ec6138115d0e1f45258969cd90b3b274e0ff2258/dapps/earth-64x64.jpg' +}; + +const builtins = builtinsJson + .filter((app) => app.id) + .map((app) => { + app.source = { + imageUrl: REGISTER_URLS[app.id] + }; + + return app; + }); + +export { + builtins +}; diff --git a/js/src/dapps/chaindeploy/contracts/abi/jg-voting.json b/js/src/dapps/chaindeploy/contracts/abi/jg-voting.json new file mode 100644 index 000000000..83a07ef7c --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/abi/jg-voting.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"count","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalVotes","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"hasSenderVoted","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_index","type":"uint256"},{"name":"_answer","type":"uint256"}],"name":"newAnswer","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_fee","type":"uint256"}],"name":"setQuestionFee","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"questionFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"get","outputs":[{"name":"closed","type":"bool"},{"name":"owner","type":"address"},{"name":"question","type":"string"},{"name":"balanceNo","type":"uint256"},{"name":"balanceYes","type":"uint256"},{"name":"balanceMaybe","type":"uint256"},{"name":"votesNo","type":"uint256"},{"name":"votesYes","type":"uint256"},{"name":"votesMaybe","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_question","type":"string"}],"name":"newQuestion","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"},{"constant":true,"inputs":[],"name":"totalBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"answerFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_index","type":"uint256"}],"name":"closeQuestion","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_fee","type":"uint256"}],"name":"setAnswerFee","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"index","type":"uint256"},{"indexed":false,"name":"question","type":"string"}],"name":"NewQuestion","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"index","type":"uint256"},{"indexed":true,"name":"answer","type":"uint256"},{"indexed":false,"name":"value","type":"uint256"}],"name":"NewAnswer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}] diff --git a/js/src/dapps/chaindeploy/contracts/badgereg.js b/js/src/dapps/chaindeploy/contracts/badgereg.js new file mode 100644 index 000000000..ccd6b28c1 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/badgereg.js @@ -0,0 +1,30 @@ +// 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 . + +import abi from '~/contracts/abi/badgereg'; +import { compiler, source as sourceUrl, output as byteCode } from './code/badgereg'; + +const id = 'badgereg'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/code/badgereg.json b/js/src/dapps/chaindeploy/contracts/code/badgereg.json new file mode 100644 index 000000000..e6613ed26 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/badgereg.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/58842b92c00e3c45a84b6d0ac9b842f016dde50a/BadgeReg.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316179055670de0b6b3a7640000600455341561003357fe5b5b610a6f806100436000396000f300606060405236156100bf5763ffffffff60e060020a60003504166313af403581146100c15780631e7a505f146100df5780632c0f5f591461010a5780635b8066451461014557806369fe0e2d146101675780637958533a1461017c5780638da5cb5b146101a45780639890220b146101d0578063a02b161e146101e2578063ac4ce2c6146101f7578063b72e717d14610218578063c0f6faed1461025b578063dd93890b14610299578063ddbcb5cb146102b4578063ddca3f43146102e6575bfe5b34156100c957fe5b6100dd600160a060020a0360043516610308565b005b6100f6600160a060020a036004351660243561037c565b604080519115158252519081900360200190f35b341561011257fe5b61011d600435610392565b60408051938452600160a060020a039283166020850152911682820152519081900360600190f35b341561014d57fe5b6101556103ef565b60408051918252519081900360200190f35b341561016f57fe5b6100dd6004356103f6565b005b341561018457fe5b61015560043560243561041b565b60408051918252519081900360200190f35b34156101ac57fe5b6101b461045a565b60408051600160a060020a039092168252519081900360200190f35b34156101d857fe5b6100dd610469565b005b34156101ea57fe5b6100dd6004356104bc565b005b34156101ff57fe5b6100dd600435600160a060020a03602435166105ee565b005b341561022057fe5b610234600160a060020a0360043516610721565b604080519384526020840192909252600160a060020a031682820152519081900360600190f35b341561026357fe5b61026e600435610789565b60408051600160a060020a039485168152602081019390935292168183015290519081900360600190f35b34156102a157fe5b6100dd6004356024356044356107dc565b005b6100f6600160a060020a036004358116906024359060443516610899565b604080519115158252519081900360200190f35b34156102ee57fe5b6101556109cc565b60408051918252519081900360200190f35b60005433600160a060020a0390811691161461032357610378565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a360008054600160a060020a031916600160a060020a0383161790555b5b50565b6000610389838333610899565b90505b92915050565b60008181526002602052604081205460038054600019909201929182918291859081106103bb57fe5b906000526020600020906004020160005b5080546002820154600160a060020a03918216955016925090505b509193909250565b6003545b90565b60005433600160a060020a0390811691161461041157610378565b60048190555b5b50565b600060038381548110151561042c57fe5b906000526020600020906004020160005b506000838152600391909101602052604090205490505b92915050565b600054600160a060020a031681565b60005433600160a060020a03908116911614610484576104b8565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1935050505015156104b857610000565b5b5b565b60005433600160a060020a039081169116146104d757610378565b806003828154811015156104e757fe5b906000526020600020906004020160005b50600101546040517f844e89a9d524dabb877007aa0e9c395e8938fcfee93ece70c2cd0353db79c8e590600090a36001600060038381548110151561053957fe5b906000526020600020906004020160005b5054600160a060020a03168152602081019190915260400160009081208190556003805460029291908490811061057d57fe5b906000526020600020906004020160005b50600101548152602081019190915260400160009081205560038054829081106105b457fe5b906000526020600020906004020160005b508054600160a060020a03199081168255600060018301556002909101805490911690555b5b50565b60008233600160a060020a031660038281548110151561060a57fe5b906000526020600020906004020160005b5060020154600160a060020a0316146106335761071b565b600160a060020a03831660009081526001602052604090205483901561065857610718565b600380548690811061066657fe5b906000526020600020906004020160005b505460038054600160a060020a03909216945085918790811061069657fe5b906000526020600020906004020160005b508054600160a060020a031916600160a060020a039283161790558381166000908152600160209081526040808320839055928716808352918390208890558251918252915187927fa5d871c0e725767cd5aefc99c53aeca35f09dcc268145cbb13b74a7e2f48f196928290030190a25b5b505b50505050565b600160a060020a038116600090815260016020526040812054600380546000199092019291829182918590811061075457fe5b906000526020600020906004020160005b5060018101546002820154909450600160a060020a0316925090505b509193909250565b60006000600060006003858154811015156107a057fe5b906000526020600020906004020160005b50805460018201546002830154600160a060020a03928316975090955016925090505b509193909250565b8233600160a060020a03166003828154811015156107f657fe5b906000526020600020906004020160005b5060020154600160a060020a03161461081f5761071b565b8160038581548110151561082f57fe5b906000526020600020906004020160005b50600085815260039190910160209081526040918290209290925580518481529051859287927f7991c63a749706fd298fc2387764d640be6e714307b6357b1d3c2ce35cba3b52929081900390910190a35b5b50505050565b60006004543410156108aa576109c5565b600160a060020a0384166000908152600160205260409020548490156108cf576109c3565b6000848152600260205260409020548490156108ea576109c0565b60038054600181016108fc83826109d2565b916000526020600020906004020160005b5060408051606081018252600160a060020a03808b1680835260208084018c9052918a169284018390528454600160a060020a03199081168217865560018087018d905560029687018054909216909417905560035460008281529383528484208190558b8452948252918390208490558251918252915160001993909301935088927febbfb6376bef000063e6e33494e4c543a6197091a04eb6a6f55013d85a1c5386929181900390910190a3600192505b5b505b505b9392505050565b60045481565b8154818355818115116109fe576004028160040283600052602060002091820191016109fe9190610a04565b5b505050565b6103f391905b80821115610a3c578054600160a060020a03199081168255600060018301556002820180549091169055600401610a0a565b5090565b905600a165627a7a72305820526fc95faec325cec5dd3e1bb67c165265282c5fc6db21e96197060b823aaa490029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/dappreg.json b/js/src/dapps/chaindeploy/contracts/code/dappreg.json new file mode 100644 index 000000000..eae53272a --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/dappreg.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/225bf022ddd967af2b9ea188e8f611489ca5d7fe/DappReg.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316179055670de0b6b3a7640000600355341561003357fe5b5b6106ee806100436000396000f300606060405236156100a95763ffffffff60e060020a6000350416630257c48c81146100ab57806306661abd146100d357806313af4035146100f55780631a0919dc1461011357806369fe0e2d146101285780638da5cb5b1461013d5780638eaa6ac01461016957806391cd242d1461019d5780639890220b146101b8578063c52bd836146101ca578063ddca3f43146101eb578063e0886f901461020d578063e1fa8e8414610241575bfe5b34156100b357fe5b6100c160043560243561024e565b60408051918252519081900360200190f35b34156100db57fe5b6100c1610272565b60408051918252519081900360200190f35b34156100fd57fe5b610111600160a060020a0360043516610279565b005b341561011b57fe5b6101116004356102ed565b005b341561013057fe5b610111600435610388565b005b341561014557fe5b61014d6103ad565b60408051600160a060020a039092168252519081900360200190f35b341561017157fe5b61017c6004356103bc565b60408051928352600160a060020a0390911660208301528051918290030190f35b34156101a557fe5b6101116004356024356044356103e4565b005b34156101c057fe5b61011161046d565b005b34156101d257fe5b610111600435600160a060020a03602435166104c0565b005b34156101f357fe5b6100c161054e565b60408051918252519081900360200190f35b341561021557fe5b61017c600435610554565b60408051928352600160a060020a0390911660208301528051918290030190f35b6101116004356105ab565b005b60008281526001602090815260408083208484526002019091529020545b92915050565b6002545b90565b60005433600160a060020a0390811691161461029457610000565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a360008054600160a060020a031916600160a060020a0383161790555b5b50565b60008181526001602081905260409091200154819033600160a060020a0390811691161480159061032d575060005433600160a060020a03908116911614155b1561033757610000565b60008281526001602081905260408083208381559091018054600160a060020a03191690555183917fe17fec26316aebe957e188549d659a89f359c49766bcc0ae2fb7ded274ffe14691a25b5b5050565b60005433600160a060020a039081169116146103a357610000565b60038190555b5b50565b600054600160a060020a031681565b6000818152600160208190526040909120805491810154600160a060020a0316905b50915091565b60008381526001602081905260409091200154839033600160a060020a0390811691161461041157610000565b600084815260016020908152604080832086845260020182529182902084905581518481529151859287927f4dcd4fb147bb133a0da8fbf4e5fc3ddd64f04d4b3f6cbee584374b889d28c78d92918290030190a35b5b50505050565b60005433600160a060020a0390811691161461048857610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1935050505015156104bc57610000565b5b5b565b60008281526001602081905260409091200154829033600160a060020a039081169116146104ed57610000565b60008381526001602081905260408083209091018054600160a060020a031916600160a060020a0386169081179091559051909185917fd3d10d874a10020c2bce719499d1fd8756d880b128eb2945dd01b3830854e7169190a35b5b505050565b60035481565b6000600060006001600060028681548110151561056d57fe5b906000526020600020900160005b50548152602081019190915260400160002080546001820154909450600160a060020a0316925090505b50915091565b6003543410156105ba57610000565b6000818152600160205260409020548190156105d557610000565b60028054600181016105e78382610677565b916000526020600020900160005b508390555060408051808201825283815233600160a060020a0390811660208084018281526000888152600192839052868120955186559051949091018054600160a060020a0319169490931693909317909155915184917f7d917fcbc9a29a9705ff9936ffa599500e4fd902e4486bae317414fe967b307c91a35b5b505b50565b815481835581811511610548576000838152602090206105489181019083016106a1565b5b505050565b61027691905b808211156106bb57600081556001016106a7565b5090565b905600a165627a7a7230582011d8a45e381635e9de17e14cc4de97a1e17758cfac1fd25e8a5bc1d5f4d1da9d0029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/gavcoin.json b/js/src/dapps/chaindeploy/contracts/code/gavcoin.json new file mode 100644 index 000000000..dbf53fdeb --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/gavcoin.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/58842b92c00e3c45a84b6d0ac9b842f016dde50a/GavCoin.sol", + "output": "0x606060405266038d7ea4c680006002556305f5e100600355341561001f57fe5b5b6108008061002f6000396000f300606060405236156100885763ffffffff60e060020a600035041663095ea7b3811461009f57806318160ddd146100d257806323b872dd146100f457806329cbdc861461012d57806355234ec0146101465780635af36e3e1461016857806370a0823114610192578063a035b1fe146101c0578063a9059cbb146101e2578063dd62ed3e14610215575b61009d5b61009a3360ff60020a610249565b5b565b005b34156100a757fe5b6100be600160a060020a0360043516602435610390565b604080519115158252519081900360200190f35b34156100da57fe5b6100e2610416565b60408051918252519081900360200190f35b34156100fc57fe5b6100be600160a060020a036004358116906024351660443561041c565b604080519115158252519081900360200190f35b61009d600160a060020a036004351660243561052a565b005b341561014e57fe5b6100e2610539565b60408051918252519081900360200190f35b341561017057fe5b6100be60043560243561053f565b604080519115158252519081900360200190f35b341561019a57fe5b6100e2600160a060020a03600435166106d0565b60408051918252519081900360200190f35b34156101c857fe5b6100e26106ef565b60408051918252519081900360200190f35b34156101ea57fe5b6100be600160a060020a03600435166024356106f5565b604080519115158252519081900360200190f35b341561021d57fe5b6100e2600160a060020a03600435811690602435166107a3565b60408051918252519081900360200190f35b34600080805b60008411801561026157508460025411155b1561038757600354600254620f424091025b0492508284116102835783610285565b825b9150600254620f4240830281151561029957fe5b33600160a060020a03166000818152600160208181526040808420805497909604968701865560028054855295830190915280832080548701905584548352808320909101805463ffffffff191662093a80420163ffffffff161790558154850182559254925193945084937f689dcb02b6a65e0e2f1d23ef47c1ec86604ffbed0bcb65f20150cfc7d5e5a9489190a4600380548290039081905593829003931515610382576002805466038d7ea4c6800001908190556305f5e1006003556040517f23c3dae768238f239632b5c4acb89485b440e0fa72481c4aad9f9b4f9b5a0a5f90600090a25b61024f565b5b505050505050565b600082600160a060020a031633600160a060020a03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a350600160a060020a0333811660009081526001602081815260408084209487168452600290940190529190208054830190555b92915050565b60005481565b600160a060020a038316600090815260016020526040812054849083908190101561044657610521565b600160a060020a0380871660009081526001602090815260408083203394851684526002019091529020548791908690819010156104835761051c565b87600160a060020a031689600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef896040518082815260200191505060405180910390a3600160a060020a03808a166000908152600160208181526040808420338616855260028101835281852080548e900390559183905281548c9003909155928b16825291902080548901905595505b5b5050505b50509392505050565b6105348282610249565b5b5050565b60035481565b600160a060020a0333166000908152600160208181526040808420868552909201905281205483908390819010806105a35750600160a060020a03331660009081526001602081815260408084208685528301909152909120015463ffffffff1642105b156105ad576106c8565b33600160a060020a0381166000908152600160205260409020548590819010156105d6576106c4565b60405186908890600160a060020a033316907f73f04af9dcc582a923ec15d3eea990fe34adabfff2879e28d44572e01a54abb690600090a433600160a060020a0316600090815260016020818152604080842080548b9003815584548b0185558b855290920190529020805487900390819055151561068457600160a060020a03331660009081526001602081815260408084208b85528301909152822091825501805463ffffffff191690555b600160a060020a0333166108fc620f4240888a025b604051919004801590920291906000818181858888f1935050505015156106bf57610000565b600194505b5b50505b505092915050565b600160a060020a0381166000908152600160205260409020545b919050565b60025481565b33600160a060020a038116600090815260016020526040812054909190839081901015610721576106c8565b84600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef866040518082815260200191505060405180910390a3600160a060020a03338116600090815260016020526040808220805488900390559187168152208054850190555b5b505092915050565b600160a060020a03808316600090815260016020908152604080832093851683526002909301905220545b929150505600a165627a7a72305820ca533a37c92e41888bda66ae0e66415d21a61c60027b269bca633d85b727875c0029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/githubhint.json b/js/src/dapps/chaindeploy/contracts/code/githubhint.json new file mode 100644 index 000000000..1dedacfe8 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/githubhint.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/58842b92c00e3c45a84b6d0ac9b842f016dde50a/GithubHint.sol", + "output": "0x6060604052341561000c57fe5b5b6105868061001c6000396000f300606060405263ffffffff60e060020a60003504166302f2008d81146100425780632196ae0d1461009b578063267b6922146101055780637c8c6643146101c9575bfe5b341561004a57fe5b60408051602060046024803582810135601f810185900485028601850190965285855261009995833595939460449493929092019181908401838280828437509496506101de95505050505050565b005b34156100a357fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100999583359593946044949392909201918190840183828082843750949650505092356bffffffffffffffffffffffff191692506102be915050565b005b341561010d57fe5b6101186004356103b1565b604080516bffffffffffffffffffffffff1984166020820152600160a060020a03831691810191909152606080825284546002600019610100600184161502019091160490820181905281906080820190869080156101b85780601f1061018d576101008083540402835291602001916101b8565b820191906000526020600020905b81548152906001019060200180831161019b57829003601f168201915b505094505050505060405180910390f35b34156101d157fe5b6100996004356103de565b005b6000828152602081905260409020600201548290600160a060020a031615801590610227575060008181526020819052604090206002015433600160a060020a03908116911614155b15610231576102b8565b6040805160608101825283815260006020808301829052600160a060020a0333168385015286825281815292902081518051929391926102749284920190610472565b506020820151600182018054606060020a909204600160a060020a031992831617905560409092015160029091018054600160a060020a0392909216919092161790555b5b505050565b6000838152602081905260409020600201548390600160a060020a031615801590610307575060008181526020819052604090206002015433600160a060020a03908116911614155b15610311576103aa565b604080516060810182528481526bffffffffffffffffffffffff198416602080830191909152600160a060020a0333168284015260008781528082529290922081518051929391926103669284920190610472565b506020820151600182018054606060020a909204600160a060020a031992831617905560409092015160029091018054600160a060020a0392909216919092161790555b5b50505050565b600060208190529081526040902060018101546002820154606060020a90910290600160a060020a031683565b6000818152602081905260409020600201548190600160a060020a031615801590610427575060008181526020819052604090206002015433600160a060020a03908116911614155b156104315761046d565b60008281526020819052604081209061044a82826104f1565b50600181018054600160a060020a03199081169091556002909101805490911690555b5b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106104b357805160ff19168380011785556104e0565b828001600101855582156104e0579182015b828111156104e05782518255916020019190600101906104c5565b5b506104ed929150610539565b5090565b50805460018160011615610100020316600290046000825580601f106105175750610535565b601f0160209004906000526020600020908101906105359190610539565b5b50565b61055791905b808211156104ed576000815560010161053f565b5090565b905600a165627a7a72305820a83571409e7b0cc4fe48edd09087f315930ab4e017c62b6d100462285a8f4ae70029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/jg-voting.json b/js/src/dapps/chaindeploy/contracts/code/jg-voting.json new file mode 100644 index 000000000..08ec4d0ed --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/jg-voting.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/jacogr/dapp-voting/blob/9b20754b13b9a387704c0955d88b51d2e0e1896d/src/solidity/Voting.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316178155600281905560038190556004556611c37937e0800060055534156200004057fe5b5b60408051808201909152600781527f48756e6772793f0000000000000000000000000000000000000000000000000060208201526200008e906401000000006200090a6200009682021704565b505b620003af565b60008054819033600160a060020a03908116911614801590620000ba575060055434105b15620000c65762000000565b82600481511080620000d9575060a08151115b15620000e55762000000565b60018054925082810190620000fb908262000244565b50336001838154811015156200010d57fe5b906000526020600020906005020160005b508054600160a060020a03929092166101000261010060a860020a031990921691909117905560018054859190849081106200015657fe5b906000526020600020906005020160005b5060010190805190602001906200018092919062000279565b508133600160a060020a03167f7793f929911ad07e07894a20378f1eccce0fb493486c569d74045731fb583b8e866040518080602001828103825283818151815260200191508051906020019080838360008314620001fc575b805182526020831115620001fc57601f199092019160209182019101620001da565b505050905090810190601f168015620002295780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600192505b5b505b50919050565b8154818355818115116200027357600502816005028360005260206000209182019101620002739190620002ff565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002bc57805160ff1916838001178555620002ec565b82800160010185558215620002ec579182015b82811115620002ec578251825591602001919060010190620002cf565b5b50620002fb9291506200033f565b5090565b6200033c91905b80821115620002fb578054600160a860020a031916815560006200032e600183018262000363565b5060050162000306565b5090565b90565b6200033c91905b80821115620002fb576000815560010162000346565b5090565b90565b50805460018160011615610100020316600290046000825580601f106200038b5750620003ab565b601f016020900490600052602060002090810190620003ab91906200033f565b5b50565b610d2f80620003bf6000396000f300606060405236156100bf5763ffffffff60e060020a60003504166306661abd81146100c15780630d15fd77146100e357806313af40351461010557806331d3164714610123578063476c494c1461014a5780634df6ca2a1461016c5780638a55b54d146101935780638da5cb5b146101b55780639507d39a146101e15780639890220b146102c7578063a3f66b46146102eb578063ad7a672f1461034d578063bd12b4b51461036f578063c09f32e814610391578063f41c1c93146103b8575bfe5b34156100c957fe5b6100d16103df565b60408051918252519081900360200190f35b34156100eb57fe5b6100d16103e6565b60408051918252519081900360200190f35b341561010d57fe5b610121600160a060020a03600435166103ec565b005b341561012b57fe5b61013660043561046d565b604080519115158252519081900360200190f35b6101366004356024356104b8565b604080519115158252519081900360200190f35b341561017457fe5b6101366004356106c3565b604080519115158252519081900360200190f35b341561019b57fe5b6100d16106ee565b60408051918252519081900360200190f35b34156101bd57fe5b6101c56106f4565b60408051600160a060020a039092168252519081900360200190f35b34156101e957fe5b6101f4600435610703565b604051808a15151515815260200189600160a060020a0316600160a060020a0316815260200180602001888152602001878152602001868152602001858152602001848152602001838152602001828103825289818151815260200191508051906020019080838360008314610285575b80518252602083111561028557601f199092019160209182019101610265565b505050905090810190601f1680156102b15780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390f35b34156102cf57fe5b6101366108b2565b604080519115158252519081900360200190f35b610136600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965061090a95505050505050565b604080519115158252519081900360200190f35b341561035557fe5b6100d1610ab5565b60408051918252519081900360200190f35b341561037757fe5b6100d1610abb565b60408051918252519081900360200190f35b341561039957fe5b610136600435610ac1565b604080519115158252519081900360200190f35b34156103c057fe5b610136600435610b63565b604080519115158252519081900360200190f35b6001545b90565b60035481565b60005433600160a060020a0390811691161461040757610000565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b600060018281548110151561047e57fe5b906000526020600020906005020160005b50600160a060020a0333166000908152600491909101602052604090205460ff1690505b919050565b6000805433600160a060020a039081169116148015906104d9575060045434105b156104e357610000565b600154839081106104f357610000565b8360018181548110151561050357fe5b906000526020600020906005020160005b505460ff1615156001141561052857610000565b8460018181548110151561053857fe5b906000526020600020906005020160005b50600160a060020a0333166000908152600491909101602052604090205460ff1615156001141561057957610000565b84600281111561058857610000565b60038054600190810190915560028054600160a060020a0333163101905580548190899081106105b457fe5b906000526020600020906005020160005b5033600160a060020a031660008181526004929092016020526040909120805460ff191692151592909217909155600180549131918990811061060457fe5b906000526020600020906005020160005b50600088815260029190910160205260409020805490910190556001805481908990811061063f57fe5b906000526020600020906005020160005b506000888152600391909101602090815260409182902080549093019092558051600160a060020a033316318152905188928a927f8b8ed2ef61b90da02f78bd8647287f46833d5b11467db4451e5c4b165485bf46929081900390910190a3600194505b5b505b505b505b505b92915050565b6000805433600160a060020a039081169116146106df57610000565b50600581905560015b5b919050565b60055481565b600054600160a060020a031681565b6000600061070f610b8e565b600060006000600060006000600060018b81548110151561072c57fe5b906000526020600020906005020160005b5090508060000160009054906101000a900460ff1699508060000160019054906101000a9004600160a060020a03169850806001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108065780601f106107db57610100808354040283529160200191610806565b820191906000526020600020905b8154815290600101906020018083116107e957829003601f168201915b505050505097508060020160006000815260200190815260200160002054965080600201600060018152602001908152602001600020549550806002016000600281526020019081526020016000205494508060030160006000815260200190815260200160002054935080600301600060018152602001908152602001600020549250806003016000600281526020019081526020016000205491505b509193959799909294969850565b6000805433600160a060020a039081169116146108ce57610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f19350505050151561090257610000565b5060015b5b90565b60008054819033600160a060020a0390811691161480159061092d575060055434105b1561093757610000565b82600481511080610949575060a08151115b1561095357610000565b600180549250828101906109679082610ba0565b503360018381548110151561097857fe5b906000526020600020906005020160005b508054600160a060020a03929092166101000274ffffffffffffffffffffffffffffffffffffffff001990921691909117905560018054859190849081106109cd57fe5b906000526020600020906005020160005b5060010190805190602001906109f5929190610bd2565b508133600160a060020a03167f7793f929911ad07e07894a20378f1eccce0fb493486c569d74045731fb583b8e866040518080602001828103825283818151815260200191508051906020019080838360008314610a6e575b805182526020831115610a6e57601f199092019160209182019101610a4e565b505050905090810190601f168015610a9a5780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600192505b5b505b50919050565b60025481565b60045481565b60008133600160a060020a0316600182815481101515610add57fe5b906000526020600020906005020160005b50546101009004600160a060020a031614801590610b1b575060005433600160a060020a03908116911614155b15610b2557610000565b6001600184815481101515610b3657fe5b906000526020600020906005020160005b50805460ff1916911515919091179055600191505b5b50919050565b6000805433600160a060020a03908116911614610b7f57610000565b50600481905560015b5b919050565b60408051602081019091526000815290565b815481835581811511610bcc57600502816005028360005260206000209182019101610bcc9190610c51565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610c1357805160ff1916838001178555610c40565b82800160010185558215610c40579182015b82811115610c40578251825591602001919060010190610c25565b5b50610c4d929150610c9a565b5090565b6103e391905b80821115610c4d57805474ffffffffffffffffffffffffffffffffffffffffff191681556000610c8a6001830182610cbb565b50600501610c57565b5090565b90565b6103e391905b80821115610c4d5760008155600101610ca0565b5090565b90565b50805460018160011615610100020316600290046000825580601f10610ce15750610469565b601f0160209004906000526020600020908101906104699190610c9a565b5b505600a165627a7a72305820b084dcce4e3d78f8a86c925f6c3f2ed689e3674655482541076a1a22f6cdedad0029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/registry.json b/js/src/dapps/chaindeploy/contracts/code/registry.json new file mode 100644 index 000000000..6976dee58 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/registry.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/b1e0348144793e4ce6f7d6d2c4c7d0bb4ae9765e/SimpleRegistry.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316179055670de0b6b3a7640000600355341561003357fe5b5b611b2f806100436000396000f300606060405236156101225763ffffffff60e060020a60003504166306b2ff47811461012457806313af40351461015457806319362a28146101725780633f3935d1146101df578063432ced04146102495780634f39ca59146102685780636795dbcd1461028f57806369fe0e2d1461030257806379ce9fac146103295780638da5cb5b1461035c57806390b97fc11461038857806392698814146103f15780639890220b14610418578063ac4e73f91461043c578063ac72c120146104b1578063c3a3582514610388578063ddca3f4314610541578063deb931a214610563578063df57b74214610592578063e30bd740146105c1578063eadf976014610172578063ef5454d6146106ca578063f25eb5c11461073f578063f6d339e414610751575bfe5b341561012c57fe5b610140600160a060020a03600435166107c7565b604080519115158252519081900360200190f35b341561015c57fe5b610170600160a060020a03600435166107fa565b005b341561017a57fe5b60408051602060046024803582810135601f81018590048502860185019096528585526101409583359593946044949392909201918190840183828082843750949650509335935061086e92505050565b604080519115158252519081900360200190f35b34156101e757fe5b610140600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650610a1495505050505050565b604080519115158252519081900360200190f35b610140600435610b6e565b604080519115158252519081900360200190f35b341561027057fe5b610140600435610c03565b604080519115158252519081900360200190f35b341561029757fe5b60408051602060046024803582810135601f81018590048502860185019096528585526102e69583359593946044949392909201918190840183828082843750949650610cc495505050505050565b60408051600160a060020a039092168252519081900360200190f35b341561030a57fe5b610140600435610d40565b604080519115158252519081900360200190f35b341561033157fe5b610140600435600160a060020a0360243516610d9e565b604080519115158252519081900360200190f35b341561036457fe5b6102e6610e2e565b60408051600160a060020a039092168252519081900360200190f35b341561039057fe5b60408051602060046024803582810135601f81018590048502860185019096528585526103df9583359593946044949392909201918190840183828082843750949650610cc495505050505050565b60408051918252519081900360200190f35b34156103f957fe5b610140600435610eb9565b604080519115158252519081900360200190f35b341561042057fe5b610140610ed9565b604080519115158252519081900360200190f35b341561044457fe5b610140600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965050509235600160a060020a03169250610f6e915050565b604080519115158252519081900360200190f35b34156104b957fe5b6101406004356112ac565b604080519115158252519081900360200190f35b341561039057fe5b60408051602060046024803582810135601f81018590048502860185019096528585526103df9583359593946044949392909201918190840183828082843750949650610cc495505050505050565b60408051918252519081900360200190f35b341561054957fe5b6103df61134c565b60408051918252519081900360200190f35b341561056b57fe5b6102e6600435611352565b60408051600160a060020a039092168252519081900360200190f35b341561059a57fe5b6102e6600435611370565b60408051600160a060020a039092168252519081900360200190f35b34156105c957fe5b6105dd600160a060020a0360043516611392565b604080516020808252835181830152835191928392908301918501908083838215610623575b80518252602083111561062357601f199092019160209182019101610603565b505050905090810190601f16801561064f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561017a57fe5b60408051602060046024803582810135601f81018590048502860185019096528585526101409583359593946044949392909201918190840183828082843750949650509335935061086e92505050565b604080519115158252519081900360200190f35b34156106d257fe5b610140600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965050509235600160a060020a031692506115e8915050565b604080519115158252519081900360200190f35b341561074757fe5b6101706116c6565b005b341561075957fe5b60408051602060046024803582810135601f8101859004850286018501909652858552610140958335959394604494939290920191819084018382808284375094965050509235600160a060020a0316925061185a915050565b604080519115158252519081900360200190f35b600160a060020a03811660009081526002602081905260409091205460001961010060018316150201160415155b919050565b60005433600160a060020a039081169116146108155761086a565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a360008054600160a060020a031916600160a060020a0383161790555b5b50565b600083815260016020526040812054849033600160a060020a0390811691161461089757610a0b565b6000858152600160209081526040918290209151865186936002019288929182918401908083835b602083106108de5780518252601f1990920191602091820191016108bf565b51815160209384036101000a60001901801990921691161790529201948552506040519384900381018420949094555050855186928291908401908083835b6020831061093c5780518252601f19909201916020918201910161091d565b51815160209384036101000a6000190180199092169116179052604080519290940182900382208183528a51838301528a519096508b95507fb829c3e412537bbe794c048ccb9e4605bb4aaaa8e4d4c15c1a6e0c2adc1716ea948b94508392908301919085019080838382156109cd575b8051825260208311156109cd57601f1990920191602091820191016109ad565b505050905090810190601f1680156109f95780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b509392505050565b60008133600160a060020a031660016000836040518082805190602001908083835b60208310610a555780518252601f199092019160209182019101610a36565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002060010154600160a060020a0316939093149250610aab91505057610b67565b600160a060020a03331660009081526002602090815260409091208451610ad492860190611a09565b5033600160a060020a0316836040518082805190602001908083835b60208310610b0f5780518252601f199092019160209182019101610af0565b5181516020939093036101000a60001901801990911692169190911790526040519201829003822093507f098ae8581bb8bd9af1beaf7f2e9f51f31a8e5a8bfada4e303a645d71d9c9192092506000919050a3600191505b5b50919050565b6000818152600160205260408120548290600160a060020a031615610b9257610b67565b600354341015610ba157610b67565b6000838152600160205260408082208054600160a060020a03191633600160a060020a03169081179091559051909185917f4963513eca575aba66fdcd25f267aae85958fe6fb97e75fa25d783f1a091a2219190a3600191505b5b5b50919050565b600081815260016020526040812054829033600160a060020a03908116911614610c2c57610b67565b600083815260016020818152604080842090920154600160a060020a03168352600290528120610c5b91611a88565b60008381526001602081905260408083208054600160a060020a03199081168255920180549092169091555133600160a060020a03169185917fef1961b4d2909dc23643b309bfe5c3e5646842d98c3a58517037ef3871185af39190a3600191505b5b50919050565b600082815260016020908152604080832090518451600290920192859282918401908083835b60208310610d095780518252601f199092019160209182019101610cea565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054925050505b92915050565b6000805433600160a060020a03908116911614610d5c576107f5565b60038290556040805183815290517f6bbc57480a46553fa4d156ce702beef5f3ad66303b0ed1a5d4cb44966c6584c39181900360200190a15060015b5b919050565b600082815260016020526040812054839033600160a060020a03908116911614610dc757610e26565b6000848152600160205260408082208054600160a060020a031916600160a060020a0387811691821790925591519192339091169187917f7b97c62130aa09acbbcbf7482630e756592496f1759eaf702f469cf64dfb779491a4600191505b5b5092915050565b600054600160a060020a031681565b600082815260016020908152604080832090518451600290920192859282918401908083835b60208310610d095780518252601f199092019160209182019101610cea565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054925050505b92915050565b600081815260016020526040902054600160a060020a031615155b919050565b6000805433600160a060020a03908116911614610ef557610f6a565b60408051600160a060020a03301631815290517fdef931299fe61d176f949118058530c1f3f539dcb6950b4e372c9b835c33ca079181900360200190a1604051600160a060020a0333811691309091163180156108fc02916000818181858888f193505050501515610f6657610000565b5060015b5b90565b60006000836040518082805190602001908083835b60208310610fa25780518252601f199092019160209182019101610f83565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526001909252929020549193505033600160a060020a039081169116149050610ff6576112a3565b846040518082805190602001908083835b602083106110265780518252601f199092019160209182019101611007565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120600081815260019283905293909320015491955050600160a060020a03161580159250905061111257506000828152600160208181526040808420830154600160a060020a031684526002918290529283902092518354869493919283928592908116156101000260001901160480156110ff5780601f106110dd5761010080835404028352918201916110ff565b820191906000526020600020905b8154815290600101906020018083116110eb575b5050915050604051809103902060001916145b156111eb57600082815260016020818152604080842090920154600160a060020a0316835260029052812061114691611a88565b6000828152600160208181526040928390209091015491518751600160a060020a039093169288928291908401908083835b602083106111975780518252601f199092019160209182019101611178565b5181516020939093036101000a60001901801990911692169190911790526040519201829003822093507f12491ad95fd945e444d88a894ffad3c21959880a4dcd8af99d4ae4ffc71d4abd92506000919050a35b6000828152600160208181526040928390209091018054600160a060020a031916600160a060020a0388169081179091559151875188928291908401908083835b6020831061124b5780518252601f19909201916020918201910161122c565b5181516020939093036101000a60001901801990911692169190911790526040519201829003822093507f728435a0031f6a04538fcdd24922a7e06bc7bc945db03e83d22122d1bc5f28df92506000919050a3600192505b5b505092915050565b60008181526001602081905260409091200154600160a060020a031615155b919050565b600082815260016020908152604080832090518451600290920192859282918401908083835b60208310610d095780518252601f199092019160209182019101610cea565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054925050505b92915050565b60035481565b600081815260016020526040902054600160a060020a03165b919050565b60008181526001602081905260409091200154600160a060020a03165b919050565b61139a611ad0565b600160a060020a038216600090815260026020818152604092839020805484516001821615610100026000190190911693909304601f81018390048302840183019094528383529192908301828280156114355780601f1061140a57610100808354040283529160200191611435565b820191906000526020600020905b81548152906001019060200180831161141857829003601f168201915b505050505090505b919050565b600083815260016020526040812054849033600160a060020a0390811691161461089757610a0b565b6000858152600160209081526040918290209151865186936002019288929182918401908083835b602083106108de5780518252601f1990920191602091820191016108bf565b51815160209384036101000a60001901801990921691161790529201948552506040519384900381018420949094555050855186928291908401908083835b6020831061093c5780518252601f19909201916020918201910161091d565b51815160209384036101000a6000190180199092169116179052604080519290940182900382208183528a51838301528a519096508b95507fb829c3e412537bbe794c048ccb9e4605bb4aaaa8e4d4c15c1a6e0c2adc1716ea948b94508392908301919085019080838382156109cd575b8051825260208311156109cd57601f1990920191602091820191016109ad565b505050905090810190601f1680156109f95780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b509392505050565b6000805433600160a060020a0390811691161461160457610d3a565b600160a060020a0382166000908152600260209081526040909120845161162d92860190611a09565b5081600160a060020a0316836040518082805190602001908083835b602083106116685780518252601f199092019160209182019101611649565b5181516020939093036101000a60001901801990911692169190911790526040519201829003822093507f098ae8581bb8bd9af1beaf7f2e9f51f31a8e5a8bfada4e303a645d71d9c9192092506000919050a35060015b5b92915050565b33600160a060020a03166002600033600160a060020a0316600160a060020a0316815260200190815260200160002060405180828054600181600116156101000203166002900480156117505780601f1061172e576101008083540402835291820191611750565b820191906000526020600020905b81548152906001019060200180831161173c575b505060405190819003812092507f12491ad95fd945e444d88a894ffad3c21959880a4dcd8af99d4ae4ffc71d4abd9150600090a3600160006002600033600160a060020a0316600160a060020a0316815260200190815260200160002060405180828054600181600116156101000203166002900480156118085780601f106117e6576101008083540402835291820191611808565b820191906000526020600020905b8154815290600101906020018083116117f4575b50506040805191829003909120845260208085019590955292830160009081206001018054600160a060020a031916905533600160a060020a0316815260029094525050812061185791611a88565b5b565b600083815260016020526040812054849033600160a060020a0390811691161461188357610a0b565b60008581526001602090815260409182902091518651600160a060020a038716936002019288929182918401908083835b602083106108de5780518252601f1990920191602091820191016108bf565b51815160209384036101000a60001901801990921691161790529201948552506040519384900381018420949094555050855186928291908401908083835b6020831061093c5780518252601f19909201916020918201910161091d565b51815160209384036101000a6000190180199092169116179052604080519290940182900382208183528a51838301528a519096508b95507fb829c3e412537bbe794c048ccb9e4605bb4aaaa8e4d4c15c1a6e0c2adc1716ea948b94508392908301919085019080838382156109cd575b8051825260208311156109cd57601f1990920191602091820191016109ad565b505050905090810190601f1680156109f95780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b509392505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a84929150611ae2565b5090565b50805460018160011615610100020316600290046000825580601f10611aae575061086a565b601f01602090049060005260206000209081019061086a9190611ae2565b5b50565b60408051602081019091526000815290565b610f6a91905b80821115611a845760008155600101611ae8565b5090565b905600a165627a7a723058202a8f09bd2a20f43dfe4c6adb69bf4bfa211cda23787d972cd6e33eee989cafc50029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/signaturereg.json b/js/src/dapps/chaindeploy/contracts/code/signaturereg.json new file mode 100644 index 000000000..c3caf9276 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/signaturereg.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/58842b92c00e3c45a84b6d0ac9b842f016dde50a/SignatureReg.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316178155600255341561002a57fe5b5b60408051808201909152601081527f726567697374657228737472696e67290000000000000000000000000000000060208201526100759064010000000061036661007c82021704565b505b61031c565b60006100f7826040518082805190602001908083835b602083106100b15780518252601f199092019160209182019101610092565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020836100ff640100000000026103d6176401000000009004565b90505b919050565b7fffffffff000000000000000000000000000000000000000000000000000000008216600090815260016020819052604082205484916002908216156101000260001901909116041561015157610274565b7fffffffff000000000000000000000000000000000000000000000000000000008416600090815260016020908152604090912084516101939286019061027c565b5060028054600101905560408051602080825285518183015285517fffffffff00000000000000000000000000000000000000000000000000000000881693600160a060020a033316937f50e01e16719d6c699e516c57f4c514e77f6bc21a978d33f23980acdddbcbd0b293899391928392908301918501908083838215610236575b80518252602083111561023657601f199092019160209182019101610216565b505050905090810190601f1680156102625780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b5092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106102bd57805160ff19168380011785556102ea565b828001600101855582156102ea579182015b828111156102ea5782518255916020019190600101906102cf565b5b506102f79291506102fb565b5090565b61031991905b808211156102f75760008155600101610301565b5090565b90565b6105d78061032b6000396000f3006060604052361561005c5763ffffffff60e060020a60003504166313af4035811461005e5780633015a5211461007c5780638da5cb5b1461009e5780639890220b146100ca578063b46bcdaa146100dc578063f2c298be14610179575bfe5b341561006657fe5b61007a600160a060020a03600435166101e3565b005b341561008457fe5b61008c610264565b60408051918252519081900360200190f35b34156100a657fe5b6100ae61026a565b60408051600160a060020a039092168252519081900360200190f35b34156100d257fe5b61007a610279565b005b34156100e457fe5b6100f9600160e060020a0319600435166102cc565b60408051602080825283518183015283519192839290830191850190808383821561013f575b80518252602083111561013f57601f19909201916020918201910161011f565b505050905090810190601f16801561016b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561018157fe5b6101cf600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965061036695505050505050565b604080519115158252519081900360200190f35b60005433600160a060020a039081169116146101fe57610260565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b60025481565b600054600160a060020a031681565b60005433600160a060020a03908116911614610294576102c8565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1935050505015156102c857610000565b5b5b565b60016020818152600092835260409283902080548451600294821615610100026000190190911693909304601f810183900483028401830190945283835291929083018282801561035e5780601f106103335761010080835404028352916020019161035e565b820191906000526020600020905b81548152906001019060200180831161034157829003601f168201915b505050505081565b60006103ce826040518082805190602001908083835b6020831061039b5780518252601f19909201916020918201910161037c565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020836103d6565b90505b919050565b600160e060020a03198216600090815260016020819052604082205484916002908216156101000260001901909116041561041057610503565b600160e060020a031984166000908152600160209081526040909120845161043a9286019061050b565b506002805460010190556040805160208082528551818301528551600160e060020a0319881693600160a060020a033316937f50e01e16719d6c699e516c57f4c514e77f6bc21a978d33f23980acdddbcbd0b2938993919283929083019185019080838382156104c5575b8051825260208311156104c557601f1990920191602091820191016104a5565b505050905090810190601f1680156104f15780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b5092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061054c57805160ff1916838001178555610579565b82800160010185558215610579579182015b8281111561057957825182559160200191906001019061055e565b5b5061058692915061058a565b5090565b6105a891905b808211156105865760008155600101610590565b5090565b905600a165627a7a723058206830357dde798fafa19dd78a4460c047f76cc132713db13442c5da7485fc0ff40029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/tokendeploy.json b/js/src/dapps/chaindeploy/contracts/code/tokendeploy.json new file mode 100644 index 000000000..b04fdb38b --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/tokendeploy.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/0ca02d60066202432305c8e9b1cbf33267478ab3/BasicCoin.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316179055341561002757fe5b5b610f43806100376000396000f3006060604052361561007d5763ffffffff60e060020a600035041663061ea8cc811461007f57806306661abd146100ad57806313af4035146100cf5780635001f3b5146100ed5780638da5cb5b1461010f5780639507d39a1461013b5780639890220b14610179578063acfdfd1c1461018b578063c00ca38314610236575bfe5b341561008757fe5b61009b600160a060020a0360043516610280565b60408051918252519081900360200190f35b34156100b557fe5b61009b61029f565b60408051918252519081900360200190f35b34156100d757fe5b6100eb600160a060020a03600435166102a6565b005b34156100f557fe5b61009b610327565b60408051918252519081900360200190f35b341561011757fe5b61011f61032e565b60408051600160a060020a039092168252519081900360200190f35b341561014357fe5b61014e60043561033d565b60408051600160a060020a039485168152928416602084015292168183015290519081900360600190f35b341561018157fe5b6100eb610392565b005b60408051602060046024803582810135601f8101859004850286018501909652858552610222958335959394604494939290920191819084018382808284375050604080516020601f89358b0180359182018390048302840183019094528083529799988101979196509182019450925082915084018382808284375094965050509235600160a060020a031692506103e5915050565b604080519115158252519081900360200190f35b341561023e57fe5b61014e600160a060020a036004351660243561079b565b60408051600160a060020a039485168152928416602084015292168183015290519081900360600190f35b600160a060020a0381166000908152600260205260409020545b919050565b6001545b90565b60005433600160a060020a039081169116146102c157610000565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b620f424081565b600054600160a060020a031681565b600060006000600060018581548110151561035457fe5b906000526020600020906003020160005b50805460018201546002830154600160a060020a039283169750908216955016925090505b509193909250565b60005433600160a060020a039081169116146103ad57610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1935050505015156103e157610000565b5b5b565b60008181808088336103f56107eb565b918252600160a060020a03166020820152604080519182900301906000f080151561041c57fe5b925061042733610280565b915083600160a060020a031663ddca3f436000604051602001526040518163ffffffff1660e060020a028152600401809050602060405180830381600087803b151561046f57fe5b60325a03f1151561047c57fe5b50506040805151600160a060020a03331660009081526002602052919091209092506001840191506104ae90826107fb565b50600154600160a060020a03331660009081526002602052604090208054849081106104d657fe5b906000526020600020900160005b5055600180548082016104f78382610825565b916000526020600020906003020160005b60606040519081016040528087600160a060020a0316815260200133600160a060020a0316815260200188600160a060020a0316815250909190915060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010160006101000a815481600160a060020a030219169083600160a060020a0316021790555060408201518160020160006101000a815481600160a060020a030219169083600160a060020a0316021790555050505083600160a060020a0316637b1a547c82858b620f42408c336000604051602001526040518763ffffffff1660e060020a0281526004018086600160a060020a0316600160a060020a03168152602001806020018581526020018060200184600160a060020a0316600160a060020a03168152602001838103835287818151815260200191508051906020019080838360008314610686575b80518252602083111561068657601f199092019160209182019101610666565b505050905090810190601f1680156106b25780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838382156106f1575b8051825260208311156106f157601f1990920191602091820191016106d1565b505050905090810190601f16801561071d5780820380516001836020036101000a031916815260200191505b509750505050505050506020604051808303818588803b151561073c57fe5b61235a5a03f1151561074a57fe5b5050604051600160a060020a03808716935087811692503316907f454b0172f64812df0cd504c2bd7df7aab8ff328a54d946b4bd0fa7c527adf9cc90600090a4600194505b50505050949350505050565b600160a060020a03821660009081526002602052604081208054829182916107dd9190869081106107c857fe5b906000526020600020900160005b505461033d565b9250925092505b9250925092565b604051610650806108c883390190565b81548183558181151161081f5760008381526020902061081f918101908301610857565b5b505050565b81548183558181151161081f5760030281600302836000526020600020918201910161081f9190610878565b5b505050565b6102a391905b80821115610871576000815560010161085d565b5090565b90565b6102a391905b8082111561087157805473ffffffffffffffffffffffffffffffffffffffff19908116825560018201805482169055600282018054909116905560030161087e565b5090565b905600606060405260008054600160a060020a03191633600160a060020a0316179055341561002757fe5b6040516040806106508339810160405280516020909101515b600034111561004e57610000565b8180151561005b57610000565b600183905560008054600160a060020a031916600160a060020a038416908117825581526002602052604090208390555b5b505b50505b6105af806100a16000396000f3006060604052361561007d5763ffffffff60e060020a600035041663095ea7b3811461009257806313af4035146100c557806318160ddd146100e357806323b872dd146101055780635001f3b51461013e57806370a08231146101605780638da5cb5b1461018e578063a9059cbb146101ba578063dd62ed3e146101ed575b341561008557fe5b6100905b610000565b565b005b341561009a57fe5b6100b1600160a060020a0360043516602435610221565b604080519115158252519081900360200190f35b34156100cd57fe5b610090600160a060020a03600435166102b6565b005b34156100eb57fe5b6100f3610337565b60408051918252519081900360200190f35b341561010d57fe5b6100b1600160a060020a036004358116906024351660443561033d565b604080519115158252519081900360200190f35b341561014657fe5b6100f361045d565b60408051918252519081900360200190f35b341561016857fe5b6100f3600160a060020a0360043516610464565b60408051918252519081900360200190f35b341561019657fe5b61019e610483565b60408051600160a060020a039092168252519081900360200190f35b34156101c257fe5b6100b1600160a060020a0360043516602435610492565b604080519115158252519081900360200190f35b34156101f557fe5b6100f3600160a060020a0360043581169060243516610552565b60408051918252519081900360200190f35b6000600034111561023157610000565b82600160a060020a031633600160a060020a03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a350600160a060020a0333811660009081526002602090815260408083209386168352600193840190915290208054830190555b5b92915050565b60005433600160a060020a039081169116146102d157610000565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b60015481565b6000600034111561034d57610000565b600160a060020a038416600090815260026020526040902054849083908190101561037757610000565b600160a060020a0380871660009081526002602090815260408083203394851684526001019091529020548791908690819010156103b457610000565b87600160a060020a031689600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef896040518082815260200191505060405180910390a3600160a060020a03808a16600090815260026020818152604080842033861685526001808201845282862080548f900390559390925281548c9003909155928b16825291902080548901905595505b5b5050505b50505b9392505050565b620f424081565b600160a060020a0381166000908152600260205260409020545b919050565b600054600160a060020a031681565b600060003411156104a257610000565b33600160a060020a0381166000908152600260205260409020548390819010156104cb57610000565b84600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef866040518082815260200191505060405180910390a3600160a060020a0333811660009081526002602052604080822080548890039055918716815220805485019055600192505b5b50505b92915050565b600160a060020a03808316600090815260026020908152604080832093851683526001909301905220545b929150505600a165627a7a72305820b5bf89a0a85c15df1e9717e49be06fe1a4f9dcc1e0cebf5483dd1c0bcd14a0910029a165627a7a723058207f96b7ad40c02cfaeaf29e65c79456dd3fd9828c9d3fbaf801fb60010456c3880029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/tokenreg.json b/js/src/dapps/chaindeploy/contracts/code/tokenreg.json new file mode 100644 index 000000000..bd96f16b1 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/tokenreg.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/58842b92c00e3c45a84b6d0ac9b842f016dde50a/TokenReg.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316179055670de0b6b3a7640000600455341561003357fe5b5b611473806100436000396000f300606060405236156100b45763ffffffff60e060020a600035041663044215c681146100b657806313af4035146101df57806366b42dcb146101fd57806369fe0e2d146102ab5780637958533a146102c05780637b1a547c146102e8578063891de9ed146103a15780638da5cb5b146104bc5780639890220b146104e85780639f181b5e146104fa578063a02b161e1461051c578063b72e717d14610531578063dd93890b1461066a578063ddca3f4314610685575bfe5b34156100be57fe5b6100c96004356106a7565b60408051600160a060020a038088168252918101859052908216608082015260a060208083018281528751928401929092528651606084019160c0850191908901908083838215610135575b80518252602083111561013557601f199092019160209182019101610115565b505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838382156101a0575b8051825260208311156101a057601f199092019160209182019101610180565b505050905090810190601f1680156101cc5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390f35b34156101e757fe5b6101fb600160a060020a036004351661083a565b005b60408051602060046024803582810135601f8101859004850286018501909652858552610297958335600160a060020a0316959394604494939290920191819084018382808284375050604080516020601f818a01358b0180359182018390048302840183018552818452989a8a359a9099940197509195509182019350915081908401838280828437509496506108ae95505050505050565b604080519115158252519081900360200190f35b34156102b357fe5b6101fb6004356108c8565b005b34156102c857fe5b6102d66004356024356108ed565b60408051918252519081900360200190f35b60408051602060046024803582810135601f8101859004850286018501909652858552610297958335600160a060020a0316959394604494939290920191819084018382808284375050604080516020601f818a01358b0180359182018390048302840183018552818452989a8a359a90999401975091955091820193509150819084018382808284375094965050509235600160a060020a0316925061092c915050565b604080519115158252519081900360200190f35b34156103a957fe5b6103f7600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650610c6695505050505050565b6040518086815260200185600160a060020a0316600160a060020a031681526020018481526020018060200183600160a060020a0316600160a060020a0316815260200182810382528481815181526020019150805190602001908083836000831461047e575b80518252602083111561047e57601f19909201916020918201910161045e565b505050905090810190601f1680156104aa5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390f35b34156104c457fe5b6104cc610dca565b60408051600160a060020a039092168252519081900360200190f35b34156104f057fe5b6101fb610dd9565b005b341561050257fe5b6102d6610e2c565b60408051918252519081900360200190f35b341561052457fe5b6101fb600435610e33565b005b341561053957fe5b61054d600160a060020a0360043516611047565b60405180868152602001806020018581526020018060200184600160a060020a0316600160a060020a03168152602001838103835287818151815260200191508051906020019080838360008314610135575b80518252602083111561013557601f199092019160209182019101610115565b505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838382156101a0575b8051825260208311156101a057601f199092019160209182019101610180565b505050905090810190601f1680156101cc5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390f35b341561067257fe5b6101fb6004356024356044356111f3565b005b341561068d57fe5b6102d66112b0565b60408051918252519081900360200190f35b60006106b16112b6565b60006106bb6112b6565b600060006003878154811015156106ce57fe5b906000526020600020906006020160005b50805460018083018054604080516020601f600260001997861615610100029790970190941695909504928301859004850281018501909152818152600160a060020a039094169a5093945091929083018282801561077f5780601f106107545761010080835404028352916020019161077f565b820191906000526020600020905b81548152906001019060200180831161076257829003601f168201915b505050600280850154600386018054604080516020601f6000196101006001871615020190941696909604928301869004860281018601909152818152969b50919950935091508301828280156108175780601f106107ec57610100808354040283529160200191610817565b820191906000526020600020905b8154815290600101906020018083116107fa57829003601f168201915b50505050600483015491945050600160a060020a031691505b5091939590929450565b60005433600160a060020a03908116911614610855576108aa565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a360008054600160a060020a031916600160a060020a0383161790555b5b50565b60006108bd858585853361092c565b90505b949350505050565b60005433600160a060020a039081169116146108e3576108aa565b60048190555b5b50565b60006003838154811015156108fe57fe5b906000526020600020906006020160005b506000838152600591909101602052604090205490505b92915050565b600060045434101561093d57610c5d565b600160a060020a03861660009081526001602052604090205486901561096257610c5b565b8551869060031461097257610c59565b866002816040518082805190602001908083835b602083106109a55780518252601f199092019160209182019101610986565b51815160209384036101000a60001901801990921691161790529201948552506040519384900301909220541591506109df905057610c56565b60038054600181016109f183826112c8565b916000526020600020906006020160005b506040805160a081018252600160a060020a03808e1680835260208084018f90529383018d9052606083018c9052908a1660808301528354600160a060020a0319161783558b51909291610a5d9160018401918e01906112fa565b506040820151600282015560608201518051610a839160038401916020909101906112fa565b506080919091015160049091018054600160a060020a031916600160a060020a03928316179055600354908b1660009081526001602090815260409182902083905590518b519293506002928c928291908401908083835b60208310610afa5780518252601f199092019160209182019101610adb565b51815160001960209485036101000a81019182169119929092161790915293909101958652604051958690038101862096909655506003548d519101948d9493508392508401908083835b60208310610b645780518252601f199092019160209182019101610b45565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f25074d730da65a10e171fe5589d2182313ef00da38d23a9ae3b78923568bdf2d8b896040518083600160a060020a0316600160a060020a0316815260200180602001828103825283818151815260200191508051906020019080838360008314610c17575b805182526020831115610c1757601f199092019160209182019101610bf7565b505050905090810190601f168015610c435780820380516001836020036101000a031916815260200191505b50935050505060405180910390a3600193505b5b505b505b505b95945050505050565b600060006000610c746112b6565b6000600060016002886040518082805190602001908083835b60208310610cac5780518252601f199092019160209182019101610c8d565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902054039550600386815481101515610cf257fe5b906000526020600020906006020160005b5080546002808301546003840180546040805160206101006001851615026000190190931695909504601f8101839004830286018301909152808552600160a060020a039095169a50919850939450909291908301828280156108175780601f106107ec57610100808354040283529160200191610817565b820191906000526020600020905b8154815290600101906020018083116107fa57829003601f168201915b50505050600483015491945050600160a060020a031691505b5091939590929450565b600054600160a060020a031681565b60005433600160a060020a03908116911614610df457610e28565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f193505050501515610e2857610000565b5b5b565b6003545b90565b60005433600160a060020a03908116911614610e4e576108aa565b80600382815481101515610e5e57fe5b906000526020600020906006020160005b506001016040518082805460018160011615610100020316600290048015610ece5780601f10610eac576101008083540402835291820191610ece565b820191906000526020600020905b815481529060010190602001808311610eba575b505060405190819003812092507f96e76fa77fea85d8abeb7533fdb8288c214bb1dcf1f867c8f36a95f1f509c1759150600090a360016000600383815481101515610f1557fe5b906000526020600020906006020160005b5054600160a060020a031681526020810191909152604001600090812055600380546002919083908110610f5657fe5b906000526020600020906006020160005b506001016040518082805460018160011615610100020316600290048015610fc65780601f10610fa4576101008083540402835291820191610fc6565b820191906000526020600020905b815481529060010190602001808311610fb2575b50509283525050604051908190036020019020600090556003805482908110610feb57fe5b906000526020600020906006020160005b8154600160a060020a0319168255611018600183016000611379565b60028201600090556003820160006110309190611379565b506004018054600160a060020a03191690555b5b50565b60006110516112b6565b600061105b6112b6565b600160a060020a03851660009081526001602052604081205460038054600019909201965082918790811061108c57fe5b906000526020600020906006020160005b509050806001018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561077f5780601f106107545761010080835404028352916020019161077f565b820191906000526020600020905b81548152906001019060200180831161076257829003601f168201915b505050600280850154600386018054604080516020601f6000196101006001871615020190941696909604928301869004860281018601909152818152969b50919950935091508301828280156108175780601f106107ec57610100808354040283529160200191610817565b820191906000526020600020905b8154815290600101906020018083116107fa57829003601f168201915b50505050600483015491945050600160a060020a031691505b5091939590929450565b8233600160a060020a031660038281548110151561120d57fe5b906000526020600020906006020160005b5060040154600160a060020a031614611236576112a9565b8160038581548110151561124657fe5b906000526020600020906006020160005b50600085815260059190910160209081526040918290209290925580518481529051859287927f7991c63a749706fd298fc2387764d640be6e714307b6357b1d3c2ce35cba3b52929081900390910190a35b5b50505050565b60045481565b60408051602081019091526000815290565b8154818355818115116112f4576006028160060283600052602060002091820191016112f491906113c1565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061133b57805160ff1916838001178555611368565b82800160010185558215611368579182015b8281111561136857825182559160200191906001019061134d565b5b50611375929150611426565b5090565b50805460018160011615610100020316600290046000825580601f1061139f57506108aa565b601f0160209004906000526020600020908101906108aa9190611426565b5b50565b610e3091905b80821115611375578054600160a060020a031916815560006113ec6001830182611379565b60028201600090556003820160006114049190611379565b50600481018054600160a060020a03191690556006016113c7565b5090565b90565b610e3091905b80821115611375576000815560010161142c565b5090565b905600a165627a7a72305820ab1d1a18270ba278cc2f74cd1b7b547cdcd6308a9df1dec1120fa9f6199b1f480029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/verifyEmail.json b/js/src/dapps/chaindeploy/contracts/code/verifyEmail.json new file mode 100644 index 000000000..fff3fb07d --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/verifyEmail.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/e5afdacc716ca743ceddf80978d4e6b2b465dbe9/ProofOfEmail.sol", + "output": "0x606060405260008054600160a060020a03191633600160a060020a0316178155600355341561002a57fe5b5b6108a48061003a6000396000f300606060405236156100ca5763ffffffff60e060020a60003504166306b2ff4781146100cc57806313af4035146100fc5780632650b9881461011a5780634b59e8801461018c57806359c87d70146101b05780636795dbcd146101bd57806369fe0e2d1461023057806370c4d5f214610245578063797af627146103255780638da5cb5b1461034c5780639890220b14610378578063ac72c1201461038a578063cc1d4c02146103b1578063ddca3f43146103e1578063df57b74214610403578063e30bd74014610432575bfe5b34156100d457fe5b6100e8600160a060020a03600435166104ce565b604080519115158252519081900360200190f35b341561010457fe5b610118600160a060020a03600435166104d6565b005b341561012257fe5b60408051602060046024803582810135601f810185900485028601850190965285855261017a958335600160a060020a0316959394604494939290920191819084018382808284375094965061055795505050505050565b60408051918252519081900360200190f35b341561019457fe5b610118600160a060020a0360043516602435604435610577565b005b6101186004356105eb565b005b34156101c557fe5b60408051602060046024803582810135601f8101859004850286018501909652858552610214958335959394604494939290920191819084018382808284375094965061063595505050505050565b60408051600160a060020a039092168252519081900360200190f35b341561023857fe5b610118600435610654565b005b341561024d57fe5b60408051602060046024803582810135601f81018590048502860185019096528585526102a5958335600160a060020a0316959394604494939290920191819084018382808284375094965061067995505050505050565b6040805160208082528351818301528351919283929083019185019080838382156102eb575b8051825260208311156102eb57601f1990920191602091820191016102cb565b505050905090810190601f1680156103175780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561032d57fe5b6100e8600435610688565b604080519115158252519081900360200190f35b341561035457fe5b610214610791565b60408051600160a060020a039092168252519081900360200190f35b341561038057fe5b6101186107a0565b005b341561039257fe5b6100e86004356107f3565b604080519115158252519081900360200190f35b34156103b957fe5b6100e8600160a060020a0360043516610813565b604080519115158252519081900360200190f35b34156103e957fe5b61017a610834565b60408051918252519081900360200190f35b341561040b57fe5b61021460043561083a565b60408051600160a060020a039092168252519081900360200190f35b341561043a57fe5b6102a5600160a060020a0360043516610858565b6040805160208082528351818301528351919283929083019185019080838382156102eb575b8051825260208311156102eb57601f1990920191602091820191016102cb565b505050905090810190601f1680156103175780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60005b919050565b60005433600160a060020a039081169116146104f157610553565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b600160a060020a0382166000908152600260205260409020545b92915050565b60005433600160a060020a03908116911614610592576105e5565b600082815260046020908152604091829020839055815184815291518392600160a060020a038716927f76babef7e9f1065118be3f9d7094016a1cc06dd12811501c7712deb22144f37b92918290030190a35b5b505050565b6003543410156105fa57610553565b6040518190600160a060020a033316907f070669e6be82aa9b077a096b0f9617893a4dc5cb05897e27fd7a6112c8e6629e90600090a35b5b50565b600082815260016020526040902054600160a060020a03165b92915050565b60005433600160a060020a0390811691161461066f57610553565b60038190555b5b50565b610571610866565b5b92915050565b6040805182815281516020918190038201902060009081526004909152908120548015156106b55761078b565b6040805184815281516020918190038201902060009081526004825282812081905583815260019091522054600160a060020a031615158061070e5750600160a060020a03331660009081526002602052604090205415155b156107185761078b565b6000818152600160209081526040808320805473ffffffffffffffffffffffffffffffffffffffff191633600160a060020a031690811790915580845260029092528083208490555190917fd415b905d4dd806bfba99a7a0e6351bd0c9db3a9912add21c0e6bef4479f673f91a2600191505b50919050565b600054600160a060020a031681565b60005433600160a060020a039081169116146107bb576107ef565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1935050505015156107ef57610000565b5b5b565b600081815260016020526040902054600160a060020a031615155b919050565b600160a060020a03811660009081526002602052604090205415155b919050565b60035481565b600081815260016020526040902054600160a060020a03165b919050565b6104d1610866565b5b919050565b604080516020810190915260008152905600a165627a7a7230582081d03388dd06c78ee4098c4f1e23cd3c25e38d249d5da59962c6b28ec6e20ea70029" +} diff --git a/js/src/dapps/chaindeploy/contracts/code/verifySms.json b/js/src/dapps/chaindeploy/contracts/code/verifySms.json new file mode 100644 index 000000000..79b9c0459 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/code/verifySms.json @@ -0,0 +1,5 @@ +{ + "compiler": "v0.4.9+commit.364da425", + "source": "https://github.com/ethcore/contracts/blob/58842b92c00e3c45a84b6d0ac9b842f016dde50a/SMSVerification.sol", + "output": "0x606060405260008054600160a060020a033316600160a060020a03199182168117909255600280549091169091179055666a94d74f430000600455341561004257fe5b5b6109a0806100526000396000f300606060405236156100ca5763ffffffff60e060020a60003504166313af403581146100cc57806314253887146100ea578063338cdca1146101085780633da5c3ce146101125780635283f3391461013357806369fe0e2d146101af57806374a8f103146101c4578063797af627146101e25780638da5cb5b146102095780639890220b14610235578063c89e436114610247578063ca4cbf6714610273578063ca5eb5e1146102e5578063cc1d4c0214610303578063ddca3f4314610333578063fc2525ab14610273575bfe5b34156100d457fe5b6100e8600160a060020a03600435166103c7565b005b34156100f257fe5b6100e8600160a060020a0360043516610448565b005b6100e86104b4565b005b341561011a57fe5b6100e8600160a060020a0360043516602435610521565b005b341561013b57fe5b60408051602060046024803582810135601f8101859004850286018501909652858552610193958335600160a060020a0316959394604494939290920191819084018382808284375094965061059295505050505050565b60408051600160a060020a039092168252519081900360200190f35b34156101b757fe5b6100e8600435610623565b005b34156101cc57fe5b6100e8600160a060020a0360043516610648565b005b34156101ea57fe5b6101f56004356106d9565b604080519115158252519081900360200190f35b341561021157fe5b610193610771565b60408051600160a060020a039092168252519081900360200190f35b341561023d57fe5b6100e8610780565b005b341561024f57fe5b6101936107d3565b60408051600160a060020a039092168252519081900360200190f35b341561027b57fe5b60408051602060046024803582810135601f81018590048502860185019096528585526102d3958335600160a060020a0316959394604494939290920191819084018382808284375094965061059295505050505050565b60408051918252519081900360200190f35b34156102ed57fe5b6100e8600160a060020a0360043516610873565b005b341561030b57fe5b6101f5600160a060020a03600435166108bb565b604080519115158252519081900360200190f35b341561033b57fe5b6102d36108dd565b60408051918252519081900360200190f35b341561027b57fe5b60408051602060046024803582810135601f81018590048502860185019096528585526102d3958335600160a060020a0316959394604494939290920191819084018382808284375094965061059295505050505050565b60408051918252519081900360200190f35b60005433600160a060020a039081169116146103e257610444565b60008054604051600160a060020a03808516939216917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b60025433600160a060020a0390811691161461046357610444565b600160a060020a0381166000818152600160208190526040808320805460ff1916909217909155517fd415b905d4dd806bfba99a7a0e6351bd0c9db3a9912add21c0e6bef4479f673f9190a25b5b50565b6004543410156104c35761051e565b600160a060020a03331660009081526001602052604090205460ff16156104e95761051e565b604051600160a060020a033316907f039f711c9c18dd815b225b1424855e6118e746c6b5d688907f10c4dd29ebe92a90600090a25b5b565b60025433600160a060020a0390811691161461053c5761058d565b600160a060020a038216600081815260036020908152604091829020849055815184815291517fa9a343b39eac85ffb326e93ecd46785b814e72dc9f2b33bb0b4a315ba2859f439281900390910190a25b5b5050565b60006001600084600160a060020a0316600160a060020a03168152602001908152602001600020600101826040518082805190602001908083835b602083106105ec5780518252601f1990920191602091820191016105cd565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054925050505b92915050565b60005433600160a060020a0390811691161461063e57610444565b60048190555b5b50565b60025433600160a060020a0390811691161461066357610444565b600160a060020a038116600090815260016020526040902054819060ff16151561068c5761058d565b600160a060020a038216600081815260016020526040808220805460ff19169055517fb6fa8b8bd5eab60f292eca876e3ef90722275b785309d84b1de113ce0b8c4e749190a25b5b505b50565b6040805182815281516020918190038201902033600160a060020a031660009081526003909252918120549091146107105761076c565b600160a060020a0333166000818152600360209081526040808320839055600191829052808320805460ff1916909217909155517fd415b905d4dd806bfba99a7a0e6351bd0c9db3a9912add21c0e6bef4479f673f9190a25060015b919050565b600054600160a060020a031681565b60005433600160a060020a0390811691161461079b5761051e565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f19350505050151561051e57610000565b5b5b565b600254600160a060020a031681565b60006001600084600160a060020a0316600160a060020a03168152602001908152602001600020600101826040518082805190602001908083835b602083106105ec5780518252601f1990920191602091820191016105cd565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054925050505b92915050565b60005433600160a060020a0390811691161461088e57610444565b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b600160a060020a03811660009081526001602052604090205460ff165b919050565b60045481565b60006001600084600160a060020a0316600160a060020a03168152602001908152602001600020600101826040518082805190602001908083835b602083106105ec5780518252601f1990920191602091820191016105cd565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054925050505b929150505600a165627a7a72305820f6beb9c0ae3b45609ad6fc26c1b74600cbaa5f0088ca07be3e9c392a12b2c6150029" +} diff --git a/js/src/dapps/chaindeploy/contracts/dappreg.js b/js/src/dapps/chaindeploy/contracts/dappreg.js new file mode 100644 index 000000000..71379bf8b --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/dappreg.js @@ -0,0 +1,30 @@ +// 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 . + +import abi from '~/contracts/abi/dappreg'; +import { compiler, source as sourceUrl, output as byteCode } from './code/dappreg'; + +const id = 'dappreg'; // 7bbc4f1a27628781b96213e781a1b8eec6982c1db8fac739af6e4c5a55862c03 +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/gavcoin.js b/js/src/dapps/chaindeploy/contracts/gavcoin.js new file mode 100644 index 000000000..f7518ef53 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/gavcoin.js @@ -0,0 +1,32 @@ +// 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 . + +import abi from '~/contracts/abi/gavcoin'; +import { compiler, source as sourceUrl, output as byteCode } from './code/gavcoin'; + +const isExternal = true; +const id = 'gavcoin'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + isExternal, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/githubhint.js b/js/src/dapps/chaindeploy/contracts/githubhint.js new file mode 100644 index 000000000..5198e38b5 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/githubhint.js @@ -0,0 +1,30 @@ +// 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 . + +import abi from '~/contracts/abi/githubhint'; +import { compiler, source as sourceUrl, output as byteCode } from './code/githubhint'; + +const id = 'githubhint'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/index.js b/js/src/dapps/chaindeploy/contracts/index.js new file mode 100644 index 000000000..5e066f758 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/index.js @@ -0,0 +1,52 @@ +// 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 . + +import * as badgereg from './badgereg'; +import * as dappreg from './dappreg'; +import * as gavcoin from './gavcoin'; +import * as githubhint from './githubhint'; +import * as jgvoting from './jg-voting'; +import * as registry from './registry'; +import * as signaturereg from './signaturereg'; +import * as tokendeployMgr from './tokendeployMgr'; +import * as tokendeployReg from './tokendeployReg'; +import * as tokenreg from './tokenreg'; +import * as verifyEmail from './verifyEmail'; +import * as verifySms from './verifySms'; +import * as wallet from './wallet'; + +const contracts = [ + // builtin + githubhint, + badgereg, + dappreg, + signaturereg, + tokenreg, + tokendeployReg, + tokendeployMgr, + verifyEmail, + verifySms, + wallet, + + // external + gavcoin, + jgvoting +]; + +export { + contracts, + registry +}; diff --git a/js/src/dapps/chaindeploy/contracts/jg-voting.js b/js/src/dapps/chaindeploy/contracts/jg-voting.js new file mode 100644 index 000000000..8ffbed3c5 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/jg-voting.js @@ -0,0 +1,32 @@ +// 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 . + +import abi from './abi/jg-voting'; +import { compiler, source as sourceUrl, output as byteCode } from './code/jg-voting'; + +const isExternal = true; +const id = 'jg-voting'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + isExternal, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/registry.js b/js/src/dapps/chaindeploy/contracts/registry.js new file mode 100644 index 000000000..1b44f4245 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/registry.js @@ -0,0 +1,30 @@ +// 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 . + +import abi from '~/contracts/abi/registry2'; +import { compiler, source as sourceUrl, output as byteCode } from './code/registry'; + +const id = 'registry'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/signaturereg.js b/js/src/dapps/chaindeploy/contracts/signaturereg.js new file mode 100644 index 000000000..6d9f9bf60 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/signaturereg.js @@ -0,0 +1,30 @@ +// 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 . + +import abi from '~/contracts/abi/signaturereg'; +import { compiler, source as sourceUrl, output as byteCode } from './code/signaturereg'; + +const id = 'signaturereg'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/tokendeployMgr.js b/js/src/dapps/chaindeploy/contracts/tokendeployMgr.js new file mode 100644 index 000000000..d07435fdd --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/tokendeployMgr.js @@ -0,0 +1,30 @@ +// 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 . + +import abi from '~/contracts/abi/basiccoinmanager'; +import { compiler, source as sourceUrl, output as byteCode } from './code/tokendeploy'; + +const id = 'basiccoinmgr'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/tokendeployReg.js b/js/src/dapps/chaindeploy/contracts/tokendeployReg.js new file mode 100644 index 000000000..1db07e91a --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/tokendeployReg.js @@ -0,0 +1,28 @@ +// 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 . + +import { abi, sourceUrl, deployParams, compiler, byteCode } from './tokenreg'; + +const id = 'basiccoinreg'; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/tokenreg.js b/js/src/dapps/chaindeploy/contracts/tokenreg.js new file mode 100644 index 000000000..11ee29fa1 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/tokenreg.js @@ -0,0 +1,30 @@ +// 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 . + +import abi from '~/contracts/abi/tokenreg'; +import { compiler, source as sourceUrl, output as byteCode } from './code/tokenreg'; + +const id = 'tokenreg'; +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/verifyEmail.js b/js/src/dapps/chaindeploy/contracts/verifyEmail.js new file mode 100644 index 000000000..d011f4c51 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/verifyEmail.js @@ -0,0 +1,37 @@ +// 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 . + +import abi from '~/contracts/abi/email-verification'; +import { compiler, source as sourceUrl, output as byteCode } from './code/verifyEmail'; + +const isBadge = true; +const id = 'emailverification'; +const deployParams = []; +const badgeSource = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/c4721a87cb95375da91f8699438d8d7907b3f5e9/certifications/email-verification.svg', + imageHash: '0x5617a14da2a0c210939da6eafb734e60906f64a504c3e107812668860a752dc6' +}; + +export { + abi, + badgeSource, + byteCode, + compiler, + deployParams, + id, + isBadge, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/verifySms.js b/js/src/dapps/chaindeploy/contracts/verifySms.js new file mode 100644 index 000000000..59bf1ba36 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/verifySms.js @@ -0,0 +1,37 @@ +// 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 . + +import abi from '~/contracts/abi/sms-verification'; +import { compiler, source as sourceUrl, output as byteCode } from './code/verifySms'; + +const isBadge = true; +const id = 'smsverification'; +const deployParams = []; +const badgeSource = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/1b1beb57ab1f4d3a93a12711b233b5cded791a2f/certifications/sms-verification.svg', + imageHash: '0x49fa653c35c0a9ce128579883babd673ad4cfc94bf9f1cfe96a2bbc30a7552c6' +}; + +export { + abi, + badgeSource, + byteCode, + compiler, + deployParams, + id, + isBadge, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/contracts/wallet.js b/js/src/dapps/chaindeploy/contracts/wallet.js new file mode 100644 index 000000000..6639cba80 --- /dev/null +++ b/js/src/dapps/chaindeploy/contracts/wallet.js @@ -0,0 +1,29 @@ +// 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 . + +import { walletCompiler as compiler, walletLibrary as byteCode, walletLibraryABI as abiJson, walletLibraryRegKey as id, walletSource as sourceUrl } from '~/contracts/code/wallet'; + +const abi = JSON.parse(abiJson); +const deployParams = []; + +export { + abi, + byteCode, + compiler, + deployParams, + id, + sourceUrl +}; diff --git a/js/src/dapps/chaindeploy/dapps/console.js b/js/src/dapps/chaindeploy/dapps/console.js new file mode 100644 index 000000000..f67165502 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/console.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'console'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/console/3ea0dbfefded359ccdbea37bc4cf350c0aa16948/console.jpeg', + imageHash: '0xc3962e2eab7afaeb9cd11522381723afbafdc41dc7ba31bee472e187c4459e81' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/dappreg.js b/js/src/dapps/chaindeploy/dapps/dappreg.js new file mode 100644 index 000000000..a9baae82a --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/dappreg.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'dappreg'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/cdd6ac4f1e2f11619bed72a53ae71217dffe19ad/dapps/legos-64x64.png', + imageHash: '0xa8feea35c761cc6c2fe862fe336419f11ca5421f578757720a899b89fc1df154' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/gavcoin.js b/js/src/dapps/chaindeploy/dapps/gavcoin.js new file mode 100644 index 000000000..6fd8b1d86 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/gavcoin.js @@ -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 . + +import { api } from '../parity'; + +const isExternal = true; +const id = 'gavcoin'; +const hashId = api.util.sha3(id); +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/9e135f76fe9ba61e2d8ccbd72ed144c26c450780/tokens/gavcoin-64x64.png', + imageHash: '0xd40679a3a234d8421c678d64f4df3308859e8ad07ac95ce4a228aceb96955287', + manifestUrl: 'https://raw.githubusercontent.com/gavofyork/gavcoin/eb2f8dc4d3ad4dd5f4562690525b7cfedc9681ba/manifest.json', + manifestHash: '0xd582c572fbef8015837f2c1a8798f2c3149a1d9d655b4020edb1bbece725371d', + contentUrl: { + repo: 'gavofyork/gavcoin', + commit: '0xeb2f8dc4d3ad4dd5f4562690525b7cfedc9681ba' + }, + contentHash: '0x0b6c7b3fc8dad3edb39fd1465904ce9a11938ef18f08f8115f275047ba249530' +}; +const name = 'GavCoin'; + +export { + hashId, + id, + isExternal, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/githubhint.js b/js/src/dapps/chaindeploy/dapps/githubhint.js new file mode 100644 index 000000000..d723cb61c --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/githubhint.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'githubhint'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/link-64x64.jpg', + imageHash: '0x6568901e711886e2c61eef1bbc7e2d8d37a27b9eb3e9e270eda8548f2ec796e8' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/index.js b/js/src/dapps/chaindeploy/dapps/index.js new file mode 100644 index 000000000..e95bf5648 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/index.js @@ -0,0 +1,50 @@ +// 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 . + +import * as consolejs from './console'; +import * as dappreg from './dappreg'; +import * as gavcoin from './gavcoin'; +import * as githubhint from './githubhint'; +import * as jgvoting from './jg-voting'; +import * as jgwhenblock from './jg-whenblock'; +import * as localtx from './localtx'; +import * as registry from './registry'; +import * as signaturereg from './signaturereg'; +import * as tokendeploy from './tokendeploy'; +import * as tokenreg from './tokenreg'; +import * as web from './web'; + +const apps = [ + // builtin + consolejs, + dappreg, + githubhint, + localtx, + registry, + signaturereg, + tokendeploy, + tokenreg, + web, + + // external + gavcoin, + jgvoting, + jgwhenblock +]; + +export { + apps +}; diff --git a/js/src/dapps/chaindeploy/dapps/jg-voting.js b/js/src/dapps/chaindeploy/dapps/jg-voting.js new file mode 100644 index 000000000..899e95894 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/jg-voting.js @@ -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 . + +import { api } from '../parity'; + +const isExternal = true; +const id = 'jg-voting'; +const hashId = api.util.sha3(id); +const source = { + imageUrl: 'https://raw.githubusercontent.com/jacogr/dapp-voting/038ff4074544f2babc7aed9c4ac3dc070b85b804/assets/images/vote.jpg', + imageHash: '0x3620828e1a745d2714e9f37dc2d47cdab5ef9982190a845b5e7665b7a7767661', + manifestUrl: 'https://raw.githubusercontent.com/jacogr/dapp-voting/682f0fe4b86508a1a2487de6c7c61f7b100ba5b2/manifest.json', + manifestHash: '0x9b83e01f87d225e7bfdd305c51319504ff9b4cf8d517ca4b64f606762e72f59e', + contentUrl: { + repo: 'jacogr/dapp-voting', + commit: '0x7d941597e862a600a60b9d6ecd3a6f606d96cd7b' + }, + contentHash: '0x9fcc0910f6a8c4e45715d41aea2d287da31bf1d7321003fc66df6a012ce2d753' +}; +const name = 'Yes, No, Maybe'; + +export { + hashId, + id, + isExternal, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/jg-whenblock.js b/js/src/dapps/chaindeploy/dapps/jg-whenblock.js new file mode 100644 index 000000000..0005ca454 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/jg-whenblock.js @@ -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 . + +const isExternal = true; +const id = 'whenarewethere'; +const hashId = '0xfef3bfded03695e38a9ff476a0999e1fa421e72d1fb3b55a87d6c2bdb6fc18ef'; +const source = { + imageUrl: 'https://raw.githubusercontent.com/jacogr/dapp-when-are-we-there/167aa4d904c5aa6246d0d6d6f41c4ed8a56889cd/assets/images/clock.jpg', + imageHash: '0x2534b44f685b6399bf63f86679128216c43e9a58be1dfb58533923f0bcffeba7', + manifestUrl: 'https://raw.githubusercontent.com/jacogr/dapp-when-are-we-there/bf72dc3033711a3ab41bec3c1249638f70bae768/manifest.json', + manifestHash: '0xfe26f6a19ea9393d69bc5d8c73c5072ccf126f51c10c135b42d6bf162d774fd9', + contentUrl: { + repo: 'jacogr/dapp-when-are-we-there', + commit: '0xbf72dc3033711a3ab41bec3c1249638f70bae768' + }, + contentHash: '0x3505cbbef5c2243eedba07d340d4abccfaa3cfb799f51827e33c9721a5254d13' +}; +const name = 'When are we there'; + +export { + hashId, + id, + isExternal, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/localtx.js b/js/src/dapps/chaindeploy/dapps/localtx.js new file mode 100644 index 000000000..e6dd59fbe --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/localtx.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'localtx'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/cdd6ac4f1e2f11619bed72a53ae71217dffe19ad/dapps/stack-64x64.png', + imageHash: '0x22b924801e1971659a51956dcdfc5a2d592d8bdd03780dd72d5bc4c84b595b4c' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/registry.js b/js/src/dapps/chaindeploy/dapps/registry.js new file mode 100644 index 000000000..d6addaaac --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/registry.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'registry'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/register-64x64.jpg', + imageHash: '0xf7100024052cd78b5e043287c05392b5db0bfce5caedd6d39555d40283ef0a1c' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/signaturereg.js b/js/src/dapps/chaindeploy/dapps/signaturereg.js new file mode 100644 index 000000000..3ce1442c3 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/signaturereg.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'signaturereg'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/hex-64x64.jpg', + imageHash: '0x26f7f2415cd5cbbffa58e8119fdbdd7181cac79119dd7f6ba6ee99d7f4445640' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/tokendeploy.js b/js/src/dapps/chaindeploy/dapps/tokendeploy.js new file mode 100644 index 000000000..5f15bd903 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/tokendeploy.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'tokendeploy'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/interlock-64x64.png', + imageHash: '0xde104baf02aec783e0bffc624514ee267dbcb455382375e3ffa715790c1c939f' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/tokenreg.js b/js/src/dapps/chaindeploy/dapps/tokenreg.js new file mode 100644 index 000000000..0e59f004e --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/tokenreg.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'tokenreg'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/dapps/coins-64x64.jpg', + imageHash: '0xe23d429d15de98c7878d92bc90b79c7afabe1b04c2ad5e3e2c89adc8f439edc9' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/dapps/web.js b/js/src/dapps/chaindeploy/dapps/web.js new file mode 100644 index 000000000..c8d45cb32 --- /dev/null +++ b/js/src/dapps/chaindeploy/dapps/web.js @@ -0,0 +1,33 @@ +// 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 . + +import builtins from '~/views/Dapps/builtin.json'; + +const id = 'web'; +const app = builtins.find((app) => app.url === id); +const hashId = app.id; +const source = { + imageUrl: 'https://raw.githubusercontent.com/ethcore/dapp-assets/ec6138115d0e1f45258969cd90b3b274e0ff2258/dapps/earth-64x64.jpg', + imageHash: '0x0b9b62a9262f75461191d4e8bf686c56528cbc0fe885c1f5878052ca8b2f65bf' +}; +const name = app.name; + +export { + hashId, + id, + name, + source +}; diff --git a/js/src/dapps/chaindeploy/parity.js b/js/src/dapps/chaindeploy/parity.js new file mode 100644 index 000000000..1dea0d696 --- /dev/null +++ b/js/src/dapps/chaindeploy/parity.js @@ -0,0 +1,21 @@ +// 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 . + +const api = window.parity.api; + +export { + api +}; diff --git a/js/src/dapps/chaindeploy/store.js b/js/src/dapps/chaindeploy/store.js new file mode 100644 index 000000000..07b693135 --- /dev/null +++ b/js/src/dapps/chaindeploy/store.js @@ -0,0 +1,714 @@ +// 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 . + +import { action, computed, observable } from 'mobx'; + +import { contracts as contractsInfo, registry as registryInfo } from './contracts'; +import { apps } from './dapps'; +import { api } from './parity'; +import { executeContract, isValidNumber, validateCode } from './utils'; + +export default class ContractsStore { + @observable apps = null; + @observable badges = null; + @observable contracts = null; + @observable error = null; + @observable registry = null; + + constructor () { + this.apps = apps; + this.badges = contractsInfo.filter((contract) => contract.isBadge); + this.contracts = contractsInfo.filter((contract) => !contract.isBadge); + this.registry = registryInfo; + + api.subscribe('eth_blockNumber', this.onNewBlockNumber); + } + + @computed get contractBadgereg () { + return this.contracts.find((contract) => contract.id === 'badgereg'); + } + + @computed get contractDappreg () { + return this.contracts.find((contract) => contract.id === 'dappreg'); + } + + @computed get contractGithubhint () { + return this.contracts.find((contract) => contract.id === 'githubhint'); + } + + @computed get contractTokenreg () { + return this.contracts.find((contract) => contract.id === 'tokenreg'); + } + + @computed get isBadgeDeploying () { + return this.badges + .filter((contract) => contract.isDeploying) + .length !== 0; + } + + @computed get isContractDeploying () { + return this.contracts + .filter((contract) => contract.isDeploying) + .length !== 0; + } + + @computed get isDappDeploying () { + return this.apps + .filter((app) => app.isDeploying) + .length !== 0; + } + + @computed get haveAllBadges () { + return this.badges + .filter((contract) => !contract.instance || !contract.hasLatestCode || !contract.badgeImageHash || !contract.badgeImageMatch || !contract.isBadgeRegistered) + .length === 0; + } + + @computed get haveAllContracts () { + return this.contracts + .filter((contract) => !contract.instance || !contract.hasLatestCode) + .length === 0; + } + + @computed get haveAllDapps () { + return this.apps + .filter((app) => { + return !app.isOnChain || + !app.imageHash || !app.imageMatch || + (app.source.contentHash && !app.contentMatch) || + (app.source.manifestHash && !app.manifestMatch); + }) + .length === 0; + } + + @action refreshApps = () => { + this.apps = [].concat(this.apps.peek()); + } + + @action refreshContracts = () => { + this.badges = [].concat(this.badges.peek()); + this.contracts = [].concat(this.contracts.peek()); + } + + @action setError = (error) => { + console.error(error); + + this.error = error.message + ? error.message + : error; + } + + @action setRegistryAddress = (address, isOnChain = false) => { + if (this.registry.address !== address || !this.registry.instance) { + console.log(`registry found at ${address}`); + + this.registry = Object.assign({}, this.registry, { + address, + instance: api.newContract(this.registry.abi, address).instance, + isOnChain + }); + } + } + + @action setRegistryCode (byteCode) { + this.registry.hasLatestCode = validateCode(this.registry.byteCode, byteCode); + } + + @action setRegistryDeploying = (isDeploying = false) => { + this.registry = Object.assign({}, this.registry, { + isDeploying, + status: isDeploying + ? 'Deploying contract' + : null + }); + } + + @action setBadgeId = (badge, badgeId) => { + badge.badgeId = badgeId; + badge.isBadgeRegistered = true; + + this.refreshContracts(); + } + + @action setBadgeImageHash = (badge, imageHash) => { + badge.badgeImageHash = imageHash; + badge.badgeImageMatch = badge.badgeSource.imageHash === imageHash; + + this.refreshContracts(); + } + + @action setContractAddress = (contract, address, isOnChain = false) => { + if (contract.address !== address || !contract.instance || contract.isOnChain !== isOnChain) { + console.log(`${contract.id} found at ${address}`); + + contract.address = address; + contract.instance = api.newContract(contract.abi, address).instance; + contract.isOnChain = isOnChain; + + this.refreshContracts(); + } + } + + @action setContractCode (contract, byteCode) { + contract.hasLatestCode = validateCode(contract.byteCode, byteCode); + + this.refreshContracts(); + } + + @action setContractDeploying = (contract, isDeploying = false) => { + contract.isDeploying = isDeploying; + contract.status = isDeploying + ? 'Deploying contract' + : null; + + this.refreshContracts(); + } + + @action setContractStatus = (contract, status) => { + contract.status = status; + + this.refreshContracts(); + } + + @action setAppDeploying = (app, isDeploying = false) => { + app.isDeploying = isDeploying; + app.status = isDeploying + ? 'Registering app' + : null; + + this.refreshApps(); + } + + @action setAppFound = (app, isOnChain = false) => { + if (app.isOnChain !== isOnChain) { + console.log(`${app.name} found on dappreg`); + + app.isOnChain = isOnChain; + + this.refreshApps(); + } + } + + @action setAppContentHash = (app, contentHash) => { + if (app.contentHash !== contentHash) { + console.log(`${app.name} has contentHash ${contentHash}`); + + app.contentHash = contentHash; + app.contentMatch = contentHash === app.source.contentHash; + + this.refreshApps(); + } + } + + @action setAppImageHash = (app, imageHash) => { + if (app.imageHash !== imageHash) { + console.log(`${app.name} has imageHash ${imageHash}`); + + app.imageHash = imageHash; + app.imageMatch = imageHash === app.source.imageHash; + + this.refreshApps(); + } + } + + @action setAppManifestHash = (app, manifestHash) => { + if (app.manifestHash !== manifestHash) { + console.log(`${app.name} has manifestHash ${manifestHash}`); + + app.manifestHash = manifestHash; + app.manifestMatch = manifestHash === app.source.manifestHash; + + this.refreshApps(); + } + } + + @action setAppStatus = (app, status) => { + console.log(app.id, status); + + app.status = status; + + this.refreshApps(); + } + + deployApp = (app) => { + console.log(`Registering application ${app.id}`); + + this.setAppDeploying(app, true); + + const options = {}; + const values = [app.hashId]; + + return api.parity + .defaultAccount() + .then((defaultAccount) => { + options.from = defaultAccount; + + if (app.isOnChain) { + return true; + } + + return this.contractDappreg.instance + .fee.call({}, []) + .then((fee) => { + options.value = fee; + + return executeContract(app.id, this.contractDappreg, 'register', options, values); + }); + }) + .then(() => { + if (app.imageHash && app.imageMatch) { + return true; + } + + this.setAppStatus(app, 'Registering image url'); + + return this + .registerHash(app.source.imageHash, app.source.imageUrl, options.from) + .then(() => this.setAppMeta(app, 'IMG', app.source.imageHash, options.from)); + }) + .then(() => { + if (!app.source.manifestHash || app.manifestMatch) { + return true; + } + + this.setAppStatus(app, 'Registering manifest url'); + + return this + .registerHash(app.source.manifestHash, app.source.manifestUrl, options.from) + .then(() => this.setAppMeta(app, 'MANIFEST', app.source.manifestHash, options.from)); + }) + .then(() => { + if (!app.source.contentHash || app.contentMatch) { + return true; + } + + this.setAppStatus(app, 'Registering content url'); + + return this + .registerRepo(app.source.contentHash, app.source.contentUrl, options.from) + .then(() => this.setAppMeta(app, 'CONTENT', app.source.contentHash, options.from)); + }) + .catch(() => { + return null; + }) + .then(() => { + this.setAppDeploying(app, false); + }); + } + + deployApps = () => { + this.apps + .filter((app) => { + return !app.isDeploying && + ( + !app.isOnChain || + (!app.imageHash || !app.imageMatch) || + (app.source.contentHash && !app.contentMatch) || + (app.source.manifestHash && !app.manifestMatch) + ); + }) + .forEach(this.deployApp); + } + + _deployContract = (contract) => { + console.log(`Deploying contract ${contract.id}`); + + const options = { + data: contract.byteCode + }; + + return api.parity + .defaultAccount() + .then((defaultAccount) => { + options.from = defaultAccount; + + return api + .newContract(contract.abi) + .deploy(options, contract.deployParams, (error, data) => { + if (error) { + console.error(contract.id, error); + } else { + console.log(contract.id, data); + } + }) + .then((contractAddress) => { + return [contractAddress, defaultAccount]; + }); + }); + } + + deployContract = (contract) => { + if (contract.hasLatestCode) { + return Promise.resolve(false); + } + + let defaultAccount = '0x0'; + + this.setContractDeploying(contract, true); + + return this + ._deployContract(contract) + .then(([address, _defaultAccount]) => { + const isOnChain = contract.isOnChain; + + defaultAccount = _defaultAccount; + + this.setContractAddress(contract, address); + + return isOnChain + ? true + : this.reserveAddress(contract, defaultAccount); + }) + .then(() => { + return this.registerAddress(contract, defaultAccount); + }) + .catch(() => { + return null; + }) + .then(() => { + this.setContractDeploying(contract, false); + }); + } + + deployBadge = (badge) => { + let defaultAccount; + + return this + .deployContract(badge) + .then(() => { + this.setContractDeploying(badge, true); + + return api.parity.defaultAccount(); + }) + .then((_defaultAccount) => { + defaultAccount = _defaultAccount; + + if (badge.isBadgeRegistered) { + return true; + } + + this.setContractStatus(badge, 'Registering with badgereg'); + + return this.registerBadge(badge, defaultAccount); + }) + .then(() => { + if (badge.badgeImageMatch) { + return true; + } + + this.setContractStatus(badge, 'Registering image url'); + + return this + .registerHash(badge.badgeSource.imageHash, badge.badgeSource.imageUrl, defaultAccount) + .then(() => this.registerBadgeImage(badge, badge.badgeSource.imageHash, defaultAccount)); + }) + .then(() => { + this.setContractDeploying(badge, false); + }); + } + + deployContracts = () => { + this.contracts + .filter((contract) => !contract.isDeploying && (!contract.instance || !contract.hasLatestCode)) + .forEach(this.deployContract); + } + + deployBadges = () => { + this.badges + .filter((contract) => !contract.isDeploying && (!contract.instance || !contract.hasLatestCode || !contract.badgeImageHash || !contract.badgeImageMatch || !contract.isBadgeRegistered)) + .forEach(this.deployBadge); + } + + deployRegistry = () => { + this.setRegistryDeploying(true); + + return this + ._deployContract(this.registry) + .then(([address]) => { + this.setRegistryDeploying(false); + this.setRegistryAddress(address); + }); + } + + registerBadge = (badge, fromAddress) => { + const options = { + from: fromAddress + }; + const values = [badge.address, api.util.sha3.text(badge.id.toLowerCase())]; + + return this.contractBadgereg.instance + .fee.call({}, []) + .then((fee) => { + options.value = fee; + + return executeContract(badge.id, this.contractBadgereg, 'register', options, values); + }); + } + + registerBadgeImage = (badge, hash, fromAddress) => { + const options = { + from: fromAddress + }; + const values = [badge.badgeId, 'IMG', hash]; + + this.setContractStatus(badge, 'Setting meta IMG'); + + return executeContract(badge.id, this.contractBadgereg, 'setMeta', options, values); + } + + setAppMeta = (app, key, meta, fromAddress) => { + const options = { + from: fromAddress + }; + const values = [app.hashId, key, meta]; + + this.setAppStatus(app, `Setting meta ${key}`); + + return executeContract(app.id, this.contractDappreg, 'setMeta', options, values); + } + + reserveAddress = (contract, fromAddress) => { + const options = { from: fromAddress }; + const values = [api.util.sha3.text(contract.id.toLowerCase())]; + + this.setContractStatus(contract, 'Reserving name'); + + return this.registry.instance + .fee.call({}, []) + .then((value) => { + options.value = value; + + return executeContract(contract.id, this.registry, 'reserve', options, values); + }); + } + + registerAddress = (contract, fromAddress) => { + const options = { from: fromAddress }; + const values = [api.util.sha3.text(contract.id.toLowerCase()), 'A', contract.address]; + + this.setContractStatus(contract, 'Setting lookup address'); + + return executeContract(contract.id, this.registry, 'setAddress', options, values); + } + + registerRepo = (hash, content, fromAddress) => { + const options = { + from: fromAddress + }; + const values = [hash, content.repo || content, content.commit || 0]; + + return this.contractGithubhint.instance + .entries.call({}, [hash]) + .then(([imageUrl, commit, owner]) => { + if (isValidNumber(owner)) { + return true; + } + + return executeContract(hash, this.contractGithubhint, 'hint', options, values); + }) + .catch(() => false); + } + + registerHash = (hash, url, fromAddress) => { + const options = { + from: fromAddress + }; + const values = [hash, url]; + + return this.contractGithubhint.instance + .entries.call({}, [hash]) + .then(([imageUrl, commit, owner]) => { + if (isValidNumber(owner)) { + return true; + } + + return executeContract(hash, this.contractGithubhint, 'hintURL', options, values); + }) + .catch(() => false); + } + + findRegistry = () => { + if (this.registry.address && this.registry.hasLatestCode) { + return Promise.resolve(this.registry); + } + + return api.parity + .registryAddress() + .then((address) => { + if (isValidNumber(address)) { + this.setRegistryAddress(address, true); + } + + return api.eth.getCode(address); + }) + .then((byteCode) => { + this.setRegistryCode(byteCode); + }); + } + + findApps = () => { + if (!this.contractDappreg.instance) { + return Promise.resolve(false); + } + + return Promise + .all( + this.apps.map((app) => { + return app.isOnChain + ? Promise.resolve([[0]]) + : this.contractDappreg.instance.get.call({}, [app.hashId]); + }) + ) + .then((apps) => { + apps.forEach(([_id, owner], index) => { + const id = api.util.bytesToHex(_id); + + if (isValidNumber(id)) { + this.setAppFound(this.apps[index], true); + } + }); + + return Promise.all( + this.apps.map((app) => { + return !app.isOnChain || (app.imageHash && app.imageMatch) + ? Promise.resolve([[0], [0], [0]]) + : Promise.all([ + this.contractDappreg.instance.meta.call({}, [app.hashId, 'CONTENT']), + this.contractDappreg.instance.meta.call({}, [app.hashId, 'IMG']), + this.contractDappreg.instance.meta.call({}, [app.hashId, 'MANIFEST']) + ]); + }) + ); + }) + .then((hashes) => { + hashes.forEach(([content, image, manifest], index) => { + const contentHash = api.util.bytesToHex(content); + const imageHash = api.util.bytesToHex(image); + const manifestHash = api.util.bytesToHex(manifest); + + if (isValidNumber(contentHash)) { + this.setAppContentHash(this.apps[index], contentHash); + } + + if (isValidNumber(imageHash)) { + this.setAppImageHash(this.apps[index], imageHash); + } + + if (isValidNumber(manifestHash)) { + this.setAppManifestHash(this.apps[index], manifestHash); + } + }); + }); + } + + findBadges = () => { + if (!this.contractBadgereg.instance) { + return Promise.resolve(false); + } + + return this + .findContracts(this.badges) + .then(() => { + return Promise.all( + this.badges.map((badge) => { + return badge.isBadgeRegistered + ? Promise.resolve([0, 0, 0]) + : this.contractBadgereg.instance.fromAddress.call({}, [badge.address]); + }) + ); + }) + .then((badgeInfos) => { + badgeInfos.forEach(([id, name, owner], index) => { + if (isValidNumber(owner)) { + this.setBadgeId(this.badges[index], id); + } + }); + + return Promise + .all( + this.badges.map((badge) => { + return !badge.isBadgeRegistered + ? Promise.resolve([0]) + : this.contractBadgereg.instance.meta.call({}, [badge.badgeId, 'IMG']); + }) + ); + }) + .then((images) => { + images.forEach((imageBytes, index) => { + const imageHash = api.util.bytesToHex(imageBytes); + + if (isValidNumber(imageHash)) { + this.setBadgeImageHash(this.badges[index], imageHash); + } + }); + }); + } + + findContracts = (contracts = this.contracts) => { + if (!this.registry.instance) { + return Promise.resolve(false); + } + + return Promise + .all( + contracts.map((contract) => { + const hashId = api.util.sha3.text(contract.id.toLowerCase()); + + return contract.isOnChain + ? Promise.resolve([0, 0]) + : Promise.all([ + this.registry.instance.getAddress.call({}, [hashId, 'A']), + this.registry.instance.getOwner.call({}, [hashId]) + ]); + }) + ) + .then((addresses) => { + addresses.forEach(([address, owner], index) => { + if (isValidNumber(owner) && isValidNumber(address)) { + this.setContractAddress(contracts[index], address, true); + } + }); + + return Promise.all( + contracts.map((contract) => { + return !contract.address || contract.hasLatestCode + ? Promise.resolve(null) + : api.eth.getCode(contract.address); + }) + ); + }) + .then((codes) => { + codes.forEach((byteCode, index) => { + if (byteCode) { + this.setContractCode(contracts[index], byteCode); + } + }); + }); + } + + onNewBlockNumber = (error, blockNumber) => { + if (error) { + return; + } + + return this + .findRegistry() + .then(this.findContracts) + .then(this.findApps) + .then(this.findBadges) + .catch(this.setError); + } +} diff --git a/js/src/dapps/chaindeploy/utils.js b/js/src/dapps/chaindeploy/utils.js new file mode 100644 index 000000000..87e7279e3 --- /dev/null +++ b/js/src/dapps/chaindeploy/utils.js @@ -0,0 +1,82 @@ +// 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 . + +import BigNumber from 'bignumber.js'; + +import { api } from './parity'; + +export function validateCode (source, retrieved) { + const original = source.substr(12); + const bytecode = retrieved.substr(12); + + const knownHash = api.util.sha3(original.slice(-1 * bytecode.length)); + const codeHash = api.util.sha3(bytecode); + + return knownHash === codeHash; +} + +export function isValidNumber (number) { + return number && !(new BigNumber(number)).isZero(); +} + +export function executeContract (logId, contract, funcName, options, values) { + const func = contract.instance[funcName]; + + return func + .estimateGas(options, values) + .then((gasEst) => { + options.gas = gasEst.mul(1.2); + + return trackRequest( + func.postTransaction(options, values), + (error, data) => { + if (error) { + console.error(logId, error); + } else { + console.log(logId, data); + } + } + ); + }); +} + +export function trackRequest (promise, callback) { + return promise + .then((requestId) => { + callback(null, { state: 'checkRequest', requestId }); + + return api.pollMethod('parity_checkRequest', requestId); + }) + .then((txHash) => { + callback(null, { state: 'getTransactionReceipt', txHash }); + + return api.pollMethod('eth_getTransactionReceipt', txHash, (receipt) => { + if (!receipt || !receipt.blockNumber || receipt.blockNumber.eq(0)) { + return false; + } + + return true; + }); + }) + .then((receipt) => { + callback(null, { state: 'hasReceipt', receipt }); + }) + .catch((error) => { + callback(error); + + throw error; + }); +} diff --git a/js/src/dapps/dappreg/dappsStore.js b/js/src/dapps/dappreg/dappsStore.js index ea2e6f054..c6f45922a 100644 --- a/js/src/dapps/dappreg/dappsStore.js +++ b/js/src/dapps/dappreg/dappsStore.js @@ -20,12 +20,15 @@ import { flatten } from 'lodash'; import * as abis from '~/contracts/abi'; import Contracts from '~/contracts'; -import builtins from '~/views/Dapps/builtin.json'; +import builtinJson from '~/views/Dapps/builtin.json'; + import Dapp from './dappStore.js'; import { deleteDapp, registerDapp, updateDapp } from './utils'; import { api, trackRequest } from './parity'; +const builtins = builtinJson.filter((app) => app.id); + let instance = null; export default class DappsStore { diff --git a/js/src/util/dapps.js b/js/src/util/dapps.js index a82b2ae1c..2ca416e1a 100644 --- a/js/src/util/dapps.js +++ b/js/src/util/dapps.js @@ -21,7 +21,9 @@ import Contracts from '~/contracts'; import { hashToImageUrl } from '~/redux/util'; import { bytesToHex } from '~/api/util/format'; -import builtinApps from '~/views/Dapps/builtin.json'; +import builtinJson from '~/views/Dapps/builtin.json'; + +const builtinApps = builtinJson.filter((app) => app.id); function getHost (api) { const host = process.env.DAPPS_URL || diff --git a/js/src/views/Dapps/builtin.json b/js/src/views/Dapps/builtin.json index 45dccb327..97ebcc0cc 100644 --- a/js/src/views/Dapps/builtin.json +++ b/js/src/views/Dapps/builtin.json @@ -1,4 +1,12 @@ [ + { + "url": "chaindeploy", + "name": "Chain Deployment", + "description": "Deploy all basic contracts, names & applications to the network", + "author": "Parity Team ", + "version": "1.0.0", + "visible": false + }, { "id": "0xf9f2d620c2e08f83e45555247146c62185e4ab7cf82a4b9002a265a0d020348f", "url": "tokendeploy", From b7862ac23a021f0f10a7e8212450d1cddd243d51 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 13 Mar 2017 12:52:02 +0100 Subject: [PATCH 33/36] Update parity-ui-precompiled with branch (#4850) * Update parity-ui-precompiled with branch * In-place sed via -i * Explicitly specify branch * Only in-place edit branch (thanks @ngotchac) * Add override & single-line comment --- dapps/ui/Cargo.toml | 3 ++- js/scripts/release.sh | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dapps/ui/Cargo.toml b/dapps/ui/Cargo.toml index 2ab128ad5..17fc2d448 100644 --- a/dapps/ui/Cargo.toml +++ b/dapps/ui/Cargo.toml @@ -11,7 +11,8 @@ rustc_version = "0.1" [dependencies] parity-ui-dev = { path = "../../js", optional = true } -parity-ui-precompiled = { git = "https://github.com/ethcore/js-precompiled.git", optional = true } +# This is managed by the js/scripts/release.sh script on CI - keep it in a single line +parity-ui-precompiled = { git = "https://github.com/ethcore/js-precompiled.git", optional = true, branch = "master" } [features] no-precompiled-js = ["parity-ui-dev"] diff --git a/js/scripts/release.sh b/js/scripts/release.sh index 80c0fc819..be19e217e 100755 --- a/js/scripts/release.sh +++ b/js/scripts/release.sh @@ -89,11 +89,13 @@ fi echo "*** Updating cargo parity-ui-precompiled#$PRECOMPILED_HASH" git submodule update +sed -i "/^parity-ui-precompiled/ { s/branch = \".*\"/branch = \"$BRANCH\"/g; }" dapps/ui/Cargo.toml cargo update -p parity-ui-precompiled # --precise "$PRECOMPILED_HASH" echo "*** Committing updated files" git add js +git add dapps/ui/Cargo.toml git add Cargo.lock git commit -m "[ci skip] js-precompiled $UTCDATE" git push origin HEAD:refs/heads/$BRANCH 2>$GITLOG From fddbc9e5cb5fe9c1d8e161c91828b2a2ff6fd337 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 13 Mar 2017 14:54:56 +0300 Subject: [PATCH 34/36] Secretstore DKG protocol draft + distributed encryption/decryption tests (#4725) * ECDKG protocol prototype * added test for enc/dec math * get rid of decryption_session * added licenses * fix after merge * get rid of unused serde dependency * doc * decryption session [without commutative enc] * failed_dec_session * fixed tests * added commen * added more decryption session tests * helper to localize an issue * more computations to localize error * decryption_session::SessionParams * added tests for EC math to localize problem --- ethkey/src/error.rs | 6 + ethkey/src/math.rs | 43 + ethkey/src/secret.rs | 51 + .../src/key_server_cluster/cluster.rs | 90 ++ .../key_server_cluster/decryption_session.rs | 707 ++++++++++ .../key_server_cluster/encryption_session.rs | 1197 +++++++++++++++++ secret_store/src/key_server_cluster/math.rs | 338 +++++ .../src/key_server_cluster/message.rs | 168 +++ secret_store/src/key_server_cluster/mod.rs | 76 ++ secret_store/src/lib.rs | 1 + 10 files changed, 2677 insertions(+) create mode 100644 secret_store/src/key_server_cluster/cluster.rs create mode 100644 secret_store/src/key_server_cluster/decryption_session.rs create mode 100644 secret_store/src/key_server_cluster/encryption_session.rs create mode 100644 secret_store/src/key_server_cluster/math.rs create mode 100644 secret_store/src/key_server_cluster/message.rs create mode 100644 secret_store/src/key_server_cluster/mod.rs diff --git a/ethkey/src/error.rs b/ethkey/src/error.rs index bc5dd9fa4..0ac2d221a 100644 --- a/ethkey/src/error.rs +++ b/ethkey/src/error.rs @@ -51,6 +51,12 @@ impl fmt::Display for Error { } } +impl Into for Error { + fn into(self) -> String { + format!("{}", self) + } +} + impl From<::secp256k1::Error> for Error { fn from(e: ::secp256k1::Error) -> Error { match e { diff --git a/ethkey/src/math.rs b/ethkey/src/math.rs index 45e5d04e6..536f4ee7d 100644 --- a/ethkey/src/math.rs +++ b/ethkey/src/math.rs @@ -36,6 +36,17 @@ pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> { Ok(()) } +/// Inplace sub one public key from another (EC point - EC point) +pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> { + let mut key_neg_other = to_secp256k1_public(other)?; + key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?; + + let mut key_public = to_secp256k1_public(public)?; + key_public.add_assign(&SECP256K1, &key_neg_other)?; + set_public(public, &key_public); + Ok(()) +} + /// Return base point of secp256k1 pub fn generation_point() -> Public { let mut public_sec_raw = [0u8; 65]; @@ -64,3 +75,35 @@ fn set_public(public: &mut Public, key_public: &key::PublicKey) { let key_public_serialized = key_public.serialize_vec(&SECP256K1, false); public.copy_from_slice(&key_public_serialized[1..65]); } + +#[cfg(test)] +mod tests { + use super::super::{Random, Generator}; + use super::{public_add, public_sub}; + + #[test] + fn public_addition_is_commutative() { + let public1 = Random.generate().unwrap().public().clone(); + let public2 = Random.generate().unwrap().public().clone(); + + let mut left = public1.clone(); + public_add(&mut left, &public2).unwrap(); + + let mut right = public2.clone(); + public_add(&mut right, &public1).unwrap(); + + assert_eq!(left, right); + } + + #[test] + fn public_addition_is_reversible_with_subtraction() { + let public1 = Random.generate().unwrap().public().clone(); + let public2 = Random.generate().unwrap().public().clone(); + + let mut sum = public1.clone(); + public_add(&mut sum, &public2).unwrap(); + public_sub(&mut sum, &public2).unwrap(); + + assert_eq!(sum, public1); + } +} diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index d8696ef73..9c9fd05ad 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -130,3 +130,54 @@ impl Deref for Secret { &self.inner } } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use super::super::{Random, Generator}; + use super::Secret; + + #[test] + fn multiplicating_secret_inversion_with_secret_gives_one() { + let secret = Random.generate().unwrap().secret().clone(); + let mut inversion = secret.clone(); + inversion.inv().unwrap(); + inversion.mul(&secret).unwrap(); + assert_eq!(inversion, Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap()); + } + + #[test] + fn secret_inversion_is_reversible_with_inversion() { + let secret = Random.generate().unwrap().secret().clone(); + let mut inversion = secret.clone(); + inversion.inv().unwrap(); + inversion.inv().unwrap(); + assert_eq!(inversion, secret); + } + + #[test] + fn secret_pow() { + let secret = Random.generate().unwrap().secret().clone(); + + let mut pow0 = secret.clone(); + pow0.pow(0).unwrap(); + assert_eq!(pow0, Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap()); + + let mut pow1 = secret.clone(); + pow1.pow(1).unwrap(); + assert_eq!(pow1, secret); + + let mut pow2 = secret.clone(); + pow2.pow(2).unwrap(); + let mut pow2_expected = secret.clone(); + pow2_expected.mul(&secret).unwrap(); + assert_eq!(pow2, pow2_expected); + + let mut pow3 = secret.clone(); + pow3.pow(3).unwrap(); + let mut pow3_expected = secret.clone(); + pow3_expected.mul(&secret).unwrap(); + pow3_expected.mul(&secret).unwrap(); + assert_eq!(pow3, pow3_expected); + } +} diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs new file mode 100644 index 000000000..5f6c99808 --- /dev/null +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -0,0 +1,90 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use key_server_cluster::{Error, NodeId}; +use key_server_cluster::message::Message; + +/// Cluster access for single encryption/decryption participant. +pub trait Cluster { + /// Broadcast message to all other nodes. + fn broadcast(&self, message: Message) -> Result<(), Error>; + /// Send message to given node. + fn send(&self, to: &NodeId, message: Message) -> Result<(), Error>; + /// Blacklist node, close connection and remove all pending messages. + fn blacklist(&self, node: &NodeId); +} + +#[cfg(test)] +pub mod tests { + use std::collections::VecDeque; + use parking_lot::Mutex; + use key_server_cluster::{NodeId, Error}; + use key_server_cluster::message::Message; + use key_server_cluster::cluster::Cluster; + + #[derive(Debug)] + pub struct DummyCluster { + id: NodeId, + data: Mutex, + } + + #[derive(Debug, Default)] + struct DummyClusterData { + nodes: Vec, + messages: VecDeque<(NodeId, Message)>, + } + + impl DummyCluster { + pub fn new(id: NodeId) -> Self { + DummyCluster { + id: id, + data: Mutex::new(DummyClusterData::default()) + } + } + + pub fn node(&self) -> NodeId { + self.id.clone() + } + + pub fn add_node(&self, node: NodeId) { + self.data.lock().nodes.push(node); + } + + pub fn take_message(&self) -> Option<(NodeId, Message)> { + self.data.lock().messages.pop_front() + } + } + + impl Cluster for DummyCluster { + fn broadcast(&self, message: Message) -> Result<(), Error> { + let mut data = self.data.lock(); + let all_nodes: Vec<_> = data.nodes.iter().cloned().filter(|n| n != &self.id).collect(); + for node in all_nodes { + data.messages.push_back((node, message.clone())); + } + Ok(()) + } + + fn send(&self, to: &NodeId, message: Message) -> Result<(), Error> { + debug_assert!(&self.id != to); + self.data.lock().messages.push_back((to.clone(), message)); + Ok(()) + } + + fn blacklist(&self, _node: &NodeId) { + } + } +} diff --git a/secret_store/src/key_server_cluster/decryption_session.rs b/secret_store/src/key_server_cluster/decryption_session.rs new file mode 100644 index 000000000..d4160851e --- /dev/null +++ b/secret_store/src/key_server_cluster/decryption_session.rs @@ -0,0 +1,707 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::{BTreeSet, BTreeMap}; +use std::sync::Arc; +use parking_lot::Mutex; +use ethkey::{self, Secret, Public, Signature}; +use key_server_cluster::{Error, AclStorage, EncryptedData, NodeId, SessionId}; +use key_server_cluster::cluster::Cluster; +use key_server_cluster::math; +use key_server_cluster::message::{Message, InitializeDecryptionSession, ConfirmDecryptionInitialization, + RequestPartialDecryption, PartialDecryption}; + +/// Distributed decryption session. +/// Based on "ECDKG: A Distributed Key Generation Protocol Based on Elliptic Curve Discrete Logarithm" paper: +/// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.124.4128&rep=rep1&type=pdf +/// Brief overview: +/// 1) initialization: master node (which has received request for decrypting the secret) requests all other nodes to decrypt the secret +/// 2) ACL check: all nodes which have received the request are querying ACL-contract to check if requestor has access to the document +/// 3) partial decryption: every node which has succussfully checked access for the requestor do a partial decryption +/// 4) decryption: master node receives all partial decryptions of the secret and restores the secret +pub struct Session { + /// Encryption session id. + id: SessionId, + /// Decryption session access key. + access_key: Secret, + /// Public identifier of this node. + self_node_id: NodeId, + /// Encrypted data. + encrypted_data: EncryptedData, + /// ACL storate to check access to the resource. + acl_storage: Arc, + /// Cluster which allows this node to send messages to other nodes in the cluster. + cluster: Arc, + /// Mutable session data. + data: Mutex, +} + +/// Session creation parameters +pub struct SessionParams { + /// Session identifier. + pub id: SessionId, + /// Session access key. + pub access_key: Secret, + /// Id of node, on which this session is running. + pub self_node_id: Public, + /// Encrypted data (result of running encryption_session::Session). + pub encrypted_data: EncryptedData, + /// ACL storage. + pub acl_storage: Arc, + /// Cluster + pub cluster: Arc, +} + +#[derive(Debug)] +/// Mutable data of encryption (distributed key generation) session. +struct SessionData { + /// Current state of the session. + state: SessionState, + + // === Values, filled when session initialization just starts === + /// Reference to the node, which has started this session. + master: Option, + /// Public key of requestor. + requestor: Option, + + // === Values, filled during session initialization === + /// Nodes, which have been requested for decryption initialization. + requested_nodes: BTreeSet, + /// Nodes, which have responded with reject to initialization request. + rejected_nodes: BTreeSet, + /// Nodes, which have responded with confirm to initialization request. + confirmed_nodes: BTreeSet, + + // === Values, filled during partial decryption === + /// Shadow points, received from nodes as a response to partial decryption request. + shadow_points: BTreeMap, + + /// === Values, filled during final decryption === + /// Decrypted secret + decrypted_secret: Option, +} + +#[derive(Debug)] +struct NodeData { + /// Node-generated shadow point. + shadow_point: Option, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum SessionState { + /// Every node starts in this state. + WaitingForInitialization, + /// Master node waits for other nodes to confirm decryption. + WaitingForInitializationConfirm, + /// Waiting for partial decrypion request. + WaitingForPartialDecryptionRequest, + /// Waiting for partial decryption responses. + WaitingForPartialDecryption, + /// Decryption session is finished for this node. + Finished, + /// Decryption session is failed for this node. + Failed, +} + +impl Session { + /// Create new decryption session. + pub fn new(params: SessionParams) -> Result { + check_encrypted_data(¶ms.self_node_id, ¶ms.encrypted_data)?; + + Ok(Session { + id: params.id, + access_key: params.access_key, + self_node_id: params.self_node_id, + encrypted_data: params.encrypted_data, + acl_storage: params.acl_storage, + cluster: params.cluster, + data: Mutex::new(SessionData { + state: SessionState::WaitingForInitialization, + master: None, + requestor: None, + requested_nodes: BTreeSet::new(), + rejected_nodes: BTreeSet::new(), + confirmed_nodes: BTreeSet::new(), + shadow_points: BTreeMap::new(), + decrypted_secret: None, + }) + }) + } + + /// Get this node Id. + pub fn node(&self) -> &NodeId { + &self.self_node_id + } + + /// Get this session access key. + pub fn access_key(&self) -> &Secret { + &self.access_key + } + + /// Get current session state. + pub fn state(&self) -> SessionState { + self.data.lock().state.clone() + } + + /// Get decrypted secret + pub fn decrypted_secret(&self) -> Option { + self.data.lock().decrypted_secret.clone() + } + + /// Initialize decryption session. + pub fn initialize(&self, requestor_signature: Signature) -> Result<(), Error> { + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForInitialization { + return Err(Error::InvalidStateForRequest); + } + + // recover requestor signature + let requestor_public = ethkey::recover(&requestor_signature, &self.id)?; + + // update state + data.master = Some(self.node().clone()); + data.state = SessionState::WaitingForInitializationConfirm; + data.requestor = Some(requestor_public.clone()); + data.requested_nodes.extend(self.encrypted_data.id_numbers.keys().cloned()); + + // ..and finally check access on our's own + let is_requestor_allowed_to_read = self.acl_storage.check(&requestor_public, &self.id).unwrap_or(false); + process_initialization_response(&self.encrypted_data, &mut *data, self.node(), is_requestor_allowed_to_read)?; + + // check if we have enough nodes to decrypt data + match data.state { + // not enough nodes => pass initialization message to all other nodes + SessionState::WaitingForInitializationConfirm => { + for node in self.encrypted_data.id_numbers.keys().filter(|n| *n != self.node()) { + self.cluster.send(node, Message::InitializeDecryptionSession(InitializeDecryptionSession { + session: self.id.clone(), + sub_session: self.access_key.clone(), + requestor_signature: requestor_signature.clone(), + }))?; + } + }, + // we can decrypt data on our own + SessionState::WaitingForPartialDecryption => unimplemented!(), + // we can not decrypt data + SessionState::Failed => (), + // cannot reach other states + _ => unreachable!("process_initialization_response can change state to WaitingForPartialDecryption or Failed; checked that we are in WaitingForInitializationConfirm state above; qed"), + } + + Ok(()) + } + + /// When session initialization message is received. + pub fn on_initialize_session(&self, sender: NodeId, message: InitializeDecryptionSession) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(self.access_key == message.sub_session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForInitialization { + return Err(Error::InvalidStateForRequest); + } + + // recover requestor signature + let requestor_public = ethkey::recover(&message.requestor_signature, &self.id)?; + + // check access + let is_requestor_allowed_to_read = self.acl_storage.check(&requestor_public, &self.id).unwrap_or(false); + data.state = if is_requestor_allowed_to_read { SessionState::WaitingForPartialDecryptionRequest } + else { SessionState::Failed }; + data.requestor = Some(requestor_public); + + // respond to master node + data.master = Some(sender.clone()); + self.cluster.send(&sender, Message::ConfirmDecryptionInitialization(ConfirmDecryptionInitialization { + session: self.id.clone(), + sub_session: self.access_key.clone(), + is_confirmed: is_requestor_allowed_to_read, + })) + } + + /// When session initialization confirmation message is reeived. + pub fn on_confirm_initialization(&self, sender: NodeId, message: ConfirmDecryptionInitialization) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(self.access_key == message.sub_session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForInitializationConfirm { + // if there were enough confirmations/rejections before this message + // we have already moved to the next state + return Ok(()); + } + + // update state + process_initialization_response(&self.encrypted_data, &mut *data, &sender, message.is_confirmed)?; + + // check if we have enough nodes to decrypt data + match data.state { + // we do not yet have enough nodes for decryption + SessionState::WaitingForInitializationConfirm => Ok(()), + // we have enough nodes for decryption + SessionState::WaitingForPartialDecryption => { + let confirmed_nodes: BTreeSet<_> = data.confirmed_nodes.clone(); + for node in data.confirmed_nodes.iter().filter(|n| n != &self.node()) { + self.cluster.send(node, Message::RequestPartialDecryption(RequestPartialDecryption { + session: self.id.clone(), + sub_session: self.access_key.clone(), + nodes: confirmed_nodes.clone(), + }))?; + } + + assert!(data.confirmed_nodes.remove(self.node())); + + let shadow_point = { + let requestor = data.requestor.as_ref().expect("requestor public is filled during initialization; WaitingForPartialDecryption follows initialization; qed"); + do_partial_decryption(self.node(), &requestor, &data.confirmed_nodes, &self.access_key, &self.encrypted_data)? + }; + data.shadow_points.insert(self.node().clone(), shadow_point); + + Ok(()) + }, + // we can not have enough nodes for decryption + SessionState::Failed => Ok(()), + // cannot reach other states + _ => unreachable!("process_initialization_response can change state to WaitingForPartialDecryption or Failed; checked that we are in WaitingForInitializationConfirm state above; qed"), + } + } + + /// When partial decryption is requested. + pub fn on_partial_decryption_requested(&self, sender: NodeId, message: RequestPartialDecryption) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(self.access_key == message.sub_session); + debug_assert!(&sender != self.node()); + + // check message + if message.nodes.len() != self.encrypted_data.threshold + 1 { + return Err(Error::InvalidMessage); + } + + let mut data = self.data.lock(); + + // check state + if data.master != Some(sender) { + return Err(Error::InvalidMessage); + } + if data.state != SessionState::WaitingForPartialDecryptionRequest { + return Err(Error::InvalidStateForRequest); + } + + // calculate shadow point + let shadow_point = { + let requestor = data.requestor.as_ref().expect("requestor public is filled during initialization; WaitingForPartialDecryptionRequest follows initialization; qed"); + do_partial_decryption(self.node(), &requestor, &message.nodes, &self.access_key, &self.encrypted_data)? + }; + self.cluster.send(&sender, Message::PartialDecryption(PartialDecryption { + session: self.id.clone(), + sub_session: self.access_key.clone(), + shadow_point: shadow_point, + }))?; + + // update sate + data.state = SessionState::Finished; + + Ok(()) + } + + /// When partial decryption is received. + pub fn on_partial_decryption(&self, sender: NodeId, message: PartialDecryption) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(self.access_key == message.sub_session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForPartialDecryption { + return Err(Error::InvalidStateForRequest); + } + + if !data.confirmed_nodes.remove(&sender) { + return Err(Error::InvalidStateForRequest); + } + data.shadow_points.insert(sender, message.shadow_point); + + // check if we have enough shadow points to decrypt the secret + if data.shadow_points.len() != self.encrypted_data.threshold + 1 { + return Ok(()); + } + + // decrypt the secret using shadow points + let joint_shadow_point = math::compute_joint_shadow_point(data.shadow_points.values())?; + let decrypted_secret = math::decrypt_with_joint_shadow(&self.access_key, &self.encrypted_data.encrypted_point, &joint_shadow_point)?; + data.decrypted_secret = Some(decrypted_secret); + data.state = SessionState::Finished; + + Ok(()) + } +} + +fn check_encrypted_data(self_node_id: &Public, encrypted_data: &EncryptedData) -> Result<(), Error> { + use key_server_cluster::encryption_session::{check_cluster_nodes, check_threshold}; + + let nodes = encrypted_data.id_numbers.keys().cloned().collect(); + check_cluster_nodes(self_node_id, &nodes)?; + check_threshold(encrypted_data.threshold, &nodes)?; + + Ok(()) +} + +fn process_initialization_response(encrypted_data: &EncryptedData, data: &mut SessionData, node: &NodeId, check_result: bool) -> Result<(), Error> { + if !data.requested_nodes.remove(node) { + return Err(Error::InvalidMessage); + } + + match check_result { + true => { + data.confirmed_nodes.insert(node.clone()); + + // check if we have enough nodes to do a decryption? + if data.confirmed_nodes.len() == encrypted_data.threshold + 1 { + data.state = SessionState::WaitingForPartialDecryption; + } + }, + false => { + data.rejected_nodes.insert(node.clone()); + + // check if we still can receive enough confirmations to do a decryption? + if encrypted_data.id_numbers.len() - data.rejected_nodes.len() < encrypted_data.threshold + 1 { + data.state = SessionState::Failed; + } + }, + } + + Ok(()) +} + +fn do_partial_decryption(node: &NodeId, _requestor_public: &Public, participants: &BTreeSet, access_key: &Secret, encrypted_data: &EncryptedData) -> Result { + let node_id_number = &encrypted_data.id_numbers[node]; + let node_secret_share = &encrypted_data.secret_share; + let other_id_numbers = participants.iter() + .filter(|id| *id != node) + .map(|id| &encrypted_data.id_numbers[id]); + // TODO: commutative encryption using _requestor_public + let node_shadow = math::compute_node_shadow(node_id_number, node_secret_share, other_id_numbers)?; + math::compute_node_shadow_point(access_key, &encrypted_data.common_point, &node_shadow) +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + use std::str::FromStr; + use std::collections::BTreeMap; + use super::super::super::acl_storage::DummyAclStorage; + use ethkey::{self, Random, Generator, Public, Secret}; + use key_server_cluster::{NodeId, EncryptedData, SessionId, Error}; + use key_server_cluster::cluster::tests::DummyCluster; + use key_server_cluster::decryption_session::{Session, SessionParams, SessionState}; + use key_server_cluster::message::{self, Message}; + + const SECRET_PLAIN: &'static str = "d2b57ae7619e070af0af6bc8c703c0cd27814c54d5d6a999cacac0da34ede279ca0d9216e85991029e54e2f0c92ee0bd30237725fa765cbdbfc4529489864c5f"; + + fn prepare_decryption_sessions() -> (Vec>, Vec>, Vec) { + // prepare encrypted data + cluster configuration for scheme 4-of-5 + let session_id = SessionId::default(); + let access_key = Random.generate().unwrap().secret().clone(); + let secret_shares = vec![ + Secret::from_str("834cb736f02d9c968dfaf0c37658a1d86ff140554fc8b59c9fdad5a8cf810eec").unwrap(), + Secret::from_str("5a3c1d90fafafa66bb808bcc464354a98b05e6b2c95b5f609d4511cdd1b17a0b").unwrap(), + Secret::from_str("71bf61e7848e08e3a8486c308ce521bdacfebcf9116a0151447eb301f3a2d0e9").unwrap(), + Secret::from_str("80c0e5e2bea66fa9b2e07f7ce09630a9563e8242446d5ee63221feb09c4338f4").unwrap(), + Secret::from_str("c06546b5669877ba579ca437a5602e89425c53808c708d44ccd6afcaa4610fad").unwrap(), + ]; + let id_numbers: Vec<(NodeId, Secret)> = vec![ + ("b486d3840218837b035c66196ecb15e6b067ca20101e11bd5e626288ab6806ecc70b8307012626bd512bad1559112d11d21025cef48cc7a1d2f3976da08f36c8".into(), + Secret::from_str("281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c").unwrap()), + ("1395568277679f7f583ab7c0992da35f26cde57149ee70e524e49bdae62db3e18eb96122501e7cbb798b784395d7bb5a499edead0706638ad056d886e56cf8fb".into(), + Secret::from_str("00125d85a05e5e63e214cb60fe63f132eec8a103aa29266b7e6e6c5b7597230b").unwrap()), + ("99e82b163b062d55a64085bacfd407bb55f194ba5fb7a1af9c34b84435455520f1372e0e650a4f91aed0058cb823f62146ccb5599c8d13372c300dea866b69fc".into(), + Secret::from_str("f43ac0fba42a5b6ed95707d2244659e89ba877b1c9b82c0d0a9dcf834e80fc62").unwrap()), + ("7e05df9dd077ec21ed4bc45c9fe9e0a43d65fa4be540630de615ced5e95cf5c3003035eb713317237d7667feeeb64335525158f5f7411f67aca9645169ea554c".into(), + Secret::from_str("5a324938dfb2516800487d25ab7289ba8ec38811f77c3df602e4e65e3c9acd9f").unwrap()), + ("321977760d1d8e15b047a309e4c7fe6f355c10bb5a06c68472b676926427f69f229024fa2692c10da167d14cdc77eb95d0fce68af0a0f704f0d3db36baa83bb2".into(), + Secret::from_str("12cf422d50002d04e52bd4906fd7f5f235f051ca36abfe37e061f8da248008d8").unwrap()), + ]; + let common_point: Public = "6962be696e1bcbba8e64cc7fddf140f854835354b5804f3bb95ae5a2799130371b589a131bd39699ac7174ccb35fc4342dab05331202209582fc8f3a40916ab0".into(); + let encrypted_point: Public = "b07031982bde9890e12eff154765f03c56c3ab646ad47431db5dd2d742a9297679c4c65b998557f8008469afd0c43d40b6c5f6c6a1c7354875da4115237ed87a".into(); + let encrypted_datas: Vec<_> = (0..5).map(|i| EncryptedData { + threshold: 3, + id_numbers: id_numbers.clone().into_iter().collect(), + secret_share: secret_shares[i].clone(), + common_point: common_point.clone(), + encrypted_point: encrypted_point.clone(), + }).collect(); + let acl_storages: Vec<_> = (0..5).map(|_| Arc::new(DummyAclStorage::default())).collect(); + let clusters: Vec<_> = (0..5).map(|i| Arc::new(DummyCluster::new(id_numbers.iter().nth(i).clone().unwrap().0))).collect(); + let sessions: Vec<_> = (0..5).map(|i| Session::new(SessionParams { + id: session_id.clone(), + access_key: access_key.clone(), + self_node_id: id_numbers.iter().nth(i).clone().unwrap().0, + encrypted_data: encrypted_datas[i].clone(), + acl_storage: acl_storages[i].clone(), + cluster: clusters[i].clone() + }).unwrap()).collect(); + + (clusters, acl_storages, sessions) + } + + fn do_messages_exchange(clusters: &[Arc], sessions: &[Session]) { + do_messages_exchange_until(clusters, sessions, |_, _, _| false); + } + + fn do_messages_exchange_until(clusters: &[Arc], sessions: &[Session], mut cond: F) where F: FnMut(&NodeId, &NodeId, &Message) -> bool { + while let Some((from, to, message)) = clusters.iter().filter_map(|c| c.take_message().map(|(to, msg)| (c.node(), to, msg))).next() { + let session = &sessions[sessions.iter().position(|s| s.node() == &to).unwrap()]; + if cond(&from, &to, &message) { + break; + } + + match message { + Message::InitializeDecryptionSession(message) => session.on_initialize_session(from, message).unwrap(), + Message::ConfirmDecryptionInitialization(message) => session.on_confirm_initialization(from, message).unwrap(), + Message::RequestPartialDecryption(message) => session.on_partial_decryption_requested(from, message).unwrap(), + Message::PartialDecryption(message) => session.on_partial_decryption(from, message).unwrap(), + _ => panic!("unexpected"), + } + } + } + + #[test] + fn fails_to_construct_in_cluster_of_single_node() { + let mut nodes = BTreeMap::new(); + let self_node_id = Random.generate().unwrap().public().clone(); + nodes.insert(self_node_id, Random.generate().unwrap().secret().clone()); + match Session::new(SessionParams { + id: SessionId::default(), + access_key: Random.generate().unwrap().secret().clone(), + self_node_id: self_node_id.clone(), + encrypted_data: EncryptedData { + threshold: 0, + id_numbers: nodes, + secret_share: Random.generate().unwrap().secret().clone(), + common_point: Random.generate().unwrap().public().clone(), + encrypted_point: Random.generate().unwrap().public().clone(), + }, + acl_storage: Arc::new(DummyAclStorage::default()), + cluster: Arc::new(DummyCluster::new(self_node_id.clone())), + }) { + Err(Error::InvalidNodesCount) => (), + _ => panic!("unexpected"), + } + } + + #[test] + fn fails_to_construct_if_not_a_part_of_cluster() { + let mut nodes = BTreeMap::new(); + let self_node_id = Random.generate().unwrap().public().clone(); + nodes.insert(Random.generate().unwrap().public().clone(), Random.generate().unwrap().secret().clone()); + nodes.insert(Random.generate().unwrap().public().clone(), Random.generate().unwrap().secret().clone()); + match Session::new(SessionParams { + id: SessionId::default(), + access_key: Random.generate().unwrap().secret().clone(), + self_node_id: self_node_id.clone(), + encrypted_data: EncryptedData { + threshold: 0, + id_numbers: nodes, + secret_share: Random.generate().unwrap().secret().clone(), + common_point: Random.generate().unwrap().public().clone(), + encrypted_point: Random.generate().unwrap().public().clone(), + }, + acl_storage: Arc::new(DummyAclStorage::default()), + cluster: Arc::new(DummyCluster::new(self_node_id.clone())), + }) { + Err(Error::InvalidNodesConfiguration) => (), + _ => panic!("unexpected"), + } + } + + #[test] + fn fails_to_construct_if_threshold_is_wrong() { + let mut nodes = BTreeMap::new(); + let self_node_id = Random.generate().unwrap().public().clone(); + nodes.insert(self_node_id.clone(), Random.generate().unwrap().secret().clone()); + nodes.insert(Random.generate().unwrap().public().clone(), Random.generate().unwrap().secret().clone()); + match Session::new(SessionParams { + id: SessionId::default(), + access_key: Random.generate().unwrap().secret().clone(), + self_node_id: self_node_id.clone(), + encrypted_data: EncryptedData { + threshold: 2, + id_numbers: nodes, + secret_share: Random.generate().unwrap().secret().clone(), + common_point: Random.generate().unwrap().public().clone(), + encrypted_point: Random.generate().unwrap().public().clone(), + }, + acl_storage: Arc::new(DummyAclStorage::default()), + cluster: Arc::new(DummyCluster::new(self_node_id.clone())), + }) { + Err(Error::InvalidThreshold) => (), + _ => panic!("unexpected"), + } + } + + #[test] + fn fails_to_initialize_when_already_initialized() { + let (_, _, sessions) = prepare_decryption_sessions(); + assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap(), ()); + assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_accept_initialization_when_already_initialized() { + let (_, _, sessions) = prepare_decryption_sessions(); + assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap(), ()); + assert_eq!(sessions[0].on_initialize_session(sessions[1].node().clone(), message::InitializeDecryptionSession { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_partial_decrypt_if_not_waiting() { + let (_, _, sessions) = prepare_decryption_sessions(); + assert_eq!(sessions[1].on_initialize_session(sessions[0].node().clone(), message::InitializeDecryptionSession { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), + }).unwrap(), ()); + assert_eq!(sessions[1].on_partial_decryption_requested(sessions[0].node().clone(), message::RequestPartialDecryption { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + nodes: sessions.iter().map(|s| s.node().clone()).take(4).collect(), + }).unwrap(), ()); + assert_eq!(sessions[1].on_partial_decryption_requested(sessions[0].node().clone(), message::RequestPartialDecryption { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + nodes: sessions.iter().map(|s| s.node().clone()).take(4).collect(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_partial_decrypt_if_requested_by_slave() { + let (_, _, sessions) = prepare_decryption_sessions(); + assert_eq!(sessions[1].on_initialize_session(sessions[0].node().clone(), message::InitializeDecryptionSession { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), + }).unwrap(), ()); + assert_eq!(sessions[1].on_partial_decryption_requested(sessions[2].node().clone(), message::RequestPartialDecryption { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + nodes: sessions.iter().map(|s| s.node().clone()).take(4).collect(), + }).unwrap_err(), Error::InvalidMessage); + } + + #[test] + fn fails_to_partial_decrypt_if_wrong_number_of_nodes_participating() { + let (_, _, sessions) = prepare_decryption_sessions(); + assert_eq!(sessions[1].on_initialize_session(sessions[0].node().clone(), message::InitializeDecryptionSession { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), + }).unwrap(), ()); + assert_eq!(sessions[1].on_partial_decryption_requested(sessions[0].node().clone(), message::RequestPartialDecryption { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + nodes: sessions.iter().map(|s| s.node().clone()).take(2).collect(), + }).unwrap_err(), Error::InvalidMessage); + } + + #[test] + fn fails_to_accept_partial_decrypt_if_not_waiting() { + let (_, _, sessions) = prepare_decryption_sessions(); + assert_eq!(sessions[0].on_partial_decryption(sessions[1].node().clone(), message::PartialDecryption { + session: SessionId::default(), + sub_session: sessions[0].access_key().clone(), + shadow_point: Random.generate().unwrap().public().clone(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_accept_partial_decrypt_twice() { + let (clusters, _, sessions) = prepare_decryption_sessions(); + sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap(); + + let mut pd_from = None; + let mut pd_msg = None; + do_messages_exchange_until(&clusters, &sessions, |from, _, msg| match msg { + &Message::PartialDecryption(ref msg) => { + pd_from = Some(from.clone()); + pd_msg = Some(msg.clone()); + true + }, + _ => false, + }); + + assert_eq!(sessions[0].on_partial_decryption(pd_from.clone().unwrap(), pd_msg.clone().unwrap()).unwrap(), ()); + assert_eq!(sessions[0].on_partial_decryption(pd_from.unwrap(), pd_msg.unwrap()).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn complete_dec_session() { + let (clusters, _, sessions) = prepare_decryption_sessions(); + + // now let's try to do a decryption + let key_pair = Random.generate().unwrap(); + let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap(); + sessions[0].initialize(signature).unwrap(); + + do_messages_exchange(&clusters, &sessions); + + // now check that: + // 1) 4 of 5 sessions are in Finished state + assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::Finished).count(), 4); + // 2) 1 session is in WaitingForPartialDecryptionRequest state + assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::WaitingForPartialDecryptionRequest).count(), 1); + // 3) 1 session has decrypted key value + assert!(sessions.iter().skip(1).all(|s| s.decrypted_secret().is_none())); + assert_eq!(sessions[0].decrypted_secret(), Some(SECRET_PLAIN.into())); + } + + #[test] + fn failed_dec_session() { + let (clusters, acl_storages, sessions) = prepare_decryption_sessions(); + + // now let's try to do a decryption + let key_pair = Random.generate().unwrap(); + let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap(); + sessions[0].initialize(signature).unwrap(); + + // we need 4 out of 5 nodes to agree to do a decryption + // let's say that 2 of these nodes are disagree + acl_storages[1].prohibit(key_pair.public().clone(), SessionId::default()); + acl_storages[2].prohibit(key_pair.public().clone(), SessionId::default()); + + do_messages_exchange(&clusters, &sessions); + + // now check that: + // 1) 3 of 5 sessions are in Failed state + assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::Failed).count(), 3); + // 2) 2 of 5 sessions are in WaitingForPartialDecryptionRequest state + assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::WaitingForPartialDecryptionRequest).count(), 2); + // 3) 0 sessions have decrypted key value + assert!(sessions.iter().all(|s| s.decrypted_secret().is_none())); + } +} diff --git a/secret_store/src/key_server_cluster/encryption_session.rs b/secret_store/src/key_server_cluster/encryption_session.rs new file mode 100644 index 000000000..6f5705a73 --- /dev/null +++ b/secret_store/src/key_server_cluster/encryption_session.rs @@ -0,0 +1,1197 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::{BTreeSet, BTreeMap, VecDeque}; +use std::fmt::{Debug, Formatter, Error as FmtError}; +use std::sync::Arc; +use parking_lot::Mutex; +use ethkey::{Public, Secret}; +use key_server_cluster::{Error, NodeId, SessionId}; +use key_server_cluster::math; +use key_server_cluster::cluster::Cluster; +use key_server_cluster::message::{Message, InitializeSession, ConfirmInitialization, CompleteInitialization, + KeysDissemination, Complaint, ComplaintResponse, PublicKeyShare}; + +/// Encryption (distributed key generation) session. +/// Based on "ECDKG: A Distributed Key Generation Protocol Based on Elliptic Curve Discrete Logarithm" paper: +/// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.124.4128&rep=rep1&type=pdf +/// Brief overview: +/// 1) initialization: master node (which has received request for generating joint public + secret) initializes the session on all other nodes +/// 2) key dissemination (KD): all nodes are generating secret + public values and send these to appropriate nodes +/// 3) key verification (KV): all nodes are checking values, received for other nodes and complaining if keys are wrong +/// 4) key check phase (KC): nodes are processing complaints, received from another nodes +/// 5) key generation phase (KG): nodes are exchanging with information, enough to generate joint public key +pub struct Session { + /// Unique session id. + id: SessionId, + /// Public identifier of this node. + self_node_id: NodeId, + /// Cluster which allows this node to send messages to other nodes in the cluster. + cluster: Arc, + /// Mutable session data. + data: Mutex, +} + +#[derive(Debug)] +/// Mutable data of encryption (distributed key generation) session. +struct SessionData { + /// Current state of the session. + state: SessionState, + + // === Values, filled when session initialization just starts === + /// Reference to the node, which has started this session. + master: Option, + + // === Values, filled when session initialization is completed === + /// Threshold value for this DKG. Only `threshold + 1` will be able to collectively recreate joint secret, + /// and thus - decrypt message, encrypted with joint public. + threshold: Option, + /// Random point, jointly generated by every node in the cluster. + derived_point: Option, + /// Nodes-specific data. + nodes: BTreeMap, + + // === Values, filled during KD phase === + /// Value of polynom1[0], generated by this node. + secret_coeff: Option, + + // === Values, filled during KG phase === + /// Secret share, which this node holds. Persistent + private. + secret_share: Option, + + /// === Values, filled when DKG session is completed successfully === + /// Jointly generated public key, which can be used to encrypt secret. Public. + joint_public: Option, +} + +#[derive(Debug, Clone)] +/// Mutable node-specific data. +struct NodeData { + /// Random unique scalar. Persistent. + pub id_number: Secret, + + // === Values, filled during KD phase === + /// Secret value1, which has been sent to this node. + pub secret1_sent: Option, + /// Secret value2, which has been sent to this node. + pub secret2_sent: Option, + /// Secret value1, which has been received from this node. + pub secret1: Option, + /// Secret value2, which has been received from this node. + pub secret2: Option, + /// Public values, which have been received from this node. + pub publics: Option>, + + /// === Values, filled during KC phase === + /// Nodes, complaining against this node. + pub complaints: BTreeSet, + + /// === Values, filled during KG phase === + /// Public share, which has been received from this node. + pub public_share: Option, +} + +#[derive(Debug, Clone, PartialEq)] +/// Schedule for visiting other nodes of cluster. +pub struct EveryOtherNodeVisitor { + /// Already visited nodes. + visited: BTreeSet, + /// Not yet visited nodes. + unvisited: VecDeque, + /// Nodes, which are currently visited. + in_progress: BTreeSet, +} + +#[derive(Debug, Clone, PartialEq)] +/// Encryption (distributed key generation) session state. +pub enum SessionState { + // === Initialization states === + /// Every node starts in this state. + WaitingForInitialization, + /// Master node asks every other node to confirm initialization. + /// Derived point is generated by all nodes in the cluster. + WaitingForInitializationConfirm(EveryOtherNodeVisitor), + /// Slave nodes are in this state until initialization completion is reported by master node. + WaitingForInitializationComplete, + + // === KD phase states === + /// Node is waiting for generated keys from every other node. + WaitingForKeysDissemination, + + // === KC phase states === + /// Keys check currently occurs. + KeyCheck, + + // === KG phase states === + /// Node is waiting for joint public key share to be received from every other node. + WaitingForPublicKeyShare, + + // === Final states of the session === + /// Joint public key generation is completed. + Finished, + /// Joint public key generation is failed. + Failed, +} + +impl Session { + /// Create new encryption session. + pub fn new(id: SessionId, self_node_id: Public, cluster: Arc) -> Self { + Session { + id: id, + self_node_id: self_node_id, + cluster: cluster, + data: Mutex::new(SessionData { + state: SessionState::WaitingForInitialization, + master: None, + threshold: None, + derived_point: None, + nodes: BTreeMap::new(), + secret_coeff: None, + secret_share: None, + joint_public: None, + }), + } + } + + /// Get this node Id. + pub fn node(&self) -> &NodeId { + &self.self_node_id + } + + /// Get current session state. + pub fn state(&self) -> SessionState { + self.data.lock().state.clone() + } + + /// Get joint public key. + pub fn joint_public_key(&self) -> Option { + self.data.lock().joint_public.clone() + } + + #[cfg(test)] + /// Get derived point. + pub fn derived_point(&self) -> Option { + self.data.lock().derived_point.clone() + } + + #[cfg(test)] + /// Get qualified nodes. + pub fn qualified_nodes(&self) -> BTreeSet { + self.data.lock().nodes.keys().cloned().collect() + } + + /// Start new session initialization. This must be called on master node. + pub fn initialize(&self, threshold: usize, nodes: BTreeSet) -> Result<(), Error> { + check_cluster_nodes(self.node(), &nodes)?; + check_threshold(threshold, &nodes)?; + + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForInitialization { + return Err(Error::InvalidStateForRequest); + } + + // update state + data.master = Some(self.node().clone()); + data.threshold = Some(threshold); + for node_id in &nodes { + // generate node identification parameter + let node_id_number = math::generate_random_scalar()?; + data.nodes.insert(node_id.clone(), NodeData::with_id_number(node_id_number)); + } + + let mut visit_policy = EveryOtherNodeVisitor::new(self.node(), data.nodes.keys().cloned()); + let next_node = visit_policy.next_node().expect("at least two nodes are in cluster"); + data.state = SessionState::WaitingForInitializationConfirm(visit_policy); + + // start initialization + let derived_point = math::generate_random_point()?; + self.cluster.send(&next_node, Message::InitializeSession(InitializeSession { + session: self.id.clone(), + derived_point: derived_point, + })) + } + + /// When session initialization message is received. + pub fn on_initialize_session(&self, sender: NodeId, mut message: InitializeSession) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForInitialization { + return Err(Error::InvalidStateForRequest); + } + + // update derived point with random scalar + math::update_random_point(&mut message.derived_point)?; + + // send confirmation back to master node + self.cluster.send(&sender, Message::ConfirmInitialization(ConfirmInitialization { + session: self.id.clone(), + derived_point: message.derived_point, + }))?; + + // update state + data.master = Some(sender); + data.state = SessionState::WaitingForInitializationComplete; + + Ok(()) + } + + /// When session initialization confirmation message is reeived. + pub fn on_confirm_initialization(&self, sender: NodeId, mut message: ConfirmInitialization) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + debug_assert!(data.nodes.contains_key(&sender)); + + // check state && select new node to be initialized + let next_receiver = match data.state { + SessionState::WaitingForInitializationConfirm(ref mut visit_policy) => { + if !visit_policy.mark_visited(&sender) { + return Err(Error::InvalidStateForRequest); + } + + visit_policy.next_node() + }, + _ => return Err(Error::InvalidStateForRequest), + }; + + // proceed message + match next_receiver { + Some(next_receiver) => { + return self.cluster.send(&next_receiver, Message::InitializeSession(InitializeSession { + session: self.id.clone(), + derived_point: message.derived_point, + })); + }, + None => { + // update point once again to make sure that derived point is not generated by last node + math::update_random_point(&mut message.derived_point)?; + + // remember derived point + data.derived_point = Some(message.derived_point.clone()); + + // broadcast derived point && other session paraeters to every other node + self.cluster.broadcast(Message::CompleteInitialization(CompleteInitialization { + session: self.id.clone(), + nodes: data.nodes.iter().map(|(id, data)| (id.clone(), data.id_number.clone())).collect(), + threshold: data.threshold.expect("threshold is filled in initialization phase; KD phase follows initialization phase; qed"), + derived_point: message.derived_point, + }))?; + }, + } + + // now it is time for keys dissemination (KD) phase + drop(data); + self.disseminate_keys() + } + + /// When session initialization completion message is received. + pub fn on_complete_initialization(&self, sender: NodeId, message: CompleteInitialization) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(&sender != self.node()); + + // check message + let nodes_ids = message.nodes.keys().cloned().collect(); + check_cluster_nodes(self.node(), &nodes_ids)?; + check_threshold(message.threshold, &nodes_ids)?; + + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForInitializationComplete { + return Err(Error::InvalidStateForRequest); + } + if data.master != Some(sender) { + return Err(Error::InvalidMessage); + } + + // remember passed data + data.threshold = Some(message.threshold); + data.derived_point = Some(message.derived_point); + data.nodes = message.nodes.into_iter().map(|(id, number)| (id, NodeData::with_id_number(number))).collect(); + + // now it is time for keys dissemination (KD) phase + drop(data); + self.disseminate_keys() + } + + /// When keys dissemination message is received. + pub fn on_keys_dissemination(&self, sender: NodeId, message: KeysDissemination) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + debug_assert!(data.nodes.contains_key(&sender)); + + // check state + if data.state != SessionState::WaitingForKeysDissemination { + return Err(Error::InvalidStateForRequest); + } + + // check message + let threshold = data.threshold.expect("threshold is filled in initialization phase; KD phase follows initialization phase; qed"); + if message.publics.len() != threshold + 1 { + return Err(Error::InvalidMessage); + } + + // update node data + { + let node_data = data.nodes.get_mut(&sender).ok_or(Error::InvalidMessage)?; + if node_data.secret1.is_some() || node_data.secret2.is_some() || node_data.publics.is_some() { + return Err(Error::InvalidStateForRequest); + } + + node_data.secret1 = Some(message.secret1); + node_data.secret2 = Some(message.secret2); + node_data.publics = Some(message.publics); + } + + // check if we have received keys from every other node + if data.nodes.iter().any(|(node_id, node_data)| node_id != self.node() && (node_data.publics.is_none() || node_data.secret1.is_none() || node_data.secret2.is_none())) { + return Ok(()) + } + + // key verification (KV) phase: check that other nodes have passed correct secrets + let derived_point = data.derived_point.clone().expect("derived point generated on initialization phase; KV phase follows initialization phase; qed"); + let number_id = data.nodes[self.node()].id_number.clone(); + for (node_id, node_data) in data.nodes.iter_mut().filter(|&(node_id, _)| node_id != self.node()) { + let secret1 = node_data.secret1.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed"); + let secret2 = node_data.secret2.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed"); + let publics = node_data.publics.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed"); + let is_key_verification_ok = math::keys_verification(threshold, &derived_point, &number_id, + secret1, secret2, publics)?; + + if !is_key_verification_ok { + node_data.complaints.insert(self.node().clone()); + self.cluster.broadcast(Message::Complaint(Complaint { + session: self.id.clone(), + against: node_id.clone(), + }))?; + } + } + + // update state + data.state = SessionState::KeyCheck; + + Ok(()) + } + + /// When complaint is received. + pub fn on_complaint(&self, sender: NodeId, message: Complaint) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + debug_assert!(data.nodes.contains_key(&sender)); + + // check state + if data.state != SessionState::KeyCheck && data.state != SessionState::WaitingForKeysDissemination { + // message can be received after timeout is passed + // => encryption is already in progress + // => we can not treat it as an error + return Ok(()); + } + + // respond to complaint + if &message.against == self.node() { + let secret1_sent = data.nodes[&sender].secret1_sent.clone().expect("secrets were sent on KD phase; KC phase follows KD phase; qed"); + let secret2_sent = data.nodes[&sender].secret2_sent.clone().expect("secrets were sent on KD phase; KC phase follows KD phase; qed"); + + // someone is complaining against us => let's respond + return self.cluster.broadcast(Message::ComplaintResponse(ComplaintResponse { + session: self.id.clone(), + secret1: secret1_sent, + secret2: secret2_sent, + })); + } + + // someone is complaining against someone else => let's remember this + let threshold = data.threshold.expect("threshold is filled in initialization phase; KD phase follows initialization phase; qed"); + let is_critical_complaints_num = { + let node = data.nodes.get_mut(&message.against).ok_or(Error::InvalidMessage)?; + node.complaints.insert(sender); + node.complaints.len() >= threshold + 1 + }; + + if is_critical_complaints_num { + // too many complaints => exclude from session + Session::disqualify_node(&message.against, &*self.cluster, &mut *data); + } + + Ok(()) + } + + /// When complaint response is received + pub fn on_complaint_response(&self, sender: NodeId, message: ComplaintResponse) -> Result<(), Error> { + debug_assert!(self.id == message.session); + debug_assert!(&sender != self.node()); + + let mut data = self.data.lock(); + debug_assert!(data.nodes.contains_key(&sender)); + + // check state + if data.state != SessionState::KeyCheck { + // in theory this message can be received before KeyCheck (in WaitingForKeysDissemination state) + // => but the fact that someone is complaining about keys means that sender has already sent its keys + // => complaint response can't reach us before keys, as the cluster guarantees that messages are received in FIFO order + + // message can be received after timeout is passed + // => encryption is already in progress + // => we can not treat it as an error + return Ok(()); + } + + // check keys again + let is_key_verification_ok = { + let threshold = data.threshold.expect("threshold is filled in initialization phase; KD phase follows initialization phase; qed"); + let derived_point = data.derived_point.as_ref().expect("derived point generated on initialization phase; KV phase follows initialization phase; qed"); + let number_id = &data.nodes[self.node()].id_number; + let node_data = data.nodes.get(&sender).expect("cluster guarantees to deliver messages from qualified nodes only; qed"); + let publics = node_data.publics.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed"); + math::keys_verification(threshold, derived_point, number_id, &message.secret1, &message.secret2, publics)? + }; + + if !is_key_verification_ok { + Session::disqualify_node(&sender, &*self.cluster, &mut *data); + } else { + let node_data = data.nodes.get_mut(&sender).expect("cluster guarantees to deliver messages from qualified nodes only; qed"); + node_data.secret1 = Some(message.secret1); + node_data.secret2 = Some(message.secret2); + node_data.complaints.remove(self.node()); + } + + Ok(()) + } + + /// When KC-phase timeout is expired, it is time to start KG phase. + pub fn start_key_generation_phase(&self) -> Result<(), Error> { + let mut data = self.data.lock(); + + if data.state != SessionState::KeyCheck { + return Err(Error::InvalidStateForRequest); + } + + // calculate public share + let self_public_share = { + let self_secret_coeff = data.secret_coeff.as_ref().expect("secret_coeff is generated on KD phase; KG phase follows KD phase; qed"); + math::compute_public_share(self_secret_coeff)? + }; + + // calculate self secret + public shares + let self_secret_share = { + let secret_values_iter = data.nodes.values() + .map(|n| n.secret1.as_ref().expect("keys received on KD phase; KG phase follows KD phase; qed")); + math::compute_secret_share(secret_values_iter)? + }; + + // update state + data.state = SessionState::WaitingForPublicKeyShare; + data.secret_share = Some(self_secret_share); + let self_node = data.nodes.get_mut(self.node()).expect("node is always qualified by himself; qed"); + self_node.public_share = Some(self_public_share.clone()); + + // broadcast self public key share + self.cluster.broadcast(Message::PublicKeyShare(PublicKeyShare { + session: self.id.clone(), + public_share: self_public_share, + })) + } + + /// When public key share is received. + pub fn on_public_key_share(&self, sender: NodeId, message: PublicKeyShare) -> Result<(), Error> { + let mut data = self.data.lock(); + + // check state + if data.state != SessionState::WaitingForPublicKeyShare { + return Err(Error::InvalidStateForRequest); + } + + // update node data with received public share + { + let node_data = &mut data.nodes.get_mut(&sender).ok_or(Error::InvalidMessage)?; + if node_data.public_share.is_some() { + return Err(Error::InvalidMessage); + } + + node_data.public_share = Some(message.public_share); + } + + // if there's also nodes, which has not sent us their public shares - do nothing + if data.nodes.iter().any(|(node_id, node_data)| node_id != self.node() && node_data.public_share.is_none()) { + return Ok(()); + } + + // else - calculate joint public key && finish session + data.joint_public = { + let public_shares = data.nodes.values().map(|n| n.public_share.as_ref().expect("keys received on KD phase; KG phase follows KD phase; qed")); + Some(math::compute_joint_public(public_shares)?) + }; + data.state = SessionState::Finished; + + Ok(()) + } + + /// Keys dissemination (KD) phase + fn disseminate_keys(&self) -> Result<(), Error> { + let mut data = self.data.lock(); + + // pick 2t + 2 random numbers as polynomial coefficients for 2 polynoms + let threshold = data.threshold.expect("threshold is filled on initialization phase; KD phase follows initialization phase; qed"); + let polynom1 = math::generate_random_polynom(threshold)?; + let polynom2 = math::generate_random_polynom(threshold)?; + data.secret_coeff = Some(polynom1[0].clone()); + + // compute t+1 public values + let publics = math::public_values_generation(threshold, + data.derived_point.as_ref().expect("keys dissemination occurs after derived point is agreed; qed"), + &polynom1, + &polynom2)?; + + // compute secret values for every other node + for (node, node_data) in data.nodes.iter_mut() { + let secret1 = math::compute_polynom(&polynom1, &node_data.id_number)?; + let secret2 = math::compute_polynom(&polynom2, &node_data.id_number)?; + + // send a message containing secret1 && secret2 to other node + if node != self.node() { + node_data.secret1_sent = Some(secret1.clone()); + node_data.secret2_sent = Some(secret2.clone()); + + self.cluster.send(&node, Message::KeysDissemination(KeysDissemination { + session: self.id.clone(), + secret1: secret1, + secret2: secret2, + publics: publics.clone(), + }))?; + } else { + node_data.secret1 = Some(secret1); + node_data.secret2 = Some(secret2); + node_data.publics = Some(publics.clone()); + } + } + + // update state + data.state = SessionState::WaitingForKeysDissemination; + + Ok(()) + } + + /// Disqualify node + fn disqualify_node(node: &NodeId, cluster: &Cluster, data: &mut SessionData) { + let threshold = data.threshold + .expect("threshold is filled on initialization phase; node can only be disqualified during KC phase; KC phase follows initialization phase; qed"); + + // blacklist node + cluster.blacklist(&node); + // too many complaints => exclude from session + data.nodes.remove(&node); + // check if secret still can be reconstructed + if data.nodes.len() < threshold + 1 { + // not enough nodes => session is failed + data.state = SessionState::Failed; + } + } +} + +impl EveryOtherNodeVisitor { + pub fn new(self_id: &NodeId, nodes: I) -> Self where I: Iterator { + EveryOtherNodeVisitor { + visited: BTreeSet::new(), + unvisited: nodes.filter(|n| n != self_id).collect(), + in_progress: BTreeSet::new(), + } + } + + pub fn next_node(&mut self) -> Option { + let next_node = self.unvisited.pop_front(); + if let Some(ref next_node) = next_node { + self.in_progress.insert(next_node.clone()); + } + next_node + } + + pub fn mark_visited(&mut self, node: &NodeId) -> bool { + if !self.in_progress.remove(node) { + return false; + } + self.visited.insert(node.clone()) + } +} + +impl NodeData { + fn with_id_number(node_id_number: Secret) -> Self { + NodeData { + id_number: node_id_number, + complaints: BTreeSet::new(), + secret1_sent: None, + secret2_sent: None, + secret1: None, + secret2: None, + publics: None, + public_share: None, + } + } +} + +impl Debug for Session { + fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + write!(f, "Encryption session {} on {}", self.id, self.self_node_id) + } +} + +pub fn check_cluster_nodes(self_node_id: &NodeId, nodes: &BTreeSet) -> Result<(), Error> { + // at least two nodes must be in cluster + if nodes.len() < 2 { + return Err(Error::InvalidNodesCount); + } + // this node must be a part of cluster + if !nodes.contains(self_node_id) { + return Err(Error::InvalidNodesConfiguration); + } + + Ok(()) +} + +pub fn check_threshold(threshold: usize, nodes: &BTreeSet) -> Result<(), Error> { + // at least threshold + 1 nodes are required to collectively decrypt message + if threshold >= nodes.len() { + return Err(Error::InvalidThreshold); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + use std::collections::{BTreeSet, BTreeMap}; + use ethkey::{Random, Generator}; + use key_server_cluster::{NodeId, SessionId, Error}; + use key_server_cluster::message::{self, Message}; + use key_server_cluster::cluster::tests::DummyCluster; + use key_server_cluster::encryption_session::{Session, SessionState}; + use key_server_cluster::math; + use key_server_cluster::math::tests::do_encryption_and_decryption; + + #[derive(Debug)] + struct Node { + pub cluster: Arc, + pub session: Session, + } + + #[derive(Debug)] + struct MessageLoop { + pub session_id: SessionId, + pub nodes: BTreeMap, + } + + impl MessageLoop { + pub fn new(nodes_num: usize) -> Self { + let mut nodes = BTreeMap::new(); + let session_id = SessionId::default(); + for _ in 0..nodes_num { + let key_pair = Random.generate().unwrap(); + let node_id = key_pair.public().clone(); + let cluster = Arc::new(DummyCluster::new(node_id.clone())); + let session = Session::new(session_id.clone(), node_id.clone(), cluster.clone()); + nodes.insert(node_id, Node { cluster: cluster, session: session }); + } + + let nodes_ids: Vec<_> = nodes.keys().cloned().collect(); + for node in nodes.values() { + for node_id in &nodes_ids { + node.cluster.add_node(node_id.clone()); + } + } + + MessageLoop { + session_id: session_id, + nodes: nodes, + } + } + + pub fn master(&self) -> &Session { + &self.nodes.values().nth(0).unwrap().session + } + + pub fn first_slave(&self) -> &Session { + &self.nodes.values().nth(1).unwrap().session + } + + pub fn second_slave(&self) -> &Session { + &self.nodes.values().nth(2).unwrap().session + } + + pub fn third_slave(&self) -> &Session { + &self.nodes.values().nth(3).unwrap().session + } + + pub fn take_message(&mut self) -> Option<(NodeId, NodeId, Message)> { + self.nodes.values() + .filter_map(|n| n.cluster.take_message().map(|m| (n.session.node().clone(), m.0, m.1))) + .nth(0) + } + + pub fn process_message(&mut self, msg: (NodeId, NodeId, Message)) -> Result<(), Error> { + match msg.2 { + Message::InitializeSession(message) => self.nodes[&msg.1].session.on_initialize_session(msg.0, message), + Message::ConfirmInitialization(message) => self.nodes[&msg.1].session.on_confirm_initialization(msg.0, message), + Message::CompleteInitialization(message) => self.nodes[&msg.1].session.on_complete_initialization(msg.0, message), + Message::KeysDissemination(message) => self.nodes[&msg.1].session.on_keys_dissemination(msg.0, message), + Message::Complaint(message) => self.nodes[&msg.1].session.on_complaint(msg.0, message), + Message::ComplaintResponse(message) => self.nodes[&msg.1].session.on_complaint_response(msg.0, message), + Message::PublicKeyShare(message) => self.nodes[&msg.1].session.on_public_key_share(msg.0, message), + _ => panic!("unexpected"), + } + } + + pub fn take_and_process_message(&mut self) -> Result<(), Error> { + let msg = self.take_message().unwrap(); + self.process_message(msg) + } + + pub fn take_and_process_all_messages(&mut self) -> Result<(), Error> { + while let Some(msg) = self.take_message() { + self.process_message(msg)?; + } + Ok(()) + } + } + + fn make_simple_cluster(threshold: usize, num_nodes: usize) -> Result<(SessionId, NodeId, NodeId, MessageLoop), Error> { + let l = MessageLoop::new(num_nodes); + l.master().initialize(threshold, l.nodes.keys().cloned().collect())?; + + let session_id = l.session_id.clone(); + let master_id = l.master().node().clone(); + let slave_id = l.first_slave().node().clone(); + Ok((session_id, master_id, slave_id, l)) + } + + #[test] + fn fails_to_initialize_in_cluster_of_single_node() { + assert_eq!(make_simple_cluster(0, 1).unwrap_err(), Error::InvalidNodesCount); + } + + #[test] + fn fails_to_initialize_if_not_a_part_of_cluster() { + let node_id = math::generate_random_point().unwrap(); + let cluster = Arc::new(DummyCluster::new(node_id.clone())); + let session = Session::new(SessionId::default(), node_id.clone(), cluster); + let cluster_nodes: BTreeSet<_> = (0..2).map(|_| math::generate_random_point().unwrap()).collect(); + assert_eq!(session.initialize(0, cluster_nodes).unwrap_err(), Error::InvalidNodesConfiguration); + } + + #[test] + fn fails_to_initialize_if_threshold_is_wrong() { + assert_eq!(make_simple_cluster(2, 2).unwrap_err(), Error::InvalidThreshold); + } + + #[test] + fn fails_to_initialize_when_already_initialized() { + let (_, _, _, l) = make_simple_cluster(0, 2).unwrap(); + assert_eq!(l.master().initialize(0, l.nodes.keys().cloned().collect()).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_accept_initialization_when_already_initialized() { + let (sid, m, _, mut l) = make_simple_cluster(0, 2).unwrap(); + l.take_and_process_message().unwrap(); + assert_eq!(l.first_slave().on_initialize_session(m, message::InitializeSession { + session: sid, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn slave_updates_derived_point_on_initialization() { + let (_, _, _, mut l) = make_simple_cluster(0, 2).unwrap(); + let passed_point = match l.take_message().unwrap() { + (f, t, Message::InitializeSession(message)) => { + let point = message.derived_point.clone(); + l.process_message((f, t, Message::InitializeSession(message))).unwrap(); + point + }, + _ => panic!("unexpected"), + }; + + match l.take_message().unwrap() { + (_, _, Message::ConfirmInitialization(message)) => assert!(passed_point != message.derived_point), + _ => panic!("unexpected"), + } + } + + #[test] + fn fails_to_accept_initialization_confirmation_if_already_accepted_from_the_same_node() { + let (sid, _, s, mut l) = make_simple_cluster(0, 3).unwrap(); + l.take_and_process_message().unwrap(); + l.take_and_process_message().unwrap(); + l.take_and_process_message().unwrap(); + assert_eq!(l.master().on_confirm_initialization(s, message::ConfirmInitialization { + session: sid, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_accept_initialization_confirmation_if_initialization_already_completed() { + let (sid, _, s, mut l) = make_simple_cluster(0, 2).unwrap(); + l.take_and_process_message().unwrap(); + l.take_and_process_message().unwrap(); + assert_eq!(l.master().on_confirm_initialization(s, message::ConfirmInitialization { + session: sid, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn master_updates_derived_point_on_initialization_completion() { + let (_, _, _, mut l) = make_simple_cluster(0, 2).unwrap(); + l.take_and_process_message().unwrap(); + let passed_point = match l.take_message().unwrap() { + (f, t, Message::ConfirmInitialization(message)) => { + let point = message.derived_point.clone(); + l.process_message((f, t, Message::ConfirmInitialization(message))).unwrap(); + point + }, + _ => panic!("unexpected"), + }; + + assert!(passed_point != l.master().derived_point().unwrap()); + } + + #[test] + fn fails_to_complete_initialization_in_cluster_of_single_node() { + let (sid, m, s, l) = make_simple_cluster(0, 2).unwrap(); + let mut nodes = BTreeMap::new(); + nodes.insert(s, math::generate_random_scalar().unwrap()); + assert_eq!(l.first_slave().on_complete_initialization(m, message::CompleteInitialization { + session: sid, + nodes: nodes, + threshold: 0, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidNodesCount); + } + + #[test] + fn fails_to_complete_initialization_if_not_a_part_of_cluster() { + let (sid, m, _, l) = make_simple_cluster(0, 2).unwrap(); + let mut nodes = BTreeMap::new(); + nodes.insert(m, math::generate_random_scalar().unwrap()); + nodes.insert(math::generate_random_point().unwrap(), math::generate_random_scalar().unwrap()); + assert_eq!(l.first_slave().on_complete_initialization(m, message::CompleteInitialization { + session: sid, + nodes: nodes, + threshold: 0, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidNodesConfiguration); + } + + #[test] + fn fails_to_complete_initialization_if_threshold_is_wrong() { + let (sid, m, s, l) = make_simple_cluster(0, 2).unwrap(); + let mut nodes = BTreeMap::new(); + nodes.insert(m, math::generate_random_scalar().unwrap()); + nodes.insert(s, math::generate_random_scalar().unwrap()); + assert_eq!(l.first_slave().on_complete_initialization(m, message::CompleteInitialization { + session: sid, + nodes: nodes, + threshold: 2, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidThreshold); + } + + #[test] + fn fails_to_complete_initialization_if_not_waiting_for_it() { + let (sid, m, s, l) = make_simple_cluster(0, 2).unwrap(); + let mut nodes = BTreeMap::new(); + nodes.insert(m, math::generate_random_scalar().unwrap()); + nodes.insert(s, math::generate_random_scalar().unwrap()); + assert_eq!(l.first_slave().on_complete_initialization(m, message::CompleteInitialization { + session: sid, + nodes: nodes, + threshold: 0, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_complete_initialization_from_non_master_node() { + let (sid, m, s, mut l) = make_simple_cluster(0, 3).unwrap(); + l.take_and_process_message().unwrap(); + l.take_and_process_message().unwrap(); + l.take_and_process_message().unwrap(); + l.take_and_process_message().unwrap(); + let mut nodes = BTreeMap::new(); + nodes.insert(m, math::generate_random_scalar().unwrap()); + nodes.insert(s, math::generate_random_scalar().unwrap()); + nodes.insert(l.second_slave().node().clone(), math::generate_random_scalar().unwrap()); + assert_eq!(l.first_slave().on_complete_initialization(l.second_slave().node().clone(), message::CompleteInitialization { + session: sid, + nodes: nodes, + threshold: 0, + derived_point: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidMessage); + } + + #[test] + fn fails_to_accept_keys_dissemination_if_not_waiting_for_it() { + let (sid, _, s, l) = make_simple_cluster(0, 2).unwrap(); + assert_eq!(l.master().on_keys_dissemination(s, message::KeysDissemination { + session: sid, + secret1: math::generate_random_scalar().unwrap(), + secret2: math::generate_random_scalar().unwrap(), + publics: vec![math::generate_random_point().unwrap()], + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn fails_to_accept_keys_dissemination_if_wrong_number_of_publics_passed() { + let (sid, m, _, mut l) = make_simple_cluster(0, 3).unwrap(); + l.take_and_process_message().unwrap(); // m -> s1: InitializeSession + l.take_and_process_message().unwrap(); // m -> s2: InitializeSession + l.take_and_process_message().unwrap(); // s1 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // s2 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // m -> s1: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s2: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s1: KeysDissemination + assert_eq!(l.first_slave().on_keys_dissemination(m, message::KeysDissemination { + session: sid, + secret1: math::generate_random_scalar().unwrap(), + secret2: math::generate_random_scalar().unwrap(), + publics: vec![math::generate_random_point().unwrap(), math::generate_random_point().unwrap()], + }).unwrap_err(), Error::InvalidMessage); + } + + #[test] + fn fails_to_accept_keys_dissemination_second_time_from_the_same_node() { + let (sid, m, _, mut l) = make_simple_cluster(0, 3).unwrap(); + l.take_and_process_message().unwrap(); // m -> s1: InitializeSession + l.take_and_process_message().unwrap(); // m -> s2: InitializeSession + l.take_and_process_message().unwrap(); // s1 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // s2 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // m -> s1: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s2: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s1: KeysDissemination + assert_eq!(l.first_slave().on_keys_dissemination(m, message::KeysDissemination { + session: sid, + secret1: math::generate_random_scalar().unwrap(), + secret2: math::generate_random_scalar().unwrap(), + publics: vec![math::generate_random_point().unwrap()], + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn defends_if_receives_complain_on_himself() { + let (sid, m, s, mut l) = make_simple_cluster(1, 3).unwrap(); + l.take_and_process_all_messages().unwrap(); + l.master().on_complaint(s, message::Complaint { + session: sid, + against: m, + }).unwrap(); + match l.take_message().unwrap() { + (_, _, Message::ComplaintResponse(_)) => (), + _ => panic!("unexpected"), + } + } + + #[test] + fn node_is_disqualified_if_enough_complaints_received() { + let (sid, _, s, mut l) = make_simple_cluster(1, 4).unwrap(); + l.take_and_process_all_messages().unwrap(); + l.master().on_complaint(l.second_slave().node().clone(), message::Complaint { + session: sid, + against: s.clone(), + }).unwrap(); + l.master().on_complaint(l.third_slave().node().clone(), message::Complaint { + session: sid, + against: s, + }).unwrap(); + assert_eq!(l.master().qualified_nodes().len(), 3); + } + + #[test] + fn node_is_not_disqualified_if_enough_complaints_received_from_the_same_node() { + let (sid, _, s, mut l) = make_simple_cluster(1, 4).unwrap(); + l.take_and_process_all_messages().unwrap(); + l.master().on_complaint(l.second_slave().node().clone(), message::Complaint { + session: sid, + against: s.clone(), + }).unwrap(); + l.master().on_complaint(l.second_slave().node().clone(), message::Complaint { + session: sid, + against: s, + }).unwrap(); + assert_eq!(l.master().qualified_nodes().len(), 4); + } + + #[test] + fn node_is_disqualified_if_responds_to_complain_with_invalid_data() { + let (sid, _, _, mut l) = make_simple_cluster(1, 3).unwrap(); + l.take_and_process_message().unwrap(); // m -> s1: InitializeSession + l.take_and_process_message().unwrap(); // m -> s2: InitializeSession + l.take_and_process_message().unwrap(); // s1 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // s2 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // m -> s1: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s2: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s1: KeysDissemination + l.take_and_process_message().unwrap(); // m -> s2: KeysDissemination + l.take_and_process_message().unwrap(); // s1 -> m: KeysDissemination + l.take_and_process_message().unwrap(); // s1 -> s2: KeysDissemination + let s2 = l.second_slave().node().clone(); + l.master().on_keys_dissemination(s2.clone(), message::KeysDissemination { + session: sid.clone(), + secret1: math::generate_random_scalar().unwrap(), + secret2: math::generate_random_scalar().unwrap(), + publics: vec![math::generate_random_point().unwrap(), math::generate_random_point().unwrap()], + }).unwrap(); + assert_eq!(l.master().qualified_nodes().len(), 3); + l.master().on_complaint_response(s2, message::ComplaintResponse { + session: sid, + secret1: math::generate_random_scalar().unwrap(), + secret2: math::generate_random_scalar().unwrap(), + }).unwrap(); + assert_eq!(l.master().qualified_nodes().len(), 2); + } + + #[test] + fn node_is_not_disqualified_if_responds_to_complain_with_valid_data() { + let (sid, _, _, mut l) = make_simple_cluster(1, 3).unwrap(); + l.take_and_process_message().unwrap(); // m -> s1: InitializeSession + l.take_and_process_message().unwrap(); // m -> s2: InitializeSession + l.take_and_process_message().unwrap(); // s1 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // s2 -> m: ConfirmInitialization + l.take_and_process_message().unwrap(); // m -> s1: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s2: CompleteInitialization + l.take_and_process_message().unwrap(); // m -> s1: KeysDissemination + l.take_and_process_message().unwrap(); // m -> s2: KeysDissemination + l.take_and_process_message().unwrap(); // s1 -> m: KeysDissemination + l.take_and_process_message().unwrap(); // s1 -> s2: KeysDissemination + let (f, t, msg) = match l.take_message() { + Some((f, t, Message::KeysDissemination(msg))) => (f, t, msg), + _ => panic!("unexpected"), + }; + assert_eq!(&f, l.second_slave().node()); + assert_eq!(&t, l.master().node()); + l.master().on_keys_dissemination(f.clone(), message::KeysDissemination { + session: sid.clone(), + secret1: math::generate_random_scalar().unwrap(), + secret2: math::generate_random_scalar().unwrap(), + publics: msg.publics.clone(), + }).unwrap(); + assert_eq!(l.master().qualified_nodes().len(), 3); + l.master().on_complaint_response(f, message::ComplaintResponse { + session: sid, + secret1: msg.secret1, + secret2: msg.secret2, + }).unwrap(); + assert_eq!(l.master().qualified_nodes().len(), 3); + } + + #[test] + fn should_not_start_key_generation_when_not_in_key_check_state() { + let (_, _, _, l) = make_simple_cluster(1, 3).unwrap(); + assert_eq!(l.master().start_key_generation_phase().unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn should_not_accept_public_key_share_when_is_not_waiting_for_it() { + let (sid, _, s, l) = make_simple_cluster(1, 3).unwrap(); + assert_eq!(l.master().on_public_key_share(s, message::PublicKeyShare { + session: sid, + public_share: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidStateForRequest); + } + + #[test] + fn should_not_accept_public_key_share_when_receiving_twice() { + let (sid, m, _, mut l) = make_simple_cluster(0, 3).unwrap(); + l.take_and_process_all_messages().unwrap(); + l.master().start_key_generation_phase().unwrap(); + l.first_slave().start_key_generation_phase().unwrap(); + let (f, t, msg) = match l.take_message() { + Some((f, t, Message::PublicKeyShare(msg))) => (f, t, msg), + _ => panic!("unexpected"), + }; + assert_eq!(&f, l.master().node()); + assert_eq!(&t, l.first_slave().node()); + l.process_message((f, t, Message::PublicKeyShare(msg.clone()))).unwrap(); + assert_eq!(l.first_slave().on_public_key_share(m, message::PublicKeyShare { + session: sid, + public_share: math::generate_random_point().unwrap(), + }).unwrap_err(), Error::InvalidMessage); + } + + #[test] + fn complete_enc_dec_session() { + // TODO: when number of nodes, needed to decrypt message is odd, algorithm won't work + // let test_cases = [/*(0, 2), */(1, 2), (1, 3), (2, 3), (1, 4), (2, 4), (3, 4), (1, 5), (2, 5), (3, 5), (4, 5), + // (1, 10), (2, 10), (3, 10), (4, 10), (5, 10), (6, 10), (7, 10), (8, 10), (9, 10)]; + let test_cases = [(3, 5)]; + for &(threshold, num_nodes) in &test_cases { + let mut l = MessageLoop::new(num_nodes); + l.master().initialize(threshold, l.nodes.keys().cloned().collect()).unwrap(); + assert_eq!(l.nodes.len(), num_nodes); + + // let nodes do initialization + keys dissemination + while let Some((from, to, message)) = l.take_message() { + l.process_message((from, to, message)).unwrap(); + } + + // check that all nodes are waiting for complaint timeout is passed + for node in l.nodes.values() { + let state = node.session.state(); + assert_eq!(state, SessionState::KeyCheck); + + // simulate timeout pass + node.session.start_key_generation_phase().unwrap(); + } + + // let nodes do joint public generation + while let Some((from, to, message)) = l.take_message() { + l.process_message((from, to, message)).unwrap(); + } + + // check that all nodes has finished joint public generation + let joint_public_key = l.master().joint_public_key().unwrap(); + for node in l.nodes.values() { + let state = node.session.state(); + assert_eq!(state, SessionState::Finished); + assert_eq!(node.session.joint_public_key().as_ref(), Some(&joint_public_key)); + } + + // now let's encrypt some secret (which is a point on EC) + let document_secret_plain = Random.generate().unwrap().public().clone(); + let all_nodes_id_numbers: Vec<_> = l.master().data.lock().nodes.values().map(|n| n.id_number.clone()).collect(); + let all_nodes_secret_shares: Vec<_> = l.nodes.values().map(|n| n.session.data.lock().secret_share.as_ref().unwrap().clone()).collect(); + let document_secret_decrypted = do_encryption_and_decryption(threshold, &joint_public_key, + &all_nodes_id_numbers, + &all_nodes_secret_shares, + None, + document_secret_plain.clone() + ).0; + assert_eq!(document_secret_plain, document_secret_decrypted); + } + } + + // TODO: add test where some nodes are disqualified from session +} diff --git a/secret_store/src/key_server_cluster/math.rs b/secret_store/src/key_server_cluster/math.rs new file mode 100644 index 000000000..4da17ebc7 --- /dev/null +++ b/secret_store/src/key_server_cluster/math.rs @@ -0,0 +1,338 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use ethkey::{Public, Secret, Random, Generator, math}; +use key_server_cluster::Error; + +#[derive(Debug)] +/// Encryption result. +pub struct EncryptedSecret { + /// Common encryption point. + pub common_point: Public, + /// Ecnrypted point. + pub encrypted_point: Public, +} + +/// Generate random scalar +pub fn generate_random_scalar() -> Result { + Ok(Random.generate()?.secret().clone()) +} + +/// Generate random point +pub fn generate_random_point() -> Result { + Ok(Random.generate()?.public().clone()) +} + +/// Update point by multiplying to random scalar +pub fn update_random_point(point: &mut Public) -> Result<(), Error> { + Ok(math::public_mul_secret(point, &generate_random_scalar()?)?) +} + +/// Generate random polynom of threshold degree +pub fn generate_random_polynom(threshold: usize) -> Result, Error> { + let mut polynom: Vec<_> = Vec::with_capacity(threshold + 1); + for _ in 0..threshold + 1 { + polynom.push(generate_random_scalar()?); + } + debug_assert_eq!(polynom.len(), threshold + 1); + Ok(polynom) +} + +/// Compute value of polynom, using `node_number` as argument +pub fn compute_polynom(polynom: &[Secret], node_number: &Secret) -> Result { + debug_assert!(!polynom.is_empty()); + + let mut result = polynom[0].clone(); + for i in 1..polynom.len() { + // calculate pow(node_number, i) + let mut appendum = node_number.clone(); + appendum.pow(i)?; + + // calculate coeff * pow(point, i) + appendum.mul(&polynom[i])?; + + // calculate result + coeff * pow(point, i) + result.add(&appendum)?; + } + + Ok(result) +} + +/// Generate public keys for other participants. +pub fn public_values_generation(threshold: usize, derived_point: &Public, polynom1: &[Secret], polynom2: &[Secret]) -> Result, Error> { + debug_assert_eq!(polynom1.len(), threshold + 1); + debug_assert_eq!(polynom2.len(), threshold + 1); + + // compute t+1 public values + let mut publics = Vec::with_capacity(threshold + 1); + for i in 0..threshold + 1 { + let coeff1 = &polynom1[i]; + + let mut multiplication1 = math::generation_point(); + math::public_mul_secret(&mut multiplication1, &coeff1)?; + + let coeff2 = &polynom2[i]; + let mut multiplication2 = derived_point.clone(); + math::public_mul_secret(&mut multiplication2, &coeff2)?; + + math::public_add(&mut multiplication1, &multiplication2)?; + + publics.push(multiplication1); + } + debug_assert_eq!(publics.len(), threshold + 1); + + Ok(publics) +} + +/// Check keys passed by other participants. +pub fn keys_verification(threshold: usize, derived_point: &Public, number_id: &Secret, secret1: &Secret, secret2: &Secret, publics: &[Public]) -> Result { + // calculate left part + let mut multiplication1 = math::generation_point(); + math::public_mul_secret(&mut multiplication1, secret1)?; + + let mut multiplication2 = derived_point.clone(); + math::public_mul_secret(&mut multiplication2, secret2)?; + + math::public_add(&mut multiplication1, &multiplication2)?; + let left = multiplication1; + + // calculate right part + let mut right = publics[0].clone(); + for i in 1..threshold + 1 { + let mut secret_pow = number_id.clone(); + secret_pow.pow(i)?; + + let mut public_k = publics[i].clone(); + math::public_mul_secret(&mut public_k, &secret_pow)?; + + math::public_add(&mut right, &public_k)?; + } + + Ok(left == right) +} + +/// Compute secret share. +pub fn compute_secret_share<'a, I>(mut secret_values: I) -> Result where I: Iterator { + let mut secret_share = secret_values.next().expect("compute_secret_share is called when cluster has at least one node; qed").clone(); + while let Some(secret_value) = secret_values.next() { + secret_share.add(secret_value)?; + } + Ok(secret_share) +} + +/// Compute public key share. +pub fn compute_public_share(self_secret_value: &Secret) -> Result { + let mut public_share = math::generation_point(); + math::public_mul_secret(&mut public_share, self_secret_value)?; + Ok(public_share) +} + +/// Compute joint public key. +pub fn compute_joint_public<'a, I>(mut public_shares: I) -> Result where I: Iterator { + let mut joint_public = public_shares.next().expect("compute_joint_public is called when cluster has at least one node; qed").clone(); + while let Some(public_share) = public_shares.next() { + math::public_add(&mut joint_public, &public_share)?; + } + Ok(joint_public) +} + +#[cfg(test)] +/// Compute joint secret key. +pub fn compute_joint_secret<'a, I>(mut secret_coeffs: I) -> Result where I: Iterator { + let mut joint_secret = secret_coeffs.next().expect("compute_joint_private is called when cluster has at least one node; qed").clone(); + while let Some(secret_coeff) = secret_coeffs.next() { + joint_secret.add(secret_coeff)?; + } + Ok(joint_secret) +} + +/// Encrypt secret with joint public key. +pub fn encrypt_secret(secret: Public, joint_public: &Public) -> Result { + // this is performed by KS-cluster client (or KS master) + let key_pair = Random.generate()?; + + // k * T + let mut common_point = math::generation_point(); + math::public_mul_secret(&mut common_point, key_pair.secret())?; + + // M + k * y + let mut encrypted_point = joint_public.clone(); + math::public_mul_secret(&mut encrypted_point, key_pair.secret())?; + math::public_add(&mut encrypted_point, &secret)?; + + Ok(EncryptedSecret { + common_point: common_point, + encrypted_point: encrypted_point, + }) +} + +/// Compute shadow for the node. +pub fn compute_node_shadow<'a, I>(node_number: &Secret, node_secret_share: &Secret, mut other_nodes_numbers: I) -> Result where I: Iterator { + let other_node_number = other_nodes_numbers.next().expect("compute_node_shadow is called when at least two nodes are required to decrypt secret; qed"); + let mut shadow = node_number.clone(); + shadow.sub(other_node_number)?; + shadow.inv()?; + shadow.mul(other_node_number)?; + while let Some(other_node_number) = other_nodes_numbers.next() { + let mut shadow_element = node_number.clone(); + shadow_element.sub(other_node_number)?; + shadow_element.inv()?; + shadow_element.mul(other_node_number)?; + shadow.mul(&shadow_element)?; + } + + shadow.mul(&node_secret_share)?; + Ok(shadow) +} + +/// Compute shadow point for the node. +pub fn compute_node_shadow_point(access_key: &Secret, common_point: &Public, node_shadow: &Secret) -> Result { + let mut shadow_key = access_key.clone(); + shadow_key.mul(node_shadow)?; + let mut node_shadow_point = common_point.clone(); + math::public_mul_secret(&mut node_shadow_point, &shadow_key)?; + Ok(node_shadow_point) +} + +/// Compute joint shadow point. +pub fn compute_joint_shadow_point<'a, I>(mut nodes_shadow_points: I) -> Result where I: Iterator { + let mut joint_shadow_point = nodes_shadow_points.next().expect("compute_joint_shadow_point is called when at least two nodes are required to decrypt secret; qed").clone(); + while let Some(node_shadow_point) = nodes_shadow_points.next() { + math::public_add(&mut joint_shadow_point, &node_shadow_point)?; + } + Ok(joint_shadow_point) +} + +#[cfg(test)] +/// Compute joint shadow point (version for tests). +pub fn compute_joint_shadow_point_test<'a, I>(access_key: &Secret, common_point: &Public, mut nodes_shadows: I) -> Result where I: Iterator { + let mut joint_shadow = nodes_shadows.next().expect("compute_joint_shadow_point_test is called when at least two nodes are required to decrypt secret; qed").clone(); + while let Some(node_shadow) = nodes_shadows.next() { + joint_shadow.add(node_shadow)?; + } + joint_shadow.mul(access_key)?; + + let mut joint_shadow_point = common_point.clone(); + math::public_mul_secret(&mut joint_shadow_point, &joint_shadow)?; + Ok(joint_shadow_point) +} + +/// Decrypt data using joint shadow point. +pub fn decrypt_with_joint_shadow(access_key: &Secret, encrypted_point: &Public, joint_shadow_point: &Public) -> Result { + let mut inv_access_key = access_key.clone(); + inv_access_key.inv()?; + + let mut decrypted_point = joint_shadow_point.clone(); + math::public_mul_secret(&mut decrypted_point, &inv_access_key)?; + math::public_add(&mut decrypted_point, encrypted_point)?; + + Ok(decrypted_point) +} + +/// Decrypt data using joint secret (version for tests). +pub fn decrypt_with_joint_secret(encrypted_point: &Public, common_point: &Public, joint_secret: &Secret) -> Result { + let mut common_point_mul = common_point.clone(); + math::public_mul_secret(&mut common_point_mul, joint_secret)?; + + let mut decrypted_point = encrypted_point.clone(); + math::public_sub(&mut decrypted_point, &common_point_mul)?; + + Ok(decrypted_point) +} + +#[cfg(test)] +pub mod tests { + use ethkey::KeyPair; + use super::*; + + pub fn do_encryption_and_decryption(t: usize, joint_public: &Public, id_numbers: &[Secret], secret_shares: &[Secret], joint_secret: Option<&Secret>, document_secret_plain: Public) -> (Public, Public) { + // === PART2: encryption using joint public key === + + // the next line is executed on KeyServer-client + let encrypted_secret = encrypt_secret(document_secret_plain.clone(), &joint_public).unwrap(); + + // === PART3: decryption === + + // next line is executed on KeyServer client + let access_key = generate_random_scalar().unwrap(); + + // use t + 1 nodes to compute joint shadow point + let nodes_shadows: Vec<_> = (0..t + 1).map(|i| + compute_node_shadow(&id_numbers[i], &secret_shares[i], id_numbers.iter() + .enumerate() + .filter(|&(j, _)| j != i) + .take(t) + .map(|(_, id_number)| id_number)).unwrap()).collect(); + let nodes_shadow_points: Vec<_> = nodes_shadows.iter().map(|s| compute_node_shadow_point(&access_key, &encrypted_secret.common_point, s).unwrap()).collect(); + assert_eq!(nodes_shadows.len(), t + 1); + assert_eq!(nodes_shadow_points.len(), t + 1); + + let joint_shadow_point = compute_joint_shadow_point(nodes_shadow_points.iter()).unwrap(); + let joint_shadow_point_test = compute_joint_shadow_point_test(&access_key, &encrypted_secret.common_point, nodes_shadows.iter()).unwrap(); + assert_eq!(joint_shadow_point, joint_shadow_point_test); + + // decrypt encrypted secret using joint shadow point + let document_secret_decrypted = decrypt_with_joint_shadow(&access_key, &encrypted_secret.encrypted_point, &joint_shadow_point).unwrap(); + + // decrypt encrypted secret using joint secret [just for test] + let document_secret_decrypted_test = match joint_secret { + Some(joint_secret) => decrypt_with_joint_secret(&encrypted_secret.encrypted_point, &encrypted_secret.common_point, joint_secret).unwrap(), + None => document_secret_decrypted.clone(), + }; + + (document_secret_decrypted, document_secret_decrypted_test) + } + + #[test] + fn full_encryption_math_session() { + let test_cases = [(1, 3)]; + for &(t, n) in &test_cases { + // === PART1: DKG === + + // data, gathered during initialization + let id_numbers: Vec<_> = (0..n).map(|_| generate_random_scalar().unwrap()).collect(); + + // data, generated during keys dissemination + let polynoms1: Vec<_> = (0..n).map(|_| generate_random_polynom(t).unwrap()).collect(); + let secrets1: Vec<_> = (0..n).map(|i| (0..n).map(|j| compute_polynom(&polynoms1[i], &id_numbers[j]).unwrap()).collect::>()).collect(); + + // data, generated during keys generation + let public_shares: Vec<_> = (0..n).map(|i| compute_public_share(&polynoms1[i][0]).unwrap()).collect(); + let secret_shares: Vec<_> = (0..n).map(|i| compute_secret_share(secrets1.iter().map(|s| &s[i])).unwrap()).collect(); + + // joint public key, as a result of DKG + let joint_public = compute_joint_public(public_shares.iter()).unwrap(); + + // compute joint private key [just for test] + let joint_secret = compute_joint_secret(polynoms1.iter().map(|p| &p[0])).unwrap(); + let joint_key_pair = KeyPair::from_secret(joint_secret.clone()).unwrap(); + assert_eq!(&joint_public, joint_key_pair.public()); + + // check secret shares computation [just for test] + let secret_shares_polynom: Vec<_> = (0..t + 1).map(|k| compute_secret_share(polynoms1.iter().map(|p| &p[k])).unwrap()).collect(); + let secret_shares_calculated_from_polynom: Vec<_> = id_numbers.iter().map(|id_number| compute_polynom(&*secret_shares_polynom, id_number).unwrap()).collect(); + assert_eq!(secret_shares, secret_shares_calculated_from_polynom); + + // now encrypt and decrypt data + let document_secret_plain = generate_random_point().unwrap(); + let (document_secret_decrypted, document_secret_decrypted_test) = + do_encryption_and_decryption(t, &joint_public, &id_numbers, &secret_shares, Some(&joint_secret), document_secret_plain.clone()); + + assert_eq!(document_secret_plain, document_secret_decrypted_test); + assert_eq!(document_secret_plain, document_secret_decrypted); + } + } +} diff --git a/secret_store/src/key_server_cluster/message.rs b/secret_store/src/key_server_cluster/message.rs new file mode 100644 index 000000000..800dcf705 --- /dev/null +++ b/secret_store/src/key_server_cluster/message.rs @@ -0,0 +1,168 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::{BTreeSet, BTreeMap}; +use ethkey::{Public, Secret, Signature}; +use key_server_cluster::{NodeId, SessionId}; + +#[derive(Clone, Debug)] +/// All possible messages that can be sent during DKG. +pub enum Message { + /// Initialize new DKG session. + InitializeSession(InitializeSession), + /// Confirm DKG session initialization. + ConfirmInitialization(ConfirmInitialization), + /// Broadcast data, calculated during session initialization phase. + CompleteInitialization(CompleteInitialization), + /// Generated keys are sent to every node. + KeysDissemination(KeysDissemination), + /// Complaint against another node is broadcasted. + Complaint(Complaint), + /// Complaint response is broadcasted. + ComplaintResponse(ComplaintResponse), + /// Broadcast self public key portion. + PublicKeyShare(PublicKeyShare), + + /// Initialize decryption session. + InitializeDecryptionSession(InitializeDecryptionSession), + /// Confirm/reject decryption session initialization. + ConfirmDecryptionInitialization(ConfirmDecryptionInitialization), + /// Request partial decryption from node. + RequestPartialDecryption(RequestPartialDecryption), + /// Partial decryption is completed + PartialDecryption(PartialDecryption), +} + +#[derive(Clone, Debug)] +/// Initialize new DKG session. +pub struct InitializeSession { + /// Session Id. + pub session: SessionId, + /// Derived generation point. Starting from originator, every node must multiply this + /// point by random scalar (unknown by other nodes). At the end of initialization + /// `point` will be some (k1 * k2 * ... * kn) * G = `point` where `(k1 * k2 * ... * kn)` + /// is unknown for every node. + pub derived_point: Public, +} + +#[derive(Clone, Debug)] +/// Confirm DKG session initialization. +pub struct ConfirmInitialization { + /// Session Id. + pub session: SessionId, + /// Derived generation point. + pub derived_point: Public, +} + +#[derive(Clone, Debug)] +/// Broadcast generated point to every other node. +pub struct CompleteInitialization { + /// Session Id. + pub session: SessionId, + /// All session participants along with their identification numbers. + pub nodes: BTreeMap, + /// Decryption threshold. During decryption threshold-of-route.len() nodes must came to + /// consensus to successfully decrypt message. + pub threshold: usize, + /// Derived generation point. + pub derived_point: Public, +} + +#[derive(Clone, Debug)] +/// Generated keys are sent to every node. +pub struct KeysDissemination { + /// Session Id. + pub session: SessionId, + /// Secret 1. + pub secret1: Secret, + /// Secret 2. + pub secret2: Secret, + /// Public values. + pub publics: Vec, +} + +#[derive(Clone, Debug)] +/// Complaint against node is broadcasted. +pub struct Complaint { + /// Session Id. + pub session: SessionId, + /// Public values. + pub against: NodeId, +} + +#[derive(Clone, Debug)] +/// Node is responding to complaint. +pub struct ComplaintResponse { + /// Session Id. + pub session: SessionId, + /// Secret 1. + pub secret1: Secret, + /// Secret 2. + pub secret2: Secret, +} + +#[derive(Clone, Debug)] +/// Node is sharing its public key share. +pub struct PublicKeyShare { + /// Session Id. + pub session: SessionId, + /// Public key share. + pub public_share: Public, +} + +#[derive(Clone, Debug)] +/// Node is requested to decrypt data, encrypted in given session. +pub struct InitializeDecryptionSession { + /// Encryption session Id. + pub session: SessionId, + /// Decryption session Id. + pub sub_session: Secret, + /// Requestor signature. + pub requestor_signature: Signature, +} + +#[derive(Clone, Debug)] +/// Node is responding to decryption request. +pub struct ConfirmDecryptionInitialization { + /// Encryption session Id. + pub session: SessionId, + /// Decryption session Id. + pub sub_session: Secret, + /// Is node confirmed to make a decryption?. + pub is_confirmed: bool, +} + +#[derive(Clone, Debug)] +/// Node is requested to do a partial decryption. +pub struct RequestPartialDecryption { + /// Encryption session Id. + pub session: SessionId, + /// Decryption session Id. + pub sub_session: Secret, + /// Nodes that are agreed to do a decryption. + pub nodes: BTreeSet, +} + +#[derive(Clone, Debug)] +/// Node has partially decrypted the secret. +pub struct PartialDecryption { + /// Encryption session Id. + pub session: SessionId, + /// Decryption session Id. + pub sub_session: Secret, + /// Partially decrypted secret. + pub shadow_point: Public, +} diff --git a/secret_store/src/key_server_cluster/mod.rs b/secret_store/src/key_server_cluster/mod.rs new file mode 100644 index 000000000..5d0dacd11 --- /dev/null +++ b/secret_store/src/key_server_cluster/mod.rs @@ -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 . + +#![allow(dead_code)] // TODO: remove me + +use std::collections::BTreeMap; +use ethkey::{self, Public, Secret, Signature}; +use super::types::all::DocumentAddress; + +pub use super::acl_storage::AclStorage; + +pub type NodeId = Public; +pub type SessionId = DocumentAddress; +pub type SessionIdSignature = Signature; + +#[derive(Debug, PartialEq)] +/// Errors which can occur during encryption/decryption session +pub enum Error { + /// Invalid number of nodes. + /// There must be at least two nodes participating in encryption. + /// There must be at least one node participating in decryption. + InvalidNodesCount, + /// Node which is required to start encryption/decryption session is not a part of cluster. + InvalidNodesConfiguration, + /// Invalid threshold value has been passed. + /// Threshold value must be in [0; n - 1], where n is a number of nodes participating in the encryption. + InvalidThreshold, + /// Current state of encryption/decryption session does not allow to proceed request. + /// This means that either there is some comm-failure or node is misbehaving/cheating. + InvalidStateForRequest, + /// Some data in passed message was recognized as invalid. + /// This means that node is misbehaving/cheating. + InvalidMessage, + /// Cryptographic error. + EthKey(String), +} + +#[derive(Debug, Clone)] +/// Data, which is stored on every node after DKG && encryption is completed. +pub struct EncryptedData { + /// Decryption threshold (at least threshold + 1 nodes are required to decrypt data). + threshold: usize, + /// Nodes ids numbers. + id_numbers: BTreeMap, + /// Node secret share. + secret_share: Secret, + /// Common (shared) encryption point. + common_point: Public, + /// Encrypted point. + encrypted_point: Public, +} + +impl From for Error { + fn from(err: ethkey::Error) -> Self { + Error::EthKey(err.into()) + } +} + +mod cluster; +mod decryption_session; +mod encryption_session; +mod math; +mod message; diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 390ae1e5e..41d658963 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -26,6 +26,7 @@ extern crate ethcore_ipc as ipc; extern crate ethcrypto; extern crate ethkey; +mod key_server_cluster; mod types; mod traits { From 8a37f9599ffd573bdc1f275dad6be9a824a60f42 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 13 Mar 2017 13:19:43 +0100 Subject: [PATCH 35/36] Reload UI on network switch (#4864) * Reload UI on network switch * Don't bither with timeout. --- js/src/redux/providers/chainMiddleware.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/src/redux/providers/chainMiddleware.js b/js/src/redux/providers/chainMiddleware.js index 3920eb7c3..2df40ed86 100644 --- a/js/src/redux/providers/chainMiddleware.js +++ b/js/src/redux/providers/chainMiddleware.js @@ -29,7 +29,10 @@ export default class ChainMiddleware { const { nodeStatus } = store.getState(); if (newChain !== nodeStatus.netChain && nodeStatus.netChain !== DEFAULT_NETCHAIN) { - store.dispatch(showSnackbar(`Switched to ${newChain}. Please reload the page.`, 60000)); + store.dispatch(showSnackbar(`Switched to ${newChain}. The UI will reload now...`)); + setTimeout(() => { + window.location.reload(); + }, 0); // Fetch the new balances without notifying the user of any change BalancesProvider.get(store).fetchAllBalances({ From 29bed6ff691370cb5e6d0d76b7b44d64642909fd Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Mon, 13 Mar 2017 12:32:24 +0000 Subject: [PATCH 36/36] [ci skip] js-precompiled 20170313-122643 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5e41f647..93d3d0ac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1706,7 +1706,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#d5eaa484594b30d0be267ba670400a840f749b08" +source = "git+https://github.com/ethcore/js-precompiled.git#24514f56ade650f54b97c2cff4e27d798b274e41" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index ebc979344..b4ea09a50 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.11", + "version": "1.7.12", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ",