......@@ -8,9 +8,9 @@ use message::{Error, MessageHeader, MessageResult, Command};
use bytes::Bytes;
use io::{read_header, ReadHeader};
pub fn read_any_message<A>(a: A, magic: Magic) -> ReadAnyMessage<A> where A: AsyncRead {
pub fn read_any_message<A>(a: A, flags: u32, magic: Magic) -> ReadAnyMessage<A> where A: AsyncRead {
ReadAnyMessage {
state: ReadAnyMessageState::ReadHeader(read_header(a, magic)),
state: ReadAnyMessageState::ReadHeader(read_header(a, flags, magic)),
}
}
......@@ -74,20 +74,20 @@ mod tests {
let nonce = "5845303b6da97786".into();
let expected = (name, nonce);
assert_eq!(read_any_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Ok(expected));
assert_eq!(read_any_message(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidMagic));
assert_eq!(read_any_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Ok(expected));
assert_eq!(read_any_message(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidMagic));
}
#[test]
fn test_read_too_short_any_message() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da977".into();
assert!(read_any_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err());
assert!(read_any_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err());
}
#[test]
fn test_read_any_message_with_invalid_checksum() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c01c765845303b6da97786".into();
assert_eq!(read_any_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidChecksum));
assert_eq!(read_any_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidChecksum));
}
}
......@@ -5,15 +5,17 @@ use tokio_io::io::{ReadExact, read_exact};
use message::{MessageHeader, MessageResult};
use network::Magic;
pub fn read_header<A>(a: A, magic: Magic) -> ReadHeader<A> where A: AsyncRead {
pub fn read_header<A>(a: A, flags: u32, magic: Magic) -> ReadHeader<A> where A: AsyncRead {
ReadHeader {
reader: read_exact(a, [0u8; 24]),
magic: magic,
flags: flags,
}
}
pub struct ReadHeader<A> {
reader: ReadExact<A, [u8; 24]>,
flags: u32,
magic: Magic,
}
......@@ -23,7 +25,7 @@ impl<A> Future for ReadHeader<A> where A: AsyncRead {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let (read, data) = try_ready!(self.reader.poll());
let header = MessageHeader::deserialize(&data, self.magic);
let header = MessageHeader::deserialize(&data, self.flags, self.magic);
Ok(Async::Ready((read, header)))
}
}
......@@ -46,19 +48,19 @@ mod tests {
checksum: "ed52399b".into(),
};
assert_eq!(read_header(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Ok(expected));
assert_eq!(read_header(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
assert_eq!(read_header(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Ok(expected));
assert_eq!(read_header(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
}
#[test]
fn test_read_header_with_invalid_magic() {
let raw: Bytes = "f9beb4d86164647200000000000000001f000000ed52399b".into();
assert_eq!(read_header(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
assert_eq!(read_header(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
}
#[test]
fn test_read_too_short_header() {
let raw: Bytes = "f9beb4d96164647200000000000000001f000000ed5239".into();
assert!(read_header(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err());
assert!(read_header(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err());
}
}
......@@ -6,14 +6,15 @@ use network::Magic;
use message::{MessageResult, Error, Payload};
use io::{read_header, ReadHeader, read_payload, ReadPayload};
pub fn read_message<M, A>(a: A, magic: Magic, version: u32) -> ReadMessage<M, A>
pub fn read_message<M, A>(a: A, flags: u32, magic: Magic, version: u32) -> ReadMessage<M, A>
where A: AsyncRead, M: Payload {
ReadMessage {
state: ReadMessageState::ReadHeader {
version: version,
future: read_header(a, magic),
future: read_header(a, flags, magic),
},
message_type: PhantomData
flags: flags,
message_type: PhantomData,
}
}
......@@ -29,6 +30,7 @@ enum ReadMessageState<M, A> {
pub struct ReadMessage<M, A> {
state: ReadMessageState<M, A>,
flags: u32,
message_type: PhantomData<M>,
}
......@@ -45,11 +47,12 @@ impl<M, A> Future for ReadMessage<M, A> where A: AsyncRead, M: Payload {
Ok(header) => header,
Err(err) => return Ok((read, Err(err)).into()),
};
if header.command != M::command() {
return Ok((read, Err(Error::InvalidCommand)).into());
}
let future = read_payload(
read, version, header.len as usize, header.checksum,
read, version, self.flags, header.len as usize, header.checksum,
);
ReadMessageState::ReadPayload {
future: future,
......@@ -78,21 +81,21 @@ mod tests {
fn test_read_message() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da97786".into();
let ping = Ping::new(u64::from_str_radix("8677a96d3b304558", 16).unwrap());
assert_eq!(read_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Ok(ping));
assert_eq!(read_message::<Ping, _>(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidMagic));
assert_eq!(read_message::<Pong, _>(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidCommand));
assert_eq!(read_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Ok(ping));
assert_eq!(read_message::<Ping, _>(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidMagic));
assert_eq!(read_message::<Pong, _>(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidCommand));
}
#[test]
fn test_read_too_short_message() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da977".into();
assert!(read_message::<Ping, _>(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().is_err());
assert!(read_message::<Ping, _>(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().is_err());
}
#[test]
fn test_read_message_with_invalid_checksum() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c01c765845303b6da97786".into();
assert_eq!(read_message::<Ping, _>(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidChecksum));
assert_eq!(read_message::<Ping, _>(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidChecksum));
}
}
......@@ -8,11 +8,12 @@ use hash::H32;
use crypto::checksum;
use message::{Error, MessageResult, Payload, deserialize_payload};
pub fn read_payload<M, A>(a: A, version: u32, len: usize, checksum: H32) -> ReadPayload<M, A>
pub fn read_payload<M, A>(a: A, version: u32, flags: u32, len: usize, checksum: H32) -> ReadPayload<M, A>
where A: AsyncRead, M: Payload {
ReadPayload {
reader: read_exact(a, Bytes::new_with_len(len)),
version: version,
flags: flags,
checksum: checksum,
payload_type: PhantomData,
}
......@@ -21,6 +22,7 @@ pub fn read_payload<M, A>(a: A, version: u32, len: usize, checksum: H32) -> Read
pub struct ReadPayload<M, A> {
reader: ReadExact<A, Bytes>,
version: u32,
flags: u32,
checksum: H32,
payload_type: PhantomData<M>,
}
......@@ -34,7 +36,7 @@ impl<M, A> Future for ReadPayload<M, A> where A: AsyncRead, M: Payload {
if checksum(&data) != self.checksum {
return Ok((read, Err(Error::InvalidChecksum)).into());
}
let payload = deserialize_payload(&data, self.version);
let payload = deserialize_payload(&data, self.version, self.flags);
Ok((read, payload).into())
}
}
......@@ -51,18 +53,18 @@ mod tests {
fn test_read_payload() {
let raw: Bytes = "5845303b6da97786".into();
let ping = Ping::new(u64::from_str_radix("8677a96d3b304558", 16).unwrap());
assert_eq!(read_payload(raw.as_ref(), 0, 8, "83c00c76".into()).wait().unwrap().1, Ok(ping));
assert_eq!(read_payload(raw.as_ref(), 0, 0, 8, "83c00c76".into()).wait().unwrap().1, Ok(ping));
}
#[test]
fn test_read_payload_with_invalid_checksum() {
let raw: Bytes = "5845303b6da97786".into();
assert_eq!(read_payload::<Ping, _>(raw.as_ref(), 0, 8, "83c00c75".into()).wait().unwrap().1, Err(Error::InvalidChecksum));
assert_eq!(read_payload::<Ping, _>(raw.as_ref(), 0, 0, 8, "83c00c75".into()).wait().unwrap().1, Err(Error::InvalidChecksum));
}
#[test]
fn test_read_too_short_payload() {
let raw: Bytes = "5845303b6da977".into();
assert!(read_payload::<Ping, _>(raw.as_ref(), 0, 8, "83c00c76".into()).wait().is_err());
assert!(read_payload::<Ping, _>(raw.as_ref(), 0, 0, 8, "83c00c76".into()).wait().is_err());
}
}
......@@ -10,7 +10,7 @@ use net::{Config, Connection};
pub fn accept_connection(stream: TcpStream, handle: &Handle, config: &Config, address: net::SocketAddr) -> Deadline<AcceptConnection> {
let accept = AcceptConnection {
handshake: accept_handshake(stream, config.magic, config.version(&address), config.protocol_minimum),
handshake: accept_handshake(stream, config.serialization_flags, config.magic, config.version(&address), config.protocol_minimum),
magic: config.magic,
address: address,
};
......
......@@ -23,7 +23,7 @@ impl Channel {
}
pub fn read_message(&self) -> ReadAnyMessage<SharedTcpStream> {
read_any_message(self.stream.clone(), self.peer_info.magic)
read_any_message(self.stream.clone(), self.peer_info.flags, self.peer_info.magic)
}
pub fn shutdown(&self) {
......
......@@ -15,6 +15,7 @@ pub struct Config {
pub user_agent: String,
pub start_height: i32,
pub relay: bool,
pub serialization_flags: u32,
}
impl Config {
......
......@@ -19,6 +19,7 @@ pub fn connect(address: &SocketAddr, handle: &Handle, config: &Config) -> Deadli
magic: config.magic,
address: *address,
protocol_minimum: config.protocol_minimum,
flags: config.serialization_flags,
};
deadline(Duration::new(5, 0), handle, connect).expect("Failed to create timeout")
......@@ -38,6 +39,7 @@ pub struct Connect {
magic: Magic,
address: SocketAddr,
protocol_minimum: u32,
flags: u32,
}
impl Future for Connect {
......@@ -49,7 +51,7 @@ impl Future for Connect {
ConnectState::TcpConnect { ref mut future, ref mut version } => {
let stream = try_ready!(future.poll());
let version = version.take().expect("state TcpConnect must have version");
let handshake = handshake(stream, self.magic, version, self.protocol_minimum);
let handshake = handshake(stream, self.flags, self.magic, version, self.protocol_minimum);
(ConnectState::Handshake(handshake), Async::NotReady)
},
ConnectState::Handshake(ref mut future) => {
......
......@@ -58,6 +58,7 @@ impl Connections {
version: connection.version,
version_message: connection.version_message,
magic: connection.magic,
flags: context.serialization_flags(),
};
let session = T::new_session(context, peer_info.clone(), SYNCHRONOUS_RESPONSES);
......
......@@ -167,9 +167,9 @@ impl Context {
channel.session().initialize();
Context::on_message(context, channel)
},
Ok(DeadlineStatus::Meet(Err(_))) => {
Ok(DeadlineStatus::Meet(Err(err))) => {
// protocol error
trace!("Handshake with {} failed", socket);
trace!("Handshake with {} failed with: {}", socket, err);
// TODO: close socket
context.node_table.write().note_failure(&socket);
context.connection_counter.note_close_outbound_connection();
......@@ -402,6 +402,10 @@ impl Context {
pub fn nodes(&self) -> Vec<Node> {
self.node_table.read().nodes()
}
pub fn serialization_flags(&self) -> u32 {
self.config.serialization_flags
}
}
pub struct P2P {
......
......@@ -34,12 +34,12 @@ impl Protocol for AddrProtocol {
// normal nodes send addr message only after they receive getaddr message
// meanwhile seednodes, surprisingly, send addr message even before they are asked for it
if command == &GetAddr::command() {
let _: GetAddr = try!(deserialize_payload(payload, self.context.info().version));
let _: GetAddr = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
let entries = self.context.global().node_table_entries().into_iter().map(Into::into).collect();
let addr = Addr::new(entries);
self.context.send_response_inline(&addr);
} else if command == &Addr::command() {
let addr: Addr = try!(deserialize_payload(payload, self.context.info().version));
let addr: Addr = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
match addr {
Addr::V0(_) => {
unreachable!("This version of protocol is not supported!");
......
......@@ -78,11 +78,11 @@ impl Protocol for PingProtocol {
self.state = State::WaitingTimeout(time::precise_time_s());
if command == &Ping::command() {
let ping: Ping = try!(deserialize_payload(payload, self.context.info().version));
let ping: Ping = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
let pong = Pong::new(ping.nonce);
self.context.send_response_inline(&pong);
} else if command == &Pong::command() {
let pong: Pong = try!(deserialize_payload(payload, self.context.info().version));
let pong: Pong = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
if Some(pong.nonce) != self.last_ping_nonce.take() {
return Err(Error::InvalidCommand)
}
......
......@@ -202,82 +202,83 @@ impl Protocol for SyncProtocol {
fn on_message(&mut self, command: &Command, payload: &Bytes) -> Result<(), Error> {
let version = self.context.info().version;
let flags = self.context.info().flags;
if command == &types::Inv::command() {
let message: types::Inv = try!(deserialize_payload(payload, version));
let message: types::Inv = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_inventory(message);
}
else if command == &types::GetData::command() {
let message: types::GetData = try!(deserialize_payload(payload, version));
let message: types::GetData = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_getdata(message);
}
else if command == &types::GetBlocks::command() {
let message: types::GetBlocks = try!(deserialize_payload(payload, version));
let message: types::GetBlocks = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_getblocks(message);
}
else if command == &types::GetHeaders::command() {
let message: types::GetHeaders = try!(deserialize_payload(payload, version));
let message: types::GetHeaders = try!(deserialize_payload(payload, version, flags));
let id = self.context.declare_response();
trace!("declared response {} for request: {}", id, types::GetHeaders::command());
self.inbound_connection.on_getheaders(message, id);
}
else if command == &types::Tx::command() {
let message: types::Tx = try!(deserialize_payload(payload, version));
let message: types::Tx = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_transaction(message);
}
else if command == &types::Block::command() {
let message: types::Block = try!(deserialize_payload(payload, version));
let message: types::Block = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_block(message);
}
else if command == &types::MemPool::command() {
let message: types::MemPool = try!(deserialize_payload(payload, version));
let message: types::MemPool = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_mempool(message);
}
else if command == &types::Headers::command() {
let message: types::Headers = try!(deserialize_payload(payload, version));
let message: types::Headers = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_headers(message);
}
else if command == &types::FilterLoad::command() {
let message: types::FilterLoad = try!(deserialize_payload(payload, version));
let message: types::FilterLoad = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_filterload(message);
}
else if command == &types::FilterAdd::command() {
let message: types::FilterAdd = try!(deserialize_payload(payload, version));
let message: types::FilterAdd = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_filteradd(message);
}
else if command == &types::FilterClear::command() {
let message: types::FilterClear = try!(deserialize_payload(payload, version));
let message: types::FilterClear = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_filterclear(message);
}
else if command == &types::MerkleBlock::command() {
let message: types::MerkleBlock = try!(deserialize_payload(payload, version));
let message: types::MerkleBlock = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_merkleblock(message);
}
else if command == &types::SendHeaders::command() {
let message: types::SendHeaders = try!(deserialize_payload(payload, version));
let message: types::SendHeaders = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_sendheaders(message);
}
else if command == &types::FeeFilter::command() {
let message: types::FeeFilter = try!(deserialize_payload(payload, version));
let message: types::FeeFilter = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_feefilter(message);
}
else if command == &types::SendCompact::command() {
let message: types::SendCompact = try!(deserialize_payload(payload, version));
let message: types::SendCompact = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_send_compact(message);
}
else if command == &types::CompactBlock::command() {
let message: types::CompactBlock = try!(deserialize_payload(payload, version));
let message: types::CompactBlock = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_compact_block(message);
}
else if command == &types::GetBlockTxn::command() {
let message: types::GetBlockTxn = try!(deserialize_payload(payload, version));
let message: types::GetBlockTxn = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_get_block_txn(message);
}
else if command == &types::BlockTxn::command() {
let message: types::BlockTxn = try!(deserialize_payload(payload, version));
let message: types::BlockTxn = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_block_txn(message);
}
else if command == &types::NotFound::command() {
let message: types::NotFound = try!(deserialize_payload(payload, version));
let message: types::NotFound = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_notfound(message);
}
Ok(())
......
......@@ -19,5 +19,6 @@ pub struct PeerInfo {
pub version: u32,
pub version_message: types::Version,
pub magic: Magic,
pub flags: u32,
}
......@@ -15,6 +15,9 @@ args:
- bch:
long: bch
help: Use Bitcoin Cash verification rules (BCH).
- zcash:
long: zcash
help: Use ZCash verification rules (ZCH).
- connect:
short: c
long: connect
......
......@@ -18,7 +18,7 @@ pub fn rollback(cfg: Config, matches: &ArgMatches) -> Result<(), String> {
};
let required_block_hash = cfg.db.block_header(block_ref.clone()).ok_or(format!("Block {:?} is unknown", block_ref))?.hash();
let genesis_hash = cfg.network.genesis_block().hash();
let genesis_hash = cfg.network.genesis_block(&cfg.consensus.fork).hash();
let mut best_block_hash = cfg.db.best_block().hash;
debug_assert!(best_block_hash != H256::default()); // genesis inserted in init_db
......
......@@ -4,9 +4,10 @@ use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::atomic::{AtomicBool, Ordering};
use sync::{create_sync_peers, create_local_sync_node, create_sync_connection_factory, SyncListener};
use network::ConsensusFork;
use primitives::hash::H256;
use util::{init_db, node_table_path};
use {config, p2p, PROTOCOL_VERSION, PROTOCOL_MINIMUM};
use {config, p2p, PROTOCOL_VERSION, PROTOCOL_MINIMUM, ZCASH_PROTOCOL_VERSION, ZCASH_PROTOCOL_MINIMUM};
use super::super::rpc;
enum BlockNotifierTask {
......@@ -88,25 +89,39 @@ pub fn start(cfg: config::Config) -> Result<(), String> {
let nodes_path = node_table_path(&cfg);
let SERIALIZE_ZCASH = 0x80000000; // TODO
let serialization_flags = match cfg.consensus.fork {
ConsensusFork::ZCash(_) => SERIALIZE_ZCASH,
_ => 0,
};
let p2p_cfg = p2p::Config {
threads: cfg.p2p_threads,
inbound_connections: cfg.inbound_connections,
outbound_connections: cfg.outbound_connections,
connection: p2p::NetConfig {
protocol_version: PROTOCOL_VERSION,
protocol_minimum: PROTOCOL_MINIMUM,
protocol_version: match &cfg.consensus.fork {
&ConsensusFork::ZCash(_) => ZCASH_PROTOCOL_VERSION,
_ => PROTOCOL_VERSION,
},
protocol_minimum: match &cfg.consensus.fork {
&ConsensusFork::ZCash(_) => ZCASH_PROTOCOL_MINIMUM,
_ => PROTOCOL_MINIMUM,
},
magic: cfg.consensus.magic(),
local_address: SocketAddr::new(cfg.host, cfg.port),
services: cfg.services,
user_agent: cfg.user_agent,
start_height: 0,
relay: true,
serialization_flags: serialization_flags,
},
peers: cfg.connect.map_or_else(|| vec![], |x| vec![x]),
seeds: cfg.seednodes,
node_table_path: nodes_path,
preferable_services: cfg.services,
internet_protocol: cfg.internet_protocol,
serialization_flags: serialization_flags,
};
let sync_peers = create_sync_peers();
......
......@@ -2,12 +2,14 @@ use std::net;
use clap;
use storage;
use message::Services;
use network::{Network, ConsensusParams, ConsensusFork, BitcoinCashConsensusParams};
use network::{Network, ConsensusParams, ConsensusFork, BitcoinCashConsensusParams, ZCashConsensusParams};
use p2p::InternetProtocol;
use seednodes::{mainnet_seednodes, testnet_seednodes, bitcoin_cash_seednodes, bitcoin_cash_testnet_seednodes};
use seednodes::{mainnet_seednodes, testnet_seednodes, bitcoin_cash_seednodes,
bitcoin_cash_testnet_seednodes, zcash_seednodes};
use rpc_apis::ApiSet;
use {USER_AGENT, REGTEST_USER_AGENT};
use primitives::hash::H256;
use ser;
use rpc::HttpConfiguration as RpcHttpConfig;
use verification::VerificationLevel;
use sync::VerificationParameters;
......@@ -61,6 +63,11 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let consensus_fork = parse_consensus_fork(network, &db, &matches)?;
let consensus = ConsensusParams::new(network, consensus_fork);
match consensus.fork {
ConsensusFork::ZCash(_) => ser::set_default_flags(ser::SERIALIZE_ZCASH),
_ => (),
};
let (in_connections, out_connections) = match network {
Network::Testnet | Network::Mainnet | Network::Other(_) => (10, 10),
Network::Regtest | Network::Unitest => (1, 0),
......@@ -75,6 +82,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let user_agent_suffix = match consensus.fork {
ConsensusFork::BitcoinCore => "",
ConsensusFork::BitcoinCash(_) => "/UAHF",
ConsensusFork::ZCash(_) => "",
};
let user_agent = match network {
Network::Testnet | Network::Mainnet | Network::Unitest | Network::Other(_) => format!("{}{}", USER_AGENT, user_agent_suffix),
......@@ -83,13 +91,13 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let port = match matches.value_of("port") {
Some(port) => port.parse().map_err(|_| "Invalid port".to_owned())?,
None => network.port(),
None => network.port(&consensus.fork),
};
let connect = match matches.value_of("connect") {
Some(s) => Some(match s.parse::<net::SocketAddr>() {
Err(_) => s.parse::<net::IpAddr>()
.map(|ip| net::SocketAddr::new(ip, network.port()))
.map(|ip| net::SocketAddr::new(ip, network.port(&consensus.fork)))
.map_err(|_| "Invalid connect".to_owned()),
Ok(a) => Ok(a),
}?),
......@@ -99,6 +107,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let seednodes: Vec<String> = match matches.value_of("seednode") {
Some(s) => vec![s.parse().map_err(|_| "Invalid seednode".to_owned())?],
None => match (network, &consensus.fork) {
(Network::Mainnet, &ConsensusFork::ZCash(_)) => zcash_seednodes().into_iter().map(Into::into).collect(),
(Network::Mainnet, &ConsensusFork::BitcoinCash(_)) => bitcoin_cash_seednodes().into_iter().map(Into::into).collect(),
(Network::Testnet, &ConsensusFork::BitcoinCash(_)) => bitcoin_cash_testnet_seednodes().into_iter().map(Into::into).collect(),
(Network::Mainnet, _) => mainnet_seednodes().into_iter().map(Into::into).collect(),
......@@ -131,6 +140,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let services = match &consensus.fork {
&ConsensusFork::BitcoinCash(_) => services.with_bitcoin_cash(true),
&ConsensusFork::BitcoinCore => services.with_witness(true),
&ConsensusFork::ZCash(_) => services,
};
let verification_level = match matches.value_of("verification-level") {
......@@ -146,7 +156,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let edge: H256 = s.parse().map_err(|_| "Invalid verification edge".to_owned())?;
edge.reversed()
},
_ => network.default_verification_edge(),
_ => network.default_verification_edge(&consensus.fork),
};
let config = Config {
......@@ -179,14 +189,15 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
fn parse_consensus_fork(network: Network, db: &storage::SharedStore, matches: &clap::ArgMatches) -> Result<ConsensusFork, String> {
let old_consensus_fork = db.consensus_fork()?;
let new_consensus_fork = match (matches.is_present("btc"), matches.is_present("bch")) {
(false, false) => match &old_consensus_fork {
let new_consensus_fork = match (matches.is_present("btc"), matches.is_present("bch"), matches.is_present("zcash")) {
(false, false, false) => match &old_consensus_fork {
&Some(ref old_consensus_fork) => old_consensus_fork,
&None => return Err("You must select fork on first run: --btc, --bch".into()),
&None => return Err("You must select fork on first run: --btc, --bch or --zcash".into()),
},
(true, false) => "btc",
(false, true) => "bch",
_ => return Err("You can only pass single fork argument: --btc, --bch".into()),
(true, false, false) => "btc",
(false, true, false) => "bch",
(false, false, true) => "zcash",
_ => return Err("You can only pass single fork argument: --btc, --bch or --zcash".into()),
};
match &old_consensus_fork {
......@@ -196,11 +207,12 @@ fn parse_consensus_fork(network: Network, db: &storage::SharedStore, matches: &c
return Err(format!("Cannot select '{}' fork with non-empty database of '{}' fork", new_consensus_fork, old_consensus_fork)),
}
return match new_consensus_fork {
match new_consensus_fork {
"btc" => Ok(ConsensusFork::BitcoinCore),
"bch" => Ok(ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(network))),
"zcash" => Ok(ConsensusFork::ZCash(ZCashConsensusParams::new(network))),
_ => Err(String::from("Fork mandatory")),
};
}
}
fn parse_rpc_config(network: Network, matches: &clap::ArgMatches) -> Result<RpcHttpConfig, String> {
......
......@@ -22,6 +22,7 @@ extern crate import;
extern crate rpc as ethcore_rpc;
extern crate primitives;
extern crate verification;
extern crate serialization as ser;
mod commands;
mod config;
......@@ -35,7 +36,9 @@ use app_dirs::AppInfo;
pub const APP_INFO: AppInfo = AppInfo { name: "pbtc", author: "Parity" };
pub const PROTOCOL_VERSION: u32 = 70_014;
pub const PROTOCOL_MINIMUM: u32 = 70_001;
pub const USER_AGENT: &'static str = "pbtc";
pub const ZCASH_PROTOCOL_VERSION: u32 = 170_007;
pub const ZCASH_PROTOCOL_MINIMUM: u32 = 170_007;
pub const USER_AGENT: &'static str = "bcore";
pub const REGTEST_USER_AGENT: &'static str = "/Satoshi:0.12.1/";
pub const LOG_INFO: &'static str = "sync=info";
......
......@@ -47,3 +47,11 @@ pub fn bitcoin_cash_testnet_seednodes() -> Vec<&'static str> {
"testnet-seeder.criptolayer.net:18333"
]
}
pub fn zcash_seednodes() -> Vec<&'static str> {
vec![
"dnsseed.z.cash:8233",
"dnsseed.str4d.xyz:8233",
"dnsseed.znodes.org:8233",
]
}