├── crypto ├── src │ ├── json │ │ └── mod.rs │ └── groth16.rs └── Cargo.toml ├── rpc ├── src │ ├── v1 │ │ ├── helpers │ │ │ └── mod.rs │ │ ├── types │ │ │ ├── get_tx_out_set_info_response.rs │ │ │ ├── mod.rs │ │ │ ├── block.rs │ │ │ ├── nodes.rs │ │ │ ├── address.rs │ │ │ └── uint.rs │ │ ├── traits │ │ │ ├── mod.rs │ │ │ ├── miner.rs │ │ │ └── network.rs │ │ ├── impls │ │ │ └── mod.rs │ │ └── mod.rs │ ├── lib.rs │ └── rpc_server.rs └── Cargo.toml ├── tools ├── bench.sh ├── docker_build.sh ├── workspace.diff ├── doc.sh ├── graph_ratio.diff ├── draw_graph.sh ├── regtests.sh ├── clippy.sh ├── deb-build.sh └── deb_build.sh ├── keys ├── src │ ├── network.rs │ ├── display.rs │ ├── generator.rs │ ├── lib.rs │ ├── error.rs │ └── signature.rs └── Cargo.toml ├── .gitmodules ├── message ├── src │ ├── serialization │ │ ├── mod.rs │ │ ├── stream.rs │ │ └── reader.rs │ ├── message │ │ ├── mod.rs │ │ ├── payload.rs │ │ ├── message.rs │ │ └── message_header.rs │ ├── common │ │ ├── block_transactions.rs │ │ ├── block_header_and_ids.rs │ │ ├── mod.rs │ │ ├── prefilled_transaction.rs │ │ ├── block_transactions_request.rs │ │ ├── port.rs │ │ ├── service.rs │ │ └── address.rs │ ├── types │ │ ├── verack.rs │ │ ├── getaddr.rs │ │ ├── mempool.rs │ │ ├── filterclear.rs │ │ ├── sendheaders.rs │ │ ├── blocktxn.rs │ │ ├── getblocktxn.rs │ │ ├── ping.rs │ │ ├── pong.rs │ │ ├── filteradd.rs │ │ ├── block.rs │ │ ├── feefilter.rs │ │ ├── tx.rs │ │ ├── notfound.rs │ │ ├── inv.rs │ │ ├── getdata.rs │ │ ├── getblocks.rs │ │ ├── merkle_block.rs │ │ ├── getheaders.rs │ │ ├── mod.rs │ │ ├── reject.rs │ │ ├── headers.rs │ │ └── filterload.rs │ ├── lib.rs │ └── error.rs └── Cargo.toml ├── pzec ├── commands │ ├── mod.rs │ ├── import.rs │ └── rollback.rs ├── seednodes.rs ├── util.rs ├── rpc_apis.rs ├── main.rs └── rpc.rs ├── storage ├── src │ ├── nullifier_tracker.rs │ ├── block_ref.rs │ ├── best_block.rs │ ├── error.rs │ ├── block_iterator.rs │ ├── tree_state_provider.rs │ ├── block_ancestors.rs │ ├── block_origin.rs │ ├── block_impls.rs │ ├── block_provider.rs │ ├── block_chain.rs │ ├── duplex_store.rs │ └── store.rs └── Cargo.toml ├── primitives ├── src │ └── lib.rs └── Cargo.toml ├── logs ├── Cargo.toml └── src │ └── lib.rs ├── p2p ├── src │ ├── event_loop.rs │ ├── util │ │ ├── nonce.rs │ │ ├── mod.rs │ │ ├── peer.rs │ │ ├── time.rs │ │ ├── interval.rs │ │ ├── internet_protocol.rs │ │ └── response_queue.rs │ ├── net │ │ ├── connection.rs │ │ ├── mod.rs │ │ ├── channel.rs │ │ ├── config.rs │ │ ├── accept_connection.rs │ │ ├── connect.rs │ │ └── connections.rs │ ├── io │ │ ├── write_message.rs │ │ ├── mod.rs │ │ ├── deadline.rs │ │ ├── sharedtcpstream.rs │ │ ├── read_header.rs │ │ └── read_payload.rs │ ├── config.rs │ ├── protocol │ │ └── mod.rs │ └── lib.rs └── Cargo.toml ├── db ├── src │ ├── kv │ │ ├── db.rs │ │ ├── mod.rs │ │ ├── cachedb.rs │ │ └── overlaydb.rs │ └── lib.rs └── Cargo.toml ├── serialization ├── Cargo.toml └── src │ ├── lib.rs │ ├── list.rs │ ├── fixed_array.rs │ └── stream.rs ├── .gitignore ├── import ├── Cargo.toml └── src │ ├── lib.rs │ ├── block.rs │ ├── blk.rs │ └── fs.rs ├── test-data ├── src │ └── invoke.rs └── Cargo.toml ├── .editorconfig ├── .dockerignore ├── serialization_derive ├── Cargo.toml ├── src │ ├── lib.rs │ └── de.rs └── tests │ └── raw.rs ├── network ├── Cargo.toml └── src │ ├── lib.rs │ └── deployments.rs ├── chain ├── Cargo.toml └── src │ ├── read_and_hash.rs │ ├── constants.rs │ ├── solution.rs │ ├── lib.rs │ ├── indexed_header.rs │ ├── merkle_root.rs │ ├── indexed_transaction.rs │ └── indexed_block.rs ├── snap └── snapcraft.yaml ├── script ├── Cargo.toml └── src │ └── lib.rs ├── bencher ├── Cargo.toml └── src │ └── main.rs ├── miner ├── Cargo.toml └── src │ └── lib.rs ├── verification ├── Cargo.toml └── src │ ├── constants.rs │ ├── timestamp.rs │ ├── sigops.rs │ ├── verify_chain.rs │ ├── tree_cache.rs │ ├── canon.rs │ └── accept_chain.rs ├── sync ├── Cargo.toml └── src │ ├── utils │ ├── mod.rs │ ├── fee_rate_filter.rs │ ├── synchronization_state.rs │ └── average_speed_meter.rs │ ├── inbound_connection_factory.rs │ └── types.rs ├── Cargo.toml ├── .travis.yml └── CLI.md /crypto/src/json/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod groth16; 2 | pub mod pghr13; 3 | -------------------------------------------------------------------------------- /rpc/src/v1/helpers/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod errors; 3 | -------------------------------------------------------------------------------- /tools/bench.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cargo run --manifest-path ./bencher/Cargo.toml --release 3 | -------------------------------------------------------------------------------- /keys/src/network.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Clone, Copy)] 2 | pub enum Network { 3 | Mainnet, 4 | Testnet, 5 | } 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tools/compare-tool"] 2 | path = tools/compare-tool 3 | url = https://github.com/theuni/bitcoind-comparisontool 4 | -------------------------------------------------------------------------------- /rpc/src/v1/types/get_tx_out_set_info_response.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Serialize, Deserialize)] 2 | pub struct GetTxOutSetInfoResponse { 3 | } 4 | -------------------------------------------------------------------------------- /message/src/serialization/mod.rs: -------------------------------------------------------------------------------- 1 | mod stream; 2 | mod reader; 3 | 4 | pub use self::stream::serialize_payload; 5 | pub use self::reader::deserialize_payload; 6 | -------------------------------------------------------------------------------- /pzec/commands/mod.rs: -------------------------------------------------------------------------------- 1 | mod import; 2 | mod start; 3 | mod rollback; 4 | 5 | pub use self::import::import; 6 | pub use self::start::start; 7 | pub use self::rollback::rollback; -------------------------------------------------------------------------------- /storage/src/nullifier_tracker.rs: -------------------------------------------------------------------------------- 1 | use EpochRef; 2 | 3 | /// Trait to query existing nullifier. 4 | pub trait NullifierTracker : Sync { 5 | fn contains_nullifier(&self, nullifier: EpochRef) -> bool; 6 | } 7 | -------------------------------------------------------------------------------- /message/src/message/mod.rs: -------------------------------------------------------------------------------- 1 | mod message; 2 | mod message_header; 3 | pub mod payload; 4 | 5 | pub use self::message::{Message, to_raw_message}; 6 | pub use self::message_header::MessageHeader; 7 | pub use self::payload::Payload; 8 | -------------------------------------------------------------------------------- /primitives/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | #[macro_use] 3 | extern crate heapsize; 4 | extern crate rustc_hex as hex; 5 | pub extern crate bigint; 6 | 7 | pub mod bytes; 8 | pub mod compact; 9 | pub mod hash; 10 | -------------------------------------------------------------------------------- /logs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "logs" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | ansi_term = "0.11" 8 | log = "0.4" 9 | env_logger = "0.5" 10 | time = "0.1" 11 | -------------------------------------------------------------------------------- /p2p/src/event_loop.rs: -------------------------------------------------------------------------------- 1 | use futures::{empty, Empty}; 2 | use tokio_core::reactor::Core; 3 | 4 | pub fn event_loop() -> Core { 5 | Core::new().unwrap() 6 | } 7 | 8 | pub fn forever() -> Empty<(), ()> { 9 | empty() 10 | } 11 | -------------------------------------------------------------------------------- /rpc/src/v1/traits/mod.rs: -------------------------------------------------------------------------------- 1 | mod blockchain; 2 | mod miner; 3 | mod raw; 4 | mod network; 5 | 6 | pub use self::blockchain::BlockChain; 7 | pub use self::miner::Miner; 8 | pub use self::raw::Raw; 9 | pub use self::network::Network; 10 | -------------------------------------------------------------------------------- /db/src/kv/db.rs: -------------------------------------------------------------------------------- 1 | use kv::{Transaction, KeyState, Key, Value}; 2 | 3 | pub trait KeyValueDatabase: Send + Sync { 4 | fn write(&self, tx: Transaction) -> Result<(), String>; 5 | 6 | fn get(&self, key: &Key) -> Result, String>; 7 | } 8 | -------------------------------------------------------------------------------- /message/src/common/block_transactions.rs: -------------------------------------------------------------------------------- 1 | use hash::H256; 2 | use chain::Transaction; 3 | 4 | #[derive(Debug, PartialEq, Serializable, Deserializable)] 5 | pub struct BlockTransactions { 6 | pub blockhash: H256, 7 | pub transactions: Vec, 8 | } 9 | -------------------------------------------------------------------------------- /serialization/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serialization" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | byteorder = "1.0" 8 | primitives = { path = "../primitives" } 9 | rustc-hex = "2" 10 | -------------------------------------------------------------------------------- /tools/docker_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd docker/hub 4 | if [ "$1" == "latest" ]; then DOCKER_BUILD_TAG="beta-release"; fi 5 | docker build --build-arg BUILD_TAG=$DOCKER_BUILD_TAG --no-cache=true --tag $2/pbtc-ubuntu:$1 . 6 | docker push $2/pbtc-ubuntu:$1 7 | -------------------------------------------------------------------------------- /keys/src/display.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Deref; 2 | use Error; 3 | 4 | pub trait DisplayLayout { 5 | type Target: Deref; 6 | 7 | fn layout(&self) -> Self::Target; 8 | 9 | fn from_layout(data: &[u8]) -> Result where Self: Sized; 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | *.swp 6 | *.swo 7 | *.swn 8 | *.DS_Store 9 | 10 | # Visual Studio Code stuff 11 | /.vscode 12 | 13 | # GitEye stuff 14 | /.project 15 | 16 | # idea ide 17 | .idea 18 | -------------------------------------------------------------------------------- /p2p/src/util/nonce.rs: -------------------------------------------------------------------------------- 1 | use rand; 2 | 3 | pub trait NonceGenerator { 4 | fn get(&self) -> u64; 5 | } 6 | 7 | #[derive(Default)] 8 | pub struct RandomNonce; 9 | 10 | impl NonceGenerator for RandomNonce { 11 | fn get(&self) -> u64 { 12 | rand::random() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /primitives/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "primitives" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | heapsize = "0.4" 8 | rustc-hex = "2" 9 | byteorder = "1.0" 10 | bigint = "4" 11 | 12 | [features] 13 | default = ["bigint/std"] 14 | -------------------------------------------------------------------------------- /tools/workspace.diff: -------------------------------------------------------------------------------- 1 | diff --git Cargo.toml Cargo.toml 2 | index fca51d5..6a16dd6 100644 3 | --- Cargo.toml 4 | +++ Cargo.toml 5 | @@ -24,3 +24,6 @@ import = { path = "import" } 6 | [[bin]] 7 | path = "pbtc/main.rs" 8 | name = "pbtc" 9 | + 10 | +[workspace] 11 | +members = ["bencher"] 12 | -------------------------------------------------------------------------------- /import/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "import" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | log = "0.4" 8 | primitives = { path = "../primitives" } 9 | chain = { path = "../chain" } 10 | serialization = { path = "../serialization" } 11 | -------------------------------------------------------------------------------- /test-data/src/invoke.rs: -------------------------------------------------------------------------------- 1 | //! invoke helper 2 | 3 | pub trait Invoke { 4 | type Result; 5 | 6 | fn invoke(self, arg: A) -> Self::Result; 7 | } 8 | 9 | pub struct Identity; 10 | 11 | impl Invoke for Identity { 12 | type Result = A; 13 | 14 | fn invoke(self, arg: A) -> A { arg } 15 | } 16 | -------------------------------------------------------------------------------- /pzec/seednodes.rs: -------------------------------------------------------------------------------- 1 | pub fn zcash_seednodes() -> Vec<&'static str> { 2 | vec![ 3 | "dnsseed.z.cash:8233", 4 | "dnsseed.str4d.xyz:8233", 5 | "dnsseed.znodes.org:8233", 6 | ] 7 | } 8 | 9 | pub fn zcash_testnet_seednodes() -> Vec<&'static str> { 10 | vec![ 11 | "dnsseed.testnet.z.cash:18233", 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=tab 4 | indent_size=tab 5 | tab_width=4 6 | end_of_line=lf 7 | charset=utf-8 8 | trim_trailing_whitespace=true 9 | max_line_length=120 10 | insert_final_newline=true 11 | 12 | [.travis.yml] 13 | indent_style=space 14 | indent_size=2 15 | tab_width=8 16 | end_of_line=lf 17 | -------------------------------------------------------------------------------- /rpc/src/v1/impls/mod.rs: -------------------------------------------------------------------------------- 1 | mod blockchain; 2 | mod miner; 3 | mod raw; 4 | mod network; 5 | 6 | pub use self::blockchain::{BlockChainClient, BlockChainClientCore}; 7 | pub use self::miner::{MinerClient, MinerClientCore}; 8 | pub use self::raw::{RawClient, RawClientCore}; 9 | pub use self::network::{NetworkClient, NetworkClientCore}; 10 | -------------------------------------------------------------------------------- /import/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Bitcoind blockchain database importer 2 | 3 | #[macro_use] 4 | extern crate log; 5 | extern crate primitives; 6 | extern crate serialization as ser; 7 | extern crate chain; 8 | 9 | mod blk; 10 | mod block; 11 | mod fs; 12 | 13 | pub use primitives::{hash, bytes}; 14 | 15 | pub use blk::{open_blk_dir, BlkDir}; 16 | -------------------------------------------------------------------------------- /tools/doc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cargo doc --no-deps\ 4 | -p bitcrypto\ 5 | -p chain\ 6 | -p db\ 7 | -p import\ 8 | -p keys\ 9 | -p message\ 10 | -p miner\ 11 | -p network\ 12 | -p pzec\ 13 | -p p2p\ 14 | -p primitives\ 15 | -p rpc\ 16 | -p script\ 17 | -p serialization\ 18 | -p sync\ 19 | -p test-data\ 20 | -p verification 21 | -------------------------------------------------------------------------------- /tools/graph_ratio.diff: -------------------------------------------------------------------------------- 1 | diff --git tools/graph.dot tools/graph.dot 2 | index f842267..1a831d2 100644 3 | --- tools/graph.dot 4 | +++ tools/graph.dot 5 | @@ -1,4 +1,6 @@ 6 | digraph dependencies { 7 | + ratio=1.0; 8 | + size="5,5"; 9 | N0[label="pbtc",shape=box]; 10 | N1[label="app_dirs",shape=box]; 11 | N2[label="bencher",shape=box]; 12 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | target 4 | 5 | *.swp 6 | *.swo 7 | *.swn 8 | *.DS_Store 9 | 10 | # Visual Studio Code stuff 11 | .vscode 12 | 13 | # GitEye stuff 14 | .project 15 | 16 | # idea ide 17 | .idea 18 | 19 | # git stuff 20 | .git 21 | 22 | # ignore compare tools 23 | tools/compare-tool 24 | -------------------------------------------------------------------------------- /serialization_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serialization_derive" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [lib] 7 | name = "serialization_derive" 8 | proc-macro = true 9 | 10 | [dependencies] 11 | syn = "0.11.11" 12 | quote = "0.3.15" 13 | 14 | [dev-dependencies] 15 | serialization = { path = "../serialization" } 16 | -------------------------------------------------------------------------------- /storage/src/block_ref.rs: -------------------------------------------------------------------------------- 1 | use hash::H256; 2 | 3 | #[derive(Debug, Clone)] 4 | pub enum BlockRef { 5 | Number(u32), 6 | Hash(H256), 7 | } 8 | 9 | impl From for BlockRef { 10 | fn from(u: u32) -> Self { 11 | BlockRef::Number(u) 12 | } 13 | } 14 | 15 | impl From for BlockRef { 16 | fn from(hash: H256) -> Self { 17 | BlockRef::Hash(hash) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test-data/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-data" 3 | version = "0.1.0" 4 | authors = ["Nikolay Volf "] 5 | 6 | [dependencies] 7 | time = "0.1" 8 | 9 | chain = { path = "../chain" } 10 | network = { path = "../network" } 11 | primitives = { path = "../primitives" } 12 | serialization = { path = "../serialization" } 13 | script = { path = "../script" } 14 | -------------------------------------------------------------------------------- /keys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "keys" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | rand = "0.4" 8 | rustc-hex = "2" 9 | lazy_static = "1.0" 10 | base58 = "0.1" 11 | eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" } 12 | bitcrypto = { path = "../crypto" } 13 | primitives = { path = "../primitives" } 14 | -------------------------------------------------------------------------------- /p2p/src/net/connection.rs: -------------------------------------------------------------------------------- 1 | use std::net; 2 | use network::Magic; 3 | use message::common::Services; 4 | use message::types; 5 | use io::SharedTcpStream; 6 | 7 | pub struct Connection { 8 | pub stream: SharedTcpStream, 9 | pub version: u32, 10 | pub version_message: types::Version, 11 | pub magic: Magic, 12 | pub services: Services, 13 | pub address: net::SocketAddr, 14 | } 15 | -------------------------------------------------------------------------------- /message/src/common/block_header_and_ids.rs: -------------------------------------------------------------------------------- 1 | use chain::{BlockHeader, ShortTransactionID}; 2 | use common::PrefilledTransaction; 3 | 4 | #[derive(Debug, PartialEq, Serializable, Deserializable)] 5 | pub struct BlockHeaderAndIDs { 6 | pub header: BlockHeader, 7 | pub nonce: u64, 8 | pub short_ids: Vec, 9 | pub prefilled_transactions: Vec, 10 | } 11 | -------------------------------------------------------------------------------- /network/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "network" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | lazy_static = "1.0" 8 | chain = { path = "../chain" } 9 | keys = { path = "../keys" } 10 | primitives = { path = "../primitives" } 11 | serialization = { path = "../serialization" } 12 | bitcrypto = { path = "../crypto" } 13 | rustc-hex = "2" 14 | -------------------------------------------------------------------------------- /message/src/message/payload.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Reader, Stream}; 3 | use MessageResult; 4 | 5 | pub trait Payload: Send + 'static { 6 | fn version() -> u32; 7 | fn command() -> &'static str; 8 | fn deserialize_payload(reader: &mut Reader, version: u32) -> MessageResult where Self: Sized, T: io::Read; 9 | fn serialize_payload(&self, stream: &mut Stream, version: u32) -> MessageResult<()>; 10 | } 11 | -------------------------------------------------------------------------------- /chain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chain" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | rustc-hex = "2" 8 | heapsize = "0.4" 9 | bitcrypto = { path = "../crypto" } 10 | primitives = { path = "../primitives" } 11 | serialization = { path = "../serialization" } 12 | serialization_derive = { path = "../serialization_derive" } 13 | 14 | [features] 15 | default = [] 16 | test-helpers = [] 17 | -------------------------------------------------------------------------------- /message/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "message" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | byteorder = "1.0" 8 | 9 | bitcrypto = { path = "../crypto" } 10 | chain = { path = "../chain" } 11 | primitives = { path = "../primitives" } 12 | serialization = { path = "../serialization" } 13 | serialization_derive = { path = "../serialization_derive" } 14 | network = { path = "../network" } 15 | -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: parity-bitcoin 2 | version: git 3 | summary: The Parity Bitcoin client 4 | description: | 5 | Bitcoin client written in Rust. 6 | 7 | grade: devel # must be 'stable' to release into candidate/stable channels 8 | confinement: strict 9 | 10 | apps: 11 | parity-bitcoin: 12 | command: pbtc 13 | plugs: [home, network, network-bind] 14 | 15 | parts: 16 | parity-bitcoin: 17 | source: . 18 | plugin: rust 19 | build-packages: [g++] 20 | -------------------------------------------------------------------------------- /network/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | 4 | extern crate chain; 5 | extern crate primitives; 6 | extern crate serialization; 7 | extern crate bitcrypto as crypto; 8 | extern crate keys; 9 | extern crate rustc_hex as hex; 10 | 11 | mod consensus; 12 | mod deployments; 13 | mod network; 14 | 15 | pub use primitives::{hash, compact}; 16 | 17 | pub use consensus::ConsensusParams; 18 | pub use deployments::Deployment; 19 | pub use network::{Magic, Network}; 20 | -------------------------------------------------------------------------------- /db/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate parity_rocksdb as rocksdb; 2 | extern crate elastic_array; 3 | extern crate parking_lot; 4 | #[macro_use] 5 | extern crate log; 6 | extern crate bit_vec; 7 | extern crate lru_cache; 8 | 9 | extern crate primitives; 10 | extern crate serialization as ser; 11 | extern crate chain; 12 | extern crate storage; 13 | 14 | pub mod kv; 15 | mod block_chain_db; 16 | 17 | pub use block_chain_db::{BlockChainDatabase, ForkChainDatabase}; 18 | pub use primitives::{hash, bytes}; -------------------------------------------------------------------------------- /rpc/src/v1/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod helpers; 3 | pub mod impls; 4 | pub mod traits; 5 | pub mod types; 6 | 7 | pub use self::traits::Raw; 8 | pub use self::traits::Miner; 9 | pub use self::traits::BlockChain; 10 | pub use self::traits::Network; 11 | pub use self::impls::{RawClient, RawClientCore}; 12 | pub use self::impls::{MinerClient, MinerClientCore}; 13 | pub use self::impls::{BlockChainClient, BlockChainClientCore}; 14 | pub use self::impls::{NetworkClient, NetworkClientCore}; 15 | -------------------------------------------------------------------------------- /p2p/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod nonce; 2 | pub mod time; 3 | pub mod interval; 4 | mod internet_protocol; 5 | mod node_table; 6 | mod peer; 7 | mod response_queue; 8 | mod synchronizer; 9 | 10 | pub use self::internet_protocol::InternetProtocol; 11 | pub use self::node_table::{NodeTable, NodeTableError, Node}; 12 | pub use self::peer::{PeerId, PeerInfo, Direction}; 13 | pub use self::response_queue::{ResponseQueue, Responses}; 14 | pub use self::synchronizer::{Synchronizer, ConfigurableSynchronizer}; 15 | -------------------------------------------------------------------------------- /storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "storage" 3 | version = "0.1.0" 4 | authors = ["Parity Technologies "] 5 | 6 | [dependencies] 7 | elastic-array = "0.10" 8 | parking_lot = "0.8" 9 | bit-vec = "0.4" 10 | lru-cache = "0.1" 11 | primitives = { path = "../primitives" } 12 | serialization = { path = "../serialization" } 13 | chain = { path = "../chain" } 14 | display_derive = "0.0.0" 15 | bitcrypto = { path = "../crypto" } 16 | lazy_static = "*" 17 | network = { path = "../network" } 18 | -------------------------------------------------------------------------------- /script/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "script" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | bitcrypto = { path = "../crypto" } 8 | byteorder = "1.0" 9 | chain = { path = "../chain" } 10 | keys = { path = "../keys" } 11 | primitives = { path = "../primitives" } 12 | serialization = { path = "../serialization" } 13 | log = "0.4" 14 | 15 | [dev-dependencies] 16 | rustc-hex = "2" 17 | serde_json = "1.0" 18 | chain = { path = "../chain", features = ["test-helpers"] } 19 | -------------------------------------------------------------------------------- /p2p/src/util/peer.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use message::types; 3 | use network::Magic; 4 | 5 | pub type PeerId = usize; 6 | 7 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 8 | pub enum Direction { 9 | Inbound, 10 | Outbound, 11 | } 12 | 13 | #[derive(Debug, PartialEq, Clone)] 14 | pub struct PeerInfo { 15 | pub id: PeerId, 16 | pub address: SocketAddr, 17 | pub user_agent: String, 18 | pub direction: Direction, 19 | pub version: u32, 20 | pub version_message: types::Version, 21 | pub magic: Magic, 22 | } 23 | 24 | -------------------------------------------------------------------------------- /serialization/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | extern crate primitives; 3 | extern crate rustc_hex as hex; 4 | 5 | mod compact_integer; 6 | mod fixed_array; 7 | mod impls; 8 | mod list; 9 | mod reader; 10 | mod stream; 11 | 12 | pub use primitives::{hash, bytes, compact}; 13 | pub use compact_integer::CompactInteger; 14 | pub use list::List; 15 | pub use reader::{ 16 | Reader, Deserializable, deserialize, deserialize_iterator, ReadIterator, Error, 17 | }; 18 | pub use stream::{ 19 | Stream, Serializable, serialize, serialize_list, serialized_list_size, 20 | }; 21 | -------------------------------------------------------------------------------- /storage/src/best_block.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use hash::H256; 3 | 4 | /// Best block information 5 | #[derive(Clone, PartialEq, Default)] 6 | pub struct BestBlock { 7 | /// Height/number of the best block (genesis block has zero height) 8 | pub number: u32, 9 | /// Hash of the best block 10 | pub hash: H256, 11 | } 12 | 13 | impl fmt::Debug for BestBlock { 14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 15 | f.debug_struct("BestBlock") 16 | .field("number", &self.number) 17 | .field("hash", &self.hash.reversed()) 18 | .finish() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /message/src/types/verack.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct Verack; 7 | 8 | impl Payload for Verack { 9 | fn version() -> u32 { 10 | 0 11 | } 12 | 13 | fn command() -> &'static str { 14 | "verack" 15 | } 16 | 17 | fn deserialize_payload(_reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 18 | Ok(Verack) 19 | } 20 | 21 | fn serialize_payload(&self, _stream: &mut Stream, _version: u32) -> MessageResult<()> { 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /db/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "db" 3 | version = "0.1.0" 4 | authors = ["Parity Technologies "] 5 | 6 | [dependencies] 7 | parity-rocksdb = { git = "https://github.com/paritytech/rust-rocksdb" } 8 | elastic-array = "0.10" 9 | parking_lot = "0.8" 10 | log = "0.4" 11 | bit-vec = "0.4" 12 | lru-cache = "0.1" 13 | primitives = { path = "../primitives" } 14 | serialization = { path = "../serialization" } 15 | chain = { path = "../chain" } 16 | storage = { path = "../storage" } 17 | 18 | [dev-dependencies] 19 | tempdir = "0.3" 20 | test-data = { path = "../test-data" } 21 | -------------------------------------------------------------------------------- /message/src/types/getaddr.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct GetAddr; 7 | 8 | impl Payload for GetAddr { 9 | fn version() -> u32 { 10 | 0 11 | } 12 | 13 | fn command() -> &'static str { 14 | "getaddr" 15 | } 16 | 17 | fn deserialize_payload(_reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 18 | Ok(GetAddr) 19 | } 20 | 21 | fn serialize_payload(&self, _stream: &mut Stream, _version: u32) -> MessageResult<()> { 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /message/src/types/mempool.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct MemPool; 7 | 8 | impl Payload for MemPool { 9 | fn version() -> u32 { 10 | 60002 11 | } 12 | 13 | fn command() -> &'static str { 14 | "mempool" 15 | } 16 | 17 | fn deserialize_payload(_reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 18 | Ok(MemPool) 19 | } 20 | 21 | fn serialize_payload(&self, _stream: &mut Stream, _version: u32) -> MessageResult<()> { 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /p2p/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "p2p" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | tokio-core = "0.1.6" 8 | tokio-io = "0.1.12" 9 | parking_lot = "0.8" 10 | futures = "0.1" 11 | futures-cpupool = "0.1" 12 | time = "0.1" 13 | rand = "0.4" 14 | log = "0.4" 15 | abstract-ns = "0.3" 16 | ns-dns-tokio = "0.3" 17 | csv = "1" 18 | 19 | primitives = { path = "../primitives" } 20 | bitcrypto = { path = "../crypto" } 21 | message = { path = "../message" } 22 | serialization = { path = "../serialization" } 23 | network = { path = "../network" } 24 | -------------------------------------------------------------------------------- /rpc/src/v1/traits/miner.rs: -------------------------------------------------------------------------------- 1 | use jsonrpc_core::Error; 2 | 3 | use v1::types::{BlockTemplate, BlockTemplateRequest}; 4 | 5 | /// Parity-bitcoin miner data interface. 6 | #[rpc] 7 | pub trait Miner { 8 | /// Get block template for mining. 9 | /// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "getblocktemplate", "params": [{"capabilities": ["coinbasetxn", "workid", "coinbase/append"]}], "id":1 }' -H 'content-type: application/json' http://127.0.0.1:8332/ 10 | #[rpc(name = "getblocktemplate")] 11 | fn get_block_template(&self, BlockTemplateRequest) -> Result; 12 | } 13 | -------------------------------------------------------------------------------- /message/src/types/filterclear.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct FilterClear; 7 | 8 | impl Payload for FilterClear { 9 | fn version() -> u32 { 10 | 70001 11 | } 12 | 13 | fn command() -> &'static str { 14 | "filterclear" 15 | } 16 | 17 | fn deserialize_payload(_reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 18 | Ok(FilterClear) 19 | } 20 | 21 | fn serialize_payload(&self, _stream: &mut Stream, _version: u32) -> MessageResult<()> { 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /message/src/types/sendheaders.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct SendHeaders; 7 | 8 | impl Payload for SendHeaders { 9 | fn version() -> u32 { 10 | 70012 11 | } 12 | 13 | fn command() -> &'static str { 14 | "sendheaders" 15 | } 16 | 17 | fn deserialize_payload(_reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 18 | Ok(SendHeaders) 19 | } 20 | 21 | fn serialize_payload(&self, _stream: &mut Stream, _version: u32) -> MessageResult<()> { 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bencher/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bencher" 3 | version = "0.1.0" 4 | license = "GPL-3.0" 5 | authors = ["Ethcore "] 6 | description = "Parity bitcoin client." 7 | 8 | [dependencies] 9 | storage = { path = "../storage" } 10 | db = { path = "../db" } 11 | verification = { path = "../verification" } 12 | network = { path = "../network" } 13 | chain = { path = "../chain", features = ["test-helpers"] } 14 | primitives = { path = "../primitives" } 15 | test-data = { path = "../test-data" } 16 | time = "*" 17 | byteorder = "1.0" 18 | 19 | [[bin]] 20 | path = "src/main.rs" 21 | name = "bencher" 22 | -------------------------------------------------------------------------------- /p2p/src/net/mod.rs: -------------------------------------------------------------------------------- 1 | mod accept_connection; 2 | mod channel; 3 | mod config; 4 | mod connect; 5 | mod connection; 6 | mod connection_counter; 7 | mod connections; 8 | mod peer_context; 9 | mod stats; 10 | 11 | pub use self::accept_connection::{AcceptConnection, accept_connection}; 12 | pub use self::channel::Channel; 13 | pub use self::config::Config; 14 | pub use self::connect::{Connect, connect}; 15 | pub use self::connection::Connection; 16 | pub use self::connection_counter::ConnectionCounter; 17 | pub use self::connections::Connections; 18 | pub use self::peer_context::PeerContext; 19 | pub use self::stats::PeerStats; 20 | -------------------------------------------------------------------------------- /message/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | extern crate bitcrypto as crypto; 3 | extern crate chain; 4 | extern crate primitives; 5 | extern crate serialization as ser; 6 | #[macro_use] 7 | extern crate serialization_derive; 8 | extern crate network; 9 | 10 | pub mod common; 11 | mod message; 12 | mod serialization; 13 | pub mod types; 14 | mod error; 15 | 16 | pub use primitives::{hash, bytes}; 17 | 18 | pub use common::{Command, Services}; 19 | pub use message::{Message, MessageHeader, Payload, to_raw_message}; 20 | pub use serialization::{serialize_payload, deserialize_payload}; 21 | pub use error::{Error, MessageResult}; 22 | -------------------------------------------------------------------------------- /network/src/deployments.rs: -------------------------------------------------------------------------------- 1 | const VERSIONBITS_TOP_MASK: u32 = 0xe0000000; 2 | const VERSIONBITS_TOP_BITS: u32 = 0x20000000; 3 | 4 | #[derive(Debug, Clone, Copy)] 5 | pub struct Deployment { 6 | /// Deployment's name 7 | pub name: &'static str, 8 | /// Bit 9 | pub bit: u8, 10 | /// Start time 11 | pub start_time: u32, 12 | /// Timeout 13 | pub timeout: u32, 14 | /// Activation block number (if already activated) 15 | pub activation: Option, 16 | } 17 | 18 | impl Deployment { 19 | pub fn matches(&self, version: u32) -> bool { 20 | (version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS && (version & (1 << self.bit)) != 0 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /miner/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "miner" 3 | version = "0.1.0" 4 | authors = ["Ethcore "] 5 | 6 | [dependencies] 7 | byteorder = "1.0" 8 | heapsize = "0.4" 9 | bitcrypto = { path = "../crypto" } 10 | chain = { path = "../chain" } 11 | storage = { path = "../storage" } 12 | db = { path = "../db" } 13 | network = { path = "../network" } 14 | primitives = { path = "../primitives" } 15 | serialization = { path = "../serialization" } 16 | verification = { path = "../verification" } 17 | keys = { path = "../keys" } 18 | script = { path = "../script" } 19 | 20 | [dev-dependencies] 21 | test-data = { path = "../test-data" } 22 | 23 | [features] 24 | test-helpers = [] -------------------------------------------------------------------------------- /p2p/src/io/write_message.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use futures::{Future, Poll}; 3 | use tokio_io::AsyncWrite; 4 | use tokio_io::io::{WriteAll, write_all}; 5 | use message::Message; 6 | 7 | pub fn write_message(a: A, message: Message) -> WriteMessage where A: AsyncWrite { 8 | WriteMessage { 9 | future: write_all(a, message), 10 | } 11 | } 12 | 13 | pub struct WriteMessage { 14 | future: WriteAll>, 15 | } 16 | 17 | impl Future for WriteMessage where A: AsyncWrite { 18 | type Item = (A, Message); 19 | type Error = io::Error; 20 | 21 | fn poll(&mut self) -> Poll { 22 | self.future.poll() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /storage/src/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Display)] 2 | pub enum Error { 3 | /// Low level database error 4 | #[display(fmt = "Database error: {}", _0)] 5 | DatabaseError(String), 6 | /// Invalid block 7 | #[display(fmt = "Cannot canonize block")] 8 | CannotCanonize, 9 | /// Unknown parent 10 | #[display(fmt = "Block parent is unknown")] 11 | UnknownParent, 12 | /// Ancient fork 13 | #[display(fmt = "Fork is too long to proceed")] 14 | AncientFork, 15 | /// Invalid block 16 | #[display(fmt = "Cannot decanonize block (invalid database state)")] 17 | CannotDecanonize, 18 | } 19 | 20 | impl From for String { 21 | fn from(e: Error) -> String { 22 | format!("{}", e) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /serialization/src/list.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use {Serializable, Deserializable, Error, Reader, Stream}; 3 | 4 | #[derive(Debug, Clone)] 5 | pub struct List(Vec); 6 | 7 | impl List where T: Serializable + Deserializable { 8 | pub fn from(vec: Vec) -> Self { 9 | List(vec) 10 | } 11 | 12 | pub fn into(self) -> Vec { 13 | self.0 14 | } 15 | } 16 | 17 | impl Serializable for List where S: Serializable { 18 | fn serialize(&self, s: &mut Stream) { 19 | s.append_list(&self.0); 20 | } 21 | } 22 | 23 | impl Deserializable for List where D: Deserializable { 24 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 25 | reader.read_list().map(List) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /keys/src/generator.rs: -------------------------------------------------------------------------------- 1 | use rand::os::OsRng; 2 | use network::Network; 3 | use {KeyPair, SECP256K1, Error}; 4 | 5 | pub trait Generator { 6 | fn generate(&self) -> Result; 7 | } 8 | 9 | pub struct Random { 10 | network: Network 11 | } 12 | 13 | impl Random { 14 | pub fn new(network: Network) -> Self { 15 | Random { 16 | network: network, 17 | } 18 | } 19 | } 20 | 21 | impl Generator for Random { 22 | fn generate(&self) -> Result { 23 | let context = &SECP256K1; 24 | let mut rng = try!(OsRng::new().map_err(|_| Error::FailedKeyGeneration)); 25 | let (secret, public) = try!(context.generate_keypair(&mut rng)); 26 | Ok(KeyPair::from_keypair(secret, public, self.network)) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /message/src/common/mod.rs: -------------------------------------------------------------------------------- 1 | mod address; 2 | mod block_header_and_ids; 3 | mod block_transactions; 4 | mod block_transactions_request; 5 | mod command; 6 | mod inventory; 7 | mod ip; 8 | mod port; 9 | mod prefilled_transaction; 10 | mod service; 11 | 12 | pub use self::address::NetAddress; 13 | pub use self::block_header_and_ids::BlockHeaderAndIDs; 14 | pub use self::block_transactions::BlockTransactions; 15 | pub use self::block_transactions_request::BlockTransactionsRequest; 16 | pub use self::command::Command; 17 | pub use self::inventory::{InventoryVector, InventoryType}; 18 | pub use self::ip::IpAddress; 19 | pub use self::port::Port; 20 | pub use self::prefilled_transaction::PrefilledTransaction; 21 | pub use self::service::Services; 22 | -------------------------------------------------------------------------------- /p2p/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | mod deadline; 2 | mod handshake; 3 | mod read_header; 4 | mod read_message; 5 | mod read_any_message; 6 | mod read_payload; 7 | mod sharedtcpstream; 8 | mod write_message; 9 | 10 | pub use self::deadline::{deadline, Deadline, DeadlineStatus}; 11 | pub use self::handshake::{ 12 | handshake, accept_handshake, Handshake, AcceptHandshake, HandshakeResult 13 | }; 14 | pub use self::read_header::{read_header, ReadHeader}; 15 | pub use self::read_payload::{read_payload, ReadPayload}; 16 | pub use self::read_message::{read_message, ReadMessage}; 17 | pub use self::read_any_message::{read_any_message, ReadAnyMessage}; 18 | pub use self::sharedtcpstream::SharedTcpStream; 19 | pub use self::write_message::{write_message, WriteMessage}; 20 | -------------------------------------------------------------------------------- /message/src/types/blocktxn.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use common::BlockTransactions; 4 | use {MessageResult, Payload}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct BlockTxn { 8 | pub request: BlockTransactions, 9 | } 10 | 11 | impl Payload for BlockTxn { 12 | fn version() -> u32 { 13 | 70014 14 | } 15 | 16 | fn command() -> &'static str { 17 | "blocktxn" 18 | } 19 | 20 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 21 | let block = BlockTxn { 22 | request: try!(reader.read()), 23 | }; 24 | 25 | Ok(block) 26 | } 27 | 28 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 29 | stream.append(&self.request); 30 | Ok(()) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /serialization_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | extern crate syn; 3 | #[macro_use] 4 | extern crate quote; 5 | 6 | mod ser; 7 | mod de; 8 | 9 | use proc_macro::TokenStream; 10 | use ser::impl_serializable; 11 | use de::impl_deserializable; 12 | 13 | #[proc_macro_derive(Serializable)] 14 | pub fn serializable(input: TokenStream) -> TokenStream { 15 | let s = input.to_string(); 16 | let ast = syn::parse_derive_input(&s).unwrap(); 17 | let gen = impl_serializable(&ast); 18 | gen.parse().unwrap() 19 | } 20 | 21 | #[proc_macro_derive(Deserializable)] 22 | pub fn deserializable(input: TokenStream) -> TokenStream { 23 | let s = input.to_string(); 24 | let ast = syn::parse_derive_input(&s).unwrap(); 25 | let gen = impl_deserializable(&ast); 26 | gen.parse().unwrap() 27 | } 28 | 29 | -------------------------------------------------------------------------------- /p2p/src/util/time.rs: -------------------------------------------------------------------------------- 1 | use std::cell::Cell; 2 | use time; 3 | 4 | pub trait Time { 5 | fn get(&self) -> time::Timespec; 6 | } 7 | 8 | #[derive(Default, Debug)] 9 | pub struct RealTime; 10 | 11 | impl Time for RealTime { 12 | fn get(&self) -> time::Timespec { 13 | time::get_time() 14 | } 15 | } 16 | 17 | #[derive(Default)] 18 | pub struct IncrementalTime { 19 | counter: Cell, 20 | } 21 | 22 | impl Time for IncrementalTime { 23 | fn get(&self) -> time::Timespec { 24 | let c = self.counter.get(); 25 | let result = time::Timespec::new(c, 0); 26 | self.counter.set(c + 1); 27 | result 28 | } 29 | } 30 | 31 | #[derive(Default)] 32 | pub struct ZeroTime { 33 | } 34 | 35 | impl Time for ZeroTime { 36 | fn get(&self) -> time::Timespec { 37 | time::Timespec::new(0, 0) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /storage/src/block_iterator.rs: -------------------------------------------------------------------------------- 1 | use chain::IndexedBlockHeader; 2 | use {BlockRef, BlockHeaderProvider}; 3 | 4 | pub struct BlockIterator<'a> { 5 | block: u32, 6 | period: u32, 7 | headers: &'a BlockHeaderProvider, 8 | } 9 | 10 | impl<'a> BlockIterator<'a> { 11 | pub fn new(block: u32, period: u32, headers: &'a BlockHeaderProvider) -> Self { 12 | BlockIterator { 13 | block: block, 14 | period: period, 15 | headers: headers, 16 | } 17 | } 18 | } 19 | 20 | impl<'a> Iterator for BlockIterator<'a> { 21 | type Item = (u32, IndexedBlockHeader); 22 | 23 | fn next(&mut self) -> Option { 24 | let result = self.headers.block_header(BlockRef::Number(self.block)); 25 | let block = self.block; 26 | self.block += self.period; 27 | result.map(|header| (block, header)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /storage/src/tree_state_provider.rs: -------------------------------------------------------------------------------- 1 | use hash::H256; 2 | use {SproutTreeState, SaplingTreeState}; 3 | 4 | pub trait TreeStateProvider : Send + Sync { 5 | fn sprout_tree_at(&self, root: &H256) -> Option; 6 | 7 | fn sapling_tree_at(&self, root: &H256) -> Option; 8 | 9 | fn sprout_block_root(&self, block_hash: &H256) -> Option; 10 | 11 | fn sapling_block_root(&self, block_hash: &H256) -> Option; 12 | 13 | fn sprout_tree_at_block(&self, block_hash: &H256) -> Option { 14 | self.sprout_block_root(block_hash).and_then(|h| self.sprout_tree_at(&h)) 15 | } 16 | 17 | fn sapling_tree_at_block(&self, block_hash: &H256) -> Option { 18 | self.sapling_block_root(block_hash).and_then(|h| self.sapling_tree_at(&h)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tools/draw_graph.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Cargo graph does not work with cargo workspaces #33 4 | # https://github.com/kbknapp/cargo-graph/issues/33 5 | # so first we need to patch Cargo.toml and remove workspace 6 | patch -R Cargo.toml tools/workspace.diff 7 | 8 | # Now let's rebuild Cargo.lock by telling cargo to update local package 9 | cargo update -p pbtc 10 | 11 | # And draw dependencies graph using cargo graph 12 | cargo graph --build-shape box --build-line-style dashed > tools/graph.dot 13 | 14 | # Let's fix graph ratio 15 | patch tools/graph.dot tools/graph_ratio.diff 16 | 17 | dot -Tsvg > tools/graph.svg tools/graph.dot 18 | 19 | # Finally let's bring back old Cargo.toml file 20 | patch Cargo.toml tools/workspace.diff 21 | 22 | # Now let's revert Cargo.lock to previous state 23 | cargo update -p pbtc 24 | -------------------------------------------------------------------------------- /message/src/types/getblocktxn.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use common::BlockTransactionsRequest; 4 | use {Payload, MessageResult}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct GetBlockTxn { 8 | pub request: BlockTransactionsRequest, 9 | } 10 | 11 | impl Payload for GetBlockTxn { 12 | fn version() -> u32 { 13 | 70014 14 | } 15 | 16 | fn command() -> &'static str { 17 | "getblocktxn" 18 | } 19 | 20 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 21 | let get_block = GetBlockTxn { 22 | request: try!(reader.read()), 23 | }; 24 | 25 | Ok(get_block) 26 | } 27 | 28 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 29 | stream.append(&self.request); 30 | Ok(()) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /message/src/types/ping.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {MessageResult, Payload}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct Ping { 7 | pub nonce: u64, 8 | } 9 | 10 | impl Ping { 11 | pub fn new(nonce: u64) -> Self { 12 | Ping { 13 | nonce: nonce, 14 | } 15 | } 16 | } 17 | 18 | impl Payload for Ping { 19 | fn version() -> u32 { 20 | 0 21 | } 22 | 23 | fn command() -> &'static str { 24 | "ping" 25 | } 26 | 27 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 28 | let ping = Ping { 29 | nonce: try!(reader.read()), 30 | }; 31 | 32 | Ok(ping) 33 | } 34 | 35 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 36 | stream.append(&self.nonce); 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /message/src/types/pong.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct Pong { 7 | pub nonce: u64, 8 | } 9 | 10 | impl Pong { 11 | pub fn new(nonce: u64) -> Self { 12 | Pong { 13 | nonce: nonce, 14 | } 15 | } 16 | } 17 | 18 | impl Payload for Pong { 19 | fn version() -> u32 { 20 | 0 21 | } 22 | 23 | fn command() -> &'static str { 24 | "pong" 25 | } 26 | 27 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 28 | let pong = Pong { 29 | nonce: try!(reader.read()), 30 | }; 31 | 32 | Ok(pong) 33 | } 34 | 35 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 36 | stream.append(&self.nonce); 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /miner/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | extern crate heapsize; 3 | 4 | extern crate bitcrypto as crypto; 5 | extern crate chain; 6 | extern crate storage; 7 | extern crate db; 8 | extern crate keys; 9 | extern crate script; 10 | extern crate network; 11 | extern crate primitives; 12 | extern crate serialization as ser; 13 | extern crate verification; 14 | 15 | mod block_assembler; 16 | mod fee; 17 | mod memory_pool; 18 | 19 | pub use block_assembler::{BlockAssembler, BlockTemplate}; 20 | pub use memory_pool::{MemoryPool, HashedOutPoint, Information as MemoryPoolInformation, 21 | OrderingStrategy as MemoryPoolOrderingStrategy, DoubleSpendCheckResult, NonFinalDoubleSpendSet}; 22 | pub use fee::{FeeCalculator, transaction_fee, transaction_fee_rate}; 23 | 24 | #[cfg(feature = "test-helpers")] 25 | pub use fee::NonZeroFeeCalculator; -------------------------------------------------------------------------------- /verification/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "verification" 3 | version = "0.1.0" 4 | authors = ["Nikolay Volf "] 5 | 6 | [dependencies] 7 | time = "0.1" 8 | log = "0.4" 9 | rayon = "1.0" 10 | parking_lot = "0.8" 11 | byteorder = "1.2" 12 | keys = { path = "../keys" } 13 | primitives = { path = "../primitives" } 14 | chain = { path = "../chain" } 15 | serialization = { path = "../serialization" } 16 | script = { path = "../script" } 17 | network = { path = "../network" } 18 | storage = { path = "../storage" } 19 | bitcrypto = { path = "../crypto" } 20 | rustc-hex = "2" 21 | bitvec = "0.10" 22 | bitflags = "1.0" 23 | 24 | [dev-dependencies] 25 | rand = "0.4" 26 | test-data = { path = "../test-data" } 27 | db = { path = "../db" } 28 | assert_matches = "1.3.0" 29 | chain = { path = "../chain", features = ["test-helpers"] } 30 | -------------------------------------------------------------------------------- /db/src/kv/mod.rs: -------------------------------------------------------------------------------- 1 | mod cachedb; 2 | mod db; 3 | mod diskdb; 4 | mod memorydb; 5 | mod overlaydb; 6 | mod transaction; 7 | 8 | pub use self::cachedb::CacheDatabase; 9 | pub use self::db::KeyValueDatabase; 10 | pub use self::diskdb::{Database as DiskDatabase, DatabaseConfig, CompactionProfile}; 11 | pub use self::memorydb::{MemoryDatabase, SharedMemoryDatabase}; 12 | pub use self::overlaydb::{OverlayDatabase, AutoFlushingOverlayDatabase}; 13 | pub use self::transaction::{ 14 | RawTransaction, Transaction, RawOperation, Operation, Location, KeyState, 15 | Key, Value, KeyValue, RawKeyValue, RawKey, 16 | COL_COUNT, COL_META, COL_BLOCK_HASHES, COL_BLOCK_HEADERS, COL_BLOCK_TRANSACTIONS, 17 | COL_TRANSACTIONS, COL_TRANSACTIONS_META, COL_BLOCK_NUMBERS, COL_SAPLING_NULLIFIERS, 18 | COL_SPROUT_NULLIFIERS, COL_TREE_STATES, COL_SPROUT_BLOCK_ROOTS, 19 | }; 20 | -------------------------------------------------------------------------------- /storage/src/block_ancestors.rs: -------------------------------------------------------------------------------- 1 | use chain::IndexedBlockHeader; 2 | use {BlockRef, BlockHeaderProvider}; 3 | 4 | pub struct BlockAncestors<'a> { 5 | block: Option, 6 | headers: &'a BlockHeaderProvider, 7 | } 8 | 9 | impl<'a> BlockAncestors<'a> { 10 | pub fn new(block: BlockRef, headers: &'a BlockHeaderProvider) -> Self { 11 | BlockAncestors { 12 | block: Some(block), 13 | headers: headers, 14 | } 15 | } 16 | } 17 | 18 | impl<'a> Iterator for BlockAncestors<'a> { 19 | type Item = IndexedBlockHeader; 20 | 21 | fn next(&mut self) -> Option { 22 | let result = self.block.take().and_then(|block| self.headers.block_header(block)); 23 | self.block = match result { 24 | Some(ref header) => Some(BlockRef::Hash(header.raw.previous_header_hash.clone())), 25 | None => None, 26 | }; 27 | result 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /verification/src/constants.rs: -------------------------------------------------------------------------------- 1 | //! Consenus constants 2 | 3 | pub const BLOCK_MAX_FUTURE: i64 = 2 * 60 * 60; // 2 hours 4 | pub const COINBASE_MATURITY: u32 = 100; // 2 hours 5 | pub const MIN_COINBASE_SIZE: usize = 2; 6 | pub const MAX_COINBASE_SIZE: usize = 100; 7 | 8 | pub const RETARGETING_FACTOR: u32 = 4; 9 | pub const TARGET_SPACING_SECONDS: u32 = 10 * 60; 10 | pub const DOUBLE_SPACING_SECONDS: u32 = 2 * TARGET_SPACING_SECONDS; 11 | pub const TARGET_TIMESPAN_SECONDS: u32 = 2 * 7 * 24 * 60 * 60; 12 | 13 | // The upper and lower bounds for retargeting timespan 14 | pub const MIN_TIMESPAN: u32 = TARGET_TIMESPAN_SECONDS / RETARGETING_FACTOR; 15 | pub const MAX_TIMESPAN: u32 = TARGET_TIMESPAN_SECONDS * RETARGETING_FACTOR; 16 | 17 | // Target number of blocks, 2 weaks, 2016 18 | pub const RETARGETING_INTERVAL: u32 = TARGET_TIMESPAN_SECONDS / TARGET_SPACING_SECONDS; 19 | -------------------------------------------------------------------------------- /message/src/types/filteradd.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use bytes::Bytes; 3 | use ser::{Stream, Reader}; 4 | use {Payload, MessageResult}; 5 | 6 | pub const FILTERADD_MAX_DATA_LEN: usize = 520; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct FilterAdd { 10 | // TODO: check how this should be serialized 11 | pub data: Bytes, 12 | } 13 | 14 | impl Payload for FilterAdd { 15 | fn version() -> u32 { 16 | 70001 17 | } 18 | 19 | fn command() -> &'static str { 20 | "filteradd" 21 | } 22 | 23 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 24 | let filteradd = FilterAdd { 25 | data: try!(reader.read()), 26 | }; 27 | 28 | Ok(filteradd) 29 | } 30 | 31 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 32 | stream.append(&self.data); 33 | Ok(()) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate log; 2 | extern crate rustc_hex as hex; 3 | extern crate serde; 4 | extern crate serde_json; 5 | #[macro_use] 6 | extern crate serde_derive; 7 | extern crate jsonrpc_core; 8 | #[macro_use] 9 | extern crate jsonrpc_derive; 10 | extern crate jsonrpc_http_server; 11 | extern crate time; 12 | extern crate tokio_core; 13 | extern crate sync; 14 | extern crate chain; 15 | extern crate serialization as ser; 16 | extern crate primitives; 17 | extern crate p2p; 18 | extern crate network; 19 | extern crate storage; 20 | extern crate db; 21 | extern crate miner; 22 | extern crate verification; 23 | extern crate script as global_script; 24 | extern crate keys; 25 | 26 | pub mod v1; 27 | pub mod rpc_server; 28 | 29 | pub use jsonrpc_core::{MetaIoHandler, Compatibility, Error}; 30 | 31 | pub use jsonrpc_http_server::Server; 32 | pub use rpc_server::start_http; 33 | -------------------------------------------------------------------------------- /crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bitcrypto" 3 | version = "0.1.0" 4 | authors = ["debris "] 5 | 6 | [dependencies] 7 | bellman = "0.1" 8 | blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" } 9 | blake2b_simd = { git = "https://github.com/oconnor663/blake2b_simd.git" } 10 | bn = { git = "https://github.com/paritytech/bn" } 11 | ed25519-dalek = "1.0.0-pre.1" 12 | lazy_static = "1.2.0" 13 | pairing = "0.14.2" 14 | primitives = { path = "../primitives" } 15 | rust-crypto = { git = "https://github.com/nikvolf/rust-crypto", branch = "no-pad" } 16 | rustc-hex = "2" 17 | sapling-crypto = { git = "https://github.com/zcash-hackworks/sapling-crypto.git", rev = "21084bde2019c04bd34208e63c3560fe2c02fb0e" } 18 | serde = "1.0" 19 | serde_derive = "1.0" 20 | serde_json = "1.0" 21 | siphasher = "0.3.0" 22 | -------------------------------------------------------------------------------- /message/src/types/block.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use chain::Block as ChainBlock; 4 | use {Payload, MessageResult}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct Block { 8 | pub block: ChainBlock, 9 | } 10 | 11 | impl Block { 12 | pub fn with_block(block: ChainBlock) -> Self { 13 | Block { 14 | block: block, 15 | } 16 | } 17 | } 18 | 19 | impl Payload for Block { 20 | fn version() -> u32 { 21 | 0 22 | } 23 | 24 | fn command() -> &'static str { 25 | "block" 26 | } 27 | 28 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 29 | let tx = Block { 30 | block: try!(reader.read()), 31 | }; 32 | 33 | Ok(tx) 34 | } 35 | 36 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 37 | stream.append(&self.block); 38 | Ok(()) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /message/src/serialization/stream.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use ser::Stream; 3 | use {Payload, Error, MessageResult}; 4 | 5 | pub fn serialize_payload(t: &T, version: u32) -> MessageResult where T: Payload { 6 | let mut stream = PayloadStream::new(version); 7 | try!(stream.append(t)); 8 | Ok(stream.out()) 9 | } 10 | 11 | pub struct PayloadStream { 12 | stream: Stream, 13 | version: u32, 14 | } 15 | 16 | impl PayloadStream { 17 | pub fn new(version: u32) -> Self { 18 | PayloadStream { 19 | stream: Stream::new(), 20 | version: version, 21 | } 22 | } 23 | 24 | pub fn append(&mut self, t: &T) -> MessageResult<()> where T: Payload { 25 | if T::version() > self.version { 26 | return Err(Error::InvalidVersion); 27 | } 28 | 29 | t.serialize_payload(&mut self.stream, self.version) 30 | } 31 | 32 | pub fn out(self) -> Bytes { 33 | self.stream.out() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chain/src/read_and_hash.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use hash::H256; 3 | use crypto::{DHash256, Digest}; 4 | use ser::{Reader, Error as ReaderError, Deserializable}; 5 | 6 | pub struct HashedData { 7 | pub size: usize, 8 | pub hash: H256, 9 | pub data: T, 10 | } 11 | 12 | pub trait ReadAndHash { 13 | fn read_and_hash(&mut self) -> Result, ReaderError> where T: Deserializable; 14 | } 15 | 16 | impl ReadAndHash for Reader where R: io::Read { 17 | fn read_and_hash(&mut self) -> Result, ReaderError> where T: Deserializable { 18 | let mut size = 0usize; 19 | let mut hasher = DHash256::new(); 20 | let data = self.read_with_proxy(|bytes| { 21 | size += bytes.len(); 22 | hasher.input(bytes); 23 | })?; 24 | 25 | let result = HashedData { 26 | hash: hasher.finish(), 27 | data: data, 28 | size: size, 29 | }; 30 | 31 | Ok(result) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /message/src/types/feefilter.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq)] 6 | pub struct FeeFilter { 7 | pub fee_rate: u64, 8 | } 9 | 10 | impl FeeFilter { 11 | pub fn with_fee_rate(fee_rate: u64) -> Self { 12 | FeeFilter { 13 | fee_rate: fee_rate, 14 | } 15 | } 16 | } 17 | 18 | impl Payload for FeeFilter { 19 | fn version() -> u32 { 20 | 70013 21 | } 22 | 23 | fn command() -> &'static str { 24 | "feefilter" 25 | } 26 | 27 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 28 | let fee_filter = FeeFilter { 29 | fee_rate: try!(reader.read()), 30 | }; 31 | 32 | Ok(fee_filter) 33 | } 34 | 35 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 36 | stream.append(&self.fee_rate); 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /message/src/types/tx.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use chain::Transaction; 4 | use {Payload, MessageResult}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct Tx { 8 | pub transaction: Transaction, 9 | } 10 | 11 | impl Tx { 12 | pub fn with_transaction(transaction: Transaction) -> Self { 13 | Tx { 14 | transaction: transaction, 15 | } 16 | } 17 | } 18 | 19 | impl Payload for Tx { 20 | fn version() -> u32 { 21 | 0 22 | } 23 | 24 | fn command() -> &'static str { 25 | "tx" 26 | } 27 | 28 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 29 | let tx = Tx { 30 | transaction: try!(reader.read()), 31 | }; 32 | 33 | Ok(tx) 34 | } 35 | 36 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 37 | stream.append(&self.transaction); 38 | Ok(()) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /message/src/common/prefilled_transaction.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{ 3 | Serializable, Stream, CompactInteger, 4 | Deserializable, Reader, Error as ReaderError 5 | }; 6 | use chain::Transaction; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct PrefilledTransaction { 10 | pub index: usize, 11 | pub transaction: Transaction, 12 | } 13 | 14 | impl Serializable for PrefilledTransaction { 15 | fn serialize(&self, stream: &mut Stream) { 16 | stream 17 | .append(&CompactInteger::from(self.index)) 18 | .append(&self.transaction); 19 | } 20 | } 21 | 22 | impl Deserializable for PrefilledTransaction { 23 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 24 | let compact: CompactInteger = try!(reader.read()); 25 | let tx = PrefilledTransaction { 26 | index: compact.into(), 27 | transaction: try!(reader.read()), 28 | }; 29 | 30 | Ok(tx) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /p2p/src/util/interval.rs: -------------------------------------------------------------------------------- 1 | use std::time::{Instant, Duration}; 2 | 3 | pub trait Interval : Default { 4 | fn now(&self) -> Instant { 5 | Instant::now() 6 | } 7 | 8 | fn elapsed(&self, instant: Instant) -> Duration { 9 | instant.elapsed() 10 | } 11 | } 12 | 13 | #[derive(Default)] 14 | pub struct RealInterval; 15 | 16 | impl Interval for RealInterval { } 17 | 18 | #[derive(Default)] 19 | #[cfg(test)] 20 | pub struct FixedIntervalSpawner { 21 | step_millis: u64, 22 | } 23 | 24 | #[cfg(test)] 25 | impl FixedIntervalSpawner { 26 | pub fn new(step_millis: u64) -> Self { 27 | FixedIntervalSpawner { step_millis : step_millis } 28 | } 29 | } 30 | 31 | #[cfg(test)] 32 | impl Interval for FixedIntervalSpawner { 33 | fn now(&self) -> Instant { 34 | Instant::now() 35 | } 36 | 37 | fn elapsed(&self, instant: Instant) -> Duration { 38 | (instant - Duration::from_millis(self.step_millis)).elapsed() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rpc" 3 | version = "0.1.0" 4 | authors = ["Ethcore "] 5 | 6 | [lib] 7 | 8 | [dependencies] 9 | log = "0.4" 10 | serde = "1.0" 11 | serde_json = "1.0" 12 | serde_derive = "1.0" 13 | rustc-hex = "2" 14 | time = "0.1" 15 | tokio-core = "0.1.1" 16 | jsonrpc-core = "10.0" 17 | jsonrpc-derive = "10.0" 18 | jsonrpc-pubsub = "10.0" 19 | jsonrpc-http-server = "10.0" 20 | 21 | sync = { path = "../sync" } 22 | serialization = { path = "../serialization" } 23 | chain = { path = "../chain" } 24 | primitives = { path = "../primitives" } 25 | p2p = { path = "../p2p" } 26 | network = { path = "../network" } 27 | storage = { path = "../storage" } 28 | db = { path = "../db" } 29 | miner = { path = "../miner" } 30 | verification = { path = "../verification" } 31 | script = { path = "../script" } 32 | keys = { path = "../keys" } 33 | 34 | [dev-dependencies] 35 | test-data = { path = "../test-data" } 36 | -------------------------------------------------------------------------------- /p2p/src/config.rs: -------------------------------------------------------------------------------- 1 | use std::{net, path}; 2 | use message::common::Services; 3 | use net::Config as NetConfig; 4 | use util::InternetProtocol; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct Config { 8 | /// Number of threads used by p2p thread pool. 9 | pub threads: usize, 10 | /// Number of inbound connections. 11 | pub inbound_connections: u32, 12 | /// Number of outbound connections. 13 | pub outbound_connections: u32, 14 | /// Configuration for every connection. 15 | pub connection: NetConfig, 16 | /// Connect only to these nodes. 17 | pub peers: Vec, 18 | /// Connect to these nodes to retrieve peer addresses, and disconnect. 19 | pub seeds: Vec, 20 | /// p2p/nodes.csv file path. 21 | pub node_table_path: path::PathBuf, 22 | /// Peers with these services will get a boost in node_table. 23 | pub preferable_services: Services, 24 | /// Internet protocol. 25 | pub internet_protocol: InternetProtocol, 26 | } 27 | -------------------------------------------------------------------------------- /tools/regtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./target/release/pbtc --btc --regtest --db-cache=192 & 4 | ! java -jar ./tools/compare-tool/pull-tests-be0eef7.jar /tmp/regtest-db 2>&1 | tee regtests-full.log | grep -E --color=auto 'org.bitcoinj.store.BlockStoreException\:|BitcoindComparisonTool.main\: ERROR|bitcoind sent us a block it already had, make sure bitcoind has no blocks!|java.lang.NullPointerException' 5 | GREP_COLOR="01;32" grep 'BitcoindComparisonTool.main: Block "b1001" completed processing' regtests-full.log 6 | result=$? 7 | 8 | if [ $result -eq 1 ] 9 | then 10 | echo "Regtests failed" | grep --color=auto "failed" 11 | echo "-----------------------------" 12 | echo "Full log: " 13 | cat regtests-full.log 14 | else 15 | echo "Reg tests ok, test cases: " 16 | GREP_COLOR="01;32" grep -E "BitcoindComparisonTool.main: Block \"b[0-9]*\" completed processing" regtests-full.log 17 | fi 18 | 19 | pkill -f ./target/release/pbtc 20 | exit "$result" 21 | 22 | -------------------------------------------------------------------------------- /message/src/types/notfound.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use common::InventoryVector; 4 | use {Payload, MessageResult}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct NotFound { 8 | pub inventory: Vec, 9 | } 10 | 11 | impl NotFound { 12 | pub fn with_inventory(inventory: Vec) -> Self { 13 | NotFound { 14 | inventory: inventory, 15 | } 16 | } 17 | } 18 | 19 | impl Payload for NotFound { 20 | fn version() -> u32 { 21 | 0 22 | } 23 | 24 | fn command() -> &'static str { 25 | "notfound" 26 | } 27 | 28 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 29 | let inv = NotFound { 30 | inventory: try!(reader.read_list_max(50_000)), 31 | }; 32 | 33 | Ok(inv) 34 | } 35 | 36 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 37 | stream.append_list(&self.inventory); 38 | Ok(()) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /message/src/types/inv.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use common::InventoryVector; 4 | use {Payload, MessageResult}; 5 | 6 | pub const INV_MAX_INVENTORY_LEN: usize = 50_000; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct Inv { 10 | pub inventory: Vec, 11 | } 12 | 13 | impl Inv { 14 | pub fn with_inventory(inventory: Vec) -> Self { 15 | Inv { 16 | inventory: inventory, 17 | } 18 | } 19 | } 20 | 21 | impl Payload for Inv { 22 | fn version() -> u32 { 23 | 0 24 | } 25 | 26 | fn command() -> &'static str { 27 | "inv" 28 | } 29 | 30 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 31 | let inv = Inv { 32 | inventory: try!(reader.read_list_max(50_000)), 33 | }; 34 | 35 | Ok(inv) 36 | } 37 | 38 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 39 | stream.append_list(&self.inventory); 40 | Ok(()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /p2p/src/protocol/mod.rs: -------------------------------------------------------------------------------- 1 | mod addr; 2 | mod ping; 3 | mod sync; 4 | 5 | use bytes::Bytes; 6 | use message::Error; 7 | use message::common::Command; 8 | 9 | pub use self::addr::{AddrProtocol, SeednodeProtocol}; 10 | pub use self::ping::PingProtocol; 11 | pub use self::sync::{SyncProtocol, 12 | InboundSyncConnection, InboundSyncConnectionRef, 13 | InboundSyncConnectionState, InboundSyncConnectionStateRef, 14 | OutboundSyncConnection, OutboundSyncConnectionRef, 15 | LocalSyncNode, LocalSyncNodeRef, 16 | }; 17 | 18 | pub trait Protocol: Send { 19 | /// Initialize the protocol. 20 | fn initialize(&mut self) {} 21 | 22 | /// Maintain the protocol. 23 | fn maintain(&mut self) {} 24 | 25 | /// Handle the message. 26 | fn on_message(&mut self, command: &Command, payload: &Bytes) -> Result<(), Error>; 27 | 28 | /// On disconnect. 29 | fn on_close(&mut self) {} 30 | 31 | /// Boxes the protocol. 32 | fn boxed(self) -> Box where Self: Sized + 'static { 33 | Box::new(self) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /message/src/serialization/reader.rs: -------------------------------------------------------------------------------- 1 | use ser::Reader; 2 | use {Payload, Error}; 3 | 4 | pub fn deserialize_payload(buffer: &[u8], version: u32) -> Result where T: Payload { 5 | let mut reader = PayloadReader::new(buffer, version); 6 | let result = try!(reader.read()); 7 | if !reader.is_finished() { 8 | return Err(Error::Deserialize); 9 | } 10 | 11 | Ok(result) 12 | } 13 | 14 | pub struct PayloadReader { 15 | reader: Reader, 16 | version: u32, 17 | } 18 | 19 | impl<'a> PayloadReader<&'a [u8]> { 20 | pub fn new(buffer: &'a [u8], version: u32) -> Self { 21 | PayloadReader { 22 | reader: Reader::new(buffer), 23 | version: version, 24 | } 25 | } 26 | 27 | pub fn read(&mut self) -> Result where T: Payload { 28 | if T::version() > self.version { 29 | return Err(Error::InvalidVersion); 30 | } 31 | 32 | T::deserialize_payload(&mut self.reader, self.version) 33 | } 34 | 35 | pub fn is_finished(&mut self) -> bool { 36 | self.reader.is_finished() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sync/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sync" 3 | version = "0.1.0" 4 | authors = ["Ethcore "] 5 | 6 | [dependencies] 7 | parking_lot = "0.8" 8 | log = "0.4" 9 | time = "0.1" 10 | futures = "0.1" 11 | linked-hash-map = "0.5" 12 | bit-vec = "0.4.3" 13 | murmur3 = "0.4" 14 | rand = "0.4" 15 | byteorder = "1.0" 16 | 17 | chain = { path = "../chain" } 18 | bitcrypto = { path = "../crypto" } 19 | storage = { path = "../storage" } 20 | db = { path = "../db" } 21 | keys = { path = "../keys" } 22 | message = { path = "../message" } 23 | miner = { path = "../miner" } 24 | p2p = { path = "../p2p" } 25 | primitives = { path = "../primitives" } 26 | script = { path = "../script" } 27 | serialization = { path = "../serialization" } 28 | verification = { path = "../verification" } 29 | network = { path = "../network" } 30 | 31 | [dev-dependencies] 32 | test-data = { path = "../test-data" } 33 | miner = { path = "../miner", features = ["test-helpers"] } 34 | chain = { path = "../chain", features = ["test-helpers"] } 35 | -------------------------------------------------------------------------------- /message/src/types/getdata.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Stream, Reader}; 3 | use common::InventoryVector; 4 | use {Payload, MessageResult}; 5 | 6 | pub const GETDATA_MAX_INVENTORY_LEN: usize = 50_000; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct GetData { 10 | pub inventory: Vec, 11 | } 12 | 13 | impl GetData { 14 | pub fn with_inventory(inventory: Vec) -> Self { 15 | GetData { 16 | inventory: inventory, 17 | } 18 | } 19 | } 20 | 21 | impl Payload for GetData { 22 | fn version() -> u32 { 23 | 0 24 | } 25 | 26 | fn command() -> &'static str { 27 | "getdata" 28 | } 29 | 30 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 31 | let inv = GetData { 32 | inventory: try!(reader.read_list_max(50_000)), 33 | }; 34 | 35 | Ok(inv) 36 | } 37 | 38 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 39 | stream.append_list(&self.inventory); 40 | Ok(()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /verification/src/timestamp.rs: -------------------------------------------------------------------------------- 1 | use chain::BlockHeader; 2 | use storage::{BlockHeaderProvider, BlockAncestors}; 3 | use primitives::hash::H256; 4 | 5 | /// Returns median timestamp, of given header ancestors. 6 | /// The header should be later expected to have higher timestamp 7 | /// than this median timestamp 8 | pub fn median_timestamp(header: &BlockHeader, store: &BlockHeaderProvider) -> u32 { 9 | median_timestamp_inclusive(header.previous_header_hash.clone(), store) 10 | } 11 | 12 | /// Returns median timestamp, of given header + its ancestors. 13 | /// The header should be later expected to have higher timestamp 14 | /// than this median timestamp 15 | pub fn median_timestamp_inclusive(previous_header_hash: H256, store: &BlockHeaderProvider) -> u32 { 16 | let mut timestamps: Vec<_> = BlockAncestors::new(previous_header_hash.clone().into(), store) 17 | .take(11) 18 | .map(|header| header.raw.time) 19 | .collect(); 20 | 21 | if timestamps.is_empty() { 22 | return 0; 23 | } 24 | 25 | timestamps.sort(); 26 | 27 | timestamps[timestamps.len() / 2] 28 | } 29 | -------------------------------------------------------------------------------- /import/src/block.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use hash::H32; 3 | use ser::{Deserializable, Reader, Error as ReaderError}; 4 | use chain::IndexedBlock; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct Block { 8 | pub magic: H32, 9 | pub block_size: u32, 10 | pub block: IndexedBlock, 11 | } 12 | 13 | impl Deserializable for Block { 14 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 15 | // We never knew how to parse blocks index file => we were assuming that blocks are stored 16 | // in the *.blk files next to each other, without any gaps. 17 | // It seems that this isn't true && there are (sometimes) zero-filled (always???) gaps between 18 | // adjacent blocks. 19 | // The straightforward soultion is to skip zero bytes. This will work because magic is designed 20 | // not to have zero bytes in it AND block is always prefixed with magic. 21 | reader.skip_while(&|byte| byte == 0)?; 22 | 23 | Ok(Block { 24 | magic: reader.read()?, 25 | block_size: reader.read()?, 26 | block: reader.read()?, 27 | }) 28 | } 29 | } -------------------------------------------------------------------------------- /script/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate log; 2 | extern crate bitcrypto as crypto; 3 | extern crate byteorder; 4 | extern crate chain; 5 | extern crate keys; 6 | extern crate primitives; 7 | extern crate serialization as ser; 8 | 9 | #[cfg(test)] 10 | extern crate serde_json; 11 | #[cfg(test)] 12 | extern crate rustc_hex as hex; 13 | 14 | mod builder; 15 | mod error; 16 | mod flags; 17 | mod interpreter; 18 | mod num; 19 | mod opcode; 20 | mod script; 21 | mod sign; 22 | mod stack; 23 | mod verify; 24 | 25 | pub use primitives::{bytes, hash}; 26 | 27 | pub use self::builder::Builder; 28 | pub use self::error::Error; 29 | pub use self::flags::VerificationFlags; 30 | pub use self::interpreter::{eval_script, verify_script}; 31 | pub use self::opcode::Opcode; 32 | pub use self::num::Num; 33 | pub use self::script::{Script, ScriptType, ScriptAddress}; 34 | pub use self::sign::{SighashBase, SighashCache, TransactionInputSigner, UnsignedTransactionInput}; 35 | pub use self::stack::Stack; 36 | pub use self::verify::{SignatureChecker, NoopSignatureChecker, TransactionSignatureChecker}; 37 | 38 | -------------------------------------------------------------------------------- /message/src/types/getblocks.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use hash::H256; 3 | use ser::{Stream, Reader}; 4 | use {Payload, MessageResult}; 5 | 6 | pub const GETBLOCKS_MAX_RESPONSE_HASHES: usize = 500; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct GetBlocks { 10 | pub version: u32, 11 | pub block_locator_hashes: Vec, 12 | pub hash_stop: H256, 13 | } 14 | 15 | impl Payload for GetBlocks { 16 | fn version() -> u32 { 17 | 0 18 | } 19 | 20 | fn command() -> &'static str { 21 | "getblocks" 22 | } 23 | 24 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 25 | let get_blocks = GetBlocks { 26 | version: try!(reader.read()), 27 | block_locator_hashes: try!(reader.read_list_max(500)), 28 | hash_stop: try!(reader.read()), 29 | }; 30 | 31 | Ok(get_blocks) 32 | } 33 | 34 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 35 | stream 36 | .append(&self.version) 37 | .append_list(&self.block_locator_hashes) 38 | .append(&self.hash_stop); 39 | Ok(()) 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /rpc/src/rpc_server.rs: -------------------------------------------------------------------------------- 1 | // TODO: panic handler 2 | use std::io; 3 | use std::net::SocketAddr; 4 | use jsonrpc_core; 5 | use jsonrpc_http_server::{self, ServerBuilder, Server, Host}; 6 | 7 | /// Start http server asynchronously and returns result with `Server` handle on success or an error. 8 | pub fn start_http( 9 | addr: &SocketAddr, 10 | cors_domains: Option>, 11 | allowed_hosts: Option>, 12 | handler: jsonrpc_core::MetaIoHandler, 13 | ) -> Result { 14 | 15 | let cors_domains = cors_domains.map(|domains| { 16 | domains.into_iter() 17 | .map(|v| match v.as_str() { 18 | "*" => jsonrpc_http_server::AccessControlAllowOrigin::Any, 19 | "null" => jsonrpc_http_server::AccessControlAllowOrigin::Null, 20 | v => jsonrpc_http_server::AccessControlAllowOrigin::Value(v.into()), 21 | }) 22 | .collect() 23 | }); 24 | 25 | ServerBuilder::new(handler) 26 | .cors(cors_domains.into()) 27 | .allowed_hosts(allowed_hosts.map(|hosts| hosts.into_iter().map(Host::from).collect()).into()) 28 | .start_http(addr) 29 | } 30 | -------------------------------------------------------------------------------- /message/src/common/block_transactions_request.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use hash::H256; 3 | use ser::{ 4 | Serializable, Stream, CompactInteger, 5 | Deserializable, Reader, Error as ReaderError, 6 | }; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct BlockTransactionsRequest { 10 | pub blockhash: H256, 11 | pub indexes: Vec, 12 | } 13 | 14 | impl Serializable for BlockTransactionsRequest { 15 | fn serialize(&self, stream: &mut Stream) { 16 | let indexes: Vec = self.indexes 17 | .iter() 18 | .map(|x| (*x).into()) 19 | .collect(); 20 | 21 | stream 22 | .append(&self.blockhash) 23 | .append_list(&indexes); 24 | } 25 | } 26 | 27 | impl Deserializable for BlockTransactionsRequest { 28 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 29 | let blockhash = try!(reader.read()); 30 | let indexes: Vec = try!(reader.read_list()); 31 | 32 | let request = BlockTransactionsRequest { 33 | blockhash: blockhash, 34 | indexes: indexes.into_iter().map(Into::into).collect(), 35 | }; 36 | 37 | Ok(request) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/clippy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # NOTE! 4 | # this script requires nightly version of rustc 5 | # clippy plugin needs to be compiled with the same nightly version as currently set one 6 | # tested with clippy 0.0.98 7 | 8 | # temporary workaround for cargo clippy issue #1330 9 | # https://github.com/Manishearth/rust-clippy/issues/1330 10 | 11 | # first, let's enter any directory in a workspace with target kind `lib` 12 | # https://github.com/Manishearth/rust-clippy/blob/6a73c8f8e3f513f6a16c6876be3d326633dbc78d/src/main.rs#L186 13 | cd primitives 14 | 15 | # now let's run clippy 16 | # clippy does not support multiple packages, so let's run them one after another 17 | cargo clippy -p bitcrypto 18 | cargo clippy -p chain 19 | cargo clippy -p db 20 | cargo clippy -p import 21 | cargo clippy -p keys 22 | cargo clippy -p message 23 | cargo clippy -p miner 24 | cargo clippy -p network 25 | cargo clippy -p p2p 26 | cargo clippy -p primitives 27 | cargo clippy -p rpc 28 | cargo clippy -p script 29 | cargo clippy -p serialization 30 | cargo clippy -p sync 31 | cargo clippy -p test-data 32 | cargo clippy -p verification 33 | 34 | -------------------------------------------------------------------------------- /chain/src/constants.rs: -------------------------------------------------------------------------------- 1 | 2 | // Below flags apply in the context of BIP 68 3 | // If this flag set, CTxIn::nSequence is NOT interpreted as a 4 | // relative lock-time. 5 | pub const SEQUENCE_LOCKTIME_DISABLE_FLAG: u32 = 1u32 << 31; 6 | 7 | // Setting nSequence to this value for every input in a transaction 8 | // disables nLockTime. 9 | pub const SEQUENCE_FINAL: u32 = 0xffffffff; 10 | 11 | // If CTxIn::nSequence encodes a relative lock-time and this flag 12 | // is set, the relative lock-time has units of 512 seconds, 13 | // otherwise it specifies blocks with a granularity of 1. 14 | pub const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = (1 << 22); 15 | 16 | // If CTxIn::nSequence encodes a relative lock-time, this mask is 17 | // applied to extract that lock-time from the sequence field. 18 | pub const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff; 19 | 20 | /// Threshold for `nLockTime`: below this value it is interpreted as block number, 21 | /// otherwise as UNIX timestamp. 22 | pub const LOCKTIME_THRESHOLD: u32 = 500000000; // Tue Nov 5 00:53:20 1985 UTC 23 | 24 | /// Number of Satoshis in single coin 25 | pub const SATOSHIS_IN_COIN: u64 = 100_000_000; 26 | -------------------------------------------------------------------------------- /storage/src/block_origin.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use hash::H256; 3 | 4 | #[derive(Clone)] 5 | pub struct SideChainOrigin { 6 | /// newest ancestor block number 7 | pub ancestor: u32, 8 | /// side chain block hashes. Ordered from oldest to newest 9 | pub canonized_route: Vec, 10 | /// canon chain block hahses. Ordered from oldest to newest 11 | pub decanonized_route: Vec, 12 | /// new block number 13 | pub block_number: u32, 14 | } 15 | 16 | impl fmt::Debug for SideChainOrigin { 17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 18 | f.debug_struct("SideChainOrigin") 19 | .field("ancestor", &self.ancestor) 20 | .field("canonized_route", &self.canonized_route.iter().map(|h| h.reversed()).collect::>()) 21 | .field("decanonized_route", &self.decanonized_route.iter().map(|h| h.reversed()).collect::>()) 22 | .field("block_number", &self.block_number) 23 | .finish() 24 | } 25 | } 26 | 27 | #[derive(Debug)] 28 | pub enum BlockOrigin { 29 | KnownBlock, 30 | CanonChain { 31 | block_number: u32, 32 | }, 33 | SideChain(SideChainOrigin), 34 | SideChainBecomingCanonChain(SideChainOrigin), 35 | } 36 | -------------------------------------------------------------------------------- /p2p/src/net/channel.rs: -------------------------------------------------------------------------------- 1 | use tokio_io::io::{write_all, WriteAll}; 2 | use session::Session; 3 | use io::{SharedTcpStream, read_any_message, ReadAnyMessage}; 4 | use util::PeerInfo; 5 | 6 | pub struct Channel { 7 | stream: SharedTcpStream, 8 | peer_info: PeerInfo, 9 | session: Session, 10 | } 11 | 12 | impl Channel { 13 | pub fn new(stream: SharedTcpStream, peer_info: PeerInfo, session: Session) -> Self { 14 | Channel { 15 | stream: stream, 16 | peer_info: peer_info, 17 | session: session, 18 | } 19 | } 20 | 21 | pub fn write_message(&self, message: T) -> WriteAll where T: AsRef<[u8]> { 22 | write_all(self.stream.clone(), message) 23 | } 24 | 25 | pub fn read_message(&self) -> ReadAnyMessage { 26 | read_any_message(self.stream.clone(), self.peer_info.magic) 27 | } 28 | 29 | pub fn shutdown(&self) { 30 | self.stream.shutdown(); 31 | } 32 | 33 | pub fn version(&self) -> u32 { 34 | self.peer_info.version 35 | } 36 | 37 | pub fn peer_info(&self) -> PeerInfo { 38 | self.peer_info.clone() 39 | } 40 | 41 | pub fn session(&self) -> &Session { 42 | &self.session 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /keys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Bitcoin keys. 2 | 3 | extern crate rand; 4 | extern crate rustc_hex as hex; 5 | #[macro_use] 6 | extern crate lazy_static; 7 | extern crate base58; 8 | extern crate secp256k1; 9 | extern crate bitcrypto as crypto; 10 | extern crate primitives; 11 | 12 | pub mod generator; 13 | mod address; 14 | mod display; 15 | mod keypair; 16 | mod error; 17 | mod network; 18 | mod private; 19 | mod public; 20 | mod signature; 21 | 22 | pub use primitives::{hash, bytes}; 23 | 24 | pub use address::{Type, Address}; 25 | pub use display::DisplayLayout; 26 | pub use keypair::KeyPair; 27 | pub use error::Error; 28 | pub use private::Private; 29 | pub use public::Public; 30 | pub use signature::{Signature, CompactSignature}; 31 | pub use network::Network; 32 | 33 | use hash::{H160, H256}; 34 | 35 | /// 20 bytes long hash derived from public `ripemd160(sha256(public))` 36 | pub type AddressHash = H160; 37 | /// 32 bytes long secret key 38 | pub type Secret = H256; 39 | /// 32 bytes long signable message 40 | pub type Message = H256; 41 | 42 | lazy_static! { 43 | pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /p2p/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate futures; 3 | extern crate futures_cpupool; 4 | extern crate rand; 5 | extern crate time; 6 | extern crate tokio_core; 7 | extern crate tokio_io; 8 | extern crate parking_lot; 9 | #[macro_use] 10 | extern crate log; 11 | extern crate abstract_ns; 12 | extern crate ns_dns_tokio; 13 | extern crate csv; 14 | 15 | extern crate bitcrypto as crypto; 16 | extern crate message; 17 | extern crate primitives; 18 | extern crate serialization as ser; 19 | extern crate network; 20 | 21 | mod io; 22 | mod net; 23 | mod protocol; 24 | mod session; 25 | mod util; 26 | mod config; 27 | mod event_loop; 28 | mod p2p; 29 | 30 | pub use primitives::{hash, bytes}; 31 | 32 | pub use config::Config; 33 | pub use net::Config as NetConfig; 34 | pub use p2p::{P2P, Context}; 35 | pub use event_loop::{event_loop, forever}; 36 | pub use util::{NodeTableError, PeerId, PeerInfo, InternetProtocol, Direction}; 37 | pub use protocol::{ 38 | InboundSyncConnection, InboundSyncConnectionRef, 39 | InboundSyncConnectionState, InboundSyncConnectionStateRef, 40 | OutboundSyncConnection, OutboundSyncConnectionRef, 41 | LocalSyncNode, LocalSyncNodeRef, 42 | }; 43 | -------------------------------------------------------------------------------- /message/src/types/merkle_block.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use hash::H256; 3 | use bytes::Bytes; 4 | use ser::{Stream, Reader}; 5 | use chain::BlockHeader; 6 | use {Payload, MessageResult}; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct MerkleBlock { 10 | pub block_header: BlockHeader, 11 | pub total_transactions: u32, 12 | pub hashes: Vec, 13 | pub flags: Bytes, 14 | } 15 | 16 | impl Payload for MerkleBlock { 17 | fn version() -> u32 { 18 | 70014 19 | } 20 | 21 | fn command() -> &'static str { 22 | "merkleblock" 23 | } 24 | 25 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 26 | let merkle_block = MerkleBlock { 27 | block_header: try!(reader.read()), 28 | total_transactions: try!(reader.read()), 29 | hashes: try!(reader.read_list()), 30 | flags: try!(reader.read()), 31 | }; 32 | 33 | Ok(merkle_block) 34 | } 35 | 36 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 37 | stream 38 | .append(&self.block_header) 39 | .append(&self.total_transactions) 40 | .append_list(&self.hashes) 41 | .append(&self.flags); 42 | Ok(()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /message/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt, error}; 2 | use ser::Error as ReaderError; 3 | 4 | pub type MessageResult = Result; 5 | 6 | #[derive(Debug, PartialEq, Clone)] 7 | pub enum Error { 8 | /// Deserialization failed. 9 | Deserialize, 10 | /// Command has wrong format or is unsupported. 11 | InvalidCommand, 12 | /// Network magic comes from different network. 13 | InvalidMagic, 14 | /// Invalid checksum. 15 | InvalidChecksum, 16 | /// Invalid version. 17 | InvalidVersion, 18 | } 19 | 20 | impl From for Error { 21 | fn from(_: ReaderError) -> Self { 22 | Error::Deserialize 23 | } 24 | } 25 | 26 | impl fmt::Display for Error { 27 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 28 | f.write_str(error::Error::description(self)) 29 | } 30 | } 31 | 32 | impl error::Error for Error { 33 | fn description(&self) -> &str { 34 | match *self { 35 | Error::Deserialize => "Message Deserialization Error", 36 | Error::InvalidCommand => "Invalid Message Command", 37 | Error::InvalidMagic => "Invalid Network Magic", 38 | Error::InvalidChecksum => "Invalid message chacksum", 39 | Error::InvalidVersion => "Unsupported protocol version", 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rpc/src/v1/types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod address; 2 | mod block; 3 | mod block_template; 4 | mod block_template_request; 5 | mod bytes; 6 | mod get_block_response; 7 | mod get_tx_out_response; 8 | mod get_tx_out_set_info_response; 9 | mod hash; 10 | mod script; 11 | mod transaction; 12 | mod uint; 13 | mod nodes; 14 | 15 | pub use self::block::{BlockRef, RawBlock}; 16 | pub use self::block_template::{BlockTemplate, BlockTemplateTransaction}; 17 | pub use self::block_template_request::{BlockTemplateRequest, BlockTemplateRequestMode}; 18 | pub use self::bytes::Bytes; 19 | pub use self::get_block_response::{GetBlockResponse, VerboseBlock}; 20 | pub use self::get_tx_out_response::GetTxOutResponse; 21 | pub use self::get_tx_out_set_info_response::GetTxOutSetInfoResponse; 22 | pub use self::hash::{H160, H256}; 23 | pub use self::script::ScriptType; 24 | pub use self::transaction::{RawTransaction, Transaction, TransactionInput, TransactionOutput, 25 | TransactionOutputWithAddress, TransactionOutputWithScriptData, TransactionInputScript, 26 | TransactionOutputScript, SignedTransactionInput, GetRawTransactionResponse, 27 | SignedTransactionOutput, TransactionOutputs}; 28 | pub use self::uint::U256; 29 | pub use self::nodes::{AddNodeOperation, NodeInfo}; 30 | -------------------------------------------------------------------------------- /sync/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | mod average_speed_meter; 2 | mod best_headers_chain; 3 | mod bloom_filter; 4 | mod connection_filter; 5 | mod fee_rate_filter; 6 | mod hash_queue; 7 | mod known_hash_filter; 8 | mod memory_pool_transaction_provider; 9 | mod orphan_blocks_pool; 10 | mod orphan_transactions_pool; 11 | mod partial_merkle_tree; 12 | mod synchronization_state; 13 | 14 | pub use self::average_speed_meter::AverageSpeedMeter; 15 | pub use self::best_headers_chain::{BestHeadersChain, Information as BestHeadersChainInformation}; 16 | pub use self::bloom_filter::BloomFilter; 17 | pub use self::connection_filter::ConnectionFilter; 18 | pub use self::fee_rate_filter::FeeRateFilter; 19 | pub use self::hash_queue::{HashQueue, HashQueueChain, HashPosition}; 20 | pub use self::known_hash_filter::{KnownHashType, KnownHashFilter}; 21 | pub use self::memory_pool_transaction_provider::MemoryPoolTransactionOutputProvider; 22 | pub use self::orphan_blocks_pool::OrphanBlocksPool; 23 | pub use self::orphan_transactions_pool::{OrphanTransactionsPool, OrphanTransaction}; 24 | pub use self::partial_merkle_tree::{PartialMerkleTree, build_partial_merkle_tree}; 25 | pub use self::synchronization_state::SynchronizationState; 26 | 27 | /// Block height type 28 | pub type BlockHeight = u32; 29 | -------------------------------------------------------------------------------- /message/src/message/message.rs: -------------------------------------------------------------------------------- 1 | use ser::Stream; 2 | use bytes::{TaggedBytes, Bytes}; 3 | use network::Magic; 4 | use common::Command; 5 | use serialization::serialize_payload; 6 | use {Payload, MessageResult, MessageHeader}; 7 | 8 | pub fn to_raw_message(magic: Magic, command: Command, payload: &Bytes) -> Bytes { 9 | let header = MessageHeader::for_data(magic, command, payload); 10 | let mut stream = Stream::default(); 11 | stream.append(&header); 12 | stream.append_slice(payload); 13 | stream.out() 14 | } 15 | 16 | pub struct Message { 17 | bytes: TaggedBytes, 18 | } 19 | 20 | impl Message where T: Payload { 21 | pub fn new(magic: Magic, version: u32, payload: &T) -> MessageResult { 22 | let serialized = try!(serialize_payload(payload, version)); 23 | 24 | let message = Message { 25 | bytes: TaggedBytes::new(to_raw_message(magic, T::command().into(), &serialized)), 26 | }; 27 | 28 | Ok(message) 29 | } 30 | 31 | pub fn len(&self) -> usize { 32 | self.bytes.len() 33 | } 34 | } 35 | 36 | impl AsRef<[u8]> for Message { 37 | fn as_ref(&self) -> &[u8] { 38 | self.bytes.as_ref() 39 | } 40 | } 41 | 42 | impl From> for Bytes { 43 | fn from(m: Message) -> Self { 44 | m.bytes.into_raw() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /p2p/src/net/config.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use network::Magic; 3 | use message::common::{Services, NetAddress}; 4 | use message::types::version::{Version, V0, V106, V70001}; 5 | use util::time::{Time, RealTime}; 6 | use util::nonce::{NonceGenerator, RandomNonce}; 7 | 8 | #[derive(Debug, Clone)] 9 | pub struct Config { 10 | pub protocol_version: u32, 11 | pub protocol_minimum: u32, 12 | pub magic: Magic, 13 | pub local_address: SocketAddr, 14 | pub services: Services, 15 | pub user_agent: String, 16 | pub start_height: i32, 17 | pub relay: bool, 18 | } 19 | 20 | impl Config { 21 | pub fn version(&self, to: &SocketAddr) -> Version { 22 | Version::V70001(V0 { 23 | version: self.protocol_version, 24 | services: self.services, 25 | timestamp: RealTime.get().sec, 26 | receiver: NetAddress { 27 | services: self.services, 28 | address: to.ip().into(), 29 | port: to.port().into(), 30 | }, 31 | }, V106 { 32 | from: NetAddress { 33 | services: self.services, 34 | address: self.local_address.ip().into(), 35 | port: self.local_address.port().into(), 36 | }, 37 | nonce: RandomNonce.get(), 38 | user_agent: self.user_agent.clone(), 39 | start_height: self.start_height, 40 | }, V70001 { 41 | relay: self.relay, 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /crypto/src/groth16.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use hex::ToHex; 4 | 5 | use pairing::bls12_381::Bls12; 6 | use bellman::groth16::Proof as BellmanProof; 7 | 8 | #[derive(Clone)] 9 | pub struct Proof([u8; 192]); 10 | 11 | #[derive(Debug)] 12 | pub enum Error { 13 | InvalidData, 14 | } 15 | 16 | impl fmt::Debug for Proof { 17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 18 | f.write_fmt(format_args!("{:?}", &self.0.to_hex::())) 19 | } 20 | } 21 | 22 | impl PartialEq for Proof { 23 | fn eq(&self, other: &Proof) -> bool { 24 | self.0.as_ref() == other.0.as_ref() 25 | } 26 | } 27 | 28 | impl Default for Proof { 29 | fn default() -> Self { 30 | Self([0u8; 192]) 31 | } 32 | } 33 | 34 | impl From<[u8; 192]> for Proof { 35 | fn from(val: [u8; 192]) -> Self { 36 | Proof(val) 37 | } 38 | } 39 | 40 | impl Into<[u8; 192]> for Proof { 41 | fn into(self) -> [u8; 192] { 42 | self.0 43 | } 44 | } 45 | 46 | impl<'a> Into<&'a [u8; 192]> for &'a Proof { 47 | fn into(self) -> &'a [u8; 192] { 48 | &self.0 49 | } 50 | } 51 | 52 | impl Proof { 53 | pub fn to_bls_proof(&self) -> Result, Error> { 54 | BellmanProof::::read(&self.0[..]) 55 | .map_err(|_| /* only invalid point data possible, length is always ok */ Error::InvalidData) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /keys/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use secp256k1::Error as SecpError; 3 | 4 | #[derive(Debug, PartialEq)] 5 | pub enum Error { 6 | InvalidPublic, 7 | InvalidSecret, 8 | InvalidMessage, 9 | InvalidSignature, 10 | InvalidNetwork, 11 | InvalidChecksum, 12 | InvalidPrivate, 13 | InvalidAddress, 14 | FailedKeyGeneration, 15 | } 16 | 17 | impl fmt::Display for Error { 18 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 19 | let msg = match *self { 20 | Error::InvalidPublic => "Invalid Public", 21 | Error::InvalidSecret => "Invalid Secret", 22 | Error::InvalidMessage => "Invalid Message", 23 | Error::InvalidSignature => "Invalid Signature", 24 | Error::InvalidNetwork => "Invalid Network", 25 | Error::InvalidChecksum => "Invalid Checksum", 26 | Error::InvalidPrivate => "Invalid Private", 27 | Error::InvalidAddress => "Invalid Address", 28 | Error::FailedKeyGeneration => "Key generation failed", 29 | }; 30 | 31 | msg.fmt(f) 32 | } 33 | } 34 | 35 | impl From for Error { 36 | fn from(e: SecpError) -> Self { 37 | match e { 38 | SecpError::InvalidPublicKey => Error::InvalidPublic, 39 | SecpError::InvalidSecretKey => Error::InvalidSecret, 40 | SecpError::InvalidMessage => Error::InvalidMessage, 41 | _ => Error::InvalidSignature, 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tools/deb-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e # fail on any error 4 | set -u # treat unset variables as error 5 | rm -rf deb 6 | #create DEBIAN files 7 | mkdir -p deb/usr/bin/ 8 | mkdir -p deb/DEBIAN 9 | #create copyright, docs, compat 10 | cp LICENSE deb/DEBIAN/copyright 11 | echo "https://github.com/paritytech/parity-bitcoin/" >> deb/DEBIAN/docs 12 | echo "8" >> deb/DEBIAN/compat 13 | #create control file 14 | control=deb/DEBIAN/control 15 | echo "Package: pbtc" >> $control 16 | version=`grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n"` 17 | echo "Version: $version" >> $control 18 | echo "Source: pbtc" >> $control 19 | echo "Section: science" >> $control 20 | echo "Priority: extra" >> $control 21 | echo "Maintainer: Parity Technologies " >> $control 22 | echo "Build-Depends: debhelper (>=9)" >> $control 23 | echo "Standards-Version: 3.9.5" >> $control 24 | echo "Homepage: https://parity.io" >> $control 25 | echo "Vcs-Git: git://github.com/paritytech/parity-bitcoin.git" >> $control 26 | echo "Vcs-Browser: https://github.com/paritytech/parity-bitcoin" >> $control 27 | echo "Architecture: $1" >> $control 28 | echo "Depends: libssl1.0.0 (>=1.0.0)" >> $control 29 | echo "Description: Bitcoin network client by Parity Technologies" >> $control 30 | #build .deb package 31 | 32 | exit 33 | -------------------------------------------------------------------------------- /tools/deb_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e # fail on any error 4 | set -u # treat unset variables as error 5 | rm -rf deb 6 | #create DEBIAN files 7 | mkdir -p deb/usr/bin/ 8 | mkdir -p deb/DEBIAN 9 | #create copyright, docs, compat 10 | cp LICENSE deb/DEBIAN/copyright 11 | echo "https://github.com/paritytech/parity-bitcoin/" >> deb/DEBIAN/docs 12 | echo "8" >> deb/DEBIAN/compat 13 | #create control file 14 | control=deb/DEBIAN/control 15 | echo "Package: pbtc" >> $control 16 | version=`grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n"` 17 | echo "Version: $version" >> $control 18 | echo "Source: pbtc" >> $control 19 | echo "Section: science" >> $control 20 | echo "Priority: extra" >> $control 21 | echo "Maintainer: Parity Technologies " >> $control 22 | echo "Build-Depends: debhelper (>=9)" >> $control 23 | echo "Standards-Version: 3.9.5" >> $control 24 | echo "Homepage: https://parity.io" >> $control 25 | echo "Vcs-Git: git://github.com/paritytech/parity-bitcoin.git" >> $control 26 | echo "Vcs-Browser: https://github.com/paritytech/parity-bitcoin" >> $control 27 | echo "Architecture: $1" >> $control 28 | echo "Depends: libssl1.0.0 (>=1.0.0)" >> $control 29 | echo "Description: Bitcoin network client by Parity Technologies" >> $control 30 | #build .deb package 31 | 32 | exit 33 | -------------------------------------------------------------------------------- /message/src/types/getheaders.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use hash::H256; 3 | use ser::{Stream, Reader}; 4 | use {Payload, MessageResult}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct GetHeaders { 8 | pub version: u32, 9 | pub block_locator_hashes: Vec, 10 | pub hash_stop: H256, 11 | } 12 | 13 | impl GetHeaders { 14 | pub fn with_block_locator_hashes(block_locator_hashes: Vec) -> Self { 15 | GetHeaders { 16 | version: 0, // this field is ignored by implementations 17 | block_locator_hashes: block_locator_hashes, 18 | hash_stop: H256::default(), 19 | } 20 | } 21 | } 22 | 23 | impl Payload for GetHeaders { 24 | fn version() -> u32 { 25 | 0 26 | } 27 | 28 | fn command() -> &'static str { 29 | "getheaders" 30 | } 31 | 32 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 33 | let get_blocks = GetHeaders { 34 | version: try!(reader.read()), 35 | block_locator_hashes: try!(reader.read_list_max(2000)), 36 | hash_stop: try!(reader.read()), 37 | }; 38 | 39 | Ok(get_blocks) 40 | } 41 | 42 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 43 | stream 44 | .append(&self.version) 45 | .append_list(&self.block_locator_hashes) 46 | .append(&self.hash_stop); 47 | Ok(()) 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /storage/src/block_impls.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | use chain::{OutPoint, TransactionOutput, IndexedBlock, IndexedTransaction}; 3 | use {TransactionOutputProvider}; 4 | 5 | fn transaction_output(transactions: &[IndexedTransaction], prevout: &OutPoint) -> Option { 6 | transactions.iter() 7 | .find(|tx| tx.hash == prevout.hash) 8 | .and_then(|tx| tx.raw.outputs.get(prevout.index as usize)) 9 | .cloned() 10 | } 11 | 12 | fn is_spent(transactions: &[IndexedTransaction], prevout: &OutPoint) -> bool { 13 | // TODO: the code below is valid, but has rather poor performance! 14 | 15 | // if previous transaction output appears more than once than we can safely 16 | // tell that it's spent (double spent) 17 | let spends = transactions.iter() 18 | .flat_map(|tx| &tx.raw.inputs) 19 | .filter(|input| &input.previous_output == prevout) 20 | .take(2) 21 | .count(); 22 | 23 | spends == 2 24 | } 25 | 26 | impl TransactionOutputProvider for IndexedBlock { 27 | fn transaction_output(&self, outpoint: &OutPoint, transaction_index: usize) -> Option { 28 | let take = cmp::min(transaction_index, self.transactions.len()); 29 | transaction_output(&self.transactions[..take], outpoint) 30 | } 31 | 32 | fn is_spent(&self, outpoint: &OutPoint) -> bool { 33 | is_spent(&self.transactions, outpoint) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chain/src/solution.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt, io}; 2 | use hex::ToHex; 3 | use ser::{Error, Serializable, Deserializable, Stream, Reader}; 4 | 5 | /// Equihash solution size. 6 | pub const SOLUTION_SIZE: usize = 1344; 7 | 8 | #[derive(Clone)] 9 | pub struct EquihashSolution([u8; SOLUTION_SIZE]); 10 | 11 | impl AsRef<[u8]> for EquihashSolution { 12 | fn as_ref(&self) -> &[u8] { 13 | &self.0 14 | } 15 | } 16 | 17 | impl Default for EquihashSolution { 18 | fn default() -> Self { 19 | EquihashSolution([0; SOLUTION_SIZE]) 20 | } 21 | } 22 | 23 | impl PartialEq for EquihashSolution { 24 | fn eq(&self, other: &EquihashSolution) -> bool { 25 | self.0.as_ref() == other.0.as_ref() 26 | } 27 | } 28 | 29 | impl fmt::Debug for EquihashSolution { 30 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 31 | f.write_str(&self.0.to_hex::()) 32 | } 33 | } 34 | 35 | impl Serializable for EquihashSolution { 36 | fn serialize(&self, stream: &mut Stream) { 37 | stream.append_list(&self.0); 38 | } 39 | } 40 | 41 | impl Deserializable for EquihashSolution { 42 | fn deserialize(reader: &mut Reader) -> Result where Self: Sized, T: io::Read { 43 | let v = reader.read_list_exact(SOLUTION_SIZE)?; 44 | let mut sol = [0; SOLUTION_SIZE]; 45 | sol.copy_from_slice(&v); 46 | Ok(EquihashSolution(sol)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /message/src/common/port.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 3 | use ser::{Serializable, Stream, Deserializable, Reader, Error as ReaderError}; 4 | 5 | #[derive(Debug, Default, PartialEq, Clone, Copy)] 6 | pub struct Port(u16); 7 | 8 | impl From for Port { 9 | fn from(port: u16) -> Self { 10 | Port(port) 11 | } 12 | } 13 | 14 | impl From for u16 { 15 | fn from(port: Port) -> Self { 16 | port.0 17 | } 18 | } 19 | 20 | impl Serializable for Port { 21 | fn serialize(&self, stream: &mut Stream) { 22 | stream.write_u16::(self.0).unwrap(); 23 | } 24 | } 25 | 26 | impl Deserializable for Port { 27 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 28 | Ok(try!(reader.read_u16::().map(Port))) 29 | } 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use ser::{serialize, deserialize}; 35 | use super::Port; 36 | 37 | #[test] 38 | fn test_port_serialize() { 39 | assert_eq!(serialize(&Port::from(1)), "0001".into()); 40 | assert_eq!(serialize(&Port::from(0x1234)), "1234".into()); 41 | } 42 | 43 | #[test] 44 | fn test_port_deserialize() { 45 | assert_eq!(Port::from(1), deserialize(&[0x00u8, 0x01] as &[u8]).unwrap()); 46 | assert_eq!(Port::from(0x1234), deserialize(&[0x12u8, 0x34] as &[u8]).unwrap()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rpc/src/v1/types/block.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::str::FromStr; 3 | use serde::de::{Deserialize, Deserializer, Unexpected}; 4 | use super::bytes::Bytes; 5 | use super::hash::H256; 6 | 7 | /// Hex-encoded block 8 | pub type RawBlock = Bytes; 9 | 10 | /// Block reference 11 | #[derive(Debug)] 12 | pub enum BlockRef { 13 | /// References block by its number 14 | Number(u32), 15 | /// References block by its hash 16 | Hash(H256), 17 | } 18 | 19 | impl<'a> Deserialize<'a> for BlockRef { 20 | fn deserialize(deserializer: D) -> Result where D: Deserializer<'a> { 21 | use serde::de::Visitor; 22 | 23 | struct BlockRefVisitor; 24 | 25 | impl<'b> Visitor<'b> for BlockRefVisitor { 26 | type Value = BlockRef; 27 | 28 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 29 | formatter.write_str("either block number of hash") 30 | } 31 | 32 | fn visit_str(self, value: &str) -> Result where E: ::serde::de::Error { 33 | if value.len() == 64 { 34 | H256::from_str(value).map(BlockRef::Hash) 35 | .map_err(|_| E::invalid_value(Unexpected::Str(value), &self)) 36 | } else { 37 | u32::from_str(value).map(BlockRef::Number) 38 | .map_err(|_| E::invalid_value(Unexpected::Str(value), &self)) 39 | } 40 | } 41 | } 42 | 43 | deserializer.deserialize_identifier(BlockRefVisitor) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pzec/commands/import.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use sync::{create_sync_blocks_writer, Error}; 3 | use config::Config; 4 | use util::init_db; 5 | 6 | pub fn import(cfg: Config, matches: &ArgMatches) -> Result<(), String> { 7 | try!(init_db(&cfg)); 8 | 9 | let blk_path = matches.value_of("PATH").expect("PATH is required in cli.yml; qed"); 10 | let blk_dir = ::import::open_blk_dir(blk_path) 11 | .map_err(|err| format!("Failed to open import directory: {}", err))?; 12 | 13 | let mut writer = create_sync_blocks_writer(cfg.db, cfg.consensus, cfg.verification_params); 14 | let mut counter = 0; 15 | let mut previous_hash = None; 16 | for blk in blk_dir { 17 | // TODO: verify magic! 18 | let blk = blk.map_err(|err| format!("Cannot read block: {:?}. Previous block: {:?}", err, previous_hash))?; 19 | let blk_hash = blk.block.hash().reversed(); 20 | match writer.append_block(blk.block) { 21 | Ok(_) => { 22 | counter += 1; 23 | if counter % 1000 == 0 { 24 | info!(target: "sync", "Imported {} blocks", counter); 25 | } 26 | } 27 | Err(Error::TooManyOrphanBlocks) => return Err("Too many orphan (unordered) blocks".into()), 28 | Err(err) => return Err(format!("Cannot append block: {:?}. Block: {}", err, blk_hash)), 29 | } 30 | 31 | previous_hash = Some(blk_hash); 32 | } 33 | 34 | info!("Finished import of {} blocks", counter); 35 | 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /storage/src/block_provider.rs: -------------------------------------------------------------------------------- 1 | use hash::H256; 2 | use bytes::Bytes; 3 | use chain::{IndexedBlock, IndexedBlockHeader, IndexedTransaction}; 4 | use {BlockRef}; 5 | 6 | pub trait BlockHeaderProvider { 7 | /// resolves header bytes by block reference (number/hash) 8 | fn block_header_bytes(&self, block_ref: BlockRef) -> Option; 9 | 10 | /// resolves header bytes by block reference (number/hash) 11 | fn block_header(&self, block_ref: BlockRef) -> Option; 12 | } 13 | 14 | pub trait BlockProvider: BlockHeaderProvider { 15 | /// resolves number by block hash 16 | fn block_number(&self, hash: &H256) -> Option; 17 | 18 | /// resolves hash by block number 19 | fn block_hash(&self, number: u32) -> Option; 20 | 21 | /// resolves deserialized block body by block reference (number/hash) 22 | fn block(&self, block_ref: BlockRef) -> Option; 23 | 24 | /// returns true if store contains given block 25 | fn contains_block(&self, block_ref: BlockRef) -> bool { 26 | self.block_header_bytes(block_ref).is_some() 27 | } 28 | 29 | /// resolves list of block transactions by block reference (number/hash) 30 | fn block_transaction_hashes(&self, block_ref: BlockRef) -> Vec; 31 | 32 | /// returns all transactions in the block by block reference (number/hash) 33 | fn block_transactions(&self, block_ref: BlockRef) -> Vec; 34 | } 35 | -------------------------------------------------------------------------------- /p2p/src/io/deadline.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::time::Duration; 3 | use futures::{Future, Select, Poll, Async}; 4 | use tokio_core::reactor::{Handle, Timeout}; 5 | 6 | type DeadlineBox = Box::Item>, Error = ::Error> + Send>; 7 | 8 | pub fn deadline(duration: Duration, handle: &Handle, future: F) -> Result, io::Error> 9 | where F: Future + Send + 'static, T: 'static { 10 | let timeout: DeadlineBox = Box::new(try!(Timeout::new(duration, handle)).map(|_| DeadlineStatus::Timeout)); 11 | let future: DeadlineBox = Box::new(future.map(DeadlineStatus::Meet)); 12 | let deadline = Deadline { 13 | future: timeout.select(future), 14 | }; 15 | Ok(deadline) 16 | } 17 | 18 | pub enum DeadlineStatus { 19 | Meet(T), 20 | Timeout, 21 | } 22 | 23 | pub struct Deadline where F: Future + Send { 24 | future: Select, DeadlineBox>, 25 | } 26 | 27 | impl Future for Deadline where F: Future + Send { 28 | type Item = DeadlineStatus; 29 | type Error = io::Error; 30 | 31 | fn poll(&mut self) -> Poll { 32 | match self.future.poll() { 33 | Ok(Async::Ready((result, _other))) => Ok(Async::Ready(result)), 34 | Ok(Async::NotReady) => Ok(Async::NotReady), 35 | Err((err, _other)) => Err(err), 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pzec/commands/rollback.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use storage::BlockRef; 3 | use config::Config; 4 | use primitives::hash::H256; 5 | use util::init_db; 6 | 7 | pub fn rollback(cfg: Config, matches: &ArgMatches) -> Result<(), String> { 8 | try!(init_db(&cfg)); 9 | 10 | let block_ref = matches.value_of("BLOCK").expect("BLOCK is required in cli.yml; qed"); 11 | let block_ref = if block_ref.len() == 64 { 12 | BlockRef::Hash({ 13 | let hash: H256 = block_ref.parse().map_err(|e| format!("Invalid block number: {}", e))?; 14 | hash.reversed() 15 | }) 16 | } else { 17 | BlockRef::Number(block_ref.parse().map_err(|e| format!("Invalid block hash: {}", e))?) 18 | }; 19 | 20 | let required_block_hash = cfg.db.block_header(block_ref.clone()).ok_or(format!("Block {:?} is unknown", block_ref))?.hash; 21 | let genesis_hash = *cfg.network.genesis_block().hash(); 22 | 23 | let mut best_block_hash = cfg.db.best_block().hash; 24 | debug_assert!(best_block_hash != H256::default()); // genesis inserted in init_db 25 | 26 | loop { 27 | if best_block_hash == required_block_hash { 28 | info!("Reverted to block {:?}", block_ref); 29 | return Ok(()); 30 | } 31 | 32 | if best_block_hash == genesis_hash { 33 | return Err(format!("Failed to revert to block {:?}. Reverted to genesis", block_ref)); 34 | } 35 | 36 | best_block_hash = cfg.db.rollback_best().map_err(|e| format!("{:?}", e))?; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /storage/src/block_chain.rs: -------------------------------------------------------------------------------- 1 | use hash::H256; 2 | use chain::{IndexedBlock, IndexedBlockHeader}; 3 | use {Error, BlockOrigin, Store, SideChainOrigin}; 4 | 5 | pub trait ForkChain { 6 | /// Returns forks underlaying store. 7 | fn store(&self) -> &Store; 8 | 9 | /// Flush fork changes to canon chain. 10 | /// Should not be used directly from outside of `BlockChain`. 11 | fn flush(&self) -> Result<(), Error>; 12 | } 13 | 14 | pub trait BlockChain { 15 | /// Inserts new block into blockchain 16 | fn insert(&self, block: IndexedBlock) -> Result<(), Error>; 17 | 18 | /// Rollbacks single best block. Returns new best block hash 19 | fn rollback_best(&self) -> Result; 20 | 21 | /// Canonizes block with given hash 22 | fn canonize(&self, block_hash: &H256) -> Result<(), Error>; 23 | 24 | /// Decanonizes best block 25 | fn decanonize(&self) -> Result; 26 | 27 | /// Checks block origin 28 | fn block_origin(&self, header: &IndexedBlockHeader) -> Result; 29 | } 30 | 31 | pub trait Forkable { 32 | /// Forks current blockchain. 33 | /// Lifetime guarantees fork relationship with canon chain. 34 | fn fork<'a>(&'a self, side_chain: SideChainOrigin) -> Result, Error>; 35 | 36 | /// Switches blockchain to given fork. 37 | /// Lifetime guarantees that fork comes from this canon chain. 38 | fn switch_to_fork<'a>(&'a self, fork: Box) -> Result<(), Error>; 39 | } 40 | -------------------------------------------------------------------------------- /serialization/src/fixed_array.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use { 3 | Serializable, Stream, 4 | Deserializable, Reader, Error 5 | }; 6 | 7 | /// Something that can be used to initialize empty array. 8 | pub trait DefaultItem: Copy { 9 | fn default() -> Self; 10 | } 11 | 12 | macro_rules! impl_default_item { 13 | ($type: ty) => { 14 | impl DefaultItem for $type { 15 | fn default() -> Self { 16 | Default::default() 17 | } 18 | } 19 | } 20 | } 21 | 22 | macro_rules! impl_fixed_array { 23 | ($size: expr) => { 24 | impl DefaultItem for [T; $size] { 25 | fn default() -> Self { 26 | [T::default(); $size] 27 | } 28 | } 29 | 30 | impl Serializable for [T; $size] { 31 | fn serialize(&self, stream: &mut Stream) { 32 | self.iter().for_each(|item| { stream.append(item); }); 33 | } 34 | } 35 | 36 | impl Deserializable for [T; $size] { 37 | fn deserialize(reader: &mut Reader) -> Result where R: io::Read { 38 | let mut result = [T::default(); $size]; 39 | for i in 0..$size { 40 | result[i] = reader.read()?; 41 | } 42 | Ok(result) 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl_default_item!(u8); 49 | 50 | impl_fixed_array!(2); 51 | impl_fixed_array!(32); 52 | impl_fixed_array!(64); 53 | impl_fixed_array!(80); 54 | impl_fixed_array!(192); 55 | impl_fixed_array!(296); 56 | impl_fixed_array!(580); 57 | impl_fixed_array!(601); 58 | -------------------------------------------------------------------------------- /chain/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate rustc_hex as hex; 2 | extern crate heapsize; 3 | extern crate primitives; 4 | extern crate bitcrypto as crypto; 5 | extern crate serialization as ser; 6 | #[macro_use] 7 | extern crate serialization_derive; 8 | 9 | pub mod constants; 10 | 11 | mod block; 12 | mod block_header; 13 | mod solution; 14 | mod join_split; 15 | mod merkle_root; 16 | mod sapling; 17 | mod transaction; 18 | 19 | /// `IndexedBlock` extension 20 | mod read_and_hash; 21 | mod indexed_block; 22 | mod indexed_header; 23 | mod indexed_transaction; 24 | 25 | pub use primitives::{hash, bytes, bigint, compact}; 26 | 27 | pub use transaction::{BTC_TX_VERSION, SPROUT_TX_VERSION, OVERWINTER_TX_VERSION, SAPLING_TX_VERSION}; 28 | pub use transaction::{OVERWINTER_TX_VERSION_GROUP_ID, SAPLING_TX_VERSION_GROUP_ID}; 29 | 30 | pub use block::Block; 31 | pub use block_header::BlockHeader; 32 | pub use solution::EquihashSolution; 33 | pub use join_split::{JoinSplit, JoinSplitDescription, JoinSplitProof}; 34 | pub use merkle_root::{merkle_root, merkle_node_hash}; 35 | pub use sapling::{Sapling, SaplingSpendDescription, SaplingOutputDescription}; 36 | pub use transaction::{Transaction, TransactionInput, TransactionOutput, OutPoint}; 37 | 38 | pub use read_and_hash::{ReadAndHash, HashedData}; 39 | pub use indexed_block::IndexedBlock; 40 | pub use indexed_header::IndexedBlockHeader; 41 | pub use indexed_transaction::IndexedTransaction; 42 | 43 | pub type ShortTransactionID = hash::H48; 44 | -------------------------------------------------------------------------------- /storage/src/duplex_store.rs: -------------------------------------------------------------------------------- 1 | //! Some transaction validation rules, 2 | //! require sophisticated (in more than one source) previous transaction lookups 3 | 4 | use chain::{OutPoint, TransactionOutput}; 5 | use TransactionOutputProvider; 6 | 7 | #[derive(Clone, Copy)] 8 | pub struct DuplexTransactionOutputProvider<'a> { 9 | first: &'a TransactionOutputProvider, 10 | second: &'a TransactionOutputProvider, 11 | } 12 | 13 | impl<'a> DuplexTransactionOutputProvider<'a> { 14 | pub fn new(first: &'a TransactionOutputProvider, second: &'a TransactionOutputProvider) -> Self { 15 | DuplexTransactionOutputProvider { 16 | first: first, 17 | second: second, 18 | } 19 | } 20 | } 21 | 22 | impl<'a> TransactionOutputProvider for DuplexTransactionOutputProvider<'a> { 23 | fn transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { 24 | self.first.transaction_output(prevout, transaction_index) 25 | .or_else(|| self.second.transaction_output(prevout, transaction_index)) 26 | } 27 | 28 | fn is_spent(&self, prevout: &OutPoint) -> bool { 29 | self.first.is_spent(prevout) || self.second.is_spent(prevout) 30 | } 31 | } 32 | 33 | pub struct NoopStore; 34 | 35 | impl TransactionOutputProvider for NoopStore { 36 | fn transaction_output(&self, _prevout: &OutPoint, _transaction_index: usize) -> Option { 37 | None 38 | } 39 | 40 | fn is_spent(&self, _prevout: &OutPoint) -> bool { 41 | false 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sync/src/utils/fee_rate_filter.rs: -------------------------------------------------------------------------------- 1 | use message::types; 2 | 3 | /// Connection fee rate filter 4 | #[derive(Debug, Default)] 5 | pub struct FeeRateFilter { 6 | /// Minimal fee in satoshis per 1000 bytes 7 | fee_rate: u64, 8 | } 9 | 10 | impl FeeRateFilter { 11 | /// Set minimal fee rate, this filter accepts 12 | pub fn set_min_fee_rate(&mut self, message: types::FeeFilter) { 13 | self.fee_rate = message.fee_rate; 14 | } 15 | 16 | /// Filter transaction using its fee rate 17 | pub fn filter_transaction(&self, tx_fee_rate: Option) -> bool { 18 | tx_fee_rate 19 | .map(|tx_fee_rate| tx_fee_rate >= self.fee_rate) 20 | .unwrap_or(true) 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use message::types; 27 | use super::FeeRateFilter; 28 | 29 | #[test] 30 | fn fee_rate_filter_empty() { 31 | assert!(FeeRateFilter::default().filter_transaction(Some(0))); 32 | assert!(FeeRateFilter::default().filter_transaction(None)); 33 | } 34 | 35 | #[test] 36 | fn fee_rate_filter_accepts() { 37 | let mut filter = FeeRateFilter::default(); 38 | filter.set_min_fee_rate(types::FeeFilter::with_fee_rate(1000)); 39 | assert!(filter.filter_transaction(Some(1000))); 40 | assert!(filter.filter_transaction(Some(2000))); 41 | } 42 | 43 | #[test] 44 | fn fee_rate_filter_rejects() { 45 | let mut filter = FeeRateFilter::default(); 46 | filter.set_min_fee_rate(types::FeeFilter::with_fee_rate(1000)); 47 | assert!(!filter.filter_transaction(Some(500))); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /p2p/src/util/internet_protocol.rs: -------------------------------------------------------------------------------- 1 | use std::{str, net}; 2 | 3 | #[derive(Debug, PartialEq, Clone, Copy)] 4 | pub enum InternetProtocol { 5 | Any, 6 | IpV4, 7 | IpV6, 8 | } 9 | 10 | impl Default for InternetProtocol { 11 | fn default() -> Self { 12 | InternetProtocol::Any 13 | } 14 | } 15 | 16 | impl str::FromStr for InternetProtocol { 17 | type Err = &'static str; 18 | 19 | fn from_str(s: &str) -> Result { 20 | match s { 21 | "ipv4" => Ok(InternetProtocol::IpV4), 22 | "ipv6" => Ok(InternetProtocol::IpV6), 23 | _ => Err("Invalid internet protocol"), 24 | } 25 | } 26 | } 27 | 28 | impl InternetProtocol { 29 | pub fn is_allowed(&self, addr: &net::SocketAddr) -> bool { 30 | match *self { 31 | InternetProtocol::Any => true, 32 | InternetProtocol::IpV4 => match *addr { 33 | net::SocketAddr::V4(_) => true, 34 | _ => false, 35 | }, 36 | InternetProtocol::IpV6 => match *addr { 37 | net::SocketAddr::V6(_) => true, 38 | _ => false, 39 | } 40 | } 41 | } 42 | } 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | use super::InternetProtocol; 47 | 48 | #[test] 49 | fn test_default_internet_protocol() { 50 | assert_eq!(InternetProtocol::default(), InternetProtocol::Any); 51 | } 52 | 53 | #[test] 54 | fn test_parsing_internet_protocol() { 55 | assert_eq!(InternetProtocol::IpV4, "ipv4".parse().unwrap()); 56 | assert_eq!(InternetProtocol::IpV6, "ipv6".parse().unwrap()); 57 | assert!("sa".parse::().is_err()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /db/src/kv/cachedb.rs: -------------------------------------------------------------------------------- 1 | use lru_cache::LruCache; 2 | use parking_lot::Mutex; 3 | use hash::H256; 4 | use chain::BlockHeader; 5 | use kv::{KeyValueDatabase, KeyState, Operation, KeyValue, Key, Value, Transaction}; 6 | 7 | pub struct CacheDatabase where T: KeyValueDatabase { 8 | db: T, 9 | header: Mutex>>, 10 | } 11 | 12 | impl CacheDatabase where T: KeyValueDatabase { 13 | pub fn new(db: T) -> Self { 14 | CacheDatabase { 15 | db: db, 16 | // 144 (blocks per day) * 14 (days) + 100 (arbitrary number) 17 | header: Mutex::new(LruCache::new(2116)), 18 | } 19 | } 20 | } 21 | 22 | impl KeyValueDatabase for CacheDatabase where T: KeyValueDatabase { 23 | fn write(&self, tx: Transaction) -> Result<(), String> { 24 | for op in &tx.operations { 25 | match *op { 26 | Operation::Insert(KeyValue::BlockHeader(ref hash, ref header)) => { 27 | self.header.lock().insert(hash.clone(), KeyState::Insert(header.clone())); 28 | }, 29 | Operation::Delete(Key::BlockHeader(ref hash)) => { 30 | self.header.lock().insert(hash.clone(), KeyState::Delete); 31 | }, 32 | _ => (), 33 | } 34 | } 35 | self.db.write(tx) 36 | } 37 | 38 | fn get(&self, key: &Key) -> Result, String> { 39 | if let Key::BlockHeader(ref hash) = *key { 40 | let mut header = self.header.lock(); 41 | if let Some(state) = header.get_mut(hash) { 42 | return Ok(state.clone().map(Value::BlockHeader)) 43 | } 44 | } 45 | self.db.get(key) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /p2p/src/util/response_queue.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | use bytes::Bytes; 3 | 4 | /// Queue of out-of-order responses. Each peer has its own queue. 5 | #[derive(Debug, Default)] 6 | pub struct ResponseQueue { 7 | unfinished: HashMap>, 8 | finished: HashMap>, 9 | ignored: HashSet, 10 | } 11 | 12 | pub enum Responses { 13 | Unfinished(Vec), 14 | Finished(Vec), 15 | Ignored, 16 | } 17 | 18 | impl ResponseQueue { 19 | pub fn push_unfinished_response(&mut self, id: u32, response: Bytes) { 20 | self.unfinished.entry(id).or_insert_with(Vec::new).push(response) 21 | } 22 | 23 | pub fn push_finished_response(&mut self, id: u32, response: Bytes) { 24 | let mut responses = self.unfinished.remove(&id).unwrap_or_default(); 25 | responses.push(response); 26 | let previous = self.finished.insert(id, responses); 27 | assert!(previous.is_none(), "logic error; same finished response should never be pushed twice"); 28 | } 29 | 30 | pub fn push_ignored_response(&mut self, id: u32) { 31 | assert!(self.ignored.insert(id), "logic error; same response should never be ignored twice"); 32 | } 33 | 34 | pub fn responses(&mut self, id: u32) -> Option { 35 | self.unfinished.remove(&id).map(Responses::Unfinished) 36 | .or_else(|| self.finished.remove(&id).map(Responses::Finished)) 37 | .or_else(|| { 38 | if self.ignored.remove(&id) { 39 | Some(Responses::Ignored) 40 | } else { 41 | None 42 | } 43 | }) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /p2p/src/io/sharedtcpstream.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::net::Shutdown; 3 | use std::io::{Read, Write, Error}; 4 | use futures::Poll; 5 | use tokio_io::{AsyncRead, AsyncWrite}; 6 | use tokio_core::net::TcpStream; 7 | 8 | pub struct SharedTcpStream { 9 | io: Arc, 10 | } 11 | 12 | impl SharedTcpStream { 13 | pub fn new(a: Arc) -> Self { 14 | SharedTcpStream { 15 | io: a, 16 | } 17 | } 18 | 19 | pub fn shutdown(&self) { 20 | // error is irrelevant here, the connection is dropped anyway 21 | let _ = self.io.shutdown(Shutdown::Both); 22 | } 23 | } 24 | 25 | impl From for SharedTcpStream { 26 | fn from(a: TcpStream) -> Self { 27 | SharedTcpStream::new(Arc::new(a)) 28 | } 29 | } 30 | 31 | impl Read for SharedTcpStream { 32 | fn read(&mut self, buf: &mut [u8]) -> Result { 33 | Read::read(&mut (&*self.io as &TcpStream), buf) 34 | } 35 | } 36 | 37 | impl AsyncRead for SharedTcpStream {} 38 | 39 | impl AsyncWrite for SharedTcpStream { 40 | fn shutdown(&mut self) -> Poll<(), Error> { 41 | self.io.shutdown(Shutdown::Both).map(Into::into) 42 | } 43 | } 44 | 45 | impl Write for SharedTcpStream { 46 | fn write(&mut self, buf: &[u8]) -> Result { 47 | Write::write(&mut (&*self.io as &TcpStream), buf) 48 | } 49 | 50 | fn flush(&mut self) -> Result<(), Error> { 51 | Write::flush(&mut (&*self.io as &TcpStream)) 52 | } 53 | } 54 | 55 | impl Clone for SharedTcpStream { 56 | fn clone(&self) -> Self { 57 | SharedTcpStream::new(self.io.clone()) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /serialization_derive/tests/raw.rs: -------------------------------------------------------------------------------- 1 | extern crate serialization; 2 | #[macro_use] 3 | extern crate serialization_derive; 4 | 5 | use serialization::{serialize, deserialize}; 6 | 7 | #[derive(Debug, PartialEq, Serializable, Deserializable)] 8 | struct Foo { 9 | a: u8, 10 | b: u16, 11 | c: u32, 12 | d: u64, 13 | } 14 | 15 | #[derive(Debug, PartialEq, Serializable, Deserializable)] 16 | struct Bar { 17 | a: Vec, 18 | } 19 | 20 | #[test] 21 | fn test_foo_serialize() { 22 | let foo = Foo { 23 | a: 1, 24 | b: 2, 25 | c: 3, 26 | d: 4, 27 | }; 28 | 29 | let expected = vec![ 30 | 1u8, 31 | 2, 0, 32 | 3, 0, 0, 0, 33 | 4, 0, 0, 0, 0, 0, 0, 0, 34 | ].into(); 35 | 36 | let result = serialize(&foo); 37 | assert_eq!(result, expected); 38 | 39 | let d = deserialize(expected.as_ref()).unwrap(); 40 | assert_eq!(foo, d); 41 | } 42 | 43 | #[test] 44 | fn test_bar_serialize() { 45 | let foo = Foo { 46 | a: 1, 47 | b: 2, 48 | c: 3, 49 | d: 4, 50 | }; 51 | 52 | let foo2 = Foo { 53 | a: 5, 54 | b: 6, 55 | c: 7, 56 | d: 8, 57 | }; 58 | 59 | let expected = vec![ 60 | // number of items 61 | 2u8, 62 | // first 63 | 1, 64 | 2, 0, 65 | 3, 0, 0, 0, 66 | 4, 0, 0, 0, 0, 0, 0, 0, 67 | // second 68 | 5, 69 | 6, 0, 70 | 7, 0, 0, 0, 71 | 8, 0, 0, 0, 0, 0, 0, 0, 72 | ].into(); 73 | 74 | let bar = Bar { 75 | a: vec![foo, foo2], 76 | }; 77 | 78 | let result = serialize(&bar); 79 | assert_eq!(result, expected); 80 | 81 | let d = deserialize(expected.as_ref()).unwrap(); 82 | assert_eq!(bar, d); 83 | } 84 | -------------------------------------------------------------------------------- /verification/src/sigops.rs: -------------------------------------------------------------------------------- 1 | use chain::Transaction; 2 | use storage::TransactionOutputProvider; 3 | use script::Script; 4 | 5 | /// Counts signature operations in given transaction 6 | /// bip16_active flag indicates if we should also count signature operations 7 | /// in previous transactions. If one of the previous transaction outputs is 8 | /// missing, we simply ignore that fact and just carry on counting 9 | pub fn transaction_sigops( 10 | transaction: &Transaction, 11 | store: &TransactionOutputProvider, 12 | bip16_active: bool, 13 | ) -> usize { 14 | let output_sigops: usize = transaction.outputs.iter().map(|output| { 15 | let output_script: Script = output.script_pubkey.clone().into(); 16 | output_script.sigops_count(false) 17 | }).sum(); 18 | 19 | // TODO: bitcoin/bitcoin also includes input_sigops here 20 | if transaction.is_coinbase() { 21 | return output_sigops; 22 | } 23 | 24 | let mut input_sigops = 0usize; 25 | let mut bip16_sigops = 0usize; 26 | 27 | for input in &transaction.inputs { 28 | let input_script: Script = input.script_sig.clone().into(); 29 | input_sigops += input_script.sigops_count(false); 30 | if bip16_active { 31 | let previous_output = match store.transaction_output(&input.previous_output, usize::max_value()) { 32 | Some(output) => output, 33 | None => continue, 34 | }; 35 | let prevout_script: Script = previous_output.script_pubkey.into(); 36 | bip16_sigops += input_script.pay_to_script_hash_sigops(&prevout_script); 37 | } 38 | } 39 | 40 | input_sigops + output_sigops + bip16_sigops 41 | } 42 | -------------------------------------------------------------------------------- /message/src/types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod addr; 2 | mod block; 3 | mod blocktxn; 4 | mod feefilter; 5 | mod filteradd; 6 | mod filterclear; 7 | mod filterload; 8 | mod getaddr; 9 | mod getblocks; 10 | mod getblocktxn; 11 | mod getdata; 12 | mod getheaders; 13 | mod headers; 14 | mod inv; 15 | mod mempool; 16 | mod merkle_block; 17 | mod notfound; 18 | mod ping; 19 | mod pong; 20 | pub mod reject; 21 | mod sendheaders; 22 | mod tx; 23 | mod verack; 24 | pub mod version; 25 | 26 | pub use self::addr::Addr; 27 | pub use self::block::Block; 28 | pub use self::blocktxn::BlockTxn; 29 | pub use self::feefilter::FeeFilter; 30 | pub use self::filterload::{FilterLoad, FILTERLOAD_MAX_FILTER_LEN, FILTERLOAD_MAX_HASH_FUNCS}; 31 | pub use self::filterload::FilterFlags; 32 | pub use self::filterclear::FilterClear; 33 | pub use self::filteradd::{FilterAdd, FILTERADD_MAX_DATA_LEN}; 34 | pub use self::getaddr::GetAddr; 35 | pub use self::getblocks::{GetBlocks, GETBLOCKS_MAX_RESPONSE_HASHES}; 36 | pub use self::getblocktxn::GetBlockTxn; 37 | pub use self::getdata::{GetData, GETDATA_MAX_INVENTORY_LEN}; 38 | pub use self::getheaders::{GetHeaders}; 39 | pub use self::headers::{Headers, HEADERS_MAX_HEADERS_LEN}; 40 | pub use self::inv::{Inv, INV_MAX_INVENTORY_LEN}; 41 | pub use self::mempool::MemPool; 42 | pub use self::merkle_block::MerkleBlock; 43 | pub use self::notfound::NotFound; 44 | pub use self::ping::Ping; 45 | pub use self::pong::Pong; 46 | pub use self::reject::Reject; 47 | pub use self::sendheaders::SendHeaders; 48 | pub use self::tx::Tx; 49 | pub use self::verack::Verack; 50 | pub use self::version::Version; 51 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pzec" 3 | version = "0.1.0" 4 | license = "GPL-3.0" 5 | authors = ["Parity Technologies "] 6 | description = "Parity bitcoin client." 7 | 8 | [dependencies] 9 | app_dirs = { git = "https://github.com/paritytech/app-dirs-rs" } 10 | chain = { path = "chain" } 11 | clap = { version = "2", features = ["yaml"] } 12 | db = { path = "db" } 13 | env_logger = "0.5" 14 | import = { path = "import" } 15 | keys = { path = "keys" } 16 | libc = "0.2" 17 | log = "0.4" 18 | logs = { path = "logs" } 19 | message = { path = "message" } 20 | network = { path = "network" } 21 | miner = { path = "miner" } 22 | p2p = { path = "p2p" } 23 | primitives = { path = "primitives" } 24 | rpc = { path = "rpc" } 25 | script = { path = "script" } 26 | storage = { path = "storage" } 27 | sync = { path = "sync" } 28 | verification = { path = "verification" } 29 | 30 | [profile.dev] 31 | debug = true 32 | panic = 'abort' 33 | 34 | [profile.release] 35 | debug = true 36 | panic = 'abort' 37 | 38 | [profile.test] 39 | debug = true 40 | 41 | [[bin]] 42 | path = "pzec/main.rs" 43 | name = "pzec" 44 | 45 | [workspace] 46 | members = [ 47 | "bencher", 48 | "./crypto", 49 | "chain", 50 | "db", 51 | "import", 52 | "keys", 53 | "logs", 54 | "message", 55 | "miner", 56 | "network", 57 | "p2p", 58 | "primitives", 59 | "rpc", 60 | "script", 61 | "serialization", 62 | "serialization_derive", 63 | "storage", 64 | "sync", 65 | "test-data", 66 | "verification", 67 | ] 68 | 69 | [patch.crates-io] 70 | heapsize = { git = "https://github.com/cheme/heapsize.git", branch = "ec-macfix" } 71 | -------------------------------------------------------------------------------- /import/src/blk.rs: -------------------------------------------------------------------------------- 1 | use std::{io, fs, path}; 2 | use std::collections::BTreeSet; 3 | use ser::{ReadIterator, deserialize_iterator, Error as ReaderError}; 4 | use block::Block; 5 | use fs::read_blk_dir; 6 | 7 | pub fn open_blk_file

(path: P) -> Result where P: AsRef { 8 | trace!("Opening blk file: {:?}", path.as_ref()); 9 | let file = try!(fs::File::open(path)); 10 | let blk_file = BlkFile { 11 | reader: deserialize_iterator(file), 12 | }; 13 | Ok(blk_file) 14 | } 15 | 16 | pub struct BlkFile { 17 | reader: ReadIterator, 18 | } 19 | 20 | impl Iterator for BlkFile { 21 | type Item = Result; 22 | 23 | fn next(&mut self) -> Option { 24 | self.reader.next() 25 | } 26 | } 27 | 28 | /// Creates iterator over bitcoind database blocks 29 | pub fn open_blk_dir

, 18 | } 19 | 20 | #[derive(Debug, PartialEq)] 21 | pub struct HttpConfiguration { 22 | pub enabled: bool, 23 | pub interface: String, 24 | pub port: u16, 25 | pub apis: ApiSet, 26 | pub cors: Option>, 27 | pub hosts: Option>, 28 | } 29 | 30 | impl HttpConfiguration { 31 | pub fn with_port(port: u16) -> Self { 32 | HttpConfiguration { 33 | enabled: true, 34 | interface: "127.0.0.1".into(), 35 | port: port, 36 | apis: ApiSet::default(), 37 | cors: None, 38 | hosts: Some(Vec::new()), 39 | } 40 | } 41 | } 42 | 43 | pub fn new_http(conf: HttpConfiguration, deps: Dependencies) -> Result, String> { 44 | if !conf.enabled { 45 | return Ok(None); 46 | } 47 | 48 | let url = format!("{}:{}", conf.interface, conf.port); 49 | let addr = try!(url.parse().map_err(|_| format!("Invalid JSONRPC listen host/port given: {}", url))); 50 | Ok(Some(try!(setup_http_rpc_server(&addr, conf.cors, conf.hosts, conf.apis, deps)))) 51 | } 52 | 53 | pub fn setup_http_rpc_server( 54 | url: &SocketAddr, 55 | cors_domains: Option>, 56 | allowed_hosts: Option>, 57 | apis: ApiSet, 58 | deps: Dependencies, 59 | ) -> Result { 60 | let server = setup_rpc_server(apis, deps); 61 | let start_result = start_http(url, cors_domains, allowed_hosts, server); 62 | match start_result { 63 | Err(ref err) if err.kind() == io::ErrorKind::AddrInUse => { 64 | Err(format!("RPC address {} is already in use, make sure that another instance of a Bitcoin node is not running or change the address using the --jsonrpc-port and --jsonrpc-interface options.", url)) 65 | }, 66 | Err(e) => Err(format!("RPC error: {:?}", e)), 67 | Ok(server) => Ok(server), 68 | } 69 | } 70 | 71 | fn setup_rpc_server(apis: ApiSet, deps: Dependencies) -> MetaIoHandler<()> { 72 | rpc_apis::setup_rpc(MetaIoHandler::with_compatibility(Compatibility::Both), apis, deps) 73 | } 74 | -------------------------------------------------------------------------------- /message/src/types/headers.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use chain::BlockHeader; 3 | use ser::{Stream, Reader, Serializable, Deserializable, CompactInteger, Error as ReaderError}; 4 | use {Payload, MessageResult}; 5 | 6 | pub const HEADERS_MAX_HEADERS_LEN: usize = 160; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct Headers { 10 | pub headers: Vec, 11 | } 12 | 13 | impl Headers { 14 | pub fn with_headers(headers: Vec) -> Self { 15 | Headers { 16 | headers: headers, 17 | } 18 | } 19 | } 20 | 21 | #[derive(Debug, PartialEq)] 22 | struct HeaderWithTxnCount { 23 | header: BlockHeader, 24 | } 25 | 26 | impl From for BlockHeader { 27 | fn from(header: HeaderWithTxnCount) -> BlockHeader { 28 | header.header 29 | } 30 | } 31 | 32 | #[derive(Debug, PartialEq)] 33 | struct HeaderWithTxnCountRef<'a> { 34 | header: &'a BlockHeader, 35 | } 36 | 37 | impl<'a> From<&'a BlockHeader> for HeaderWithTxnCountRef<'a> { 38 | fn from(header: &'a BlockHeader) -> Self { 39 | HeaderWithTxnCountRef { 40 | header: header, 41 | } 42 | } 43 | } 44 | 45 | impl Payload for Headers { 46 | fn version() -> u32 { 47 | 0 48 | } 49 | 50 | fn command() -> &'static str { 51 | "headers" 52 | } 53 | 54 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 55 | let headers_with_txn_count: Vec = try!(reader.read_list()); 56 | let headers = Headers { 57 | headers: headers_with_txn_count.into_iter().map(Into::into).collect(), 58 | }; 59 | 60 | Ok(headers) 61 | } 62 | 63 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 64 | let headers_with_txn_count: Vec = self.headers.iter().map(Into::into).collect(); 65 | stream.append_list(&headers_with_txn_count); 66 | Ok(()) 67 | } 68 | } 69 | 70 | impl<'a> Serializable for HeaderWithTxnCountRef<'a> { 71 | fn serialize(&self, stream: &mut Stream) { 72 | stream 73 | .append(self.header) 74 | .append(&CompactInteger::from(0u32)); 75 | } 76 | } 77 | 78 | impl Deserializable for HeaderWithTxnCount { 79 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 80 | let header = HeaderWithTxnCount { 81 | header: try!(reader.read()), 82 | }; 83 | 84 | let txn_count: CompactInteger = try!(reader.read()); 85 | if txn_count != 0u32.into() { 86 | return Err(ReaderError::MalformedData); 87 | } 88 | 89 | Ok(header) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /serialization/src/stream.rs: -------------------------------------------------------------------------------- 1 | //! Stream used for serialization of Bitcoin structures 2 | use std::io::{self, Write}; 3 | use std::borrow::Borrow; 4 | use compact_integer::CompactInteger; 5 | use bytes::Bytes; 6 | 7 | pub fn serialize(t: &T) -> Bytes where T: Serializable { 8 | let mut stream = Stream::new(); 9 | stream.append(t); 10 | stream.out() 11 | } 12 | 13 | pub fn serialize_list(t: &[K]) -> Bytes where T: Serializable, K: Borrow { 14 | let mut stream = Stream::new(); 15 | stream.append_list(t); 16 | stream.out() 17 | } 18 | 19 | pub fn serialized_list_size(t: &[K]) -> usize where T: Serializable, K: Borrow { 20 | CompactInteger::from(t.len()).serialized_size() + 21 | t.iter().map(Borrow::borrow).map(Serializable::serialized_size).sum::() 22 | } 23 | 24 | pub trait Serializable { 25 | /// Serialize the struct and appends it to the end of stream. 26 | fn serialize(&self, s: &mut Stream); 27 | 28 | /// Hint about the size of serialized struct. 29 | fn serialized_size(&self) -> usize where Self: Sized { 30 | // fallback implementation 31 | serialize(self).len() 32 | } 33 | } 34 | 35 | /// Stream used for serialization of Bitcoin structures 36 | #[derive(Default)] 37 | pub struct Stream { 38 | buffer: Vec, 39 | } 40 | 41 | impl Stream { 42 | /// New stream 43 | pub fn new() -> Self { 44 | Stream { buffer: Vec::new() } 45 | } 46 | 47 | /// Serializes the struct and appends it to the end of stream. 48 | pub fn append(&mut self, t: &T) -> &mut Self where T: Serializable { 49 | t.serialize(self); 50 | self 51 | } 52 | 53 | /// Appends raw bytes to the end of the stream. 54 | pub fn append_slice(&mut self, bytes: &[u8]) -> &mut Self { 55 | // discard error for now, since we write to simple vector 56 | self.buffer.write(bytes).unwrap(); 57 | self 58 | } 59 | 60 | /// Appends a list of serializable structs to the end of the stream. 61 | pub fn append_list(&mut self, t: &[K]) -> &mut Self where T: Serializable, K: Borrow { 62 | CompactInteger::from(t.len()).serialize(self); 63 | for i in t { 64 | i.borrow().serialize(self); 65 | } 66 | self 67 | } 68 | 69 | /// Full stream. 70 | pub fn out(self) -> Bytes { 71 | self.buffer.into() 72 | } 73 | } 74 | 75 | impl Write for Stream { 76 | #[inline] 77 | fn write(&mut self, buf: &[u8]) -> Result { 78 | self.buffer.write(buf) 79 | } 80 | 81 | #[inline] 82 | fn flush(&mut self) -> Result<(), io::Error> { 83 | self.buffer.flush() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /rpc/src/v1/types/address.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use serde::{Serialize, Serializer, Deserializer}; 3 | use serde::de::{Visitor, Unexpected}; 4 | use keys::Address; 5 | 6 | pub fn serialize(address: &Address, serializer: S) -> Result where S: Serializer { 7 | address.to_string().serialize(serializer) 8 | } 9 | 10 | pub fn deserialize<'a, D>(deserializer: D) -> Result where D: Deserializer<'a> { 11 | deserializer.deserialize_any(AddressVisitor) 12 | } 13 | 14 | #[derive(Default)] 15 | pub struct AddressVisitor; 16 | 17 | impl<'b> Visitor<'b> for AddressVisitor { 18 | type Value = Address; 19 | 20 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 21 | formatter.write_str("an address") 22 | } 23 | 24 | fn visit_str(self, value: &str) -> Result where E: ::serde::de::Error { 25 | value.parse().map_err(|_| E::invalid_value(Unexpected::Str(value), &self)) 26 | } 27 | } 28 | 29 | pub mod vec { 30 | use serde::{Serialize, Serializer, Deserializer, Deserialize}; 31 | use serde::de::Visitor; 32 | use keys::Address; 33 | use super::AddressVisitor; 34 | 35 | pub fn serialize(addresses: &Vec
, serializer: S) -> Result where S: Serializer { 36 | addresses.iter().map(|address| address.to_string()).collect::>().serialize(serializer) 37 | } 38 | 39 | pub fn deserialize<'a, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'a> { 40 | as Deserialize>::deserialize(deserializer)? 41 | .into_iter() 42 | .map(|value| AddressVisitor::default().visit_str(value)) 43 | .collect() 44 | } 45 | } 46 | 47 | #[cfg(test)] 48 | mod tests { 49 | use serde_json; 50 | use keys::Address; 51 | use v1::types; 52 | 53 | #[derive(Debug, PartialEq, Serialize, Deserialize)] 54 | struct TestStruct { 55 | #[serde(with = "types::address")] 56 | address: Address, 57 | } 58 | 59 | impl TestStruct { 60 | fn new(address: Address) -> Self { 61 | TestStruct { 62 | address: address, 63 | } 64 | } 65 | } 66 | 67 | #[test] 68 | fn address_serialize() { 69 | let test = TestStruct::new("t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into()); 70 | assert_eq!(serde_json::to_string(&test).unwrap(), r#"{"address":"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi"}"#); 71 | } 72 | 73 | #[test] 74 | fn address_deserialize() { 75 | let test = TestStruct::new("t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into()); 76 | assert_eq!(serde_json::from_str::(r#"{"address":"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi"}"#).unwrap(), test); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /p2p/src/net/connect.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::time::Duration; 3 | use std::net::SocketAddr; 4 | use futures::{Future, Poll, Async}; 5 | use tokio_core::reactor::Handle; 6 | use tokio_core::net::{TcpStream, TcpStreamNew}; 7 | use network::Magic; 8 | use message::Error; 9 | use message::types::Version; 10 | use io::{handshake, Handshake, Deadline, deadline}; 11 | use net::{Config, Connection}; 12 | 13 | pub fn connect(address: &SocketAddr, handle: &Handle, config: &Config) -> Deadline { 14 | let connect = Connect { 15 | state: ConnectState::TcpConnect { 16 | future: TcpStream::connect(address, handle), 17 | version: Some(config.version(address)), 18 | }, 19 | magic: config.magic, 20 | address: *address, 21 | protocol_minimum: config.protocol_minimum, 22 | }; 23 | 24 | deadline(Duration::new(5, 0), handle, connect).expect("Failed to create timeout") 25 | } 26 | 27 | enum ConnectState { 28 | TcpConnect { 29 | future: TcpStreamNew, 30 | version: Option, 31 | }, 32 | Handshake(Handshake), 33 | Connected, 34 | } 35 | 36 | pub struct Connect { 37 | state: ConnectState, 38 | magic: Magic, 39 | address: SocketAddr, 40 | protocol_minimum: u32, 41 | } 42 | 43 | impl Future for Connect { 44 | type Item = Result; 45 | type Error = io::Error; 46 | 47 | fn poll(&mut self) -> Poll { 48 | let (next, result) = match self.state { 49 | ConnectState::TcpConnect { ref mut future, ref mut version } => { 50 | let stream = try_ready!(future.poll()); 51 | let version = version.take().expect("state TcpConnect must have version"); 52 | let handshake = handshake(stream, self.magic, version, self.protocol_minimum); 53 | (ConnectState::Handshake(handshake), Async::NotReady) 54 | }, 55 | ConnectState::Handshake(ref mut future) => { 56 | let (stream, result) = try_ready!(future.poll()); 57 | let result = match result { 58 | Ok(result) => result, 59 | Err(err) => return Ok(Async::Ready(Err(err))), 60 | }; 61 | let connection = Connection { 62 | stream: stream.into(), 63 | services: result.version.services(), 64 | version: result.negotiated_version, 65 | version_message: result.version, 66 | magic: self.magic, 67 | address: self.address, 68 | }; 69 | (ConnectState::Connected, Async::Ready(Ok(connection))) 70 | }, 71 | ConnectState::Connected => panic!("poll Connect after it's done"), 72 | }; 73 | 74 | self.state = next; 75 | match result { 76 | // by polling again, we register new future 77 | Async::NotReady => self.poll(), 78 | result => Ok(result) 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /import/src/fs.rs: -------------------------------------------------------------------------------- 1 | use std::{io, fs, path, cmp}; 2 | 3 | /// Creates an iterator over all blk .dat files 4 | pub fn read_blk_dir

(path: P) -> Result where P: AsRef { 5 | let read_blk_dir = ReadBlkDir { 6 | read_dir: try!(fs::read_dir(path)), 7 | }; 8 | 9 | Ok(read_blk_dir) 10 | } 11 | 12 | pub struct ReadBlkDir { 13 | read_dir: fs::ReadDir, 14 | } 15 | 16 | #[derive(PartialEq, Eq)] 17 | pub struct BlkEntry { 18 | pub path: path::PathBuf, 19 | } 20 | 21 | impl cmp::PartialOrd for BlkEntry { 22 | fn partial_cmp(&self, other: &Self) -> Option { 23 | cmp::PartialOrd::partial_cmp(&self.path, &other.path) 24 | } 25 | } 26 | 27 | impl cmp::Ord for BlkEntry { 28 | fn cmp(&self, other: &Self) -> cmp::Ordering { 29 | cmp::Ord::cmp(&self.path, &other.path) 30 | } 31 | } 32 | 33 | fn is_blk_file_name(file_name: &str) -> bool { 34 | if file_name.len() != 12 || !file_name.starts_with("blk") || !file_name.ends_with(".dat") { 35 | return false; 36 | } 37 | 38 | file_name[3..8].parse::().is_ok() 39 | } 40 | 41 | impl BlkEntry { 42 | fn from_dir_entry(dir_entry: fs::DirEntry) -> Option { 43 | match dir_entry.metadata() { 44 | Err(_) => return None, 45 | Ok(ref metadata) => { 46 | if !metadata.is_file() { 47 | return None; 48 | } 49 | } 50 | } 51 | 52 | match dir_entry.file_name().into_string() { 53 | Err(_) => return None, 54 | Ok(ref file_name) => { 55 | if !is_blk_file_name(file_name) { 56 | return None; 57 | } 58 | } 59 | } 60 | 61 | let entry = BlkEntry { 62 | path: dir_entry.path(), 63 | }; 64 | 65 | Some(entry) 66 | } 67 | } 68 | 69 | impl Iterator for ReadBlkDir { 70 | type Item = Result; 71 | 72 | fn next(&mut self) -> Option { 73 | let mut result = None; 74 | while result.is_none() { 75 | match self.read_dir.next() { 76 | None => return None, 77 | Some(Err(err)) => return Some(Err(err)), 78 | Some(Ok(entry)) => { 79 | result = BlkEntry::from_dir_entry(entry); 80 | } 81 | } 82 | } 83 | result.map(Ok) 84 | } 85 | } 86 | 87 | #[cfg(test)] 88 | mod test { 89 | use super::is_blk_file_name; 90 | 91 | #[test] 92 | fn test_is_blk_file_name() { 93 | assert!(is_blk_file_name("blk00000.dat")); 94 | assert!(is_blk_file_name("blk00232.dat")); 95 | assert!(!is_blk_file_name("blk0000.dat")); 96 | assert!(!is_blk_file_name("blk00000.daw")); 97 | assert!(!is_blk_file_name("blk00032.daw")); 98 | assert!(!is_blk_file_name("blk000ff.dat")); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /message/src/types/filterload.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use bytes::Bytes; 3 | use ser::{Serializable, Deserializable, Stream, Reader, Error as ReaderError}; 4 | use {Payload, MessageResult}; 5 | 6 | pub const FILTERLOAD_MAX_FILTER_LEN: usize = 36_000; 7 | pub const FILTERLOAD_MAX_HASH_FUNCS: usize = 50; 8 | 9 | #[derive(Debug, PartialEq, Clone, Copy)] 10 | #[repr(u8)] 11 | /// Controls how the filter is updated after match is found. 12 | pub enum FilterFlags { 13 | /// Means the filter is not adjusted when a match is found. 14 | None = 0, 15 | /// Means if the filter matches any data element in a scriptPubKey the outpoint is serialized and inserted into the filter. 16 | All = 1, 17 | /// Means the outpoint is inserted into the filter only if a data element in the scriptPubKey is matched, and that script is 18 | /// of the standard "pay to pubkey" or "pay to multisig" forms. 19 | PubKeyOnly = 2, 20 | } 21 | 22 | #[derive(Debug, PartialEq)] 23 | pub struct FilterLoad { 24 | // TODO: check how this should be serialized 25 | pub filter: Bytes, 26 | pub hash_functions: u32, 27 | pub tweak: u32, 28 | pub flags: FilterFlags, 29 | } 30 | 31 | impl Payload for FilterLoad { 32 | fn version() -> u32 { 33 | 70001 34 | } 35 | 36 | fn command() -> &'static str { 37 | "filterload" 38 | } 39 | 40 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 41 | let filterload = FilterLoad { 42 | filter: try!(reader.read()), 43 | hash_functions: try!(reader.read()), 44 | tweak: try!(reader.read()), 45 | flags: try!(reader.read()), 46 | }; 47 | 48 | Ok(filterload) 49 | } 50 | 51 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 52 | stream 53 | .append(&self.filter) 54 | .append(&self.hash_functions) 55 | .append(&self.tweak) 56 | .append(&self.flags); 57 | Ok(()) 58 | } 59 | } 60 | 61 | impl FilterFlags { 62 | pub fn from_u8(v: u8) -> Option { 63 | match v { 64 | 0 => Some(FilterFlags::None), 65 | 1 => Some(FilterFlags::All), 66 | 2 => Some(FilterFlags::PubKeyOnly), 67 | _ => None, 68 | } 69 | } 70 | } 71 | 72 | impl From for u8 { 73 | fn from(i: FilterFlags) -> Self { 74 | i as u8 75 | } 76 | } 77 | 78 | impl Serializable for FilterFlags { 79 | fn serialize(&self, stream: &mut Stream) { 80 | stream.append(&u8::from(*self)); 81 | } 82 | } 83 | 84 | impl Deserializable for FilterFlags { 85 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 86 | let t: u8 = try!(reader.read()); 87 | FilterFlags::from_u8(t).ok_or(ReaderError::MalformedData) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /rpc/src/v1/types/uint.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::str::FromStr; 3 | use serde; 4 | use serde::de::Unexpected; 5 | use primitives::bigint::U256 as GlobalU256; 6 | 7 | macro_rules! impl_uint { 8 | ($name: ident, $other: ident, $size: expr) => { 9 | /// Uint serialization. 10 | #[derive(Debug, Default, Clone, Copy, PartialEq, Hash)] 11 | pub struct $name($other); 12 | 13 | impl Eq for $name { } 14 | 15 | impl From for $name where $other: From { 16 | fn from(o: T) -> Self { 17 | $name($other::from(o)) 18 | } 19 | } 20 | 21 | impl FromStr for $name { 22 | type Err = <$other as FromStr>::Err; 23 | 24 | fn from_str(s: &str) -> Result { 25 | $other::from_str(s).map($name) 26 | } 27 | } 28 | 29 | impl Into<$other> for $name { 30 | fn into(self) -> $other { 31 | self.0 32 | } 33 | } 34 | 35 | impl serde::Serialize for $name { 36 | fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { 37 | let as_hex = format!("{}", self.0.to_hex()); 38 | serializer.serialize_str(&as_hex) 39 | } 40 | } 41 | 42 | impl<'a> serde::Deserialize<'a> for $name { 43 | fn deserialize(deserializer: D) -> Result<$name, D::Error> where D: serde::Deserializer<'a> { 44 | struct UintVisitor; 45 | 46 | impl<'b> serde::de::Visitor<'b> for UintVisitor { 47 | type Value = $name; 48 | 49 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 50 | formatter.write_str("an integer represented in hex string") 51 | } 52 | 53 | fn visit_str(self, value: &str) -> Result where E: serde::de::Error { 54 | if value.len() > $size * 16 { 55 | return Err(E::invalid_value(Unexpected::Str(value), &self)) 56 | } 57 | 58 | $other::from_str(value).map($name).map_err(|_| E::invalid_value(Unexpected::Str(value), &self)) 59 | } 60 | 61 | fn visit_string(self, value: String) -> Result where E: serde::de::Error { 62 | self.visit_str(&value) 63 | } 64 | } 65 | 66 | deserializer.deserialize_identifier(UintVisitor) 67 | } 68 | } 69 | } 70 | } 71 | 72 | impl_uint!(U256, GlobalU256, 4); 73 | 74 | 75 | #[cfg(test)] 76 | mod tests { 77 | use super::U256; 78 | use serde_json; 79 | 80 | #[test] 81 | fn u256_serialize() { 82 | let u256 = U256::from(256); 83 | let serialized = serde_json::to_string(&u256).unwrap(); 84 | assert_eq!(serialized, r#""100""#); 85 | } 86 | 87 | #[test] 88 | fn u256_deserialize() { 89 | let u256 = U256::from(256); 90 | let deserialized = serde_json::from_str::(r#""100""#).unwrap(); 91 | assert_eq!(deserialized, u256); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /verification/src/accept_chain.rs: -------------------------------------------------------------------------------- 1 | use rayon::prelude::{IntoParallelRefIterator, IndexedParallelIterator, ParallelIterator}; 2 | use storage::{ 3 | DuplexTransactionOutputProvider, TransactionOutputProvider, TransactionMetaProvider, 4 | BlockHeaderProvider, TreeStateProvider, NullifierTracker, 5 | }; 6 | use network::ConsensusParams; 7 | use error::Error; 8 | use canon::CanonBlock; 9 | use accept_block::BlockAcceptor; 10 | use accept_header::HeaderAcceptor; 11 | use accept_transaction::TransactionAcceptor; 12 | use deployments::BlockDeployments; 13 | use VerificationLevel; 14 | 15 | pub struct ChainAcceptor<'a> { 16 | pub block: BlockAcceptor<'a>, 17 | pub header: HeaderAcceptor<'a>, 18 | pub transactions: Vec>, 19 | } 20 | 21 | impl<'a> ChainAcceptor<'a> { 22 | pub fn new( 23 | tx_out_provider: &'a TransactionOutputProvider, 24 | tx_meta_provider: &'a TransactionMetaProvider, 25 | header_provider: &'a BlockHeaderProvider, 26 | tree_state_provider: &'a TreeStateProvider, 27 | nullifier_tracker: &'a NullifierTracker, 28 | consensus: &'a ConsensusParams, 29 | verification_level: VerificationLevel, 30 | block: CanonBlock<'a>, 31 | height: u32, 32 | time: u32, 33 | deployments: &'a BlockDeployments, 34 | ) -> Self { 35 | trace!(target: "verification", "Block verification {}", block.hash().to_reversed_str()); 36 | let output_store = DuplexTransactionOutputProvider::new(tx_out_provider, block.raw()); 37 | 38 | ChainAcceptor { 39 | block: BlockAcceptor::new( 40 | tx_out_provider, 41 | tree_state_provider, 42 | consensus, 43 | block, 44 | height, 45 | deployments, 46 | header_provider, 47 | ), 48 | header: HeaderAcceptor::new(header_provider, consensus, block.header(), height, time, deployments), 49 | transactions: block.transactions() 50 | .into_iter() 51 | .enumerate() 52 | .map(|(tx_index, tx)| TransactionAcceptor::new( 53 | tx_meta_provider, 54 | output_store, 55 | nullifier_tracker, 56 | consensus, 57 | tx, 58 | verification_level, 59 | height, 60 | block.header.raw.time, 61 | tx_index, 62 | deployments, 63 | tree_state_provider, 64 | )) 65 | .collect(), 66 | } 67 | } 68 | 69 | pub fn check(&self) -> Result<(), Error> { 70 | try!(self.block.check()); 71 | try!(self.header.check()); 72 | try!(self.check_transactions()); 73 | Ok(()) 74 | } 75 | 76 | fn check_transactions(&self) -> Result<(), Error> { 77 | self.transactions.par_iter() 78 | .enumerate() 79 | .fold(|| Ok(()), |result, (index, tx)| result.and_then(|_| tx.check().map_err(|err| Error::Transaction(index, err)))) 80 | .reduce(|| Ok(()), |acc, check| acc.and(check)) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /p2p/src/net/connections.rs: -------------------------------------------------------------------------------- 1 | use std::{mem, net}; 2 | use std::sync::Arc; 3 | use std::sync::atomic::{AtomicUsize, Ordering}; 4 | use std::collections::{HashMap, HashSet}; 5 | use parking_lot::RwLock; 6 | use net::{Connection, Channel}; 7 | use p2p::Context; 8 | use session::{SessionFactory}; 9 | use util::{Direction, PeerInfo}; 10 | use PeerId; 11 | 12 | const SYNCHRONOUS_RESPONSES: bool = true; 13 | 14 | #[derive(Default)] 15 | pub struct Connections { 16 | /// Incremental peer counter. 17 | peer_counter: AtomicUsize, 18 | /// All open connections. 19 | channels: RwLock>>, 20 | } 21 | 22 | impl Connections { 23 | /// Returns channel with given peer id. 24 | pub fn channel(&self, id: PeerId) -> Option> { 25 | self.channels.read().get(&id).cloned() 26 | } 27 | 28 | /// Returns safe (nonblocking) copy of channels. 29 | pub fn channels(&self) -> HashMap> { 30 | self.channels.read().clone() 31 | } 32 | 33 | /// Returns addresses of all active channels (nonblocking). 34 | pub fn addresses(&self) -> HashSet { 35 | self.channels().values().map(|channel| channel.peer_info().address).collect() 36 | } 37 | 38 | /// Returns info on every peer 39 | pub fn info(&self) -> Vec { 40 | self.channels().values().map(|channel| channel.peer_info()).collect() 41 | } 42 | 43 | /// Returns number of connections. 44 | pub fn count(&self) -> usize { 45 | self.channels.read().len() 46 | } 47 | 48 | /// Stores new channel. 49 | /// Returns a shared pointer to it. 50 | pub fn store(&self, context: Arc, connection: Connection, direction: Direction) -> Arc where T: SessionFactory { 51 | let id = self.peer_counter.fetch_add(1, Ordering::AcqRel); 52 | 53 | let peer_info = PeerInfo { 54 | id: id, 55 | address: connection.address, 56 | user_agent: connection.version_message.user_agent().unwrap_or("unknown".into()), 57 | direction: direction, 58 | version: connection.version, 59 | version_message: connection.version_message, 60 | magic: connection.magic, 61 | }; 62 | 63 | let session = T::new_session(context, peer_info.clone(), SYNCHRONOUS_RESPONSES); 64 | let channel = Arc::new(Channel::new(connection.stream, peer_info, session)); 65 | self.channels.write().insert(id, channel.clone()); 66 | channel 67 | } 68 | 69 | /// Removes channel with given id. 70 | pub fn remove(&self, id: PeerId) -> Option> { 71 | self.channels.write().remove(&id) 72 | } 73 | 74 | /// Drop all channels. 75 | pub fn remove_all(&self) -> Vec> { 76 | mem::replace(&mut *self.channels.write(), HashMap::new()) 77 | .into_iter() 78 | .map(|(_, value)| value) 79 | .collect() 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /keys/src/signature.rs: -------------------------------------------------------------------------------- 1 | //! Bitcoin signatures. 2 | //! 3 | //! http://bitcoin.stackexchange.com/q/12554/40688 4 | 5 | use std::{fmt, ops, str}; 6 | use hex::{ToHex, FromHex}; 7 | use hash::H520; 8 | use Error; 9 | 10 | #[derive(PartialEq)] 11 | pub struct Signature(Vec); 12 | 13 | impl fmt::Debug for Signature { 14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 15 | self.0.to_hex::().fmt(f) 16 | } 17 | } 18 | 19 | impl fmt::Display for Signature { 20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 21 | self.0.to_hex::().fmt(f) 22 | } 23 | } 24 | 25 | impl ops::Deref for Signature { 26 | type Target = [u8]; 27 | 28 | fn deref(&self) -> &Self::Target { 29 | &self.0 30 | } 31 | } 32 | 33 | impl str::FromStr for Signature { 34 | type Err = Error; 35 | 36 | fn from_str(s: &str) -> Result { 37 | let vec = try!(s.from_hex().map_err(|_| Error::InvalidSignature)); 38 | Ok(Signature(vec)) 39 | } 40 | } 41 | 42 | impl From<&'static str> for Signature { 43 | fn from(s: &'static str) -> Self { 44 | s.parse().unwrap() 45 | } 46 | } 47 | 48 | impl From> for Signature { 49 | fn from(v: Vec) -> Self { 50 | Signature(v) 51 | } 52 | } 53 | 54 | impl From for Vec { 55 | fn from(s: Signature) -> Self { 56 | s.0 57 | } 58 | } 59 | 60 | impl Signature { 61 | pub fn check_low_s(&self) -> bool { 62 | unimplemented!(); 63 | } 64 | } 65 | 66 | impl<'a> From<&'a [u8]> for Signature { 67 | fn from(v: &'a [u8]) -> Self { 68 | Signature(v.to_vec()) 69 | } 70 | } 71 | 72 | #[derive(PartialEq)] 73 | pub struct CompactSignature(H520); 74 | 75 | impl fmt::Debug for CompactSignature { 76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 77 | f.write_str(&self.0.to_hex::()) 78 | } 79 | } 80 | 81 | impl fmt::Display for CompactSignature { 82 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 83 | f.write_str(&self.0.to_hex::()) 84 | } 85 | } 86 | 87 | impl ops::Deref for CompactSignature { 88 | type Target = [u8]; 89 | 90 | fn deref(&self) -> &Self::Target { 91 | &*self.0 92 | } 93 | } 94 | 95 | impl str::FromStr for CompactSignature { 96 | type Err = Error; 97 | 98 | fn from_str(s: &str) -> Result { 99 | match s.parse() { 100 | Ok(hash) => Ok(CompactSignature(hash)), 101 | _ => Err(Error::InvalidSignature), 102 | } 103 | } 104 | } 105 | 106 | impl From<&'static str> for CompactSignature { 107 | fn from(s: &'static str) -> Self { 108 | s.parse().unwrap() 109 | } 110 | } 111 | 112 | impl From for CompactSignature { 113 | fn from(h: H520) -> Self { 114 | CompactSignature(h) 115 | } 116 | } 117 | --------------------------------------------------------------------------------

(path: P) -> Result where P: AsRef { 30 | let files = read_blk_dir(path)?.collect::, _>>()?; 31 | 32 | let iter = files.into_iter() 33 | // flatten results... 34 | .flat_map(|file| open_blk_file(file.path)) 35 | // flat iterators over each block in each file 36 | .flat_map(|file| file); 37 | 38 | let blk_dir = BlkDir { 39 | iter: Box::new(iter), 40 | }; 41 | 42 | Ok(blk_dir) 43 | } 44 | 45 | /// Bitcoind database blocks iterator 46 | pub struct BlkDir { 47 | iter: Box>>, 48 | } 49 | 50 | impl Iterator for BlkDir { 51 | type Item = Result; 52 | 53 | fn next(&mut self) -> Option { 54 | self.iter.next() 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /p2p/src/net/accept_connection.rs: -------------------------------------------------------------------------------- 1 | use std::{net, io}; 2 | use std::time::Duration; 3 | use futures::{Future, Poll}; 4 | use tokio_core::reactor::Handle; 5 | use tokio_core::net::TcpStream; 6 | use network::Magic; 7 | use message::{MessageResult}; 8 | use io::{accept_handshake, AcceptHandshake, Deadline, deadline}; 9 | use net::{Config, Connection}; 10 | 11 | pub fn accept_connection(stream: TcpStream, handle: &Handle, config: &Config, address: net::SocketAddr) -> Deadline { 12 | let accept = AcceptConnection { 13 | handshake: accept_handshake(stream, config.magic, config.version(&address), config.protocol_minimum), 14 | magic: config.magic, 15 | address: address, 16 | }; 17 | 18 | deadline(Duration::new(5, 0), handle, accept).expect("Failed to create timeout") 19 | } 20 | 21 | pub struct AcceptConnection { 22 | handshake: AcceptHandshake, 23 | magic: Magic, 24 | address: net::SocketAddr, 25 | } 26 | 27 | impl Future for AcceptConnection { 28 | type Item = MessageResult; 29 | type Error = io::Error; 30 | 31 | fn poll(&mut self) -> Poll { 32 | let (stream, result) = try_ready!(self.handshake.poll()); 33 | let result = match result { 34 | Ok(result) => result, 35 | Err(err) => return Ok(Err(err).into()), 36 | }; 37 | let connection = Connection { 38 | stream: stream.into(), 39 | services: result.version.services(), 40 | version: result.negotiated_version, 41 | version_message: result.version, 42 | magic: self.magic, 43 | address: self.address, 44 | }; 45 | Ok(Ok(connection).into()) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /sync/src/inbound_connection_factory.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicUsize, Ordering}; 2 | use p2p::{LocalSyncNode, LocalSyncNodeRef, OutboundSyncConnectionRef, InboundSyncConnectionRef}; 3 | use message::Services; 4 | use inbound_connection::InboundConnection; 5 | use types::{PeersRef, LocalNodeRef}; 6 | 7 | /// Inbound synchronization connection factory 8 | pub struct InboundConnectionFactory { 9 | /// Peers reference 10 | peers: PeersRef, 11 | /// Reference to synchronization node 12 | node: LocalNodeRef, 13 | /// Throughout counter of synchronization peers 14 | counter: AtomicUsize, 15 | } 16 | 17 | impl InboundConnectionFactory { 18 | /// Create new inbound connection factory 19 | pub fn new(peers: PeersRef, node: LocalNodeRef) -> Self { 20 | InboundConnectionFactory { 21 | peers: peers, 22 | node: node, 23 | counter: AtomicUsize::new(0), 24 | } 25 | } 26 | 27 | /// Box inbound connection factory 28 | pub fn boxed(self) -> LocalSyncNodeRef { 29 | Box::new(self) 30 | } 31 | } 32 | 33 | impl LocalSyncNode for InboundConnectionFactory { 34 | fn create_sync_session(&self, _best_block_height: i32, services: Services, outbound_connection: OutboundSyncConnectionRef) -> InboundSyncConnectionRef { 35 | let peer_index = self.counter.fetch_add(1, Ordering::SeqCst) + 1; 36 | trace!(target: "sync", "Creating new sync session with peer#{}", peer_index); 37 | // remember outbound connection 38 | self.peers.insert(peer_index, services, outbound_connection); 39 | // create new inbound connection 40 | InboundConnection::new(peer_index, self.peers.clone(), self.node.clone()).boxed() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sync/src/utils/synchronization_state.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; 2 | use p2p::InboundSyncConnectionState; 3 | use super::super::types::{StorageRef, BlockHeight}; 4 | 5 | // AtomicU32 is unstable => using AtomicUsize here 6 | 7 | /// Shared synchronization client state. 8 | /// It can be slightly inaccurate, but the accuracy is not required for it 9 | #[derive(Debug)] 10 | pub struct SynchronizationState { 11 | /// Is synchronization in progress? 12 | is_synchronizing: AtomicBool, 13 | /// Height of best block in the storage 14 | best_storage_block_height: AtomicUsize, 15 | } 16 | 17 | impl SynchronizationState { 18 | pub fn with_storage(storage: StorageRef) -> Self { 19 | let best_storage_block_height = storage.best_block().number; 20 | SynchronizationState { 21 | is_synchronizing: AtomicBool::new(false), 22 | best_storage_block_height: AtomicUsize::new(best_storage_block_height as usize), 23 | } 24 | } 25 | 26 | pub fn synchronizing(&self) -> bool { 27 | self.is_synchronizing.load(Ordering::SeqCst) 28 | } 29 | 30 | pub fn update_synchronizing(&self, synchronizing: bool) { 31 | self.is_synchronizing.store(synchronizing, Ordering::SeqCst); 32 | } 33 | 34 | pub fn best_storage_block_height(&self) -> BlockHeight { 35 | self.best_storage_block_height.load(Ordering::SeqCst) as BlockHeight 36 | } 37 | 38 | pub fn update_best_storage_block_height(&self, height: BlockHeight) { 39 | self.best_storage_block_height.store(height as usize, Ordering::SeqCst); 40 | } 41 | } 42 | 43 | impl InboundSyncConnectionState for SynchronizationState { 44 | fn synchronizing(&self) -> bool { 45 | SynchronizationState::synchronizing(self) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rpc/src/v1/traits/network.rs: -------------------------------------------------------------------------------- 1 | use jsonrpc_core::Error; 2 | use v1::types::{AddNodeOperation, NodeInfo}; 3 | 4 | /// Parity-bitcoin network interface 5 | #[rpc] 6 | pub trait Network { 7 | /// Add/remove/connect to the node 8 | /// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "addnode", "params": ["127.0.0.1:8888", "add"], "id":1 }' -H 'content-type: application/json' http://127.0.0.1:8332/ 9 | /// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "addnode", "params": ["127.0.0.1:8888", "remove"], "id":1 }' -H 'content-type: application/json' http://127.0.0.1:8332/ 10 | /// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "addnode", "params": ["127.0.0.1:8888", "onetry"], "id":1 }' -H 'content-type: application/json' http://127.0.0.1:8332/ 11 | #[rpc(name = "addnode")] 12 | fn add_node(&self, String, AddNodeOperation) -> Result<(), Error>; 13 | /// Query node(s) info 14 | /// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "id":"1", "method": "getaddednodeinfo", "params": [true] }' -H 'content-type: application/json' http://127.0.0.1:8332/ 15 | /// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "id":"1", "method": "getaddednodeinfo", "params": [true, "192.168.0.201"] }' -H 'content-type: application/json' http://127.0.0.1:8332/ 16 | #[rpc(name = "getaddednodeinfo")] 17 | fn node_info(&self, bool, Option) -> Result, Error>; 18 | /// Query node(s) info 19 | /// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "id":"1", "method": "getconnectioncount", "params": [] }' -H 'content-type: application/json' http://127.0.0.1:8332/ 20 | #[rpc(name = "getconnectioncount")] 21 | fn connection_count(&self) -> Result; 22 | } 23 | -------------------------------------------------------------------------------- /chain/src/indexed_header.rs: -------------------------------------------------------------------------------- 1 | use std::{io, cmp, fmt}; 2 | use hash::H256; 3 | use ser::{Deserializable, Reader, Error as ReaderError}; 4 | use block_header::{BlockHeader, block_header_hash}; 5 | use read_and_hash::ReadAndHash; 6 | 7 | #[derive(Clone)] 8 | pub struct IndexedBlockHeader { 9 | pub hash: H256, 10 | pub raw: BlockHeader, 11 | } 12 | 13 | impl fmt::Debug for IndexedBlockHeader { 14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 15 | f.debug_struct("IndexedBlockHeader") 16 | .field("hash", &self.hash.reversed()) 17 | .field("raw", &self.raw) 18 | .finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "test-helpers")] 23 | impl From for IndexedBlockHeader { 24 | fn from(header: BlockHeader) -> Self { 25 | Self::from_raw(header) 26 | } 27 | } 28 | impl IndexedBlockHeader { 29 | pub fn new(hash: H256, header: BlockHeader) -> Self { 30 | IndexedBlockHeader { 31 | hash: hash, 32 | raw: header, 33 | } 34 | } 35 | 36 | /// Explicit conversion of the raw BlockHeader into IndexedBlockHeader. 37 | /// 38 | /// Hashes the contents of block header. 39 | pub fn from_raw(header: BlockHeader) -> Self { 40 | IndexedBlockHeader::new(block_header_hash(&header), header) 41 | } 42 | } 43 | 44 | impl cmp::PartialEq for IndexedBlockHeader { 45 | fn eq(&self, other: &Self) -> bool { 46 | self.hash == other.hash 47 | } 48 | } 49 | 50 | impl Deserializable for IndexedBlockHeader { 51 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 52 | let data = try!(reader.read_and_hash::()); 53 | // TODO: use len 54 | let header = IndexedBlockHeader { 55 | raw: data.data, 56 | hash: data.hash, 57 | }; 58 | 59 | Ok(header) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /verification/src/verify_chain.rs: -------------------------------------------------------------------------------- 1 | use rayon::prelude::{IntoParallelRefIterator, IndexedParallelIterator, ParallelIterator}; 2 | use chain::IndexedBlock; 3 | use network::ConsensusParams; 4 | use error::Error; 5 | use verify_block::BlockVerifier; 6 | use verify_header::HeaderVerifier; 7 | use verify_transaction::TransactionVerifier; 8 | use VerificationLevel; 9 | 10 | pub struct ChainVerifier<'a> { 11 | pub block: BlockVerifier<'a>, 12 | pub header: Option>, 13 | pub transactions: Vec>, 14 | } 15 | 16 | impl<'a> ChainVerifier<'a> { 17 | pub fn new( 18 | block: &'a IndexedBlock, 19 | consensus: &'a ConsensusParams, 20 | current_time: u32, 21 | verification_level: VerificationLevel, 22 | ) -> Self { 23 | trace!(target: "verification", "Block pre-verification {}", block.hash().to_reversed_str()); 24 | ChainVerifier { 25 | block: BlockVerifier::new(block, consensus), 26 | header: if !verification_level.intersects(VerificationLevel::HINT_HEADER_PRE_VERIFIED) { 27 | Some(HeaderVerifier::new(&block.header, consensus, current_time)) 28 | } else { 29 | None 30 | }, 31 | transactions: block.transactions.iter().map(|tx| TransactionVerifier::new(tx, consensus)).collect(), 32 | } 33 | } 34 | 35 | pub fn check(&self) -> Result<(), Error> { 36 | self.block.check()?; 37 | if let Some(ref header) = self.header { 38 | header.check()?; 39 | } 40 | self.check_transactions()?; 41 | Ok(()) 42 | } 43 | 44 | fn check_transactions(&self) -> Result<(), Error> { 45 | self.transactions.par_iter() 46 | .enumerate() 47 | .fold(|| Ok(()), |result, (index, tx)| result.and_then(|_| tx.check().map_err(|err| Error::Transaction(index, err)))) 48 | .reduce(|| Ok(()), |acc, check| acc.and(check)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sync/src/types.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use futures::Future; 3 | use parking_lot::{Mutex, RwLock}; 4 | use storage; 5 | use local_node::LocalNode; 6 | use miner::MemoryPool; 7 | use super::SyncListener; 8 | use synchronization_client::SynchronizationClient; 9 | use synchronization_executor::LocalSynchronizationTaskExecutor; 10 | use synchronization_peers::Peers; 11 | use synchronization_server::ServerImpl; 12 | use synchronization_verifier::AsyncVerifier; 13 | use utils::SynchronizationState; 14 | 15 | pub use utils::BlockHeight; 16 | 17 | /// Network request id 18 | pub type RequestId = u32; 19 | 20 | /// Peer is indexed using this type 21 | pub type PeerIndex = usize; 22 | 23 | // No-error, no-result future 24 | pub type EmptyBoxFuture = Box + Send>; 25 | 26 | /// Reference to storage 27 | pub type StorageRef = storage::SharedStore; 28 | 29 | /// Reference to memory pool 30 | pub type MemoryPoolRef = Arc>; 31 | 32 | /// Shared synchronization state reference 33 | pub type SynchronizationStateRef = Arc; 34 | 35 | /// Reference to peers 36 | pub type PeersRef = Arc; 37 | 38 | /// Reference to synchronization tasks executor 39 | pub type ExecutorRef = Arc; 40 | 41 | /// Reference to synchronization client 42 | pub type ClientRef = Arc; 43 | 44 | /// Reference to synchronization client core 45 | pub type ClientCoreRef = Arc>; 46 | 47 | /// Reference to synchronization server 48 | pub type ServerRef = Arc; 49 | 50 | /// Reference to local node 51 | pub type LocalNodeRef = Arc>>; 52 | 53 | /// Synchronization events listener reference 54 | pub type SyncListenerRef = Box; 55 | -------------------------------------------------------------------------------- /pzec/util.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::path::PathBuf; 3 | use std::fs::create_dir_all; 4 | use app_dirs::{app_dir, AppDataType}; 5 | use {storage, APP_INFO}; 6 | use db; 7 | use config::Config; 8 | 9 | pub fn open_db(data_dir: &Option, db_cache: usize) -> storage::SharedStore { 10 | let db_path = match *data_dir { 11 | Some(ref data_dir) => custom_path(&data_dir, "db"), 12 | None => app_dir(AppDataType::UserData, &APP_INFO, "db").expect("Failed to get app dir"), 13 | }; 14 | Arc::new(db::BlockChainDatabase::open_at_path(db_path, db_cache).expect("Failed to open database")) 15 | } 16 | 17 | pub fn node_table_path(cfg: &Config) -> PathBuf { 18 | let mut node_table = match cfg.data_dir { 19 | Some(ref data_dir) => custom_path(&data_dir, "p2p"), 20 | None => app_dir(AppDataType::UserData, &APP_INFO, "p2p").expect("Failed to get app dir"), 21 | }; 22 | node_table.push("nodes.csv"); 23 | node_table 24 | } 25 | 26 | pub fn init_db(cfg: &Config) -> Result<(), String> { 27 | // insert genesis block if db is empty 28 | let genesis_block = cfg.network.genesis_block(); 29 | match cfg.db.block_hash(0) { 30 | Some(ref db_genesis_block_hash) if db_genesis_block_hash != genesis_block.hash() => Err("Trying to open database with incompatible genesis block".into()), 31 | Some(_) => Ok(()), 32 | None => { 33 | let hash = genesis_block.hash().clone(); 34 | cfg.db.insert(genesis_block).expect("Failed to insert genesis block to the database"); 35 | cfg.db.canonize(&hash).expect("Failed to canonize genesis block"); 36 | Ok(()) 37 | } 38 | } 39 | } 40 | 41 | fn custom_path(data_dir: &str, sub_dir: &str) -> PathBuf { 42 | let mut path = PathBuf::from(data_dir); 43 | path.push(sub_dir); 44 | create_dir_all(&path).expect("Failed to get app dir"); 45 | path 46 | } 47 | -------------------------------------------------------------------------------- /message/src/common/service.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Serializable, Deserializable)] 2 | pub struct Services(u64); 3 | 4 | impl From for u64 { 5 | fn from(s: Services) -> Self { 6 | s.0 7 | } 8 | } 9 | 10 | impl From for Services { 11 | fn from(v: u64) -> Self { 12 | Services(v) 13 | } 14 | } 15 | 16 | impl Services { 17 | pub fn network(&self) -> bool { 18 | self.bit_at(0) 19 | } 20 | 21 | pub fn with_network(mut self, v: bool) -> Self { 22 | self.set_bit(0, v); 23 | self 24 | } 25 | 26 | pub fn getutxo(&self) -> bool { 27 | self.bit_at(1) 28 | } 29 | 30 | pub fn with_getutxo(mut self, v: bool) -> Self { 31 | self.set_bit(1, v); 32 | self 33 | } 34 | 35 | pub fn bloom(&self) -> bool { 36 | self.bit_at(2) 37 | } 38 | 39 | pub fn with_bloom(mut self, v: bool) -> Self { 40 | self.set_bit(2, v); 41 | self 42 | } 43 | 44 | pub fn xthin(&self) -> bool { 45 | self.bit_at(4) 46 | } 47 | 48 | pub fn with_xthin(mut self, v: bool) -> Self { 49 | self.set_bit(4, v); 50 | self 51 | } 52 | 53 | pub fn includes(&self, other: &Self) -> bool { 54 | self.0 & other.0 == other.0 55 | } 56 | 57 | fn set_bit(&mut self, bit: usize, bit_value: bool) { 58 | if bit_value { 59 | self.0 |= 1 << bit 60 | } else { 61 | self.0 &= !(1 << bit) 62 | } 63 | } 64 | 65 | fn bit_at(&self, bit: usize) -> bool { 66 | self.0 & (1 << bit) != 0 67 | } 68 | } 69 | 70 | #[cfg(test)] 71 | mod test { 72 | use super::Services; 73 | 74 | #[test] 75 | fn test_serivces_includes() { 76 | let s1 = Services::default() 77 | .with_xthin(true); 78 | let s2 = Services::default(); 79 | 80 | assert!(s1.xthin()); 81 | assert!(!s2.xthin()); 82 | assert!(s1.includes(&s2)); 83 | assert!(!s2.includes(&s1)); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: rust 4 | branches: 5 | only: 6 | - master 7 | matrix: 8 | fast_finish: false 9 | include: 10 | - rust: stable 11 | cache: 12 | apt: true 13 | directories: 14 | - "$TRAVIS_BUILD_DIR/target" 15 | - "$HOME/.cargo" 16 | addons: 17 | apt: 18 | sources: 19 | - ubuntu-toolchain-r-test 20 | packages: 21 | - libcurl4-openssl-dev 22 | - libelf-dev 23 | - libdw-dev 24 | - gcc-4.8 25 | - g++-4.8 26 | - oracle-java8-set-default 27 | script: 28 | - cargo test --all 29 | - cargo build --release 30 | - "./tools/bench.sh" 31 | after_success: | 32 | [ true ] && 33 | [ $TRAVIS_BRANCH = master ] && 34 | [ $TRAVIS_PULL_REQUEST = false ] && 35 | [ $TRAVIS_RUST_VERSION = stable ] && 36 | ./tools/doc.sh && 37 | echo '' > target/doc/index.html && 38 | pip install --user ghp-import && 39 | /home/travis/.local/bin/ghp-import -n target/doc && 40 | git push -fq https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages 41 | env: 42 | global: 43 | - CXX="g++-4.8" 44 | - CC="gcc-4.8" 45 | - RUST_BACKTRACE=1 46 | - secure: aFox44yM3elxZswfhncexpEFFleCkuhhMpVQf8ZmnfUtaIU3l8+d4Js/dnUJ9P/BxA/U1qu3a9YCa/OjsxL/1UWiMApgBPZeC3soi2fnoVyB9+wIZ6Aw2gio1hOiLKvUysyaoGgrTBEKTm0oIbesRdVMk8XTwVWchgZxtOXx5/XBbK1J0C7hKM6rsWbCQ5JOYE1VGtEzcyjgjTtTol1iUHgT7QJkDKjZT2z4TzaomjOzj+0dW0qYtolei772Zsj1HmTdiMXxTq9W1pWH0L0FNk4LkxXrgkZcrxMn4VqKYwd7xbVXFQKYmG3+RXDGJmVsTAqmb7NRTr4XN6QW4kGsP+BL9E2y+HOy2YxxatRz+htkVuEU7cBt2R9mzKOlEljV6H4IRMu4Bc6PVwSDONH01+bN+XA4QS8N4hxFZp5m/kqWKQi2qmoh1xxv0zXJxsA9aRcmdmR62MwA2TVFi7RsJ+aYNCabAI60nSz1nmmL8RZHdkBqjdM3m2EldElBgQ5h2V73IqOlaDjc3c4UJbhs8J4hU7NMiumPHZmDJn7QQ2v5geKlFSPXAz+KivtH0iV2ErcnSfvvm6EWgF3vnjy+DIhVnWRubi92UEeig7T3YRekl3gpk+LwYt/dhRJOv5fwV7kRuxyhHY9O0h/cTCkQlE2BGhwpGKE0t1PkcUv2rx8= 47 | -------------------------------------------------------------------------------- /verification/src/tree_cache.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use chain::hash::H256; 4 | use storage::{TreeStateProvider, SproutTreeState, SaplingTreeState}; 5 | use error::TransactionError; 6 | 7 | 8 | #[derive(Clone)] 9 | pub struct TreeCache<'a> { 10 | persistent: &'a TreeStateProvider , 11 | interstitial: HashMap, 12 | } 13 | 14 | struct NoPersistentStorage; 15 | 16 | const NO_PERSISTENT: &'static NoPersistentStorage = &NoPersistentStorage; 17 | 18 | impl TreeStateProvider for NoPersistentStorage { 19 | fn sprout_tree_at(&self, _root: &H256) -> Option { None } 20 | 21 | fn sapling_tree_at(&self, _root: &H256) -> Option { None } 22 | 23 | fn sprout_block_root(&self, _block_hash: &H256) -> Option { None } 24 | 25 | fn sapling_block_root(&self, _block_hash: &H256) -> Option { None } 26 | } 27 | 28 | impl<'a> TreeCache<'a> { 29 | pub fn new(persistent: &'a TreeStateProvider) -> Self { 30 | TreeCache { 31 | persistent: persistent, 32 | interstitial: Default::default(), 33 | } 34 | } 35 | 36 | pub fn new_empty() -> TreeCache<'static> { 37 | TreeCache { 38 | persistent: NO_PERSISTENT, 39 | interstitial: Default::default(), 40 | } 41 | } 42 | 43 | pub fn continue_root(&mut self, root: &H256, commitments: &[[u8; 32]; 2]) -> Result<(), TransactionError> { 44 | let mut tree = match self.interstitial.get(root) { 45 | Some(tree) => tree.clone(), 46 | None => { 47 | self.persistent.sprout_tree_at(root).ok_or(TransactionError::UnknownAnchor(*root))? 48 | } 49 | }; 50 | 51 | tree.append(commitments[0].into()).expect("Unrecoverable error: merkle tree full"); 52 | tree.append(commitments[1].into()).expect("Unrecoverable error: merkle tree full"); 53 | 54 | self.interstitial.insert(tree.root(), tree); 55 | 56 | Ok(()) 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /chain/src/merkle_root.rs: -------------------------------------------------------------------------------- 1 | use crypto::dhash256; 2 | use hash::{H256, H512}; 3 | 4 | #[inline] 5 | fn concat(a: T, b: T) -> H512 where T: AsRef { 6 | let mut result = H512::default(); 7 | result[0..32].copy_from_slice(&**a.as_ref()); 8 | result[32..64].copy_from_slice(&**b.as_ref()); 9 | result 10 | } 11 | 12 | /// Calculates the root of the merkle tree 13 | /// https://en.bitcoin.it/wiki/Protocol_documentation#Merkle_Trees 14 | pub fn merkle_root(hashes: &[T]) -> H256 where T: AsRef { 15 | if hashes.len() == 1 { 16 | return hashes[0].as_ref().clone(); 17 | } 18 | 19 | let mut row = Vec::with_capacity(hashes.len() / 2); 20 | let mut i = 0; 21 | while i + 1 < hashes.len() { 22 | row.push(merkle_node_hash(&hashes[i], &hashes[i + 1])); 23 | i += 2 24 | } 25 | 26 | // duplicate the last element if len is not even 27 | if hashes.len() % 2 == 1 { 28 | let last = &hashes[hashes.len() - 1]; 29 | row.push(merkle_node_hash(last, last)); 30 | } 31 | 32 | merkle_root(&row) 33 | } 34 | 35 | /// Calculate merkle tree node hash 36 | pub fn merkle_node_hash(left: T, right: T) -> H256 where T: AsRef { 37 | dhash256(&*concat(left, right)) 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use hash::H256; 43 | use super::merkle_root; 44 | 45 | // block 80_000 46 | // https://blockchain.info/block/000000000043a8c0fd1d6f726790caa2a406010d19efd2780db27bdbbd93baf6 47 | #[test] 48 | fn test_merkle_root_with_2_hashes() { 49 | let tx1 = H256::from_reversed_str("c06fbab289f723c6261d3030ddb6be121f7d2508d77862bb1e484f5cd7f92b25"); 50 | let tx2 = H256::from_reversed_str("5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2"); 51 | let expected = H256::from_reversed_str("8fb300e3fdb6f30a4c67233b997f99fdd518b968b9a3fd65857bfe78b2600719"); 52 | 53 | let result = merkle_root(&[&tx1, &tx2]); 54 | let result2 = merkle_root(&[tx1, tx2]); 55 | assert_eq!(result, expected); 56 | assert_eq!(result2, expected); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pzec/rpc_apis.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | use std::collections::HashSet; 3 | use rpc::Dependencies; 4 | use ethcore_rpc::MetaIoHandler; 5 | 6 | #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] 7 | pub enum Api { 8 | /// Raw methods 9 | Raw, 10 | /// Miner-related methods 11 | Miner, 12 | /// BlockChain-related methods 13 | BlockChain, 14 | /// Network 15 | Network, 16 | } 17 | 18 | #[derive(Debug, PartialEq, Eq)] 19 | pub enum ApiSet { 20 | List(HashSet), 21 | } 22 | 23 | impl Default for ApiSet { 24 | fn default() -> Self { 25 | ApiSet::List(vec![Api::Raw, Api::Miner, Api::BlockChain, Api::Network].into_iter().collect()) 26 | } 27 | } 28 | 29 | impl FromStr for Api { 30 | type Err = String; 31 | 32 | fn from_str(s: &str) -> Result { 33 | match s { 34 | "raw" => Ok(Api::Raw), 35 | "miner" => Ok(Api::Miner), 36 | "blockchain" => Ok(Api::BlockChain), 37 | "network" => Ok(Api::Network), 38 | api => Err(format!("Unknown api: {}", api)), 39 | } 40 | } 41 | } 42 | 43 | impl ApiSet { 44 | pub fn list_apis(&self) -> HashSet { 45 | match *self { 46 | ApiSet::List(ref apis) => apis.clone(), 47 | } 48 | } 49 | } 50 | 51 | pub fn setup_rpc(mut handler: MetaIoHandler<()>, apis: ApiSet, deps: Dependencies) -> MetaIoHandler<()> { 52 | use ethcore_rpc::v1::*; 53 | 54 | for api in apis.list_apis() { 55 | match api { 56 | Api::Raw => handler.extend_with(RawClient::new(RawClientCore::new(deps.local_sync_node.clone())).to_delegate()), 57 | Api::Miner => handler.extend_with(MinerClient::new(MinerClientCore::new(deps.local_sync_node.clone(), deps.miner_address.clone())).to_delegate()), 58 | Api::BlockChain => handler.extend_with(BlockChainClient::new(BlockChainClientCore::new(deps.consensus.clone(), deps.storage.clone())).to_delegate()), 59 | Api::Network => handler.extend_with(NetworkClient::new(NetworkClientCore::new(deps.p2p_context.clone())).to_delegate()), 60 | } 61 | } 62 | 63 | handler 64 | } 65 | -------------------------------------------------------------------------------- /sync/src/utils/average_speed_meter.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | use time; 3 | 4 | /// Speed meter with given items number 5 | #[derive(Debug, Default)] 6 | pub struct AverageSpeedMeter { 7 | /// Number of items to inspect 8 | inspect_items: usize, 9 | /// Number of items currently inspected 10 | inspected_items: VecDeque, 11 | /// Current speed 12 | speed: f64, 13 | /// Last timestamp 14 | last_timestamp: Option, 15 | } 16 | 17 | impl AverageSpeedMeter { 18 | pub fn with_inspect_items(inspect_items: usize) -> Self { 19 | assert!(inspect_items > 0); 20 | AverageSpeedMeter { 21 | inspect_items: inspect_items, 22 | inspected_items: VecDeque::with_capacity(inspect_items), 23 | speed: 0_f64, 24 | last_timestamp: None, 25 | } 26 | } 27 | 28 | pub fn speed(&self) -> f64 { 29 | let items_per_second = 1_f64 / self.speed; 30 | if items_per_second.is_normal() { items_per_second } else { 0_f64 } 31 | } 32 | 33 | pub fn inspected_items_len(&self) -> usize { 34 | self.inspected_items.len() 35 | } 36 | 37 | pub fn checkpoint(&mut self) { 38 | // if inspected_items is already full => remove oldest item from average 39 | if self.inspected_items.len() == self.inspect_items { 40 | let oldest = self.inspected_items.pop_front().expect("len() is not zero; qed"); 41 | self.speed = (self.inspect_items as f64 * self.speed - oldest) / (self.inspect_items as f64 - 1_f64); 42 | } 43 | 44 | // add new item 45 | let now = time::precise_time_s(); 46 | if let Some(last_timestamp) = self.last_timestamp { 47 | let newest = now - last_timestamp; 48 | self.speed = (self.inspected_items.len() as f64 * self.speed + newest) / (self.inspected_items.len() as f64 + 1_f64); 49 | self.inspected_items.push_back(newest); 50 | } 51 | self.last_timestamp = Some(now); 52 | } 53 | 54 | pub fn start(&mut self) { 55 | self.last_timestamp = Some(time::precise_time_s()); 56 | } 57 | 58 | pub fn stop(&mut self) { 59 | self.last_timestamp = None; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /chain/src/indexed_transaction.rs: -------------------------------------------------------------------------------- 1 | use std::{cmp, io, fmt}; 2 | use hash::H256; 3 | use heapsize::HeapSizeOf; 4 | use ser::{Deserializable, Reader, Error as ReaderError}; 5 | use transaction::{Transaction, transaction_hash}; 6 | use read_and_hash::ReadAndHash; 7 | 8 | #[derive(Default, Clone)] 9 | pub struct IndexedTransaction { 10 | pub hash: H256, 11 | pub raw: Transaction, 12 | } 13 | 14 | impl fmt::Debug for IndexedTransaction { 15 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 16 | f.debug_struct("IndexedTransaction") 17 | .field("hash", &self.hash.reversed()) 18 | .field("raw", &self.raw) 19 | .finish() 20 | } 21 | } 22 | 23 | #[cfg(feature = "test-helpers")] 24 | impl From for IndexedTransaction where Transaction: From { 25 | fn from(other: T) -> Self { 26 | Self::from_raw(other) 27 | } 28 | } 29 | 30 | impl HeapSizeOf for IndexedTransaction { 31 | fn heap_size_of_children(&self) -> usize { 32 | self.raw.heap_size_of_children() 33 | } 34 | } 35 | 36 | impl IndexedTransaction { 37 | pub fn new(hash: H256, transaction: Transaction) -> Self { 38 | IndexedTransaction { 39 | hash: hash, 40 | raw: transaction, 41 | } 42 | } 43 | 44 | /// Explicit conversion of the raw Transaction into IndexedTransaction. 45 | /// 46 | /// Hashes transaction contents. 47 | pub fn from_raw(transaction: T) -> Self where Transaction: From { 48 | let transaction = Transaction::from(transaction); 49 | Self::new(transaction_hash(&transaction), transaction) 50 | } 51 | } 52 | 53 | impl cmp::PartialEq for IndexedTransaction { 54 | fn eq(&self, other: &Self) -> bool { 55 | self.hash == other.hash 56 | } 57 | } 58 | 59 | impl Deserializable for IndexedTransaction { 60 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 61 | let data = try!(reader.read_and_hash::()); 62 | // TODO: use len 63 | let tx = IndexedTransaction { 64 | raw: data.data, 65 | hash: data.hash, 66 | }; 67 | 68 | Ok(tx) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /message/src/common/address.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use ser::deserialize; 3 | use common::{Port, IpAddress, Services}; 4 | 5 | #[derive(Debug, Default, PartialEq, Clone, Serializable, Deserializable)] 6 | pub struct NetAddress { 7 | pub services: Services, 8 | pub address: IpAddress, 9 | pub port: Port, 10 | } 11 | 12 | impl From<&'static str> for NetAddress { 13 | fn from(s: &'static str) -> Self { 14 | let bytes: Bytes = s.into(); 15 | deserialize(bytes.as_ref()).unwrap() 16 | } 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use ser::{serialize, deserialize}; 22 | use common::Services; 23 | use super::NetAddress; 24 | 25 | #[test] 26 | fn test_net_address_serialize() { 27 | let expected = vec![ 28 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x01, 30 | 0x20, 0x8d 31 | ].into(); 32 | 33 | let address = NetAddress { 34 | services: Services::default().with_network(true), 35 | address: "::ffff:a00:1".into(), 36 | port: 8333.into(), 37 | }; 38 | 39 | assert_eq!(serialize(&address), expected); 40 | } 41 | 42 | #[test] 43 | fn test_net_address_deserialize() { 44 | let bytes = vec![ 45 | 0x01u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x01, 47 | 0x20, 0x8d 48 | ]; 49 | 50 | let expected = NetAddress { 51 | services: Services::default().with_network(true), 52 | address: "::ffff:a00:1".into(), 53 | port: 8333.into(), 54 | }; 55 | 56 | assert_eq!(expected, deserialize(&bytes as &[u8]).unwrap()); 57 | } 58 | 59 | #[test] 60 | fn test_net_address_from_static_str() { 61 | let expected = NetAddress { 62 | services: Services::default().with_network(true), 63 | address: "::ffff:a00:1".into(), 64 | port: 8333.into(), 65 | 66 | }; 67 | let s = "010000000000000000000000000000000000ffff0a000001208d"; 68 | assert_eq!(expected, s.into()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pzec/main.rs: -------------------------------------------------------------------------------- 1 | //! Parity bitcoin client. 2 | 3 | #[macro_use] 4 | extern crate clap; 5 | #[macro_use] 6 | extern crate log; 7 | extern crate env_logger; 8 | extern crate app_dirs; 9 | extern crate libc; 10 | 11 | extern crate storage; 12 | extern crate db; 13 | extern crate chain; 14 | extern crate keys; 15 | extern crate logs; 16 | extern crate script; 17 | extern crate message; 18 | extern crate network; 19 | extern crate p2p; 20 | extern crate sync; 21 | extern crate import; 22 | extern crate rpc as ethcore_rpc; 23 | extern crate primitives; 24 | extern crate verification; 25 | 26 | mod commands; 27 | mod config; 28 | mod seednodes; 29 | mod util; 30 | mod rpc; 31 | mod rpc_apis; 32 | 33 | use app_dirs::AppInfo; 34 | 35 | pub const APP_INFO: AppInfo = AppInfo { name: "pzec", author: "Parity" }; 36 | pub const PROTOCOL_VERSION: u32 = 70_014; 37 | pub const PROTOCOL_MINIMUM: u32 = 70_001; 38 | pub const ZCASH_PROTOCOL_VERSION: u32 = 170_007; 39 | pub const ZCASH_PROTOCOL_MINIMUM: u32 = 170_007; 40 | pub const USER_AGENT: &'static str = "pzec"; 41 | pub const REGTEST_USER_AGENT: &'static str = "/Satoshi:0.12.1/"; 42 | pub const LOG_INFO: &'static str = "sync=info"; 43 | 44 | fn main() { 45 | // Always print backtrace on panic. 46 | ::std::env::set_var("RUST_BACKTRACE", "1"); 47 | 48 | if let Err(err) = run() { 49 | println!("{}", err); 50 | } 51 | } 52 | 53 | fn run() -> Result<(), String> { 54 | let yaml = load_yaml!("cli.yml"); 55 | let matches = clap::App::from_yaml(yaml).get_matches(); 56 | let cfg = try!(config::parse(&matches)); 57 | 58 | if !cfg.quiet { 59 | if cfg!(windows) { 60 | logs::init(LOG_INFO, logs::DateLogFormatter); 61 | } else { 62 | logs::init(LOG_INFO, logs::DateAndColorLogFormatter); 63 | } 64 | } else { 65 | env_logger::init(); 66 | } 67 | 68 | match matches.subcommand() { 69 | ("import", Some(import_matches)) => commands::import(cfg, import_matches), 70 | ("rollback", Some(rollback_matches)) => commands::rollback(cfg, rollback_matches), 71 | _ => commands::start(cfg), 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /logs/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ansi_term; 2 | extern crate log; 3 | extern crate env_logger; 4 | extern crate time; 5 | 6 | use std::env; 7 | use ansi_term::Colour as Color; 8 | use log::{Record, Level}; 9 | use env_logger::Builder; 10 | use std::io::Write; 11 | 12 | fn strftime() -> String { 13 | time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now()).expect("Time is incorrectly formatted") 14 | } 15 | 16 | pub trait LogFormatter: Send + Sync + 'static { 17 | fn format(&self, log_record: &Record) -> String; 18 | } 19 | 20 | pub struct DateLogFormatter; 21 | 22 | impl LogFormatter for DateLogFormatter { 23 | fn format(&self, record: &Record) -> String { 24 | let timestamp = strftime(); 25 | format!("{} {} {} {}", timestamp, record.level(), record.target(), record.args()) 26 | } 27 | } 28 | 29 | pub struct DateAndColorLogFormatter; 30 | 31 | impl LogFormatter for DateAndColorLogFormatter { 32 | fn format(&self, record: &Record) -> String { 33 | let timestamp = strftime(); 34 | let log_level = match record.level() { 35 | Level::Error => Color::Fixed(9).bold().paint(record.level().to_string()), 36 | Level::Warn => Color::Fixed(11).bold().paint(record.level().to_string()), 37 | Level::Info => Color::Fixed(10).paint(record.level().to_string()), 38 | Level::Debug => Color::Fixed(14).paint(record.level().to_string()), 39 | Level::Trace => Color::Fixed(12).paint(record.level().to_string()), 40 | }; 41 | format!("{} {} {} {}" 42 | , Color::Fixed(8).bold().paint(timestamp) 43 | , log_level 44 | , Color::Fixed(8).paint(record.target()) 45 | , record.args()) 46 | } 47 | } 48 | 49 | pub fn init(filters: &str, formatter: T) where T: LogFormatter { 50 | let mut builder = Builder::new(); 51 | 52 | let filters = match env::var("RUST_LOG") { 53 | Ok(env_filters) => format!("{},{}", filters, env_filters), 54 | Err(_) => filters.into(), 55 | }; 56 | 57 | builder.parse(&filters); 58 | builder.format(move |buf, record| { 59 | writeln!(buf, "{}", formatter.format(record)) 60 | }); 61 | 62 | builder.init(); 63 | } 64 | -------------------------------------------------------------------------------- /p2p/src/io/read_header.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use futures::{Future, Poll, Async}; 3 | use tokio_io::AsyncRead; 4 | use tokio_io::io::{ReadExact, read_exact}; 5 | use message::{MessageHeader, MessageResult}; 6 | use network::Magic; 7 | 8 | pub fn read_header(a: A, magic: Magic) -> ReadHeader where A: AsyncRead { 9 | ReadHeader { 10 | reader: read_exact(a, [0u8; 24]), 11 | magic: magic, 12 | } 13 | } 14 | 15 | pub struct ReadHeader { 16 | reader: ReadExact, 17 | magic: Magic, 18 | } 19 | 20 | impl Future for ReadHeader where A: AsyncRead { 21 | type Item = (A, MessageResult); 22 | type Error = io::Error; 23 | 24 | fn poll(&mut self) -> Poll { 25 | let (read, data) = try_ready!(self.reader.poll()); 26 | let header = MessageHeader::deserialize(&data, self.magic); 27 | Ok(Async::Ready((read, header))) 28 | } 29 | } 30 | 31 | #[cfg(test)] 32 | mod tests { 33 | use futures::Future; 34 | use bytes::Bytes; 35 | use network::{Network}; 36 | use message::{MessageHeader, Error}; 37 | use super::read_header; 38 | 39 | #[test] 40 | fn test_read_header() { 41 | let raw: Bytes = "24e927646164647200000000000000001f000000ed52399b".into(); 42 | let expected = MessageHeader { 43 | magic: Network::Mainnet.magic(), 44 | command: "addr".into(), 45 | len: 0x1f, 46 | checksum: "ed52399b".into(), 47 | }; 48 | 49 | assert_eq!(read_header(raw.as_ref(), Network::Mainnet.magic()).wait().unwrap().1, Ok(expected)); 50 | assert_eq!(read_header(raw.as_ref(), Network::Testnet.magic()).wait().unwrap().1, Err(Error::InvalidMagic)); 51 | } 52 | 53 | #[test] 54 | fn test_read_header_with_invalid_magic() { 55 | let raw: Bytes = "f9beb4d86164647200000000000000001f000000ed52399b".into(); 56 | assert_eq!(read_header(raw.as_ref(), Network::Testnet.magic()).wait().unwrap().1, Err(Error::InvalidMagic)); 57 | } 58 | 59 | #[test] 60 | fn test_read_too_short_header() { 61 | let raw: Bytes = "24e927646164647200000000000000001f000000ed5239".into(); 62 | assert!(read_header(raw.as_ref(), Network::Mainnet.magic()).wait().is_err()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /verification/src/canon.rs: -------------------------------------------------------------------------------- 1 | use std::ops; 2 | use primitives::hash::H256; 3 | use chain::{IndexedBlock, IndexedTransaction, IndexedBlockHeader}; 4 | 5 | /// Blocks whose parents are known to be in the chain 6 | #[derive(Clone, Copy)] 7 | pub struct CanonBlock<'a> { 8 | block: &'a IndexedBlock, 9 | } 10 | 11 | impl<'a> CanonBlock<'a> { 12 | pub fn new(block: &'a IndexedBlock) -> Self { 13 | CanonBlock { 14 | block: block, 15 | } 16 | } 17 | 18 | pub fn hash<'b>(&'b self) -> &'a H256 where 'a: 'b { 19 | &self.block.header.hash 20 | } 21 | 22 | pub fn raw<'b>(&'b self) -> &'a IndexedBlock where 'a: 'b { 23 | self.block 24 | } 25 | 26 | pub fn header<'b>(&'b self) -> CanonHeader<'a> where 'a: 'b { 27 | CanonHeader::new(&self.block.header) 28 | } 29 | 30 | pub fn transactions<'b>(&'b self) -> Vec> where 'a: 'b { 31 | self.block.transactions.iter().map(CanonTransaction::new).collect() 32 | } 33 | } 34 | 35 | impl<'a> ops::Deref for CanonBlock<'a> { 36 | type Target = IndexedBlock; 37 | 38 | fn deref(&self) -> &Self::Target { 39 | self.block 40 | } 41 | } 42 | 43 | #[derive(Clone, Copy)] 44 | pub struct CanonHeader<'a> { 45 | header: &'a IndexedBlockHeader, 46 | } 47 | 48 | impl<'a> CanonHeader<'a> { 49 | pub fn new(header: &'a IndexedBlockHeader) -> Self { 50 | CanonHeader { 51 | header: header, 52 | } 53 | } 54 | } 55 | 56 | impl<'a> ops::Deref for CanonHeader<'a> { 57 | type Target = IndexedBlockHeader; 58 | 59 | fn deref(&self) -> &Self::Target { 60 | self.header 61 | } 62 | } 63 | 64 | #[derive(Clone, Copy)] 65 | pub struct CanonTransaction<'a> { 66 | transaction: &'a IndexedTransaction, 67 | } 68 | 69 | impl<'a> CanonTransaction<'a> { 70 | pub fn new(transaction: &'a IndexedTransaction) -> Self { 71 | CanonTransaction { 72 | transaction: transaction, 73 | } 74 | } 75 | 76 | pub fn join_split(&self) -> Option<&'a chain::JoinSplit> { 77 | self.transaction.raw.join_split.as_ref() 78 | } 79 | } 80 | 81 | impl<'a> ops::Deref for CanonTransaction<'a> { 82 | type Target = IndexedTransaction; 83 | 84 | fn deref(&self) -> &Self::Target { 85 | self.transaction 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /serialization_derive/src/de.rs: -------------------------------------------------------------------------------- 1 | use {syn, quote}; 2 | 3 | pub fn impl_deserializable(ast: &syn::DeriveInput) -> quote::Tokens { 4 | let body = match ast.body { 5 | syn::Body::Struct(ref s) => s, 6 | _ => panic!("#[derive(Deserializable)] is only defined for structs."), 7 | }; 8 | 9 | let stmts: Vec<_> = match *body { 10 | syn::VariantData::Struct(ref fields) => fields.iter().enumerate().map(deserialize_field_map).collect(), 11 | syn::VariantData::Tuple(ref fields) => fields.iter().enumerate().map(deserialize_field_map).collect(), 12 | syn::VariantData::Unit => panic!("#[derive(Deserializable)] is not defined for Unit structs."), 13 | }; 14 | 15 | let name = &ast.ident; 16 | 17 | let dummy_const = syn::Ident::new(format!("_IMPL_DESERIALIZABLE_FOR_{}", name)); 18 | let impl_block = quote! { 19 | impl serialization::Deserializable for #name { 20 | fn deserialize(reader: &mut serialization::Reader) -> Result where T: io::Read { 21 | let result = #name { 22 | #(#stmts)* 23 | }; 24 | 25 | Ok(result) 26 | } 27 | } 28 | }; 29 | 30 | quote! { 31 | #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] 32 | const #dummy_const: () = { 33 | extern crate serialization; 34 | use std::io; 35 | #impl_block 36 | }; 37 | } 38 | } 39 | 40 | fn deserialize_field_map(tuple: (usize, &syn::Field)) -> quote::Tokens { 41 | deserialize_field(tuple.0, tuple.1) 42 | } 43 | 44 | fn deserialize_field(index: usize, field: &syn::Field) -> quote::Tokens { 45 | let ident = match field.ident { 46 | Some(ref ident) => ident.to_string(), 47 | None => index.to_string(), 48 | }; 49 | 50 | let id = syn::Ident::new(ident.to_string()); 51 | 52 | match field.ty { 53 | syn::Ty::Path(_, ref path) => { 54 | let ident = &path.segments.first().expect("there must be at least 1 segment").ident; 55 | if &ident.to_string() == "Vec" { 56 | quote! { #id: reader.read_list()?, } 57 | } else { 58 | quote! { #id: reader.read()?, } 59 | } 60 | }, 61 | syn::Ty::Array(_, _) => { 62 | quote! { #id: reader.read()?, } 63 | }, 64 | _ => panic!("serialization not supported"), 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /bencher/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate storage; 2 | extern crate db; 3 | extern crate chain; 4 | extern crate test_data; 5 | extern crate time; 6 | extern crate verification; 7 | extern crate network; 8 | extern crate byteorder; 9 | extern crate primitives; 10 | 11 | mod database; 12 | mod verifier; 13 | 14 | use time::{PreciseTime, Duration}; 15 | use std::io::Write; 16 | use std::str; 17 | 18 | #[derive(Default)] 19 | pub struct Benchmark { 20 | start: Option, 21 | end: Option, 22 | samples: Option, 23 | } 24 | 25 | impl Benchmark { 26 | pub fn start(&mut self) { 27 | self.start = Some(PreciseTime::now()); 28 | } 29 | 30 | pub fn stop(&mut self) { 31 | self.end = Some(PreciseTime::now()); 32 | } 33 | 34 | pub fn evaluate(&self) -> Duration { 35 | self.start.expect("benchmarch never ended").to(self.end.expect("benchmark never started")) 36 | } 37 | 38 | pub fn samples(&mut self, samples: usize) { 39 | self.samples = Some(samples); 40 | } 41 | } 42 | 43 | fn decimal_mark(s: String) -> String { 44 | let bytes: Vec<_> = s.bytes().rev().collect(); 45 | let chunks: Vec<_> = bytes.chunks(3).map(|chunk| str::from_utf8(chunk).unwrap()).collect(); 46 | let result: Vec<_> = chunks.join(",").bytes().rev().collect(); 47 | String::from_utf8(result).unwrap() 48 | } 49 | 50 | 51 | fn run_benchmark(name: &str, f: F) where F: FnOnce(&mut Benchmark) { 52 | print!("{}: ", name); 53 | ::std::io::stdout().flush().unwrap(); 54 | 55 | let mut benchmark = Benchmark::default(); 56 | f(&mut benchmark); 57 | if let Some(samples) = benchmark.samples { 58 | println!("{} ns/sample", 59 | decimal_mark(format!("{}", benchmark.evaluate().num_nanoseconds().unwrap() / samples as i64)), 60 | ); 61 | } 62 | else { 63 | println!("{} ns", decimal_mark(format!("{}", benchmark.evaluate().num_nanoseconds().unwrap()))); 64 | } 65 | } 66 | 67 | macro_rules! benchmark { 68 | ($t:expr) => { 69 | run_benchmark(stringify!($t), $t); 70 | }; 71 | } 72 | 73 | fn main() { 74 | benchmark!(database::fetch); 75 | benchmark!(database::write); 76 | benchmark!(database::reorg_short); 77 | benchmark!(database::write_heavy); 78 | benchmark!(verifier::main); 79 | } 80 | -------------------------------------------------------------------------------- /p2p/src/io/read_payload.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::marker::PhantomData; 3 | use futures::{Poll, Future}; 4 | use tokio_io::AsyncRead; 5 | use tokio_io::io::{read_exact, ReadExact}; 6 | use bytes::Bytes; 7 | use hash::H32; 8 | use crypto::checksum; 9 | use message::{Error, MessageResult, Payload, deserialize_payload}; 10 | 11 | pub fn read_payload(a: A, version: u32, len: usize, checksum: H32) -> ReadPayload 12 | where A: AsyncRead, M: Payload { 13 | ReadPayload { 14 | reader: read_exact(a, Bytes::new_with_len(len)), 15 | version: version, 16 | checksum: checksum, 17 | payload_type: PhantomData, 18 | } 19 | } 20 | 21 | pub struct ReadPayload { 22 | reader: ReadExact, 23 | version: u32, 24 | checksum: H32, 25 | payload_type: PhantomData, 26 | } 27 | 28 | impl Future for ReadPayload where A: AsyncRead, M: Payload { 29 | type Item = (A, MessageResult); 30 | type Error = io::Error; 31 | 32 | fn poll(&mut self) -> Poll { 33 | let (read, data) = try_ready!(self.reader.poll()); 34 | if checksum(&data) != self.checksum { 35 | return Ok((read, Err(Error::InvalidChecksum)).into()); 36 | } 37 | let payload = deserialize_payload(&data, self.version); 38 | Ok((read, payload).into()) 39 | } 40 | } 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | use futures::Future; 45 | use bytes::Bytes; 46 | use message::Error; 47 | use message::types::Ping; 48 | use super::read_payload; 49 | 50 | #[test] 51 | fn test_read_payload() { 52 | let raw: Bytes = "5845303b6da97786".into(); 53 | let ping = Ping::new(u64::from_str_radix("8677a96d3b304558", 16).unwrap()); 54 | assert_eq!(read_payload(raw.as_ref(), 0, 8, "83c00c76".into()).wait().unwrap().1, Ok(ping)); 55 | } 56 | 57 | #[test] 58 | fn test_read_payload_with_invalid_checksum() { 59 | let raw: Bytes = "5845303b6da97786".into(); 60 | assert_eq!(read_payload::(raw.as_ref(), 0, 8, "83c00c75".into()).wait().unwrap().1, Err(Error::InvalidChecksum)); 61 | } 62 | 63 | #[test] 64 | fn test_read_too_short_payload() { 65 | let raw: Bytes = "5845303b6da977".into(); 66 | assert!(read_payload::(raw.as_ref(), 0, 8, "83c00c76".into()).wait().is_err()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /message/src/types/reject.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use ser::{Serializable, Stream, Deserializable, Reader, Error as ReaderError}; 3 | use {Payload, MessageResult}; 4 | 5 | #[derive(Debug, PartialEq, Clone, Copy)] 6 | #[repr(u8)] 7 | pub enum RejectCode { 8 | Malformed = 0x01, 9 | Invalid = 0x10, 10 | Obsolate = 0x11, 11 | Duplicate = 0x12, 12 | Nonstandard = 0x40, 13 | Dust = 0x41, 14 | InsuficientFee = 0x42, 15 | Checkpoint = 0x43, 16 | } 17 | 18 | impl From for u8 { 19 | fn from(c: RejectCode) -> Self { 20 | c as u8 21 | } 22 | } 23 | 24 | impl RejectCode { 25 | pub fn from_u8(v: u8) -> Option { 26 | let some = match v { 27 | 0x01 => RejectCode::Malformed, 28 | 0x10 => RejectCode::Invalid, 29 | 0x11 => RejectCode::Obsolate, 30 | 0x12 => RejectCode::Duplicate, 31 | 0x40 => RejectCode::Nonstandard, 32 | 0x41 => RejectCode::Dust, 33 | 0x42 => RejectCode::InsuficientFee, 34 | 0x43 => RejectCode::Checkpoint, 35 | _ => return None, 36 | }; 37 | 38 | Some(some) 39 | } 40 | } 41 | 42 | impl Serializable for RejectCode { 43 | fn serialize(&self, stream: &mut Stream) { 44 | stream.append(&u8::from(*self)); 45 | } 46 | } 47 | 48 | impl Deserializable for RejectCode { 49 | fn deserialize(reader: &mut Reader) -> Result where T: io::Read { 50 | let v: u8 = try!(reader.read()); 51 | RejectCode::from_u8(v).ok_or_else(|| ReaderError::MalformedData) 52 | } 53 | } 54 | 55 | #[derive(Debug, PartialEq)] 56 | pub struct Reject { 57 | pub message: String, 58 | pub code: RejectCode, 59 | pub reason: String, 60 | // TODO: data 61 | } 62 | 63 | impl Payload for Reject { 64 | fn version() -> u32 { 65 | 0 66 | } 67 | 68 | fn command() -> &'static str { 69 | "reject" 70 | } 71 | 72 | fn deserialize_payload(reader: &mut Reader, _version: u32) -> MessageResult where T: io::Read { 73 | let reject = Reject { 74 | message: try!(reader.read()), 75 | code: try!(reader.read()), 76 | reason: try!(reader.read()), 77 | }; 78 | 79 | Ok(reject) 80 | } 81 | 82 | fn serialize_payload(&self, stream: &mut Stream, _version: u32) -> MessageResult<()> { 83 | stream 84 | .append(&self.message) 85 | .append(&self.code) 86 | .append(&self.reason); 87 | Ok(()) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /storage/src/store.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use chain::IndexedBlockHeader; 3 | use { 4 | BestBlock, BlockProvider, BlockHeaderProvider, TransactionProvider, TransactionMetaProvider, 5 | TransactionOutputProvider, BlockChain, Forkable, NullifierTracker, TreeStateProvider, 6 | }; 7 | 8 | pub trait CanonStore: Store + Forkable { 9 | fn as_store(&self) -> &Store; 10 | } 11 | 12 | /// Blockchain storage interface 13 | pub trait Store: AsSubstore { 14 | /// get best block 15 | fn best_block(&self) -> BestBlock; 16 | 17 | /// get best header 18 | fn best_header(&self) -> IndexedBlockHeader; 19 | } 20 | 21 | /// Allows casting Arc to reference to any substore type 22 | pub trait AsSubstore: 23 | BlockChain + 24 | BlockProvider + 25 | TransactionProvider + 26 | TransactionMetaProvider + 27 | TransactionOutputProvider + 28 | NullifierTracker 29 | { 30 | fn as_block_provider(&self) -> &BlockProvider; 31 | 32 | fn as_block_header_provider(&self) -> &BlockHeaderProvider; 33 | 34 | fn as_transaction_provider(&self) -> &TransactionProvider; 35 | 36 | fn as_transaction_output_provider(&self) -> &TransactionOutputProvider; 37 | 38 | fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider; 39 | 40 | fn as_nullifier_tracker(&self) -> &NullifierTracker; 41 | 42 | fn as_tree_state_provider(&self) -> &TreeStateProvider; 43 | } 44 | 45 | impl AsSubstore for T 46 | where T: BlockChain + 47 | BlockProvider + 48 | TransactionProvider + 49 | TransactionMetaProvider + 50 | TransactionOutputProvider + 51 | NullifierTracker + 52 | TreeStateProvider 53 | { 54 | fn as_block_provider(&self) -> &BlockProvider { 55 | &*self 56 | } 57 | 58 | fn as_block_header_provider(&self) -> &BlockHeaderProvider { 59 | &*self 60 | } 61 | 62 | fn as_transaction_provider(&self) -> &TransactionProvider { 63 | &*self 64 | } 65 | 66 | fn as_transaction_output_provider(&self) -> &TransactionOutputProvider { 67 | &*self 68 | } 69 | 70 | fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider { 71 | &*self 72 | } 73 | 74 | fn as_nullifier_tracker(&self) -> &NullifierTracker { 75 | &*self 76 | } 77 | 78 | fn as_tree_state_provider(&self) -> &TreeStateProvider { 79 | &*self 80 | } 81 | } 82 | 83 | pub type SharedStore = Arc; 84 | -------------------------------------------------------------------------------- /rpc/src/v1/types/nodes.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use serde::{Serialize, Serializer, Deserialize, Deserializer}; 3 | use serde::de::Unexpected; 4 | use p2p::{Direction, PeerInfo}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub enum AddNodeOperation { 8 | Add, 9 | Remove, 10 | OneTry, 11 | } 12 | 13 | impl<'a> Deserialize<'a> for AddNodeOperation { 14 | fn deserialize(deserializer: D) -> Result where D: Deserializer<'a> { 15 | use serde::de::Visitor; 16 | 17 | struct DummyVisitor; 18 | 19 | impl<'b> Visitor<'b> for DummyVisitor { 20 | type Value = AddNodeOperation; 21 | 22 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 23 | formatter.write_str("a node operation string") 24 | } 25 | 26 | fn visit_str(self, value: &str) -> Result where E: ::serde::de::Error { 27 | match value { 28 | "add" => Ok(AddNodeOperation::Add), 29 | "remove" => Ok(AddNodeOperation::Remove), 30 | "onetry" => Ok(AddNodeOperation::OneTry), 31 | _ => Err(E::invalid_value(Unexpected::Str(value), &self)), 32 | } 33 | } 34 | } 35 | 36 | deserializer.deserialize_identifier(DummyVisitor) 37 | } 38 | } 39 | 40 | #[derive(Serialize)] 41 | pub struct NodeInfoAddress { 42 | address: String, 43 | connected: NodeInfoAddressConnectionType, 44 | } 45 | 46 | impl From for NodeInfoAddress { 47 | fn from(info: PeerInfo) -> Self { 48 | NodeInfoAddress { 49 | address: format!("{}", info.address), 50 | connected: match info.direction { 51 | Direction::Inbound => NodeInfoAddressConnectionType::Inbound, 52 | Direction::Outbound => NodeInfoAddressConnectionType::Outbound, 53 | }, 54 | } 55 | } 56 | } 57 | 58 | #[derive(Serialize)] 59 | pub struct NodeInfo { 60 | pub addednode: String, 61 | pub connected: bool, 62 | pub addresses: Vec, 63 | } 64 | 65 | pub enum NodeInfoAddressConnectionType { 66 | Inbound, 67 | Outbound, 68 | } 69 | 70 | impl Serialize for NodeInfoAddressConnectionType { 71 | fn serialize(&self, serializer: S) -> Result where S: Serializer { 72 | match *self { 73 | NodeInfoAddressConnectionType::Inbound => "inbound".serialize(serializer), 74 | NodeInfoAddressConnectionType::Outbound => "outbound".serialize(serializer), 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /CLI.md: -------------------------------------------------------------------------------- 1 | # Command-line options 2 | 3 | ``` 4 | pzec 0.1.0 5 | Parity Technologies 6 | Parity Zcash client 7 | 8 | USAGE: 9 | pzec [FLAGS] [OPTIONS] [SUBCOMMAND] 10 | 11 | FLAGS: 12 | -h, --help Prints help information 13 | --no-jsonrpc Disable the JSON-RPC API server. 14 | -q, --quiet Do not show any synchronization information in the console. 15 | --regtest Use a private network for regression tests. 16 | --testnet Use the test network (Testnet3). 17 | -V, --version Prints version information 18 | 19 | OPTIONS: 20 | --blocknotify Execute COMMAND when the best block changes (%s in COMMAND is replaced by the block hash). 21 | -c, --connect Connect only to the specified node. 22 | -d, --data-dir Specify the database and configuration directory PATH. 23 | --db-cache Sets the database cache size. 24 | --jsonrpc-apis Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited list of API names. 25 | --jsonrpc-cors Specify CORS header for JSON-RPC API responses. 26 | --jsonrpc-hosts List of allowed Host header values. 27 | --jsonrpc-interface The hostname portion of the JSONRPC API server. 28 | --jsonrpc-port Specify the PORT for the JSONRPC API server. 29 | --only-net Only connect to nodes in network version (ipv4 or ipv6). 30 | --port Listen for connections on PORT. 31 | -s, --seednode Connect to a seed-node to retrieve peer addresses, and disconnect. 32 | --verification-edge Non-default verification-level is applied until a block with given hash is met. 33 | --verification-level Sets the Blocks verification level to full (default), header (scripts are not verified), or none (no verification at all). 34 | 35 | SUBCOMMANDS: 36 | help Prints this message or the help of the given subcommand(s) 37 | import Import blocks from a zcashd database. 38 | rollback Rollback the database to given canonical-chain block. 39 | ``` 40 | -------------------------------------------------------------------------------- /db/src/kv/overlaydb.rs: -------------------------------------------------------------------------------- 1 | use parking_lot::Mutex; 2 | use kv::{Transaction, Value, KeyValueDatabase, MemoryDatabase, KeyState, Key}; 3 | 4 | pub struct OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase { 5 | db: &'a T, 6 | overlay: MemoryDatabase, 7 | } 8 | 9 | impl<'a, T> OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase { 10 | pub fn new(db: &'a T) -> Self { 11 | OverlayDatabase { 12 | db: db, 13 | overlay: MemoryDatabase::default(), 14 | } 15 | } 16 | 17 | pub fn flush(&self) -> Result<(), String> { 18 | self.db.write(self.overlay.drain_transaction()) 19 | } 20 | } 21 | 22 | impl<'a, T> KeyValueDatabase for OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase { 23 | fn write(&self, tx: Transaction) -> Result<(), String> { 24 | self.overlay.write(tx) 25 | } 26 | 27 | fn get(&self, key: &Key) -> Result, String> { 28 | match self.overlay.get(key)? { 29 | KeyState::Unknown => self.db.get(key), 30 | exists => Ok(exists) 31 | } 32 | } 33 | } 34 | 35 | pub struct AutoFlushingOverlayDatabase where T: KeyValueDatabase { 36 | db: T, 37 | overlay: MemoryDatabase, 38 | operations: Mutex, 39 | max_operations: usize, 40 | } 41 | 42 | impl AutoFlushingOverlayDatabase where T: KeyValueDatabase { 43 | pub fn new(db: T, max_operations: usize) -> Self { 44 | AutoFlushingOverlayDatabase { 45 | db: db, 46 | overlay: MemoryDatabase::default(), 47 | operations: Mutex::default(), 48 | max_operations: max_operations, 49 | } 50 | } 51 | 52 | fn flush(&self) -> Result<(), String> { 53 | self.db.write(self.overlay.drain_transaction()) 54 | } 55 | } 56 | 57 | impl KeyValueDatabase for AutoFlushingOverlayDatabase where T: KeyValueDatabase { 58 | fn write(&self, tx: Transaction) -> Result<(), String> { 59 | let mut operations = self.operations.lock(); 60 | *operations += 1; 61 | self.overlay.write(tx)?; 62 | if *operations == self.max_operations { 63 | self.flush()?; 64 | *operations = 0; 65 | } 66 | Ok(()) 67 | } 68 | 69 | fn get(&self, key: &Key) -> Result, String> { 70 | match self.overlay.get(key)? { 71 | KeyState::Unknown => self.db.get(key), 72 | exists => Ok(exists) 73 | } 74 | } 75 | } 76 | 77 | impl Drop for AutoFlushingOverlayDatabase where T: KeyValueDatabase { 78 | fn drop(&mut self) { 79 | self.flush().expect("Failed to save database"); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /chain/src/indexed_block.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | use hash::H256; 3 | use hex::FromHex; 4 | use ser::{Serializable, serialized_list_size, deserialize}; 5 | use block::Block; 6 | use transaction::Transaction; 7 | use merkle_root::merkle_root; 8 | use indexed_header::IndexedBlockHeader; 9 | use indexed_transaction::IndexedTransaction; 10 | 11 | #[derive(Debug, Clone, Deserializable)] 12 | pub struct IndexedBlock { 13 | pub header: IndexedBlockHeader, 14 | pub transactions: Vec, 15 | } 16 | 17 | #[cfg(feature = "test-helpers")] 18 | impl From for IndexedBlock { 19 | fn from(block: Block) -> Self { 20 | Self::from_raw(block) 21 | } 22 | } 23 | impl cmp::PartialEq for IndexedBlock { 24 | fn eq(&self, other: &Self) -> bool { 25 | self.header.hash == other.header.hash 26 | } 27 | } 28 | 29 | impl IndexedBlock { 30 | pub fn new(header: IndexedBlockHeader, transactions: Vec) -> Self { 31 | IndexedBlock { 32 | header: header, 33 | transactions: transactions, 34 | } 35 | } 36 | 37 | /// Explicit conversion of the raw Block into IndexedBlock. 38 | /// 39 | /// Hashes block header + transactions. 40 | pub fn from_raw(block: Block) -> Self { 41 | let Block { block_header, transactions } = block; 42 | Self::new( 43 | IndexedBlockHeader::from_raw(block_header), 44 | transactions.into_iter().map(IndexedTransaction::from_raw).collect(), 45 | ) 46 | } 47 | 48 | pub fn hash(&self) -> &H256 { 49 | &self.header.hash 50 | } 51 | 52 | pub fn to_raw_block(self) -> Block { 53 | Block::new(self.header.raw, self.transactions.into_iter().map(|tx| tx.raw).collect()) 54 | } 55 | 56 | pub fn size(&self) -> usize { 57 | let header_size = self.header.raw.serialized_size(); 58 | let transactions = self.transactions.iter().map(|tx| &tx.raw).collect::>(); 59 | let txs_size = serialized_list_size::(&transactions); 60 | header_size + txs_size 61 | } 62 | 63 | pub fn merkle_root(&self) -> H256 { 64 | merkle_root(&self.transactions.iter().map(|tx| &tx.hash).collect::>()) 65 | } 66 | 67 | pub fn is_final(&self, height: u32) -> bool { 68 | self.transactions.iter().all(|tx| tx.raw.is_final_in_block(height, self.header.raw.time)) 69 | } 70 | } 71 | 72 | impl From<&'static str> for IndexedBlock { 73 | fn from(s: &'static str) -> Self { 74 | deserialize(&s.from_hex::>().unwrap() as &[u8]).unwrap() 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /message/src/message/message_header.rs: -------------------------------------------------------------------------------- 1 | use hash::H32; 2 | use ser::{Serializable, Stream, Reader}; 3 | use crypto::checksum; 4 | use network::Magic; 5 | use common::Command; 6 | use Error; 7 | 8 | #[derive(Debug, PartialEq)] 9 | pub struct MessageHeader { 10 | pub magic: Magic, 11 | pub command: Command, 12 | pub len: u32, 13 | pub checksum: H32, 14 | } 15 | 16 | impl MessageHeader { 17 | pub fn for_data(magic: Magic, command: Command, data: &[u8]) -> Self { 18 | MessageHeader { 19 | magic: magic, 20 | command: command, 21 | len: data.len() as u32, 22 | checksum: checksum(data), 23 | } 24 | } 25 | } 26 | 27 | impl MessageHeader { 28 | pub fn deserialize(data: &[u8], expected: Magic) -> Result { 29 | if data.len() != 24 { 30 | return Err(Error::Deserialize); 31 | } 32 | 33 | let mut reader = Reader::new(data); 34 | let magic: u32 = try!(reader.read()); 35 | let magic = Magic::from(magic); 36 | if expected != magic { 37 | return Err(Error::InvalidMagic); 38 | } 39 | 40 | let header = MessageHeader { 41 | magic: magic, 42 | command: try!(reader.read()), 43 | len: try!(reader.read()), 44 | checksum: try!(reader.read()), 45 | }; 46 | 47 | Ok(header) 48 | } 49 | } 50 | 51 | impl Serializable for MessageHeader { 52 | fn serialize(&self, stream: &mut Stream) { 53 | stream 54 | .append(&self.magic) 55 | .append(&self.command) 56 | .append(&self.len) 57 | .append(&self.checksum); 58 | } 59 | } 60 | 61 | #[cfg(test)] 62 | mod tests { 63 | use bytes::Bytes; 64 | use ser::serialize; 65 | use network::Network; 66 | use super::MessageHeader; 67 | 68 | #[test] 69 | fn test_message_header_serialization() { 70 | let expected = "24e927646164647200000000000000001f000000ed52399b".into(); 71 | let header = MessageHeader { 72 | magic: Network::Mainnet.magic(), 73 | command: "addr".into(), 74 | len: 0x1f, 75 | checksum: "ed52399b".into(), 76 | }; 77 | 78 | assert_eq!(serialize(&header), expected); 79 | } 80 | 81 | #[test] 82 | fn test_message_header_deserialization() { 83 | let raw: Bytes = "24e927646164647200000000000000001f000000ed52399b".into(); 84 | let expected = MessageHeader { 85 | magic: Network::Mainnet.magic(), 86 | command: "addr".into(), 87 | len: 0x1f, 88 | checksum: "ed52399b".into(), 89 | }; 90 | 91 | assert_eq!(expected, MessageHeader::deserialize(&raw, Network::Mainnet.magic()).unwrap()); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /pzec/rpc.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use std::sync::Arc; 3 | use rpc_apis::{self, ApiSet}; 4 | use ethcore_rpc::{Server, start_http, MetaIoHandler, Compatibility}; 5 | use network::ConsensusParams; 6 | use std::io; 7 | use keys::Address; 8 | use sync; 9 | use storage; 10 | use p2p; 11 | 12 | pub struct Dependencies { 13 | pub consensus: ConsensusParams, 14 | pub local_sync_node: sync::LocalNodeRef, 15 | pub storage: storage::SharedStore, 16 | pub p2p_context: Arc, 17 | pub miner_address: Option