diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b0e4ad009..d193039b5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,9 +33,9 @@ linux-stable: - md5sum target/release/parity > parity.md5 - sh scripts/deb-build.sh amd64 - cp target/release/parity deb/usr/bin/parity - - cp target/release/parity/evm deb/usr/bin/evm - - cp target/release/parity/ethstore deb/usr/bin/ethstore - - cp target/release/parity/ethkey deb/usr/bin/ethkey + - cp target/release/evm deb/usr/bin/evm + - cp target/release/ethstore deb/usr/bin/ethstore + - cp target/release/ethkey deb/usr/bin/ethkey - export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n") - dpkg-deb -b deb "parity_"$VER"_amd64.deb" - md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5" @@ -69,11 +69,20 @@ linux-stable-debian: - triggers script: - cargo build -j $(nproc) --release --features final $CARGOFLAGS + - cargo build -j $(nproc) --release -p evmbin + - cargo build -j $(nproc) --release -p ethstore + - cargo build -j $(nproc) --release -p ethkey - strip target/release/parity + - strip target/release/evm + - strip target/release/ethstore + - strip target/release/ethkey - export SHA3=$(target/release/parity tools hash target/release/parity) - md5sum target/release/parity > parity.md5 - sh scripts/deb-build.sh amd64 - cp target/release/parity deb/usr/bin/parity + - cp target/release/evm deb/usr/bin/evm + - cp target/release/ethstore deb/usr/bin/ethstore + - cp target/release/ethkey deb/usr/bin/ethkey - export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n") - dpkg-deb -b deb "parity_"$VER"_amd64.deb" - md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5" @@ -486,14 +495,14 @@ docker-build: stage: build only: - tags + - triggers before_script: - docker info script: - cd docker/hub - if [ "$CI_BUILD_REF_NAME" == "nightly" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi - docker login -u $Docker_Hub_User -p $Docker_Hub_Pass - - docker build --no-cache=true --tag ethcore/parity:$DOCKER_TAG . - - docker push ethcore/parity:$DOCKER_TAG + - sh scripts/docker-build.sh $DOCKER_TAG tags: - docker test-darwin: diff --git a/Cargo.lock b/Cargo.lock index 349284e6c..46b1ed27c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -411,6 +411,7 @@ dependencies = [ "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stats 0.1.0", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -444,7 +445,7 @@ dependencies = [ "ethcore-rpc 1.6.0", "ethcore-util 1.6.0", "fetch 0.1.0", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", "jsonrpc-core 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "jsonrpc-http-server 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", @@ -553,12 +554,13 @@ dependencies = [ "ethcore-ipc-codegen 1.6.0", "ethcore-network 1.6.0", "ethcore-util 1.6.0", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.1.0", "smallvec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stats 0.1.0", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -618,7 +620,7 @@ dependencies = [ "ethstore 0.1.0", "ethsync 1.6.0", "fetch 0.1.0", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "jsonrpc-http-server 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "jsonrpc-ipc-server 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", @@ -633,6 +635,7 @@ dependencies = [ "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", + "stats 0.1.0", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -648,7 +651,7 @@ dependencies = [ "ethcore-util 1.6.0", "ethcrypto 0.1.0", "ethkey 0.2.0", - "hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -683,7 +686,7 @@ dependencies = [ "ethcore-ipc-codegen 1.6.0", "ethcore-ipc-nano 1.6.0", "ethcore-util 1.6.0", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "jsonrpc-macros 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "jsonrpc-tcp-server 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", @@ -846,7 +849,7 @@ dependencies = [ name = "fetch" version = "0.1.0" dependencies = [ - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -865,7 +868,7 @@ dependencies = [ [[package]] name = "futures" -version = "0.1.6" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -877,7 +880,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -952,7 +955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.9.14" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -973,7 +976,7 @@ dependencies = [ [[package]] name = "hyper" version = "0.10.0-a.0" -source = "git+https://github.com/ethcore/hyper#6baea9d444dd1652220ee9b4aeadaebb3de6a955" +source = "git+https://github.com/ethcore/hyper#2e6702984f4f9e99fe251537a755aff0badc0b3a" dependencies = [ "cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1033,7 +1036,7 @@ name = "igd" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1083,7 +1086,7 @@ name = "jsonrpc-core" version = "6.0.0" source = "git+https://github.com/ethcore/jsonrpc.git#86d7a89c85f324b5f6671315d9b71010ca995300" dependencies = [ - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1620,7 +1623,7 @@ dependencies = [ "ethabi 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-util 1.6.0", "fetch 0.1.0", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1637,6 +1640,7 @@ dependencies = [ "ethcore 1.6.0", "ethcore-util 1.6.0", "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", + "jsonrpc-http-server 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "multihash 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.1.0", @@ -1661,7 +1665,7 @@ dependencies = [ name = "parity-reactor" version = "0.1.0" dependencies = [ - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1672,7 +1676,7 @@ dependencies = [ "ethcore-rpc 1.6.0", "ethcore-signer 1.6.0", "ethcore-util 1.6.0", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1702,7 +1706,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#9fb4ab9d8ffaca9cd9f07270bf69681c2081050f" +source = "git+https://github.com/ethcore/js-precompiled.git#aaee793907e4ff61082d83ff44733363dfff6eae" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1990,7 +1994,7 @@ dependencies = [ "ethcore-bigint 0.1.2", "ethcore-rpc 1.6.0", "ethcore-util 1.6.0", - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc-client 1.4.0", "rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2223,6 +2227,13 @@ name = "stable-heap" version = "0.1.0" source = "git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47#3c5cd1ca4706f167a1de85658b5af0d6d3e65165" +[[package]] +name = "stats" +version = "0.1.0" +dependencies = [ + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.3.0" @@ -2334,7 +2345,7 @@ name = "tokio-core" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2346,7 +2357,7 @@ name = "tokio-proto" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2362,7 +2373,7 @@ name = "tokio-service" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2595,7 +2606,7 @@ dependencies = [ "checksum ethabi 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d8f6cc4c1acd005f48e1d17b06a461adac8fb6eeeb331fbf19a0e656fba91cd" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb" -"checksum futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bad0a2ac64b227fdc10c254051ae5af542cf19c9328704fd4092f7914196897" +"checksum futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c1913eb7083840b1bbcbf9631b7fda55eaf35fe7ead13cca034e8946f9e2bc41" "checksum futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bb982bb25cd8fa5da6a8eb3a460354c984ff1113da82bcb4f0b0862b5795db82" "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" @@ -2607,7 +2618,7 @@ dependencies = [ "checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae" "checksum hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)" = "" "checksum hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "220407e5a263f110ec30a071787c9535918fdfc97def5680c90013c3f30c38c1" -"checksum hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb3fc65554155980167fb821d05c7c66177f92464976c0b676a19d9e03387a7" +"checksum hyper 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9bf64f730d6ee4b0528a5f0a316363da9d8104318731509d4ccc86248f82b3" "checksum hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afe68f772f0497a7205e751626bb8e1718568b58534b6108c73a74ef80483409" "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" "checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484" diff --git a/README.md b/README.md index dfd0f533c..260566c5e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Be sure to check out [our wiki][wiki-url] for more information. Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. -Parity comes with a built-in wallet. To access [Parity Wallet](http://127.0.0.1:8080/) this simply go to http://127.0.0.1:8080/. It +Parity comes with a built-in wallet. To access [Parity Wallet](http://127.0.0.1:8080/) simply go to http://127.0.0.1:8080/. It includes various functionality allowing you to: - create and manage your Ethereum accounts; - manage your Ether and any Ethereum tokens; diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 442f8b785..c8a1c7fb5 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -43,6 +43,7 @@ rlp = { path = "../util/rlp" } ethcore-stratum = { path = "../stratum" } ethcore-bloom-journal = { path = "../util/bloom" } hardware-wallet = { path = "../hw" } +stats = { path = "../util/stats" } [dependencies.hyper] git = "https://github.com/ethcore/hyper" diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index d2444dd59..9e10449fb 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -23,6 +23,7 @@ smallvec = "0.3.1" futures = "0.1" rand = "0.3" itertools = "0.5" +stats = { path = "../../util/stats" } [features] default = [] diff --git a/ethcore/light/src/cache.rs b/ethcore/light/src/cache.rs new file mode 100644 index 000000000..185007a1b --- /dev/null +++ b/ethcore/light/src/cache.rs @@ -0,0 +1,175 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Cache for data fetched from the network. +//! +//! Stores ancient block headers, bodies, receipts, and total difficulties. +//! Furthermore, stores a "gas price corpus" of relative recency, which is a sorted +//! vector of all gas prices from a recent range of blocks. + +use ethcore::encoded; +use ethcore::header::BlockNumber; +use ethcore::receipt::Receipt; + +use stats::Corpus; +use time::{SteadyTime, Duration}; +use util::{U256, H256}; +use util::cache::MemoryLruCache; + +/// Configuration for how much data to cache. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CacheSizes { + /// Maximum size, in bytes, of cached headers. + pub headers: usize, + /// Maximum size, in bytes, of cached canonical hashes. + pub canon_hashes: usize, + /// Maximum size, in bytes, of cached block bodies. + pub bodies: usize, + /// Maximum size, in bytes, of cached block receipts. + pub receipts: usize, + /// Maximum size, in bytes, of cached chain score for the block. + pub chain_score: usize, +} + +impl Default for CacheSizes { + fn default() -> Self { + const MB: usize = 1024 * 1024; + CacheSizes { + headers: 10 * MB, + canon_hashes: 3 * MB, + bodies: 20 * MB, + receipts: 10 * MB, + chain_score: 7 * MB, + } + } +} + +/// The light client data cache. +/// +/// Note that almost all getter methods take `&mut self` due to the necessity to update +/// the underlying LRU-caches on read. +pub struct Cache { + headers: MemoryLruCache, + canon_hashes: MemoryLruCache, + bodies: MemoryLruCache, + receipts: MemoryLruCache>, + chain_score: MemoryLruCache, + corpus: Option<(Corpus, SteadyTime)>, + corpus_expiration: Duration, +} + +impl Cache { + /// Create a new data cache with the given sizes and gas price corpus expiration time. + pub fn new(sizes: CacheSizes, corpus_expiration: Duration) -> Self { + Cache { + headers: MemoryLruCache::new(sizes.headers), + canon_hashes: MemoryLruCache::new(sizes.canon_hashes), + bodies: MemoryLruCache::new(sizes.bodies), + receipts: MemoryLruCache::new(sizes.receipts), + chain_score: MemoryLruCache::new(sizes.chain_score), + corpus: None, + corpus_expiration: corpus_expiration, + } + } + + /// Query header by hash. + pub fn block_header(&mut self, hash: &H256) -> Option { + self.headers.get_mut(hash).map(|x| x.clone()) + } + + /// Query hash by number. + pub fn block_hash(&mut self, num: &BlockNumber) -> Option { + self.canon_hashes.get_mut(num).map(|x| x.clone()) + } + + /// Query block body by block hash. + pub fn block_body(&mut self, hash: &H256) -> Option { + self.bodies.get_mut(hash).map(|x| x.clone()) + } + + /// Query block receipts by block hash. + pub fn block_receipts(&mut self, hash: &H256) -> Option> { + self.receipts.get_mut(hash).map(|x| x.clone()) + } + + /// Query chain score by block hash. + pub fn chain_score(&mut self, hash: &H256) -> Option { + self.chain_score.get_mut(hash).map(|x| x.clone()) + } + + /// Cache the given header. + pub fn insert_block_header(&mut self, hash: H256, hdr: encoded::Header) { + self.headers.insert(hash, hdr); + } + + /// Cache the given canonical block hash. + pub fn insert_block_hash(&mut self, num: BlockNumber, hash: H256) { + self.canon_hashes.insert(num, hash); + } + + /// Cache the given block body. + pub fn insert_block_body(&mut self, hash: H256, body: encoded::Body) { + self.bodies.insert(hash, body); + } + + /// Cache the given block receipts. + pub fn insert_block_receipts(&mut self, hash: H256, receipts: Vec) { + self.receipts.insert(hash, receipts); + } + + /// Cache the given chain scoring. + pub fn insert_chain_score(&mut self, hash: H256, score: U256) { + self.chain_score.insert(hash, score); + } + + /// Get gas price corpus, if recent enough. + pub fn gas_price_corpus(&self) -> Option> { + let now = SteadyTime::now(); + + self.corpus.as_ref().and_then(|&(ref corpus, ref tm)| { + if *tm + self.corpus_expiration >= now { + Some(corpus.clone()) + } else { + None + } + }) + } + + /// Set the cached gas price corpus. + pub fn set_gas_price_corpus(&mut self, corpus: Corpus) { + self.corpus = Some((corpus, SteadyTime::now())) + } +} + +#[cfg(test)] +mod tests { + use super::Cache; + use time::Duration; + + #[test] + fn corpus_inaccessible() { + let mut cache = Cache::new(Default::default(), Duration::hours(5)); + + cache.set_gas_price_corpus(vec![].into()); + assert_eq!(cache.gas_price_corpus(), Some(vec![].into())); + + { + let corpus_time = &mut cache.corpus.as_mut().unwrap().1; + *corpus_time = *corpus_time - Duration::hours(6); + } + assert!(cache.gas_price_corpus().is_none()); + } +} diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 403d3555d..575938cd5 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -241,6 +241,14 @@ impl HeaderChain { self.block_header(BlockId::Latest).expect("Header for best block always stored; qed") } + /// Get an iterator over a block and its ancestry. + pub fn ancestry_iter(&self, start: BlockId) -> AncestryIter { + AncestryIter { + next: self.block_header(start), + chain: self, + } + } + /// Get the nth CHT root, if it's been computed. /// /// CHT root 0 is from block `1..2048`. @@ -295,6 +303,25 @@ impl HeapSizeOf for HeaderChain { } } +/// Iterator over a block's ancestry. +pub struct AncestryIter<'a> { + next: Option, + chain: &'a HeaderChain, +} + +impl<'a> Iterator for AncestryIter<'a> { + type Item = encoded::Header; + + fn next(&mut self) -> Option { + let next = self.next.take(); + if let Some(p_hash) = next.as_ref().map(|hdr| hdr.parent_hash()) { + self.next = self.chain.block_header(BlockId::Hash(p_hash)); + } + + next + } +} + #[cfg(test)] mod tests { use super::HeaderChain; diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 9626f9f6c..4a4da2917 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -20,7 +20,7 @@ use std::sync::Arc; use ethcore::block_import_error::BlockImportError; use ethcore::block_status::BlockStatus; -use ethcore::client::ClientReport; +use ethcore::client::{ClientReport, EnvInfo}; use ethcore::engines::Engine; use ethcore::ids::BlockId; use ethcore::header::Header; @@ -33,7 +33,7 @@ use io::IoChannel; use util::{Bytes, DBValue, H256, Mutex, RwLock}; -use self::header_chain::HeaderChain; +use self::header_chain::{AncestryIter, HeaderChain}; pub use self::service::Service; @@ -62,6 +62,12 @@ pub trait LightChainClient: Send + Sync { /// Get the best block header. fn best_block_header(&self) -> encoded::Header; + /// Get an iterator over a block and its ancestry. + fn ancestry_iter<'a>(&'a self, start: BlockId) -> Box + 'a>; + + /// Get the signing network ID. + fn signing_network_id(&self) -> Option; + /// Query whether a block is known. fn is_known(&self, hash: &H256) -> bool; @@ -164,6 +170,16 @@ impl Client { self.chain.best_header() } + /// Get an iterator over a block and its ancestry. + pub fn ancestry_iter(&self, start: BlockId) -> AncestryIter { + self.chain.ancestry_iter(start) + } + + /// Get the signing network id. + pub fn signing_network_id(&self) -> Option { + self.engine.signing_network_id(&self.latest_env_info()) + } + /// Flush the header queue. pub fn flush_queue(&self) { self.queue.flush() @@ -217,6 +233,33 @@ impl Client { pub fn engine(&self) -> &Engine { &*self.engine } + + fn latest_env_info(&self) -> EnvInfo { + let header = self.best_block_header(); + + EnvInfo { + number: header.number(), + author: header.author(), + timestamp: header.timestamp(), + difficulty: header.difficulty(), + last_hashes: self.build_last_hashes(header.hash()), + gas_used: Default::default(), + gas_limit: header.gas_limit(), + } + } + + fn build_last_hashes(&self, mut parent_hash: H256) -> Arc> { + let mut v = Vec::with_capacity(256); + for _ in 0..255 { + v.push(parent_hash); + match self.block_header(BlockId::Hash(parent_hash)) { + Some(header) => parent_hash = header.hash(), + None => break, + } + } + + Arc::new(v) + } } impl LightChainClient for Client { @@ -234,6 +277,14 @@ impl LightChainClient for Client { Client::best_block_header(self) } + fn ancestry_iter<'a>(&'a self, start: BlockId) -> Box + 'a> { + Box::new(Client::ancestry_iter(self, start)) + } + + fn signing_network_id(&self) -> Option { + Client::signing_network_id(self) + } + fn is_known(&self, hash: &H256) -> bool { self.status(hash) == BlockStatus::InChain } diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index 94d267c7a..b6e06a02b 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -37,6 +37,7 @@ pub mod cht; pub mod net; pub mod on_demand; pub mod transaction_queue; +pub mod cache; #[cfg(not(feature = "ipc"))] pub mod provider; @@ -71,6 +72,7 @@ extern crate time; extern crate futures; extern crate rand; extern crate itertools; +extern crate stats; #[cfg(feature = "ipc")] extern crate ethcore_ipc as ipc; diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 58ab9662e..181f95e95 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -329,6 +329,16 @@ impl LightProtocol { .map(|peer| peer.lock().status.clone()) } + /// Get number of (connected, active) peers. + pub fn peer_count(&self) -> (usize, usize) { + let num_pending = self.pending_peers.read().len(); + let peers = self.peers.read(); + ( + num_pending + peers.len(), + peers.values().filter(|p| !p.lock().pending_requests.is_empty()).count(), + ) + } + /// Check the maximum amount of requests of a specific type /// which a peer would be able to serve. Returns zero if the /// peer is unknown or has no credit parameters. diff --git a/ethcore/light/src/net/request_set.rs b/ethcore/light/src/net/request_set.rs index 57eb232cc..e6d4068da 100644 --- a/ethcore/light/src/net/request_set.rs +++ b/ethcore/light/src/net/request_set.rs @@ -111,6 +111,14 @@ impl RequestSet { pub fn collect_ids(&self) -> F where F: FromIterator { self.ids.keys().cloned().collect() } + + /// Number of requests in the set. + pub fn len(&self) -> usize { + self.ids.len() + } + + /// Whether the set is empty. + pub fn is_empty(&self) -> bool { self.len() == 0 } } #[cfg(test)] diff --git a/ethcore/light/src/on_demand/mod.rs b/ethcore/light/src/on_demand/mod.rs index 1efff4005..25cde402b 100644 --- a/ethcore/light/src/on_demand/mod.rs +++ b/ethcore/light/src/on_demand/mod.rs @@ -19,6 +19,7 @@ //! will take the raw data received here and extract meaningful results from it. use std::collections::HashMap; +use std::sync::Arc; use ethcore::basic_account::BasicAccount; use ethcore::encoded; @@ -30,10 +31,11 @@ use futures::{Async, Poll, Future}; use futures::sync::oneshot::{self, Sender, Receiver}; use network::PeerId; use rlp::{RlpStream, Stream}; -use util::{Bytes, DBValue, RwLock, U256}; +use util::{Bytes, DBValue, RwLock, Mutex, U256}; use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP}; use net::{Handler, Status, Capabilities, Announcement, EventContext, BasicContext, ReqId}; +use cache::Cache; use types::les_request::{self as les_request, Request as LesRequest}; pub mod request; @@ -44,9 +46,16 @@ struct Peer { capabilities: Capabilities, } +// Which portions of a CHT proof should be sent. +enum ChtProofSender { + Both(Sender<(encoded::Header, U256)>), + Header(Sender), + ChainScore(Sender), +} + // Attempted request info and sender to put received value. enum Pending { - HeaderByNumber(request::HeaderByNumber, Sender<(encoded::Header, U256)>), // num + CHT root + HeaderByNumber(request::HeaderByNumber, ChtProofSender), HeaderByHash(request::HeaderByHash, Sender), Block(request::Body, Sender), BlockReceipts(request::BlockReceipts, Sender>), @@ -61,30 +70,77 @@ enum Pending { pub struct OnDemand { peers: RwLock>, pending_requests: RwLock>, + cache: Arc>, orphaned_requests: RwLock>, } -impl Default for OnDemand { - fn default() -> Self { +impl OnDemand { + /// Create a new `OnDemand` service with the given cache. + pub fn new(cache: Arc>) -> Self { OnDemand { peers: RwLock::new(HashMap::new()), pending_requests: RwLock::new(HashMap::new()), + cache: cache, orphaned_requests: RwLock::new(Vec::new()), } } -} -impl OnDemand { /// Request a header by block number and CHT root hash. - /// Returns the header and the total difficulty. - pub fn header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver<(encoded::Header, U256)> { + /// Returns the header. + pub fn header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver { let (sender, receiver) = oneshot::channel(); - self.dispatch_header_by_number(ctx, req, sender); + let cached = { + let mut cache = self.cache.lock(); + cache.block_hash(&req.num()).and_then(|hash| cache.block_header(&hash)) + }; + + match cached { + Some(hdr) => sender.complete(hdr), + None => self.dispatch_header_by_number(ctx, req, ChtProofSender::Header(sender)), + } + receiver + } + + /// Request a canonical block's chain score. + /// Returns the chain score. + pub fn chain_score_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver { + let (sender, receiver) = oneshot::channel(); + let cached = { + let mut cache = self.cache.lock(); + cache.block_hash(&req.num()).and_then(|hash| cache.chain_score(&hash)) + }; + + match cached { + Some(score) => sender.complete(score), + None => self.dispatch_header_by_number(ctx, req, ChtProofSender::ChainScore(sender)), + } + + receiver + } + + /// Request a canonical block's chain score. + /// Returns the header and chain score. + pub fn header_and_score_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver<(encoded::Header, U256)> { + let (sender, receiver) = oneshot::channel(); + let cached = { + let mut cache = self.cache.lock(); + let hash = cache.block_hash(&req.num()); + ( + hash.clone().and_then(|hash| cache.block_header(&hash)), + hash.and_then(|hash| cache.chain_score(&hash)), + ) + }; + + match cached { + (Some(hdr), Some(score)) => sender.complete((hdr, score)), + _ => self.dispatch_header_by_number(ctx, req, ChtProofSender::Both(sender)), + } + receiver } // dispatch the request, completing the request if no peers available. - fn dispatch_header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber, sender: Sender<(encoded::Header, U256)>) { + fn dispatch_header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber, sender: ChtProofSender) { let num = req.num(); let cht_num = req.cht_num(); @@ -126,7 +182,10 @@ impl OnDemand { /// it as easily. pub fn header_by_hash(&self, ctx: &BasicContext, req: request::HeaderByHash) -> Receiver { let (sender, receiver) = oneshot::channel(); - self.dispatch_header_by_hash(ctx, req, sender); + match self.cache.lock().block_header(&req.0) { + Some(hdr) => sender.complete(hdr), + None => self.dispatch_header_by_hash(ctx, req, sender), + } receiver } @@ -184,7 +243,16 @@ impl OnDemand { sender.complete(encoded::Block::new(stream.out())) } else { - self.dispatch_block(ctx, req, sender); + match self.cache.lock().block_body(&req.hash) { + Some(body) => { + let mut stream = RlpStream::new_list(3); + stream.append_raw(&req.header.into_inner(), 1); + stream.append_raw(&body.into_inner(), 2); + + sender.complete(encoded::Block::new(stream.out())); + } + None => self.dispatch_block(ctx, req, sender), + } } receiver } @@ -227,7 +295,10 @@ impl OnDemand { if req.0.receipts_root() == SHA3_NULL_RLP { sender.complete(Vec::new()) } else { - self.dispatch_block_receipts(ctx, req, sender); + match self.cache.lock().block_receipts(&req.0.hash()) { + Some(receipts) => sender.complete(receipts), + None => self.dispatch_block_receipts(ctx, req, sender), + } } receiver @@ -425,8 +496,15 @@ impl OnDemand { for orphaned in to_dispatch { match orphaned { - Pending::HeaderByNumber(req, mut sender) => - if !check_hangup(&mut sender) { self.dispatch_header_by_number(ctx, req, sender) }, + Pending::HeaderByNumber(req, mut sender) => { + let hangup = match sender { + ChtProofSender::Both(ref mut s) => check_hangup(s), + ChtProofSender::Header(ref mut s) => check_hangup(s), + ChtProofSender::ChainScore(ref mut s) => check_hangup(s), + }; + + if !hangup { self.dispatch_header_by_number(ctx, req, sender) } + } Pending::HeaderByHash(req, mut sender) => if !check_hangup(&mut sender) { self.dispatch_header_by_hash(ctx, req, sender) }, Pending::Block(req, mut sender) => @@ -488,8 +566,19 @@ impl Handler for OnDemand { Pending::HeaderByNumber(req, sender) => { if let Some(&(ref header, ref proof)) = proofs.get(0) { match req.check_response(header, proof) { - Ok(header) => { - sender.complete(header); + Ok((header, score)) => { + let mut cache = self.cache.lock(); + let hash = header.hash(); + cache.insert_block_header(hash, header.clone()); + cache.insert_block_hash(header.number(), hash); + cache.insert_chain_score(hash, score); + + match sender { + ChtProofSender::Both(sender) => sender.complete((header, score)), + ChtProofSender::Header(sender) => sender.complete(header), + ChtProofSender::ChainScore(sender) => sender.complete(score), + } + return } Err(e) => { @@ -517,6 +606,7 @@ impl Handler for OnDemand { if let Some(ref header) = headers.get(0) { match req.check_response(header) { Ok(header) => { + self.cache.lock().insert_block_header(req.0, header.clone()); sender.complete(header); return } @@ -542,9 +632,11 @@ impl Handler for OnDemand { match req { Pending::Block(req, sender) => { - if let Some(ref block) = bodies.get(0) { - match req.check_response(block) { + if let Some(ref body) = bodies.get(0) { + match req.check_response(body) { Ok(block) => { + let body = encoded::Body::new(body.to_vec()); + self.cache.lock().insert_block_body(req.hash, body); sender.complete(block); return } @@ -573,6 +665,8 @@ impl Handler for OnDemand { if let Some(ref receipts) = receipts.get(0) { match req.check_response(receipts) { Ok(receipts) => { + let hash = req.0.hash(); + self.cache.lock().insert_block_receipts(hash, receipts.clone()); sender.complete(receipts); return } @@ -683,10 +777,16 @@ impl Handler for OnDemand { #[cfg(test)] mod tests { use super::*; + + use std::sync::Arc; + + use cache::Cache; use net::{Announcement, BasicContext, ReqId, Error as LesError}; use request::{Request as LesRequest, Kind as LesRequestKind}; + use network::{PeerId, NodeId}; - use util::H256; + use time::Duration; + use util::{H256, Mutex}; struct FakeContext; @@ -703,7 +803,8 @@ mod tests { #[test] fn detects_hangup() { - let on_demand = OnDemand::default(); + let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); + let on_demand = OnDemand::new(cache); let result = on_demand.header_by_hash(&FakeContext, request::HeaderByHash(H256::default())); assert!(on_demand.orphaned_requests.read().len() == 1); diff --git a/ethcore/light/src/transaction_queue.rs b/ethcore/light/src/transaction_queue.rs index 8ca6a64f6..d17a863f5 100644 --- a/ethcore/light/src/transaction_queue.rs +++ b/ethcore/light/src/transaction_queue.rs @@ -245,6 +245,31 @@ impl TransactionQueue { .collect() } + /// Get all transactions not ready to be propagated. + /// `best_block_number` and `best_block_timestamp` are used to filter out conditionally + /// propagated transactions. + /// + /// Returned transactions are batched by sender, in order of ascending nonce. + pub fn future_transactions(&self, best_block_number: u64, best_block_timestamp: u64) -> Vec { + self.by_account.values() + .flat_map(|acct_txs| { + acct_txs.current.iter().skip_while(|tx| match tx.condition { + None => true, + Some(Condition::Number(blk_num)) => blk_num <= best_block_number, + Some(Condition::Timestamp(time)) => time <= best_block_timestamp, + }).chain(acct_txs.future.values()).map(|info| info.hash) + }) + .filter_map(|hash| match self.by_hash.get(&hash) { + Some(tx) => Some(tx.clone()), + None => { + warn!(target: "txqueue", "Inconsistency detected between `by_hash` and `by_account`: {} not stored.", + hash); + None + } + }) + .collect() + } + /// Addresses for which we store transactions. pub fn queued_senders(&self) -> Vec
{ self.by_account.keys().cloned().collect() @@ -471,4 +496,22 @@ mod tests { assert!(txq.transaction(&hash).is_none()); } + + #[test] + fn future_transactions() { + let sender = Address::default(); + let mut txq = TransactionQueue::default(); + + for i in (0..1).chain(3..10) { + let mut tx = Transaction::default(); + tx.nonce = i.into(); + + let tx = tx.fake_sign(sender); + + txq.import(tx.into()).unwrap(); + } + + assert_eq!(txq.future_transactions(0, 0).len(), 7); + assert_eq!(txq.next_nonce(&sender).unwrap(), 1.into()); + } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8692e831a..63be1da07 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -964,13 +964,13 @@ impl BlockChainClient for Client { { while upper - lower > 1.into() { let mid = (lower + upper) / 2.into(); - trace!(target: "binary_chop", "{} .. {} .. {}", lower, mid, upper); + trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper); let c = cond(mid)?; match c { true => upper = mid, false => lower = mid, }; - trace!(target: "binary_chop", "{} => {} .. {}", c, lower, upper); + trace!(target: "estimate_gas", "{} => {} .. {}", c, lower, upper); } Ok(upper) } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 13abb33f9..4af20de0f 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -17,7 +17,6 @@ use std::collections::BTreeMap; use util::{U256, Address, H256, H2048, Bytes, Itertools}; use util::hashdb::DBValue; -use util::stats::Histogram; use blockchain::TreeRoute; use verification::queue::QueueInfo as BlockQueueInfo; use block::{OpenBlock, SealedBlock}; @@ -213,38 +212,24 @@ pub trait BlockChainClient : Sync + Send { fn ready_transactions(&self) -> Vec; /// Sorted list of transaction gas prices from at least last sample_size blocks. - fn gas_price_corpus(&self, sample_size: usize) -> Vec { + fn gas_price_corpus(&self, sample_size: usize) -> ::stats::Corpus { let mut h = self.chain_info().best_block_hash; let mut corpus = Vec::new(); while corpus.is_empty() { for _ in 0..sample_size { - let block = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed"); - let header = block.header_view(); - if header.number() == 0 { - corpus.sort(); - return corpus; + let block = match self.block(BlockId::Hash(h)) { + Some(block) => block, + None => return corpus.into(), + }; + + if block.number() == 0 { + return corpus.into(); } block.transaction_views().iter().foreach(|t| corpus.push(t.gas_price())); - h = header.parent_hash().clone(); + h = block.parent_hash().clone(); } } - corpus.sort(); - corpus - } - - /// Calculate median gas price from recent blocks if they have any transactions. - fn gas_price_median(&self, sample_size: usize) -> Option { - let corpus = self.gas_price_corpus(sample_size); - corpus.get(corpus.len() / 2).cloned() - } - - /// Get the gas price distribution based on recent blocks if they have any transactions. - fn gas_price_histogram(&self, sample_size: usize, bucket_number: usize) -> Option { - let raw_corpus = self.gas_price_corpus(sample_size); - let raw_len = raw_corpus.len(); - // Throw out outliers. - let (corpus, _) = raw_corpus.split_at(raw_len - raw_len / 40); - Histogram::new(corpus, bucket_number) + corpus.into() } /// Get the preferred network ID to sign on diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 9b750a221..1c9edd33b 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -151,12 +151,12 @@ impl Tendermint { fn generate_message(&self, block_hash: Option) -> Option { let h = self.height.load(AtomicOrdering::SeqCst); let r = self.view.load(AtomicOrdering::SeqCst); - let s = self.step.read(); - let vote_info = message_info_rlp(&VoteStep::new(h, r, *s), block_hash); + let s = *self.step.read(); + let vote_info = message_info_rlp(&VoteStep::new(h, r, s), block_hash); match self.signer.sign(vote_info.sha3()).map(Into::into) { Ok(signature) => { let message_rlp = message_full_rlp(&signature, &vote_info); - let message = ConsensusMessage::new(signature, h, r, *s, block_hash); + let message = ConsensusMessage::new(signature, h, r, s, block_hash); let validator = self.signer.address(); self.votes.vote(message.clone(), &validator); debug!(target: "engine", "Generated {:?} as {}.", message, validator); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 67c956cdc..fbb9c8a5c 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -79,6 +79,14 @@ pub struct EthashParams { pub ecip1010_continue_transition: u64, /// Maximum amount of code that can be deploying into a contract. pub max_code_size: u64, + /// Number of first block where the max gas limit becomes effective. + pub max_gas_limit_transition: u64, + /// Maximum valid block gas limit, + pub max_gas_limit: U256, + /// Number of first block where the minimum gas price becomes effective. + pub min_gas_price_transition: u64, + /// Do not alow transactions with lower gas price. + pub min_gas_price: U256, } impl From for EthashParams { @@ -106,6 +114,10 @@ impl From for EthashParams { ecip1010_pause_transition: p.ecip1010_pause_transition.map_or(u64::max_value(), Into::into), ecip1010_continue_transition: p.ecip1010_continue_transition.map_or(u64::max_value(), Into::into), max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into), + max_gas_limit_transition: p.max_gas_limit_transition.map_or(u64::max_value(), Into::into), + max_gas_limit: p.max_gas_limit.map_or(U256::max_value(), Into::into), + min_gas_price_transition: p.min_gas_price_transition.map_or(u64::max_value(), Into::into), + min_gas_price: p.min_gas_price.map_or(U256::zero(), Into::into), } } } @@ -174,8 +186,12 @@ impl Engine for Ethash { } } - fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, gas_ceil_target: U256) { + fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, mut gas_ceil_target: U256) { let difficulty = self.calculate_difficulty(header, parent); + if header.number() >= self.ethash_params.max_gas_limit_transition && gas_ceil_target > self.ethash_params.max_gas_limit { + warn!("Gas limit target is limited to {}", self.ethash_params.max_gas_limit); + gas_ceil_target = self.ethash_params.max_gas_limit; + } let gas_limit = { let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.ethash_params.gas_limit_bound_divisor; @@ -334,11 +350,15 @@ impl Engine for Ethash { return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty().clone() }))) } let gas_limit_divisor = self.ethash_params.gas_limit_bound_divisor; - let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor; - let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor; + let parent_gas_limit = *parent.gas_limit(); + let min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor; + let max_gas = parent_gas_limit + parent_gas_limit / gas_limit_divisor; if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas { return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }))); } + if header.number() >= self.ethash_params.max_gas_limit_transition && header.gas_limit() > &self.ethash_params.max_gas_limit && header.gas_limit() > &parent_gas_limit { + return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(self.ethash_params.max_gas_limit), found: header.gas_limit().clone() }))); + } Ok(()) } @@ -353,6 +373,10 @@ impl Engine for Ethash { } } + if header.number() >= self.ethash_params.min_gas_price_transition && t.gas_price < self.ethash_params.min_gas_price { + return Err(TransactionError::InsufficientGasPrice { minimal: self.ethash_params.min_gas_price, got: t.gas_price }.into()); + } + Ok(()) } } @@ -857,4 +881,100 @@ mod tests { ethash.populate_from_parent(&mut header, &parent, U256::from(150_000), U256::from(150_002)); assert_eq!(*header.gas_limit(), U256::from(150_002)); } + + #[test] + fn difficulty_max_timestamp() { + let spec = new_homestead_test(); + let ethparams = get_default_ethash_params(); + let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); + + let mut parent_header = Header::default(); + parent_header.set_number(1000000); + parent_header.set_difficulty(U256::from_str("b69de81a22b").unwrap()); + parent_header.set_timestamp(1455404053); + let mut header = Header::default(); + header.set_number(parent_header.number() + 1); + header.set_timestamp(u64::max_value()); + + let difficulty = ethash.calculate_difficulty(&header, &parent_header); + assert_eq!(U256::from(12543204905719u64), difficulty); + } + + #[test] + fn rejects_blocks_over_max_gas_limit() { + let spec = new_homestead_test(); + let mut ethparams = get_default_ethash_params(); + ethparams.max_gas_limit_transition = 10; + ethparams.max_gas_limit = 100_000.into(); + + let mut parent_header = Header::default(); + parent_header.set_number(1); + parent_header.set_gas_limit(100_000.into()); + let mut header = Header::default(); + header.set_number(parent_header.number() + 1); + header.set_gas_limit(100_001.into()); + header.set_difficulty(ethparams.minimum_difficulty); + let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); + assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok()); + + parent_header.set_number(9); + header.set_number(parent_header.number() + 1); + + parent_header.set_gas_limit(99_999.into()); + header.set_gas_limit(100_000.into()); + assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok()); + + parent_header.set_gas_limit(200_000.into()); + header.set_gas_limit(200_000.into()); + assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok()); + + parent_header.set_gas_limit(100_000.into()); + header.set_gas_limit(100_001.into()); + assert!(ethash.verify_block_family(&header, &parent_header, None).is_err()); + + parent_header.set_gas_limit(200_000.into()); + header.set_gas_limit(200_001.into()); + assert!(ethash.verify_block_family(&header, &parent_header, None).is_err()); + } + + #[test] + fn rejects_transactions_below_min_gas_price() { + use ethkey::{Generator, Random}; + use types::transaction::{Transaction, Action}; + + let spec = new_homestead_test(); + let mut ethparams = get_default_ethash_params(); + ethparams.min_gas_price_transition = 10; + ethparams.min_gas_price = 100000.into(); + + let mut header = Header::default(); + header.set_number(1); + + let keypair = Random.generate().unwrap(); + let tx1 = Transaction { + action: Action::Create, + value: U256::zero(), + data: Vec::new(), + gas: 100_000.into(), + gas_price: 100_000.into(), + nonce: U256::zero(), + }.sign(keypair.secret(), None).into(); + + let tx2 = Transaction { + action: Action::Create, + value: U256::zero(), + data: Vec::new(), + gas: 100_000.into(), + gas_price: 99_999.into(), + nonce: U256::zero(), + }.sign(keypair.secret(), None).into(); + + let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); + assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok()); + assert!(ethash.verify_transaction_basic(&tx2, &header).is_ok()); + + header.set_number(10); + assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok()); + assert!(ethash.verify_transaction_basic(&tx2, &header).is_err()); + } } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 1ec98708e..60b9dcb46 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -276,7 +276,7 @@ impl Decodable for Header { number: r.val_at(8)?, gas_limit: r.val_at(9)?, gas_used: r.val_at(10)?, - timestamp: r.val_at(11)?, + timestamp: min(r.val_at::(11)?, u64::max_value().into()).as_u64(), extra_data: r.val_at(12)?, seal: vec![], hash: RefCell::new(Some(r.as_raw().sha3())), diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index ea7de9e61..a78e2120f 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -105,6 +105,7 @@ extern crate lru_cache; extern crate ethcore_stratum; extern crate ethabi; extern crate hardware_wallet; +extern crate stats; #[macro_use] extern crate log; diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index ded70b363..3734c5520 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -28,7 +28,6 @@ use miner::Miner; use rlp::View; use spec::Spec; use views::BlockView; -use util::stats::Histogram; use ethkey::{KeyPair, Secret}; use transaction::{PendingTransaction, Transaction, Action, Condition}; use miner::MinerService; @@ -209,11 +208,11 @@ fn can_collect_garbage() { fn can_generate_gas_price_median() { let client_result = generate_dummy_client_with_data(3, 1, slice_into![1, 2, 3]); let client = client_result.reference(); - assert_eq!(Some(U256::from(2)), client.gas_price_median(3)); + assert_eq!(Some(&U256::from(2)), client.gas_price_corpus(3).median()); let client_result = generate_dummy_client_with_data(4, 1, slice_into![1, 4, 3, 2]); let client = client_result.reference(); - assert_eq!(Some(U256::from(3)), client.gas_price_median(4)); + assert_eq!(Some(&U256::from(3)), client.gas_price_corpus(3).median()); } #[test] @@ -221,8 +220,8 @@ fn can_generate_gas_price_histogram() { let client_result = generate_dummy_client_with_data(20, 1, slice_into![6354,8593,6065,4842,7845,7002,689,4958,4250,6098,5804,4320,643,8895,2296,8589,7145,2000,2512,1408]); let client = client_result.reference(); - let hist = client.gas_price_histogram(20, 5).unwrap(); - let correct_hist = Histogram { bucket_bounds: vec_into![643, 2294, 3945, 5596, 7247, 8898], counts: vec![4,2,4,6,4] }; + let hist = client.gas_price_corpus(20).histogram(5).unwrap(); + let correct_hist = ::stats::Histogram { bucket_bounds: vec_into![643, 2294, 3945, 5596, 7247, 8898], counts: vec![4,2,4,6,4] }; assert_eq!(hist, correct_hist); } @@ -231,7 +230,7 @@ fn empty_gas_price_histogram() { let client_result = generate_dummy_client_with_data(20, 0, slice_into![]); let client = client_result.reference(); - assert!(client.gas_price_histogram(20, 5).is_none()); + assert!(client.gas_price_corpus(20).histogram(5).is_none()); } #[test] diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 8a246e0be..7de46b0b3 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -456,5 +456,9 @@ pub fn get_default_ethash_params() -> EthashParams{ ecip1010_pause_transition: u64::max_value(), ecip1010_continue_transition: u64::max_value(), max_code_size: u64::max_value(), + max_gas_limit_transition: u64::max_value(), + max_gas_limit: U256::max_value(), + min_gas_price_transition: u64::max_value(), + min_gas_price: U256::zero(), } } diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index c10fce26d..6ab6d692e 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -185,7 +185,7 @@ pub mod headers { type Verified = Header; fn create(input: Self::Input, engine: &Engine) -> Result { - verify_header_params(&input, engine).map(|_| input) + verify_header_params(&input, engine, true).map(|_| input) } fn verify(unverified: Self::Unverified, engine: &Engine, check_seal: bool) -> Result { diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 548a4e71b..34a4ccbd0 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -51,12 +51,12 @@ impl HeapSizeOf for PreverifiedBlock { /// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Result<(), Error> { - verify_header_params(&header, engine)?; + verify_header_params(&header, engine, true)?; verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash())?; engine.verify_block_basic(&header, Some(bytes))?; for u in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { let u = u?; - verify_header_params(&u, engine)?; + verify_header_params(&u, engine, false)?; engine.verify_block_basic(&u, None)?; } // Verify transactions. @@ -195,7 +195,7 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> } /// Check basic header parameters. -pub fn verify_header_params(header: &Header, engine: &Engine) -> Result<(), Error> { +pub fn verify_header_params(header: &Header, engine: &Engine, is_full: bool) -> Result<(), Error> { if header.number() >= From::from(BlockNumber::max_value()) { return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { max: Some(From::from(BlockNumber::max_value())), min: None, found: header.number() }))) } @@ -210,9 +210,11 @@ pub fn verify_header_params(header: &Header, engine: &Engine) -> Result<(), Erro if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size { return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: Some(maximum_extra_data_size), found: header.extra_data().len() }))); } - let max_time = get_time().sec as u64 + 30; - if header.timestamp() > max_time { - return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() }))) + if is_full { + let max_time = get_time().sec as u64 + 30; + if header.timestamp() > max_time { + return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() }))) + } } Ok(()) } diff --git a/ethstore/src/dir/vault.rs b/ethstore/src/dir/vault.rs index 2e777360a..f321e3fbb 100755 --- a/ethstore/src/dir/vault.rs +++ b/ethstore/src/dir/vault.rs @@ -135,6 +135,10 @@ impl VaultKeyDirectory for VaultDiskDirectory { let temp_vault = VaultDiskDirectory::create_temp_vault(self, new_key.clone()).map_err(|err| SetKeyError::NonFatalOld(err))?; let mut source_path = temp_vault.path().expect("temp_vault is instance of DiskDirectory; DiskDirectory always returns path; qed").clone(); let mut target_path = self.path().expect("self is instance of DiskDirectory; DiskDirectory always returns path; qed").clone(); + + // preserve meta + temp_vault.set_meta(&self.meta()).map_err(SetKeyError::NonFatalOld)?; + // jump to next fs level source_path.push("next"); target_path.push("next"); diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 3cdf0e643..cacb6054f 100755 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -1015,4 +1015,21 @@ mod tests { // and we can sign with the derived contract assert!(store.sign(&derived, "test", &Default::default()).is_ok(), "Second password should work for second store."); } + + #[test] + fn should_save_meta_when_setting_before_password() { + // given + let mut dir = RootDiskDirectoryGuard::new(); + let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); + let name = "vault"; let password = "password1"; + let new_password = "password2"; + + // when + store.create_vault(name, password).unwrap(); + store.set_vault_meta(name, "OldMeta").unwrap(); + store.change_vault_password(name, new_password).unwrap(); + + // then + assert_eq!(store.get_vault_meta(name).unwrap(), "OldMeta".to_owned()); + } } diff --git a/ipfs/Cargo.toml b/ipfs/Cargo.toml index 7cc381ee8..992ee0710 100644 --- a/ipfs/Cargo.toml +++ b/ipfs/Cargo.toml @@ -8,6 +8,7 @@ authors = ["Parity Technologies "] [dependencies] ethcore = { path = "../ethcore" } ethcore-util = { path = "../util" } +jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" } rlp = { path = "../util/rlp" } mime = "0.2" hyper = { default-features = false, git = "https://github.com/ethcore/hyper" } diff --git a/ipfs/src/error.rs b/ipfs/src/error.rs index f379f254b..1cbd54f1c 100644 --- a/ipfs/src/error.rs +++ b/ipfs/src/error.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use {multihash, cid, hyper}; -use handler::Out; +use route::Out; pub type Result = ::std::result::Result; @@ -26,6 +26,8 @@ pub enum ServerError { IoError(::std::io::Error), /// Other `hyper` error Other(hyper::error::Error), + /// Invalid --ipfs-api-interface + InvalidInterface } #[derive(Debug, PartialEq)] @@ -89,6 +91,7 @@ impl From for String { match err { ServerError::IoError(err) => err.to_string(), ServerError::Other(err) => err.to_string(), + ServerError::InvalidInterface => "Invalid --ipfs-api-interface parameter".into(), } } } diff --git a/ipfs/src/lib.rs b/ipfs/src/lib.rs index 37373344a..80e910f9e 100644 --- a/ipfs/src/lib.rs +++ b/ipfs/src/lib.rs @@ -23,21 +23,91 @@ extern crate cid; extern crate rlp; extern crate ethcore; extern crate ethcore_util as util; +extern crate jsonrpc_http_server; -mod error; -mod handler; +pub mod error; +mod route; use std::io::Write; use std::sync::Arc; -use std::net::{SocketAddr, IpAddr, Ipv4Addr}; +use std::net::{SocketAddr, IpAddr}; use error::ServerError; -use handler::{IpfsHandler, Out}; +use route::Out; +use jsonrpc_http_server::cors; use hyper::server::{Listening, Handler, Request, Response}; use hyper::net::HttpStream; -use hyper::header::{ContentLength, ContentType, Origin}; +use hyper::header::{Vary, ContentLength, ContentType, AccessControlAllowOrigin}; use hyper::{Next, Encoder, Decoder, Method, RequestUri, StatusCode}; use ethcore::client::BlockChainClient; + +/// Request/response handler +pub struct IpfsHandler { + /// Response to send out + out: Out, + /// How many bytes from the response have been written + out_progress: usize, + /// Origin request header + origin: Option, + /// Allowed CORS domains + cors_domains: Option>, + /// Hostnames allowed in the `Host` request header + allowed_hosts: Option>, + /// Reference to the Blockchain Client + client: Arc, +} + +impl IpfsHandler { + pub fn client(&self) -> &BlockChainClient { + &*self.client + } + + pub fn new(cors: Option>, hosts: Option>, client: Arc) -> Self { + fn origin_to_header(origin: String) -> AccessControlAllowOrigin { + match origin.as_str() { + "*" => AccessControlAllowOrigin::Any, + "null" | "" => AccessControlAllowOrigin::Null, + _ => AccessControlAllowOrigin::Value(origin), + } + } + + IpfsHandler { + out: Out::Bad("Invalid Request"), + out_progress: 0, + origin: None, + cors_domains: cors.map(|vec| vec.into_iter().map(origin_to_header).collect()), + allowed_hosts: hosts, + client: client, + } + } + + fn is_host_allowed(&self, req: &Request) -> bool { + match self.allowed_hosts { + Some(ref hosts) => jsonrpc_http_server::is_host_header_valid(&req, hosts), + None => true, + } + } + + fn is_origin_allowed(&self) -> bool { + // Check origin header first, no header passed is good news + let origin = match self.origin { + Some(ref origin) => origin, + None => return true, + }; + + let cors_domains = match self.cors_domains { + Some(ref domains) => domains, + None => return false, + }; + + cors_domains.iter().any(|domain| match *domain { + AccessControlAllowOrigin::Value(ref allowed) => origin == allowed, + AccessControlAllowOrigin::Any => true, + AccessControlAllowOrigin::Null => origin == "", + }) + } +} + /// Implement Hyper's HTTP handler impl Handler for IpfsHandler { fn on_request(&mut self, req: Request) -> Next { @@ -45,9 +115,16 @@ impl Handler for IpfsHandler { return Next::write(); } - // Reject requests if the Origin header isn't valid - if req.headers().get::().map(|o| "127.0.0.1" != &o.host.hostname).unwrap_or(false) { - self.out = Out::Bad("Illegal Origin"); + self.origin = cors::read_origin(&req); + + if !self.is_host_allowed(&req) { + self.out = Out::Bad("Disallowed Host header"); + + return Next::write(); + } + + if !self.is_origin_allowed() { + self.out = Out::Bad("Disallowed Origin header"); return Next::write(); } @@ -57,7 +134,9 @@ impl Handler for IpfsHandler { _ => return Next::write(), }; - self.route(path, query) + self.out = self.route(path, query); + + Next::write() } fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next { @@ -82,25 +161,27 @@ impl Handler for IpfsHandler { res.headers_mut().set(ContentLength(bytes.len() as u64)); res.headers_mut().set(ContentType(content_type)); - Next::write() }, NotFound(reason) => { res.set_status(StatusCode::NotFound); res.headers_mut().set(ContentLength(reason.len() as u64)); res.headers_mut().set(ContentType(mime!(Text/Plain))); - - Next::write() }, Bad(reason) => { res.set_status(StatusCode::BadRequest); res.headers_mut().set(ContentLength(reason.len() as u64)); res.headers_mut().set(ContentType(mime!(Text/Plain))); - - Next::write() } } + + if let Some(cors_header) = cors::get_cors_header(&self.cors_domains, &self.origin) { + res.headers_mut().set(cors_header); + res.headers_mut().set(Vary::Items(vec!["Origin".into()])); + } + + Next::write() } fn on_response_writable(&mut self, transport: &mut Encoder) -> Next { @@ -116,11 +197,12 @@ impl Handler for IpfsHandler { } } +/// Attempt to write entire `data` from current `progress` fn write_chunk(transport: &mut W, progress: &mut usize, data: &[u8]) -> Next { // Skip any bytes that have already been written let chunk = &data[*progress..]; - // Write an get written count + // Write an get the amount of bytes written. End the connection in case of an error. let written = match transport.write(chunk) { Ok(written) => written, Err(_) => return Next::end(), @@ -128,7 +210,7 @@ fn write_chunk(transport: &mut W, progress: &mut usize, data: &[u8]) - *progress += written; - // Close the connection if the entire chunk has been written, otherwise increment progress + // Close the connection if the entire remaining chunk has been written if written < chunk.len() { Next::write() } else { @@ -136,12 +218,31 @@ fn write_chunk(transport: &mut W, progress: &mut usize, data: &[u8]) - } } -pub fn start_server(port: u16, client: Arc) -> Result { - let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); +/// Add current interface (default: "127.0.0.1:5001") to list of allowed hosts +fn include_current_interface(mut hosts: Vec, interface: String, port: u16) -> Vec { + hosts.push(match port { + 80 => interface, + _ => format!("{}:{}", interface, port), + }); + + hosts +} + +pub fn start_server( + port: u16, + interface: String, + cors: Option>, + hosts: Option>, + client: Arc +) -> Result { + + let ip: IpAddr = interface.parse().map_err(|_| ServerError::InvalidInterface)?; + let addr = SocketAddr::new(ip, port); + let hosts = hosts.map(move |hosts| include_current_interface(hosts, interface, port)); Ok( hyper::Server::http(&addr)? - .handle(move |_| IpfsHandler::new(client.clone())) + .handle(move |_| IpfsHandler::new(cors.clone(), hosts.clone(), client.clone())) .map(|(listening, srv)| { ::std::thread::spawn(move || { diff --git a/ipfs/src/handler.rs b/ipfs/src/route.rs similarity index 74% rename from ipfs/src/handler.rs rename to ipfs/src/route.rs index 543792fa5..5b571885d 100644 --- a/ipfs/src/handler.rs +++ b/ipfs/src/route.rs @@ -14,15 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use {rlp, multihash}; +use {rlp, multihash, IpfsHandler}; use error::{Error, Result}; use cid::{ToCid, Codec}; -use std::sync::Arc; use multihash::Hash; -use hyper::Next; use util::{Bytes, H256}; -use ethcore::client::{BlockId, TransactionId, BlockChainClient}; +use ethcore::client::{BlockId, TransactionId}; type Reason = &'static str; @@ -34,30 +32,10 @@ pub enum Out { Bad(Reason), } -/// Request/response handler -pub struct IpfsHandler { - /// Reference to the Blockchain Client - client: Arc, - - /// Response to send out - pub out: Out, - - /// How many bytes from the response have been written - pub out_progress: usize, -} - impl IpfsHandler { - pub fn new(client: Arc) -> Self { - IpfsHandler { - client: client, - out: Out::Bad("Invalid Request"), - out_progress: 0, - } - } - /// Route path + query string to a specialized method - pub fn route(&mut self, path: &str, query: Option<&str>) -> Next { - self.out = match path { + pub fn route(&self, path: &str, query: Option<&str>) -> Out { + match path { "/api/v0/block/get" => { let arg = query.and_then(|q| get_param(q, "arg")).unwrap_or(""); @@ -65,9 +43,7 @@ impl IpfsHandler { }, _ => Out::NotFound("Route not found") - }; - - Next::write() + } } /// Attempt to read Content ID from `arg` query parameter, get a hash and @@ -94,14 +70,14 @@ impl IpfsHandler { /// Get block header by hash as raw binary. fn block(&self, hash: H256) -> Result { let block_id = BlockId::Hash(hash); - let block = self.client.block_header(block_id).ok_or(Error::BlockNotFound)?; + let block = self.client().block_header(block_id).ok_or(Error::BlockNotFound)?; Ok(Out::OctetStream(block.into_inner())) } /// Get list of block ommers by hash as raw binary. fn block_list(&self, hash: H256) -> Result { - let uncles = self.client.find_uncles(&hash).ok_or(Error::BlockNotFound)?; + let uncles = self.client().find_uncles(&hash).ok_or(Error::BlockNotFound)?; Ok(Out::OctetStream(rlp::encode(&uncles).to_vec())) } @@ -109,21 +85,21 @@ impl IpfsHandler { /// Get transaction by hash and return as raw binary. fn transaction(&self, hash: H256) -> Result { let tx_id = TransactionId::Hash(hash); - let tx = self.client.transaction(tx_id).ok_or(Error::TransactionNotFound)?; + let tx = self.client().transaction(tx_id).ok_or(Error::TransactionNotFound)?; Ok(Out::OctetStream(rlp::encode(&*tx).to_vec())) } /// Get state trie node by hash and return as raw binary. fn state_trie(&self, hash: H256) -> Result { - let data = self.client.state_data(&hash).ok_or(Error::StateRootNotFound)?; + let data = self.client().state_data(&hash).ok_or(Error::StateRootNotFound)?; Ok(Out::OctetStream(data)) } /// Get state trie node by hash and return as raw binary. fn contract_code(&self, hash: H256) -> Result { - let data = self.client.state_data(&hash).ok_or(Error::ContractNotFound)?; + let data = self.client().state_data(&hash).ok_or(Error::ContractNotFound)?; Ok(Out::OctetStream(data)) } @@ -138,11 +114,12 @@ fn get_param<'a>(query: &'a str, name: &str) -> Option<&'a str> { #[cfg(test)] mod tests { + use std::sync::Arc; use super::*; use ethcore::client::TestBlockChainClient; fn get_mocked_handler() -> IpfsHandler { - IpfsHandler::new(Arc::new(TestBlockChainClient::new())) + IpfsHandler::new(None, None, Arc::new(TestBlockChainClient::new())) } #[test] @@ -232,37 +209,37 @@ mod tests { #[test] fn route_block() { - let mut handler = get_mocked_handler(); + let handler = get_mocked_handler(); - let _ = handler.route("/api/v0/block/get", Some("arg=z43AaGF5tmkT9SEX6urrhwpEW5ZSaACY73Vw357ZXTsur2fR8BM")); + let out = handler.route("/api/v0/block/get", Some("arg=z43AaGF5tmkT9SEX6urrhwpEW5ZSaACY73Vw357ZXTsur2fR8BM")); - assert_eq!(handler.out, Out::NotFound("Block not found")); + assert_eq!(out, Out::NotFound("Block not found")); } #[test] fn route_block_missing_query() { - let mut handler = get_mocked_handler(); + let handler = get_mocked_handler(); - let _ = handler.route("/api/v0/block/get", None); + let out = handler.route("/api/v0/block/get", None); - assert_eq!(handler.out, Out::Bad("CID parsing failed")); + assert_eq!(out, Out::Bad("CID parsing failed")); } #[test] fn route_block_invalid_query() { - let mut handler = get_mocked_handler(); + let handler = get_mocked_handler(); - let _ = handler.route("/api/v0/block/get", Some("arg=foobarz43AaGF5tmkT9SEX6urrhwpEW5ZSaACY73Vw357ZXTsur2fR8BM")); + let out = handler.route("/api/v0/block/get", Some("arg=foobarz43AaGF5tmkT9SEX6urrhwpEW5ZSaACY73Vw357ZXTsur2fR8BM")); - assert_eq!(handler.out, Out::Bad("CID parsing failed")); + assert_eq!(out, Out::Bad("CID parsing failed")); } #[test] fn route_invalid_route() { - let mut handler = get_mocked_handler(); + let handler = get_mocked_handler(); - let _ = handler.route("/foo/bar/baz", Some("arg=z43AaGF5tmkT9SEX6urrhwpEW5ZSaACY73Vw357ZXTsur2fR8BM")); + let out = handler.route("/foo/bar/baz", Some("arg=z43AaGF5tmkT9SEX6urrhwpEW5ZSaACY73Vw357ZXTsur2fR8BM")); - assert_eq!(handler.out, Out::NotFound("Route not found")); + assert_eq!(out, Out::NotFound("Route not found")); } } diff --git a/js/package.json b/js/package.json index 5bceb8032..0b5cdbaaf 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.3.94", + "version": "0.3.105", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js index 0f1bd492c..027d367d3 100644 --- a/js/src/api/rpc/parity/parity.js +++ b/js/src/api/rpc/parity/parity.js @@ -207,7 +207,7 @@ export default class Parity { importGethAccounts (accounts) { return this._transport - .execute('parity_importGethAccounts', inAddresses) + .execute('parity_importGethAccounts', inAddresses(accounts)) .then(outAddresses); } diff --git a/js/src/api/rpc/parity/parity.spec.js b/js/src/api/rpc/parity/parity.spec.js index e25d6668c..d7eb41047 100644 --- a/js/src/api/rpc/parity/parity.spec.js +++ b/js/src/api/rpc/parity/parity.spec.js @@ -73,6 +73,21 @@ describe('api/rpc/parity', () => { }); }); + describe('importGethAccounts', () => { + const ACCOUNTS = ['0x63cf90d3f0410092fc0fca41846f596223979195']; + let scope; + + beforeEach(() => { + scope = mockHttp([{ method: 'parity_importGethAccounts', reply: { result: ACCOUNTS } }]); + }); + + it('passes the addresses through', () => { + return instance.importGethAccounts(ACCOUNTS).then((result) => { + expect(scope.body['parity_importGethAccounts'].params).to.deep.equal([ACCOUNTS]); + }); + }); + }); + describe('minGasPrice', () => { it('returns the min gasprice, formatted', () => { mockHttp([{ method: 'parity_minGasPrice', reply: { result: '0x123456' } }]); diff --git a/js/src/i18n/_default/accounts.js b/js/src/i18n/_default/accounts.js index 5cafa1054..d22c5a504 100644 --- a/js/src/i18n/_default/accounts.js +++ b/js/src/i18n/_default/accounts.js @@ -15,7 +15,17 @@ // along with Parity. If not, see . export default { + button: { + newAccount: `new account`, + newWallet: `new wallet`, + vaults: `vaults` + }, summary: { minedBlock: `Mined at block #{blockNumber}` + }, + title: `Accounts Overview`, + tooltip: { + actions: `actions relating to the current view are available on the toolbar for quick access, be it for performing actions or creating a new item`, + overview: `your accounts are visible for easy access, allowing you to edit the meta information, make transfers, view transactions and fund the account` } }; diff --git a/js/src/i18n/_default/createAccount.js b/js/src/i18n/_default/createAccount.js index 562f1ff0c..485a877f8 100644 --- a/js/src/i18n/_default/createAccount.js +++ b/js/src/i18n/_default/createAccount.js @@ -61,13 +61,6 @@ export default { label: `Import raw private key` } }, - error: { - invalidKey: `the raw key needs to be hex, 64 characters in length and contain the prefix "0x"`, - noFile: `select a valid wallet file to import`, - noKey: `you need to provide the raw private key`, - noMatchPassword: `the supplied passwords does not match`, - noName: `you need to specify a valid name for the account` - }, newAccount: { hint: { hint: `(optional) a hint to help with remembering the password`, diff --git a/js/src/i18n/_default/errors.js b/js/src/i18n/_default/errors.js new file mode 100644 index 000000000..76fed24cd --- /dev/null +++ b/js/src/i18n/_default/errors.js @@ -0,0 +1,24 @@ +// 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 { + duplicateName: `the name already exists`, + invalidKey: `the raw key needs to be hex, 64 characters in length and contain the prefix "0x"`, + noFile: `select a valid wallet file to import`, + noKey: `you need to provide the raw private key`, + noMatchPassword: `the supplied passwords does not match`, + noName: `you need to specify a valid name` +}; diff --git a/js/src/i18n/_default/index.js b/js/src/i18n/_default/index.js index 59fea4b05..7e8bac8ef 100644 --- a/js/src/i18n/_default/index.js +++ b/js/src/i18n/_default/index.js @@ -29,6 +29,7 @@ export dapps from './dapps'; export deleteAccount from './deleteAccount'; export deployContract from './deployContract'; export editMeta from './editMeta'; +export errors from './errors'; export executeContract from './executeContract'; export extension from './extension'; export firstRun from './firstRun'; @@ -38,9 +39,11 @@ export parityBar from './parityBar'; export passwordChange from './passwordChange'; export settings from './settings'; export shapeshift from './shapeshift'; +export tabBar from './tabBar'; export transfer from './transfer'; export txEditor from './txEditor'; export ui from './ui'; export upgradeParity from './upgradeParity'; +export vaults from './vaults'; export walletSettings from './walletSettings'; export web from './web'; diff --git a/js/src/i18n/_default/tabBar.js b/js/src/i18n/_default/tabBar.js new file mode 100644 index 000000000..1692a1997 --- /dev/null +++ b/js/src/i18n/_default/tabBar.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 . + +export default { + tooltip: { + overview: `navigate between the different parts and views of the application, switching between an account view, token view and distributed application view` + } +}; diff --git a/js/src/i18n/_default/ui.js b/js/src/i18n/_default/ui.js index 9bed497f5..242f14b9b 100644 --- a/js/src/i18n/_default/ui.js +++ b/js/src/i18n/_default/ui.js @@ -35,6 +35,13 @@ export default { passwordStrength: { label: `password strength` }, + tooltips: { + button: { + done: `Done`, + next: `Next`, + skip: `Skip` + } + }, txHash: { confirmations: `{count} {value, plural, one {confirmation} other {confirmations}}`, oog: `The transaction might have gone out of gas. Try again with more gas.`, diff --git a/js/src/i18n/_default/vaults.js b/js/src/i18n/_default/vaults.js new file mode 100644 index 000000000..3024beed3 --- /dev/null +++ b/js/src/i18n/_default/vaults.js @@ -0,0 +1,75 @@ +// 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 { + accounts: { + button: { + cancel: `Cancel`, + execute: `Set` + }, + empty: `There are no accounts in this vault`, + title: `Manage Vault Accounts` + }, + button: { + accounts: `accounts`, + add: `create vault`, + close: `close vault`, + open: `open vault` + }, + confirmClose: { + info: `You are about to close a vault. Any accounts associated with the vault won't be visible after this operation concludes. To view the associated accounts, open the vault again.`, + title: `Close Vault` + }, + confirmOpen: { + info: `You are about to open a vault. After confirming your password, all accounts associated with this vault will be visible. Closing the vault will remove the accounts from view until the vault is opened again.`, + password: { + hint: `the password specified when creating the vault`, + label: `vault password` + }, + title: `Open Vault` + }, + create: { + button: { + close: `close`, + vault: `create vault` + }, + description: { + hint: `an extended description for the vault` + }, + descriptions: { + label: `(optional) description` + }, + hint: { + hint: `(optional) a hint to help with remembering the password`, + label: `password hint` + }, + name: { + hint: `a name for the vault`, + label: `vault name` + }, + password: { + hint: `a strong, unique password`, + label: `password` + }, + password2: { + hint: `verify your password`, + label: `password (repeat)` + }, + title: `Create a new vault` + }, + empty: `There are currently no vaults to display.`, + title: `Vault Management` +}; diff --git a/js/src/i18n/nl/account.js b/js/src/i18n/nl/account.js new file mode 100755 index 000000000..57701292a --- /dev/null +++ b/js/src/i18n/nl/account.js @@ -0,0 +1,35 @@ +// 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 { + button: { + delete: `verwijder account`, + edit: `bewerk`, + password: `wachtwoord`, + shapeshift: `shapeshift`, + transfer: `verzend`, + verify: `verifieer` + }, + header: { + outgoingTransactions: `{count} uitgaande transacties`, + uuid: `uuid: {uuid}` + }, + title: `Account Beheer`, + transactions: { + poweredBy: `Transactie lijst mede mogelijk door {etherscan}`, + title: `transacties` + } +}; diff --git a/js/src/i18n/nl/accounts.js b/js/src/i18n/nl/accounts.js new file mode 100755 index 000000000..315324632 --- /dev/null +++ b/js/src/i18n/nl/accounts.js @@ -0,0 +1,31 @@ +// 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 { + button: { + newAccount: `nieuw account`, + newWallet: `nieuw wallet`, + vaults: `kluizen` + }, + summary: { + minedBlock: `Opgenomen in blok #{blockNumber}` + }, + title: `Accounts Overzicht`, + tooltip: { + actions: `voor de huidige weergave zijn koppelingen beschikbaar op de werkbalk voor snelle toegang: het uitvoeren van acties of het creëren van een nieuw item`, + overview: `hier vind je een overzichtelijke weergave van je accounts, waarin je meta informatie kunt bewerken en transacties kunt uitvoeren en bekijken` + } +}; diff --git a/js/src/i18n/nl/addAddress.js b/js/src/i18n/nl/addAddress.js new file mode 100755 index 000000000..1b2281888 --- /dev/null +++ b/js/src/i18n/nl/addAddress.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 . + +export default { + button: { + add: `Adres Opslaan`, + close: `Annuleer` + }, + input: { + address: { + hint: `het netwerk adres van het item`, + label: `Netwerk Adres` + }, + description: { + hint: `een uitgebereide beschrijving voor het adres`, + label: `(optioneel) adres beschrijving` + }, + name: { + hint: `een beschrijvende naam van het adres`, + label: `Adres Naam` + } + }, + label: `voeg opgeslagen adres toe` +}; diff --git a/js/src/i18n/nl/addContract.js b/js/src/i18n/nl/addContract.js new file mode 100755 index 000000000..c0b60806c --- /dev/null +++ b/js/src/i18n/nl/addContract.js @@ -0,0 +1,60 @@ +// 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 { + abi: { + hint: `de abi van het contract`, + label: `contract abi` + }, + abiType: { + custom: { + description: `Contract aangemaakt met een custom ABI`, + label: `Custom Contract` + }, + multisigWallet: { + description: `Ethereum Multisig contract {link}`, + label: `Multisig Wallet`, + link: `zie contract code` + }, + token: { + description: `Een standaard {erc20} token`, + erc20: `ERC 20`, + label: `Token` + } + }, + address: { + hint: `het netwerk adres van het contract`, + label: `netwerk adres` + }, + button: { + add: `Voeg Contract toe`, + cancel: `Annuleer`, + next: `Volgende`, + prev: `Terug` + }, + description: { + hint: `een uitgebreide omschrijving van het contract`, + label: `(optioneel) contract beschrijving` + }, + name: { + hint: `een beschrijvende naam van het contract`, + label: `contract naam` + }, + title: { + details: `voer contract details in`, + type: `kies een contract type` + } +}; diff --git a/js/src/i18n/nl/addressSelect.js b/js/src/i18n/nl/addressSelect.js new file mode 100755 index 000000000..f447ee088 --- /dev/null +++ b/js/src/i18n/nl/addressSelect.js @@ -0,0 +1,26 @@ +// 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 { + fromEmail: `Geverifieerd met behulp van e-mail {email}`, + fromRegistry: `{name} (from registry)`, + labels: { + accounts: `accounts`, + contacts: `contacten`, + contracts: `contracts` + }, + noAccount: `Geen account gevonden voor deze zoekopdracht...` +}; diff --git a/js/src/i18n/nl/application.js b/js/src/i18n/nl/application.js new file mode 100755 index 000000000..1a6b2ee5c --- /dev/null +++ b/js/src/i18n/nl/application.js @@ -0,0 +1,27 @@ +// 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 { + status: { + consensus: { + capable: `Capable`, + capableUntil: `Capable tot #{blockNumber}`, + incapableSince: `Incapable sinds #{blockNumber}`, + unknown: `Onbekende capability` + }, + upgrade: `Upgrade` + } +}; diff --git a/js/src/i18n/nl/connection.js b/js/src/i18n/nl/connection.js new file mode 100755 index 000000000..3fa28effe --- /dev/null +++ b/js/src/i18n/nl/connection.js @@ -0,0 +1,26 @@ +// 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 { + connectingAPI: `Verbinden met de Parity Secure API.`, + connectingNode: `Verbinden met de Parity Node. Conroleer of je Parity node actief en op het netwerk bereikbaar is als dit bericht op je scherm blijft staan.`, + invalidToken: `ongeldige signer token`, + noConnection: `Kan geen verbinding maken met de Parity Secure API. Voer {newToken} uit en geef het token hieronder in om het secure token bij te werken of een nieuwe te genereren.`, + token: { + hint: `een Parity gegenereerd token`, + label: `secure token` + } +}; diff --git a/js/src/i18n/nl/contract.js b/js/src/i18n/nl/contract.js new file mode 100755 index 000000000..5f2ca39cc --- /dev/null +++ b/js/src/i18n/nl/contract.js @@ -0,0 +1,19 @@ +// 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 { + minedBlock: `Opgenomen in blok #{blockNumber}` +}; diff --git a/js/src/i18n/nl/createAccount.js b/js/src/i18n/nl/createAccount.js new file mode 100755 index 000000000..69585df35 --- /dev/null +++ b/js/src/i18n/nl/createAccount.js @@ -0,0 +1,156 @@ +// 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 { + accountDetails: { + address: { + hint: `Het netwerk adres van het account`, + label: `adres` + }, + name: { + hint: `Een beschrijvende naam van het account`, + label: `account naam` + }, + phrase: { + hint: `De account herstel zin`, + label: `Eigenaar's herstel zin (houd deze woorden veilig en prive want hiermee kun je volledige, ongelimiteerde toegang tot het account verkrijgen).` + } + }, + accountDetailsGeth: { + imported: `Je hebt {number} adressen geïmporteerd uit de Geth keystore:` + }, + button: { + back: `Terug`, + cancel: `Annuleer`, + close: `Sluit`, + create: `Aanmaken`, + import: `Importeer`, + next: `Volgende`, + print: `Herstel zin afdrukken` + }, + creationType: { + fromGeth: { + label: `Importeer accounts uit Geth keystore` + }, + fromJSON: { + label: `Importeer account uit een opgeslagen JSON file` + }, + fromNew: { + label: `Handmatig account aanmaken` + }, + fromPhrase: { + label: `Herstel account met een herstel zin` + }, + fromPresale: { + label: `Importeer account van een Ethereum voor-verkoop (pre-sale) wallet` + }, + fromRaw: { + label: `Importeer een prive sleutel (raw private key)` + } + }, + newAccount: { + hint: { + hint: `(optioneel) een hint om je te helpen het wachtwoord te herinneren`, + label: `wachtwoord hint` + }, + name: { + hint: `een beschrijvende naam van het account`, + label: `account naam` + }, + password: { + hint: `een sterk en uniek wachtwoord`, + label: `wachtwoord` + }, + password2: { + hint: `bevestig je wachtwoord`, + label: `wachtwoord (herhaal)` + } + }, + newGeth: { + noKeys: `Er zijn momenteel geen importeerbare sleutels (keys) beschikbaar in de Geth keystore; of ze zijn al in je Parity installatie beschikbaar` + }, + newImport: { + file: { + hint: `het te importeren wallet bestand`, + label: `wallet bestand` + }, + hint: { + hint: `(optioneel) een hint om je te helpen het wachtwoord te herinneren`, + label: `wachtwoord hint` + }, + name: { + hint: `een beschrijvende naam van het account`, + label: `account naam` + }, + password: { + hint: `het wachtwoord om je wallet te openen`, + label: `wachtwoord` + } + }, + rawKey: { + hint: { + hint: `(optioneel) een hint om je te helpen het wachtwoord te herinneren`, + label: `wachtwoord hint` + }, + name: { + hint: `een beschrijvende naam van het account`, + label: `account naam` + }, + password: { + hint: `een sterk en uniek wachtwoord`, + label: `wachtwoord` + }, + password2: { + hint: `herhaal je wachtwoord ter controle`, + label: `wachtwoord (herhaling)` + }, + private: { + hint: `de hexadecimaal gecodeerde prive sleutel (raw private key)`, + label: `prive sleutel` + } + }, + recoveryPhrase: { + hint: { + hint: `(optioneel) een hint om je te helpen het wachtwoord te herinneren`, + label: `wachtwoord hint` + }, + name: { + hint: `een beschrijvende naam van het account`, + label: `account naam` + }, + password: { + hint: `een sterk en uniek wachtwoord`, + label: `wachtwoord` + }, + password2: { + hint: `herhaal je wachtwoord ter controle`, + label: `wachtwoord (herhaling)` + }, + phrase: { + hint: `de account herstel zin opgebouwd uit een aantal willekeurige woorden`, + label: `account herstel zin` + }, + windowsKey: { + label: `Sleutel (key) is aangemaakt met Parity <1.4.5 op Windows` + } + }, + title: { + accountInfo: `account informatie`, + createAccount: `account aanmaken`, + createType: `manier van aanmaken`, + importWallet: `importeer wallet` + } +}; diff --git a/js/src/i18n/nl/createWallet.js b/js/src/i18n/nl/createWallet.js new file mode 100644 index 000000000..6acd2e2c8 --- /dev/null +++ b/js/src/i18n/nl/createWallet.js @@ -0,0 +1,105 @@ +// 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 { + button: { + add: `Voeg toe`, + cancel: `Annuleer`, + close: `Sluit`, + create: `Creëer`, + done: `Klaar`, + next: `Volgende`, + sending: `Verzenden...` + }, + deployment: { + message: `Het aanmaken wordt momenteel uitgevoerd` + }, + details: { + address: { + hint: `het wallet contract adres`, + label: `wallet adres` + }, + dayLimitMulti: { + hint: `hoeveelheid ETH die dagelijks kan worden uitgegeven zonder bevestigingen`, + label: `wallet dag limiet` + }, + description: { + hint: `de lokale omschrijving voor dit wallet`, + label: `wallet omschrijving (optioneel)` + }, + descriptionMulti: { + hint: `de lokale omschrijving voor dit wallet`, + label: `wallet omschrijving (optioneel)` + }, + name: { + hint: `de lokale naam voor dit wallet`, + label: `wallet naam` + }, + nameMulti: { + hint: `de lokale naam voor dit wallet`, + label: `wallet naam` + }, + ownerMulti: { + hint: `het eigenaars account van dit contract`, + label: `van account (contract eigenaar)` + }, + ownersMulti: { + label: `andere wallet eigenaren` + }, + ownersMultiReq: { + hint: `vereiste aantal eigenaren om de transactie goed te keuren`, + label: `vereiste eigenaren` + } + }, + info: { + added: `toegevoegd`, + copyAddress: `kopier adres naar klembord`, + created: `{name} is {deployedOrAdded} in`, + dayLimit: `De dag limiet is ingestel op {dayLimit} ETH.`, + deployed: `aangemaakt`, + numOwners: `{numOwners} eigenaren zijn vereist om de transactie goed te keuren.`, + owners: `De wallet eigenaren zijn:` + }, + rejected: { + message: `Het aanmaken is mislukt`, + state: `Je wallet zal niet worden aangemaakt. Je kunt dit venster nu veilig sluiten.`, + title: `mislukt` + }, + states: { + completed: `Het contract is succesvol aangemaakt`, + preparing: `Transactie aan het voorbereiden voor verzending op het netwerk`, + validatingCode: `De contract code van het aangemaakte contract wordt gevalideerd`, + waitingConfirm: `Wachten tot de transactie bevestigd is in de Parity Secure Signer`, + waitingReceipt: `Wachten tot het aanmaken van het contract bevestigd is` + }, + steps: { + deployment: `wallet aanmaken`, + details: `wallet details`, + info: `wallet informatie`, + type: `wallet type` + }, + type: { + multisig: { + description: `Creëer/Maak een {link} Wallet aan`, + label: `Multi-Sig wallet`, + link: `standaard multi-signature` + }, + watch: { + description: `Voeg een bestaand wallet toe aan je accounts`, + label: `Monitor/volg een wallet` + } + } +}; diff --git a/js/src/i18n/nl/dapp.js b/js/src/i18n/nl/dapp.js new file mode 100755 index 000000000..b57a6ca16 --- /dev/null +++ b/js/src/i18n/nl/dapp.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 default { + loading: `Bezig met laden`, + unavailable: `De dapp is niet bereikbaar` +}; diff --git a/js/src/i18n/nl/dapps.js b/js/src/i18n/nl/dapps.js new file mode 100644 index 000000000..3c7cf6d7b --- /dev/null +++ b/js/src/i18n/nl/dapps.js @@ -0,0 +1,46 @@ +// 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 { + add: { + builtin: { + desc: `Experimentele applicaties, ontwikkeld door het Parity team om te demonstreren wat de dapp mogelijkheden, integratie en experimentele opties zijn; en om netwerkbreed client gedrag te controleren.`, + label: `Applicaties gebundeld met Parity` + }, + label: `zichtbare applicaties`, + local: { + desc: `Alle lokaal door de gebruiker geinstalleerde applicaties die toegang hebben tot de Parity client.`, + label: `Lokaal beschikbare applicaties` + }, + network: { + desc: `Deze applicaties zijn niet bij Parity aangesloten, noch worden ze gepubliceerd door Parity. Alle applicaties blijven in beheer van hun eigen auteur. Zorg ervoor dat je snapt wat het doel van een applicatie is, voordat je ermee aan de slag gaat.`, + label: `Applicaties op het wereldwijde netwerk` + } + }, + button: { + edit: `bewerk`, + permissions: `toestemming` + }, + external: { + accept: `Ik begrijp dat deze toepassingen niet bij Parity zijn aangesloten`, + warning: `Deze applicaties gepuliceerd door derde partijen zijn niet bij Parity aangesloten, noch worden ze gepubliceerd door Parity. Alle applicaties blijven in beheer van hun eigen auteur. Zorg ervoor dat je snapt wat het doel van een applicatie is voordat je ermee aan de slag gaat.` + }, + label: `Gedecentraliseerde Applicaties`, + permissions: { + description: `{activeIcon} account is beschikbaar voor applicaties, {defaultIcon} account is het standaard account`, + label: `zichtbare dapp accounts` + } +}; diff --git a/js/src/i18n/nl/deleteAccount.js b/js/src/i18n/nl/deleteAccount.js new file mode 100755 index 000000000..e9e17faed --- /dev/null +++ b/js/src/i18n/nl/deleteAccount.js @@ -0,0 +1,24 @@ +// 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 { + password: { + hint: `Voer ter bevestiging het wachtwoord in om je account te verwijderen`, + label: `account wachtwoord` + }, + question: `Weet je zeker dat je het volgende account permanent wilt verwijderen?`, + title: `bevestig verwijderen` +}; diff --git a/js/src/i18n/nl/deployContract.js b/js/src/i18n/nl/deployContract.js new file mode 100644 index 000000000..478992464 --- /dev/null +++ b/js/src/i18n/nl/deployContract.js @@ -0,0 +1,81 @@ +// 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 { + busy: { + title: `Het contract wordt momenteel aangemaakt` + }, + button: { + cancel: `Annuleer`, + close: `Sluit`, + create: `Creëer`, + done: `Klaar`, + next: `Volgende` + }, + completed: { + description: `Je contract is aangemaakt en opgenomen in` + }, + details: { + abi: { + hint: `de abi van het aan te maken contract of solc combined-output`, + label: `abi / solc combined-output` + }, + address: { + hint: `het account wat eigenaar is van dit contract`, + label: `van account (contract eigenaar)` + }, + code: { + hint: `de gecompileerde code van het aan te maken contract`, + label: `code` + }, + contract: { + label: `selecteer een contract` + }, + description: { + hint: `een beschrijving van het contract`, + label: `contract omschrijving (optioneel)` + }, + name: { + hint: `een naam voor het aangemaakte contract`, + label: `contract naam` + } + }, + owner: { + noneSelected: `er dient een geldig account als contract eigenaar geselecteerd te zijn` + }, + parameters: { + choose: `Kies de contract parameters` + }, + rejected: { + description: `Je kunt dit scherm veilig sluiten, het contract zal niet worden aangemaakt.`, + title: `Het aanmaken van het contract is afgewezen` + }, + state: { + completed: `Het contract is succesvol aangemaakt`, + preparing: `Transactie aan het voorbereiden om te verzenden op het netwerk`, + validatingCode: `De contract code van het aangemaakte contract valideren`, + waitReceipt: `Wachten tot het aanmaken van het contract bevestigd is`, + waitSigner: `Wachten tot de transactie bevestigd is in de Parity Secure Signer` + }, + title: { + completed: `voltooid`, + deployment: `aangemaakt`, + details: `contract details`, + failed: `aanmaken mislukt`, + parameters: `contract parameters`, + rejected: `afgewezen` + } +}; diff --git a/js/src/i18n/nl/details_windows.js b/js/src/i18n/nl/details_windows.js new file mode 100644 index 000000000..fcc570066 --- /dev/null +++ b/js/src/i18n/nl/details_windows.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 `Windows`; diff --git a/js/src/i18n/nl/editMeta.js b/js/src/i18n/nl/editMeta.js new file mode 100644 index 000000000..9ab84af9d --- /dev/null +++ b/js/src/i18n/nl/editMeta.js @@ -0,0 +1,34 @@ +// 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 { + description: { + hint: `omschrijving van dit adres`, + label: `adres omschrijving` + }, + name: { + label: `naam` + }, + passwordHint: { + hint: `een hint om je wachtwoord te herstellen`, + label: `(optioneel) wachtwoord hint` + }, + tags: { + hint: `druk op om een label toe te voegen`, + label: `(optional) labels` + }, + title: `bewerk metadata` +}; diff --git a/js/src/i18n/nl/errors.js b/js/src/i18n/nl/errors.js new file mode 100644 index 000000000..02f7ae6bc --- /dev/null +++ b/js/src/i18n/nl/errors.js @@ -0,0 +1,24 @@ +// 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 { + duplicateName: `deze naam bestaat al`, + invalidKey: `de prive sleutel (raw key) is hexadecimaal, 64 karakters lang en en begint met "0x"`, + noFile: `selecteer een geldig wallet bestand om te importeren`, + noKey: `je dient de prive sleutel (raw private key) in te voeren`, + noMatchPassword: `het ingevoerde wachtwoord is onjuist`, + noName: `je dient een geldige naam voor het account op te geven` +}; diff --git a/js/src/i18n/nl/executeContract.js b/js/src/i18n/nl/executeContract.js new file mode 100644 index 000000000..c11c799ed --- /dev/null +++ b/js/src/i18n/nl/executeContract.js @@ -0,0 +1,58 @@ +// 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 { + busy: { + posted: `Je transactie is op het netwerk gepubliceerd`, + title: `De functie wordt uitgevoerd`, + waitAuth: `Wachten op autorisatie in de Parity Signer` + }, + button: { + cancel: `annuleer`, + done: `klaar`, + next: `volgende`, + post: `verzend transactie`, + prev: `vorige` + }, + details: { + address: { + hint: `van account`, + label: `het account waarmee je de transactie wilt uitvoeren` + }, + advancedCheck: { + label: `geavanceerde verzend opties` + }, + amount: { + hint: `de in deze transactie te verzenden hoeveelheid`, + label: `transactie waarde (in ETH)` + }, + function: { + hint: `de uit het contract aan te roepen functie`, + label: `uit te voeren functie` + } + }, + rejected: { + state: `Je kunt dit venster veilig sluiten, de functie zal niet worden uitgevoerd.`, + title: `De uitvoering is afgewezen` + }, + steps: { + advanced: `geavanceerde opties`, + complete: `voltooi`, + rejected: `afgewezen`, + sending: `verzenden`, + transfer: `functie details` + } +}; diff --git a/js/src/i18n/nl/extension.js b/js/src/i18n/nl/extension.js new file mode 100644 index 000000000..73d765807 --- /dev/null +++ b/js/src/i18n/nl/extension.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 default { + install: `Installeer de extensie nu`, + intro: `Parity heeft nu een extensie voor Chrome beschikbaar waarmee je veillig Ethereum-enabled gedistribueerde applicaties kunt bekijken. Het wordt ten zeerste aanbevolen om deze extensie te installeren om je Parity ervaring nog beter te maken.` +}; diff --git a/js/src/i18n/nl/firstRun.js b/js/src/i18n/nl/firstRun.js new file mode 100755 index 000000000..d182c76e1 --- /dev/null +++ b/js/src/i18n/nl/firstRun.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 . + +export default { + button: { + close: `Sluiten`, + create: `creëer`, + next: `volgende`, + print: `Woorden Afdrukken`, + skip: `Overslaan` + }, + title: { + completed: `voltooid`, + newAccount: `nieuw account`, + recovery: `herstelzin`, + terms: `voorwaarden`, + welcome: `welkom` + } +}; diff --git a/js/src/i18n/nl/home.js b/js/src/i18n/nl/home.js new file mode 100644 index 000000000..4a55894d7 --- /dev/null +++ b/js/src/i18n/nl/home.js @@ -0,0 +1,38 @@ +// 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 { + account: { + visited: `bekeken {when}` + }, + accounts: { + none: `Geen recente account geschiedenis beschikbaar`, + title: `Recente Accounts` + }, + dapp: { + visited: `bekeken {when}` + }, + dapps: { + none: `Geen recente applicatie geschiedenis beschikbaar`, + title: `Recente Dapps` + }, + title: `Parity Home`, + url: { + none: `Geen recente URL geschiedenis beschikbaar`, + title: `Web Applicaties`, + visited: `bezocht {when}` + } +}; diff --git a/js/src/i18n/nl/index.js b/js/src/i18n/nl/index.js old mode 100644 new mode 100755 index 6b50c2d53..281e9974c --- a/js/src/i18n/nl/index.js +++ b/js/src/i18n/nl/index.js @@ -14,8 +14,72 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import account from './account'; +import accounts from './accounts'; +import addAddress from './addAddress'; +import addContract from './addContract'; +import addressSelect from './addressSelect'; +import application from './application'; +import connection from './connection'; +import contract from './contract'; +import createAccount from './createAccount'; +import createWallet from './createWallet'; +import dapp from './dapp'; +import dapps from './dapps'; +import deleteAccount from './deleteAccount'; +import deployContract from './deployContract'; +import editMeta from './editMeta'; +import errors from './errors'; +import executeContract from './executeContract'; +import extension from './extension'; +import firstRun from './firstRun'; +import home from './home'; +import loadContract from './loadContract'; +import parityBar from './parityBar'; +import passwordChange from './passwordChange'; import settings from './settings'; +import shapeshift from './shapeshift'; +import tabBar from './tabBar'; +import transfer from './transfer'; +import txEditor from './txEditor'; +import ui from './ui'; +import upgradeParity from './upgradeParity'; +import vaults from './vaults'; +import walletSettings from './walletSettings'; +import web from './web'; export default { - settings + account, + accounts, + addAddress, + addContract, + addressSelect, + application, + connection, + contract, + createAccount, + createWallet, + dapp, + dapps, + deleteAccount, + deployContract, + editMeta, + errors, + executeContract, + extension, + firstRun, + home, + loadContract, + parityBar, + passwordChange, + settings, + shapeshift, + tabBar, + transfer, + txEditor, + ui, + upgradeParity, + vaults, + walletSettings, + web }; diff --git a/js/src/i18n/nl/loadContract.js b/js/src/i18n/nl/loadContract.js new file mode 100644 index 000000000..fc3f43c3b --- /dev/null +++ b/js/src/i18n/nl/loadContract.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 . + +export default { + button: { + cancel: `Annuleer`, + load: `Laad`, + no: `Nee`, + yes: `Ja` + }, + contract: { + savedAt: `Opgeslagen {when}` + }, + header: { + saved: `Opgeslagen Contracten`, + snippets: `Contract Snippets` + }, + removal: { + confirm: `Weet je zeker dat je het volgende contract van je opgeslagen contracten wilt verwijderen?`, + savedAt: `Opgeslagen {when}` + }, + tab: { + local: `Lokaal`, + snippets: `Snippets` + }, + title: { + remove: `bevestig verwijderen`, + view: `bekijk contracten` + } +}; diff --git a/js/src/i18n/nl/parityBar.js b/js/src/i18n/nl/parityBar.js new file mode 100644 index 000000000..eb10fe569 --- /dev/null +++ b/js/src/i18n/nl/parityBar.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 . + +export default { + button: { + close: `Sluit` + }, + label: { + parity: `Parity`, + signer: `Signer` + }, + title: { + accounts: `Standaard Account`, + signer: `Parity Signer: Wachten` + } +}; diff --git a/js/src/i18n/nl/passwordChange.js b/js/src/i18n/nl/passwordChange.js new file mode 100644 index 000000000..c59e50eed --- /dev/null +++ b/js/src/i18n/nl/passwordChange.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 . + +export default { + button: { + cancel: `Annuleer`, + change: `Wijzig`, + test: `Test`, + wait: `Wacht...` + }, + currentPassword: { + hint: `je huidige wachtwoord voor dit account`, + label: `huidig wachtwoord` + }, + newPassword: { + hint: `het nieuwe wachtwoord vor dit account`, + label: `nieuw wachtwoord` + }, + passwordHint: { + hint: `hint voor het nieuwe wachtwoord`, + label: `(optioneel) nieuwe wachtwoord hint` + }, + repeatPassword: { + error: `de ingevoerde wachtwoorden zijn niet gelijk`, + hint: `herhaal het nieuwe wachtwoord voor dit account`, + label: `herhaal nieuw wachtwoord` + }, + success: `Je wachtwoord is succesvol aangepast`, + tabChange: { + label: `Wijzig wachtwoord` + }, + tabTest: { + label: `Test wachtwoord` + }, + testPassword: { + hint: `je account wachtwoord`, + label: `wachtwoord` + }, + title: `Wachtwoord Manager` +}; diff --git a/js/src/i18n/nl/settings.js b/js/src/i18n/nl/settings.js index 9240859ad..81f485696 100644 --- a/js/src/i18n/nl/settings.js +++ b/js/src/i18n/nl/settings.js @@ -15,49 +15,75 @@ // along with Parity. If not, see . export default { - label: 'Instellingen', - background: { - label: 'Achtergrond' + button_more: `genereer meer`, + overview_0: `Het achtergrond patroon dat je nu kunt zien is uniek voor jouw Parity installatie. Het veranderd elke keer als je een nieuw Signer token genereerd. Op deze manier kunnen gedecentraliseerde applicaties niet doen alsof ze betrouwbaar zijn.`, + overview_1: `Kies het patroon dat je wilt en onthoud het. Dit patroon wordt vanaf nu altijd getoond, tenzij je je browser cache wist of een nieuw Signer token genereerd.`, + label: `achtergrond` }, - parity: { - label: 'Parity' + languages: { + hint: `de taal waarin deze interface wordt weergegeven`, + label: `Weergave taal` + }, + loglevels: `Kies hoeveel details er in het logboek worden bijgehouden.`, + modes: { + hint: `de synchronisatie modus van de Parity node`, + label: `Synchronisatie modus`, + mode_active: `Parity synchroniseert de chain continu`, + mode_dark: `Parity synchroniseert alleen als de RPC actief is`, + mode_offline: `Parity synchroniseert niet`, + mode_passive: `Parity synchroniseert in het begin. Daarna slaapt Parity en wordt regelmatig wakker voor synchronisatie` + }, + overview_0: `Pas de Parity node instellingen aan en kies de synchronisatie modus in dit menu.`, + label: `parity` }, - proxy: { - label: 'Proxy' + details_0: `In plaats van Parity te openen via het IP adres en poort-nummer, kun je toegang verkrijgen tot het .parity sub-domein door {homeProxy} te bezoeken. Om sub-domein gebaseerde routing in te stellen, dien je de proxy vermelding aan je browser proxy instellingen toe te voegen,`, + details_1: `Om je te helpen met het configureren van je proxy, zijn er instructies beschikbaar voor {windowsLink}, {macOSLink} or {ubuntuLink}.`, + details_macos: `macOS`, + details_ubuntu: `Ubuntu`, + details_windows: `Windows`, + overview_0: `Met de proxy instellingen heb je de mogelijkheid om via een makkelijk te onthouden adres toegang te verkrijgen tot Parity en alle onderliggende decentrale applicaties.`, + label: `proxy` }, - views: { - label: 'Weergaven', - accounts: { - label: 'Accounts' + description: `Een overzicht van alle aan deze Parity installatie verbonden accounts, inclusief geimporteerde accounts. Verzend transacties, ontvang inkomende transacties, berheer je saldo en financier je accounts.`, + label: `Accounts` }, - addresses: { - label: 'Adresboek' + description: `Een overzicht van alle contacten en adresboek items die door deze Parity installatie worden beheerd. Monitor en volg accounts waarbij je transactie details met slechts een muisklik kunt weergeven.`, + label: `Adresboek` }, - apps: { - label: 'Applicaties' + description: `Gedistibueerde applicaties die gebruik maken van het onderliggende Ethereum netwerk. Voeg applicaties toe, beheer je applicatie portfolio en maak gebruik van applicaties op het wereldwijde netwerk.`, + label: `Applicaties` }, - contracts: { - label: 'Contracten' + description: `Monitor, volg en maak gebruik van specifieke contracten die op het netwerk zijn gezet. Dit is een meer technisch gerichte omgeving, voornamelijk bedoeld voor geavanceerde gebruikers die de werking van bepaalde contracten goed begrijpen.`, + label: `Contracten` }, - - status: { - label: 'Status' - }, - - signer: { - label: 'Signer' - }, - + overview_0: `Beheer de beschikbare weergaven van deze interface en selecteer enkel de delen van de applicatie die voor jou van belang zijn.`, + overview_1: `Ben je een eind gebruiker? De standaard instellingen zijn geschikt voor zowel beginners als gevorderde gebruikers.`, + overview_2: `Ben je een ontwikkelaar? Voeg enkele functies toe om je contracten te beheren en gebruik te maken van gedecentraliseerde applicaties.`, + overview_3: `Ben je een miner of run je een grootschalige node? Voeg enkele functies toe om je alle informatie te geven die je nodig hebt om je node te monitoren.`, settings: { - label: 'Instellingen' + description: `Deze weergave. Hiermee kun je Parity aan passen in termen van opties, bediening en look en feel.`, + label: `Instellingen` + }, + signer: { + description: `Het beveiligde transactie beheergebied van de applicatie waar je elke uitgaande transactie die je hebt gemaakt met Parity evenals de transacties die in de wachtrij zijn geplaatst door gedistribueerde applicaties kan goedkeuren.`, + label: `Signer` + }, + status: { + description: `Volg hoe de Parity node zijn werk doet en je verbind met het netwerk en bekijk de logboeken van de momenteel draaiende node met mining details (indien geconfigureerd en ingeschakeld).`, + label: `Status` + }, + label: `weergaven`, + home: { + label: `Thuis` } - } + }, + label: `instellingen` }; diff --git a/js/src/i18n/nl/shapeshift.js b/js/src/i18n/nl/shapeshift.js new file mode 100755 index 000000000..caa28adaf --- /dev/null +++ b/js/src/i18n/nl/shapeshift.js @@ -0,0 +1,66 @@ +// 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 { + awaitingDepositStep: { + awaitingConfirmation: `Wachten tot bevestigd is dat je {typeSymbol} storting op het account van het wisselkantoor is aangekomen.`, + awaitingDeposit: `{shapeshiftLink} is aan het wachten op {typeSymbol} storting. Verzend de valuta vanuit je {typeSymbol} netwerk client naar -`, + minimumMaximum: `{minimum} minimum, {maximum} maximum` + }, + awaitingExchangeStep: { + awaitingCompletion: `Wachten op de voltooiing van het omwisselen van de valuta en op de overschrijving van de valuta naar je Parity account.`, + receivedInfo: `{shapeshiftLink} heeft een storting ontvangen van -` + }, + button: { + cancel: `Annuleer`, + done: `Sluit`, + shift: `Wissel valuta om` + }, + completedStep: { + completed: `{shapeshiftLink} heeft het omwisselen van de valuta voltooid.`, + parityFunds: `De saldo wijziging zal spoedig in je Parity client worden weergegeven.` + }, + errorStep: { + info: `Het omwisselen van de valuta via {shapeshiftLink} is mislukt door een fout bij het wisselkantoor. De ontvangen foutmelding van het wisselkantoor is als volgt:` + }, + optionsStep: { + noPairs: `Er is momenteel geen wisselkoers voor het valuta-paar beschikbaar om de transactie mee uit te voeren.`, + returnAddr: { + hint: `het retouradres voor wanneer het verzenden mislukt`, + label: `(optioneel) {coinSymbol} retouradres` + }, + terms: { + label: `Ik begrijp dat ShapeShift.io een dienst is van een derde partij en dat bij gebruik van deze service de overdracht van informatie en/of financiele middelen volledig buiten het beheer van Parity vallen` + }, + typeSelect: { + hint: `het type crypto valuta om te wisselen`, + label: `verzend naar account vanuit` + } + }, + price: { + minMax: `({minimum} minimum, {maximum} maximum)` + }, + title: { + completed: `voltooid`, + deposit: `wachten op storting`, + details: `details`, + error: `omwisselen mislukt`, + exchange: `wachten op omwisselen` + }, + warning: { + noPrice: `Geen prijs gevonden voor het gekozen type` + } +}; diff --git a/js/src/i18n/nl/tabBar.js b/js/src/i18n/nl/tabBar.js new file mode 100644 index 000000000..ae1cb1c52 --- /dev/null +++ b/js/src/i18n/nl/tabBar.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 . + +export default { + tooltip: { + overview: `navigeer tussen de verschillende onderdelen en weergaven in de applicatie, wissel tussen de account weergave, token weergave en gedistribueerde applicatie weergave` + } +}; diff --git a/js/src/i18n/nl/transfer.js b/js/src/i18n/nl/transfer.js new file mode 100644 index 000000000..1370711b4 --- /dev/null +++ b/js/src/i18n/nl/transfer.js @@ -0,0 +1,27 @@ +// 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 { + advanced: { + data: { + hint: `de data om door te geven met de transactie`, + label: `transactie data` + } + }, + warning: { + wallet_spent_limit: `Deze transactie waarde is boven de toegestane dag limiet en zal moeten worden bevestigd door andere eigenaren.` + } +}; diff --git a/js/src/i18n/nl/txEditor.js b/js/src/i18n/nl/txEditor.js new file mode 100644 index 000000000..2cf0b2bbd --- /dev/null +++ b/js/src/i18n/nl/txEditor.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 . + +export default { + condition: { + block: { + hint: `Het minimum blok voor het verzenden`, + label: `Transactie verzend blok` + }, + blocknumber: `Verzend na bloknummer`, + date: { + hint: `De minimale datum voor het verzenden`, + label: `Transactie verzend datum` + }, + datetime: `Verzend na datum & tijdstip`, + label: `Conditie waarbij transactie activeert`, + none: `Geen condities`, + time: { + hint: `Het minimale tijdstip voor het verzenden`, + label: `Transactie verzend tijdstip` + } + }, + gas: { + info: `Je kunt de gas prijs kiezen op basis van de gas prijs van de transacties die recentelijk in de blokken werden opgenomen. Een lagere gas prijs betekend een goedkopere transactie. Een hogere gas prijs betekend dat je transactie sneller in een blok wordt opgenomen.` + } +}; diff --git a/js/src/i18n/nl/ui.js b/js/src/i18n/nl/ui.js new file mode 100644 index 000000000..c0454e9f6 --- /dev/null +++ b/js/src/i18n/nl/ui.js @@ -0,0 +1,84 @@ +// 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 { + balance: { + none: `Er zijn geen tegoeden gekoppeld aan dit account` + }, + blockStatus: { + bestBlock: `{blockNumber} beste blok`, + syncStatus: `{currentBlock}/{highestBlock} synchroniseren`, + warpRestore: `{percentage}% warp restore`, + warpStatus: `, {percentage}% historic` + }, + confirmDialog: { + no: `nee`, + yes: `ja` + }, + identityName: { + null: `NUL`, + unnamed: `NAAMLOOS` + }, + passwordStrength: { + label: `wachtwoord sterkte` + }, + tooltips: { + button: { + done: `Klaar`, + next: `Volgende`, + skip: `Overslaan` + } + }, + txHash: { + confirmations: `{count} {value, plural, one {confirmation} other {confirmations}}`, + oog: `De transactie heeft misschien al zijn gas verbruikt. Probeer het opnieuw met meer gas.`, + posted: `De transactie is op het netwerk geplaatst met hash {hashLink}`, + waiting: `wachten op bevestigingen` + }, + verification: { + gatherData: { + accountHasRequested: { + false: `Je hebt nog geen verificatie aangevraagd voor dit account.`, + pending: `Aan het controleren of je verificatie hebt aangevraagd…`, + true: `Je hebt al verificatie aangevraagd voor dit account.` + }, + accountIsVerified: { + false: `Je account is nog niet geverifieerd`, + pending: `Aan het controleren of je account is geverifieerd…`, + true: `Je account is al geverifieerd.` + }, + email: { + hint: `de code zal naar dit adres worden verzonden`, + label: `e-mail adres` + }, + fee: `De extra vergoeding is {amount} ETH.`, + isAbleToRequest: { + pending: `Valideren van je invoer…` + }, + isServerRunning: { + false: `De verificatie server is niet actief.`, + pending: `Controleren of de verificatie server actief is…`, + true: `De verificatie server is actief.` + }, + nofee: `Er zijn geen extra kosten.`, + phoneNumber: { + hint: `De SMS zal naar dit nummer worden verstuurd`, + label: `telefoonnummer in internationaal formaat` + }, + termsOfService: `Ik ga akkoord met de voorwaarden en condities hieronder.` + } + } +}; diff --git a/js/src/i18n/nl/upgradeParity.js b/js/src/i18n/nl/upgradeParity.js new file mode 100644 index 000000000..c057c9e7d --- /dev/null +++ b/js/src/i18n/nl/upgradeParity.js @@ -0,0 +1,44 @@ +// 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 { + busy: `Parity wordt momenteel bijgewerkt naar versie {newversion}`, + button: { + close: `sluiten`, + done: `klaar`, + upgrade: `werk nu bij` + }, + completed: `Het bijwerken naar Parity {newversion} is succesvol voltooid.`, + consensus: { + capable: `Je huidige versie van Parity voldoet aan de netwerk vereisten.`, + capableUntil: `Je huidige versie van Parity voldoet aan de netwerk vereisten tot aan blok {blockNumber}`, + incapableSince: `Je huidige versie van Parity voldoet aan de netwerk vereisten vanaf blok {blockNumber}`, + unknown: `Je huidige versie van Parity voldoet aan de netwerk vereisten.` + }, + failed: `Het bijwerken naar Parity {newversion} gaf een fout en is mislukt.`, + info: { + upgrade: `Een nieuwe versie van Parity, version {newversion} is beschikbaar als upgrade vanaf je huidige versie {currentversion}` + }, + step: { + completed: `bijwerken voltooid`, + error: `fout`, + info: `nieuwe versie beschikbaar`, + updating: `Parity bijwerken` + }, + version: { + unknown: `onbekend` + } +}; diff --git a/js/src/i18n/nl/vaults.js b/js/src/i18n/nl/vaults.js new file mode 100644 index 000000000..b16c6807e --- /dev/null +++ b/js/src/i18n/nl/vaults.js @@ -0,0 +1,75 @@ +// 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 { + accounts: { + button: { + cancel: `Annuleer`, + execute: `Stel in` + }, + empty: `Er zitten geen accounts in deze kluis`, + title: `Beheer Kluis Accounts` + }, + button: { + accounts: `accounts`, + add: `Maak kluis`, + close: `sluit kluis`, + open: `open kluis` + }, + confirmClose: { + info: `Je staat op het punt op een kluis te sluiten. Alle aan deze kluis verbonden accounts zullen niet meer zichtbaar zijn na het voltooien van deze actie. Om deze accounts weer zichtbaar te maken dien je de kluis weer te openen.`, + title: `Sluit Kluis` + }, + confirmOpen: { + info: `Je staat op het punt om een kluis te openen. Na de bevestiging met je wachtwoord zullen alle aan deze kluis verbonden account zichtbaar worden. Wanneer je de kluis weer sluit zullen deze accounts weer onzichtbaar worden, tot je de kluis weer opent.`, + password: { + hint: `het wachtwoord wat je hebt gekozen bij het aanmaken van de kluis`, + label: `kluis wachtwoord` + }, + title: `Open Kluis` + }, + create: { + button: { + close: `sluit`, + vault: `maak kluis` + }, + description: { + hint: `een uitgebereide omschrijving voor de kluis` + }, + descriptions: { + label: `(optioneel) omschrijving` + }, + hint: { + hint: `(optioneel) een hint om je het wachtwoord te helpen herinneren`, + label: `wachtwoord hint` + }, + name: { + hint: `een naam voor de kluis`, + label: `kluis naam` + }, + password: { + hint: `een sterk en uniek wachtwoord`, + label: `wachtwoord` + }, + password2: { + hint: `verifieer je wachtwoord`, + label: `wachtwoord (herhaal)` + }, + title: `Maak een nieuwe kluis aan` + }, + empty: `Er zijn momenteel geen kluizen om weer tegeven.`, + title: `Kluis Beheer` +}; diff --git a/js/src/i18n/nl/walletSettings.js b/js/src/i18n/nl/walletSettings.js new file mode 100644 index 000000000..ca0842944 --- /dev/null +++ b/js/src/i18n/nl/walletSettings.js @@ -0,0 +1,57 @@ +// 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 { + changes: { + modificationString: `Om je wijzigingen door te voeren zullen + andere eigenaren deze zelfde wijzigingen moeten verzenden. Om het + makkelijk te maken kunnen ze deze string kopieren-plakken:`, + none: `Er zijn van deze Wallet geen instellingen gewijzigd.`, + overview: `Je staat op het punt om de volgende wijzignen te maken` + }, + edit: { + message: `Om de instellingen van dit contract de wijzigen zullen + minimaal {owners, number} {owners, plural, one {owner } other {owners }} precies dezelfde + wijzigingen moeten verzenden. Je kunt hier de wijzigingen in string-vorm plakken.` + }, + modifications: { + daylimit: { + hint: `hoeveelheid uit te geven ETH zonder bevestiging met wachtwoord`, + label: `wallet dag limiet` + }, + fromString: { + label: `wijzigingen` + }, + owners: { + label: `andere wallet eigenaren` + }, + required: { + hint: `vereiste aantal eigenaren om een transactie goed te keuren`, + label: `vereiste eigenaren` + }, + sender: { + hint: `verzend wijzigingen als deze eigenaar`, + label: `van account (wallet eigenaar)` + } + }, + rejected: { + busyStep: { + state: `De wallet instellingen zullen niet worden gewijzigd. Je kunt dit venster veilig sluiten.`, + title: `De wijzigingen zijn afgewezen.` + }, + title: `afgewezen` + } +}; diff --git a/js/src/i18n/nl/web.js b/js/src/i18n/nl/web.js new file mode 100644 index 000000000..359d95615 --- /dev/null +++ b/js/src/i18n/nl/web.js @@ -0,0 +1,19 @@ +// 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 { + requestToken: `Aanvragen toegangs token...` +}; diff --git a/js/src/index.ejs b/js/src/index.ejs index 590070e8b..ec8592b88 100644 --- a/js/src/index.ejs +++ b/js/src/index.ejs @@ -6,12 +6,15 @@ <%= htmlWebpackPlugin.options.title %>