......@@ -26,7 +26,7 @@ pub fn node_table_path(cfg: &Config) -> PathBuf {
pub fn init_db(cfg: &Config) -> Result<(), String> {
// insert genesis block if db is empty
let genesis_block: IndexedBlock = cfg.network.genesis_block().into();
let genesis_block: IndexedBlock = cfg.network.genesis_block(&cfg.consensus.fork).into();
match cfg.db.block_hash(0) {
Some(ref db_genesis_block_hash) if db_genesis_block_hash != genesis_block.hash() => Err("Trying to open database with incompatible genesis block".into()),
Some(_) => Ok(()),
......
......@@ -11,7 +11,7 @@ use jsonrpc_macros::Trailing;
use jsonrpc_core::Error;
use {storage, chain};
use global_script::Script;
use chain::OutPoint;
use chain::{OutPoint, BlockHeaderNonce};
use verification;
use ser::serialize;
use network::Network;
......@@ -99,7 +99,10 @@ impl BlockChainClientCoreApi for BlockChainClientCore {
bits: block.header.raw.bits.into(),
hash: block.hash().clone().into(),
merkleroot: block.header.raw.merkle_root_hash.clone().into(),
nonce: block.header.raw.nonce,
nonce: match block.header.raw.nonce {
BlockHeaderNonce::U32(v) => v,
BlockHeaderNonce::H256(_) => unimplemented!("TODO"),
},
time: block.header.raw.time,
tx: block.transactions.into_iter().map(|t| t.hash.into()).collect(),
version: block.header.raw.version,
......
......@@ -84,6 +84,7 @@ impl RawClientCore {
inputs: inputs,
outputs: outputs,
lock_time: lock_time,
joint_split: None,
};
Ok(transaction)
......@@ -111,7 +112,7 @@ impl<T> RawClient<T> where T: RawClientCoreApi {
impl<T> Raw for RawClient<T> where T: RawClientCoreApi {
fn send_raw_transaction(&self, raw_transaction: RawTransaction) -> Result<H256, Error> {
let raw_transaction_data: Vec<u8> = raw_transaction.into();
let transaction = try!(deserialize(Reader::new(&raw_transaction_data)).map_err(|e| invalid_params("tx", e)));
let transaction = try!(deserialize(Reader::new(&raw_transaction_data, 0)).map_err(|e| invalid_params("tx", e)));
self.core.accept_transaction(transaction)
.map(|h| h.reversed().into())
.map_err(|e| execution(e))
......
......@@ -55,6 +55,20 @@ impl Builder {
self
}
/// Push integer to the end of script
pub fn push_i64(mut self, int: i64) -> Self {
if int == -1 || (int >= 1 && int <= 16) {
let shift: i64 = (Opcode::OP_1 as u8 - 1) as i64;
self.data.push((int + shift) as u8);
self
} else if int == 0 {
self.data.push(Opcode::OP_0 as u8);
self
} else {
self.push_num(int.into())
}
}
/// Appends num push operation to the end of script
pub fn push_num(self, num: Num) -> Self {
self.push_data(&num.to_bytes())
......
......@@ -2384,6 +2384,7 @@ mod tests {
script_pubkey: script_pubkey.to_bytes(),
}],
lock_time: 0,
joint_split: None,
};
let tx2 = Transaction {
version: 1,
......@@ -2401,6 +2402,7 @@ mod tests {
script_pubkey: Builder::default().into_bytes(),
}],
lock_time: 0,
joint_split: None,
};
let checker = TransactionSignatureChecker {
......
......@@ -225,6 +225,7 @@ impl TransactionInputSigner {
outputs: outputs,
version: self.version,
lock_time: self.lock_time,
joint_split: None, // TODO
};
let mut stream = Stream::default();
......
......@@ -6,3 +6,4 @@ authors = ["debris <[email protected]>"]
[dependencies]
byteorder = "1.0"
primitives = { path = "../primitives" }
rustc-hex = "2"
......@@ -148,7 +148,7 @@ mod tests {
0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
];
let mut reader = Reader::new(&buffer);
let mut reader = Reader::new(&buffer, 0);
assert_eq!(reader.read::<CompactInteger>().unwrap(), 0u64.into());
assert_eq!(reader.read::<CompactInteger>().unwrap(), 0xfcu64.into());
assert_eq!(reader.read::<CompactInteger>().unwrap(), 0xfdu64.into());
......
use std::{fmt, io};
use hex::ToHex;
use primitives::hash::H256;
use {
Serializable, Stream,
Deserializable, Reader, Error as ReaderError
};
macro_rules! impl_fixed_array {
($name: ident, $type: ty, $len: expr) => {
/// A type for fixed-length array.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct $name(pub [$type; $len]);
impl Serializable for $name {
fn serialize(&self, stream: &mut Stream) {
for i in 0..$len {
stream.append(&self.0[i]);
}
}
fn serialized_size(&self) -> usize {
$len * ::std::mem::size_of::<$type>()
}
}
impl Deserializable for $name {
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
//let mut array = [Default::default(); $len];
let mut array: [$type; $len] = Default::default();
for i in 0..$len {
array[i] = reader.read()?;
}
Ok($name(array))
}
}
}
}
macro_rules! impl_fixed_array_u8 {
($name: ident, $len: expr) => {
/// A type for fixed-length array.
#[derive(Clone)]
pub struct $name(pub [u8; $len]);
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
self.0.iter().zip(other.0.iter()).all(|(l, r)| l == r)
}
}
impl Default for $name {
fn default() -> Self {
$name([0; $len])
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.to_hex::<String>().fmt(f)
}
}
impl Serializable for $name {
fn serialize(&self, stream: &mut Stream) {
stream.append_slice(&self.0);
}
fn serialized_size(&self) -> usize {
$len
}
}
impl Deserializable for $name {
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
let mut array = [0; $len];
reader.read_slice(&mut array)?;
Ok($name(array))
}
}
}
}
impl_fixed_array!(FixedArray_H256_2, H256, 2);
impl_fixed_array_u8!(FixedArray_u8_296, 296);
impl_fixed_array_u8!(FixedArray_u8_601, 601);
impl_fixed_array!(FixedArray_u8_601_2, FixedArray_u8_601, 2);
static mut default_flags: u32 = 0;
pub fn set_default_flags(flags: u32) {
unsafe {
default_flags = flags
}
}
pub fn get_default_flags() -> u32 {
unsafe {
default_flags
}
}
......@@ -261,7 +261,7 @@ mod tests {
4, 0, 0, 0, 0, 0, 0, 0
];
let mut reader = Reader::new(&buffer);
let mut reader = Reader::new(&buffer, 0);
assert!(!reader.is_finished());
assert_eq!(1u8, reader.read().unwrap());
assert_eq!(2u16, reader.read().unwrap());
......
extern crate byteorder;
extern crate primitives;
extern crate rustc_hex as hex;
mod compact_integer;
mod fixed_array;
mod flags;
mod impls;
mod list;
mod reader;
......@@ -9,11 +12,20 @@ mod stream;
pub use primitives::{hash, bytes, compact};
// TODO: use same flags for both serialization && deserialization (they're used this way on network layer)
pub use fixed_array::*;
pub use flags::{set_default_flags, get_default_flags};
pub use compact_integer::CompactInteger;
pub use list::List;
pub use reader::{Reader, Deserializable, deserialize, deserialize_iterator, ReadIterator, Error};
pub use reader::{Reader, Deserializable, deserialize, deserialize_with_flags, deserialize_iterator,
ReadIterator, Error, DESERIALIZE_ZCASH,
};
pub use stream::{
Stream, Serializable, serialize, serialize_with_flags, serialize_list, serialized_list_size,
serialized_list_size_with_flags, SERIALIZE_TRANSACTION_WITNESS,
serialized_list_size_with_flags, SERIALIZE_TRANSACTION_WITNESS, SERIALIZE_ZCASH,
};
static mut GLOBAL_SERIALIZATION_FLAGS: u32 = SERIALIZE_ZCASH;
use std::{io, marker};
use compact_integer::CompactInteger;
use flags::get_default_flags;
/// Deserialize transaction witness data.
pub const DESERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000;
/// Deserialize everything in ZCash format.
pub const DESERIALIZE_ZCASH: u32 = 0x80000000;
pub fn deserialize<R, T>(buffer: R) -> Result<T, Error> where R: io::Read, T: Deserializable {
let mut reader = Reader::from_read(buffer);
......@@ -12,6 +18,18 @@ pub fn deserialize<R, T>(buffer: R) -> Result<T, Error> where R: io::Read, T: De
}
}
pub fn deserialize_with_flags<R, T>(buffer: R, flags: u32) -> Result<T, Error> where R: io::Read, T: Deserializable {
let mut reader = Reader::from_read_with_flags(buffer, flags);
let result = try!(reader.read());
if reader.is_finished() {
Ok(result)
} else {
Err(Error::UnreadData)
}
}
pub fn deserialize_iterator<R, T>(buffer: R) -> ReadIterator<R, T> where R: io::Read, T: Deserializable {
ReadIterator {
reader: Reader::from_read(buffer),
......@@ -41,14 +59,16 @@ pub trait Deserializable {
pub struct Reader<T> {
buffer: T,
peeked: Option<u8>,
flags: u32,
}
impl<'a> Reader<&'a [u8]> {
/// Convenient way of creating for slice of bytes
pub fn new(buffer: &'a [u8]) -> Self {
pub fn new(buffer: &'a [u8], flags: u32) -> Self {
Reader {
buffer: buffer,
peeked: None,
flags: flags | get_default_flags(),
}
}
}
......@@ -74,12 +94,27 @@ impl<T> io::Read for Reader<T> where T: io::Read {
impl<R> Reader<R> where R: io::Read {
pub fn from_read(read: R) -> Self {
Self::from_read_with_flags(read, get_default_flags())
}
pub fn from_read_with_flags(read: R, flags: u32) -> Self {
Reader {
buffer: read,
peeked: None,
flags: flags,
}
}
/// Are transactions read from this stream with witness data?
pub fn read_transaction_witness(&self) -> bool {
(self.flags & DESERIALIZE_TRANSACTION_WITNESS) != 0
}
/// Is data read from this stream in ZCash format?
pub fn is_zcash_reader(&self) -> bool {
(self.flags & DESERIALIZE_ZCASH) != 0
}
pub fn read<T>(&mut self) -> Result<T, Error> where T: Deserializable {
T::deserialize(self)
}
......
......@@ -3,12 +3,15 @@ use std::io::{self, Write};
use std::borrow::Borrow;
use compact_integer::CompactInteger;
use bytes::Bytes;
use flags::get_default_flags;
/// Do not serialize transaction witness data.
/// Serialize transaction witness data.
pub const SERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000;
/// Serialize everything in ZCash format.
pub const SERIALIZE_ZCASH: u32 = 0x80000000;
pub fn serialize<T>(t: &T) -> Bytes where T: Serializable{
let mut stream = Stream::default();
let mut stream = Stream::new();
stream.append(t);
stream.out()
}
......@@ -20,7 +23,7 @@ pub fn serialize_with_flags<T>(t: &T, flags: u32) -> Bytes where T: Serializable
}
pub fn serialize_list<T, K>(t: &[K]) -> Bytes where T: Serializable, K: Borrow<T> {
let mut stream = Stream::default();
let mut stream = Stream::new();
stream.append_list(t);
stream.out()
}
......@@ -53,21 +56,26 @@ pub trait Serializable {
}
/// Stream used for serialization of Bitcoin structures
#[derive(Default)]
pub struct Stream {
buffer: Vec<u8>,
flags: u32,
}
impl Default for Stream {
fn default() -> Self {
Self::new()
}
}
impl Stream {
/// New stream
pub fn new() -> Self {
Stream { buffer: Vec::new(), flags: 0 }
Stream { buffer: Vec::new(), flags: get_default_flags() }
}
/// Create stream with given flags,
pub fn with_flags(flags: u32) -> Self {
Stream { buffer: Vec::new(), flags: flags }
Stream { buffer: Vec::new(), flags: flags | get_default_flags() }
}
/// Are transactions written to this stream with witness data?
......@@ -75,6 +83,11 @@ impl Stream {
(self.flags & SERIALIZE_TRANSACTION_WITNESS) != 0
}
/// Is data serialized to this stream in ZCash format?
pub fn is_zcash_stream(&self) -> bool {
(self.flags & SERIALIZE_ZCASH) != 0
}
/// Serializes the struct and appends it to the end of stream.
pub fn append<T>(&mut self, t: &T) -> &mut Self where T: Serializable {
t.serialize(self);
......
......@@ -382,7 +382,7 @@ pub mod tests {
.build()
.merkled_header()
.parent(rolling_hash.clone())
.bits(Network::Unitest.max_bits().into())
.bits(Network::Unitest.max_bits(&ConsensusFork::BitcoinCore).into())
.build()
.build();
rolling_hash = next_block.hash();
......@@ -401,7 +401,7 @@ pub mod tests {
.build()
.merkled_header()
.parent(last_block_hash)
.bits(Network::Unitest.max_bits().into())
.bits(Network::Unitest.max_bits(&ConsensusFork::BitcoinCore).into())
.build()
.build().into();
......
......@@ -293,7 +293,7 @@ mod tests {
// real world message
let payload: Bytes = "fd77078732c06c257f2818a0d14738804d6a18a0f0a9800e039be473286d591f48040c99e96d2e0cd8480b03c0823fdd79310e0e04c86314ae24cabaa931f39852c813172e524c4b231020557dda2023130b0f1f309de822014bf6d4305d238ea013b8539e9c138053076a22020335bc1042e543f260787993a07a155a7a560c1475f75ec109b73822491c5880924303a5545ffc465132960fe40a8822010f919c38910f31c546be6940090f0476a02570de8d28258ee8081dea073829386a9de01b0070348f0f2fb48c6a1b4e92292de7b60dbafb8df3a6cab6a824e50005744018b384f080c8265152e406b1c85906d5325d1c83ac880d02214ad401ddc07657002c47708e338020bd14fcc147bfe49335647062074a4d3276e0d3a5110826a05d4fb025129f48c26e5819dd878d851b84802b7a211097813ef952410390c95bb294a7a8faca3667f0068489a69d9c9e8405c035442874a6a8c448c60600834a22041ce36a8065b086469bbb1b46d326b7a9923054ad4e32e4b7231aa203c5acab1f5821b92d2f00728819e587e1e6ff9fa6e66ff52fb54bce3648a7b043cbd19469aa5af0891eb4979def822f06522f080830b411545b4240e01195b0f0962e628050f0f8290269c45c20aa16559d17ceca68b81a21370909a1086614531577600ad8480ae1023c9173260bc6385c0e2d46806c05401a17ac969edfe65fd4000007e1c8a13ac651922edfa5a3235a0bcc10cc0067b4404d64260aea022391b007d3010c8380fda9c821d37258e47a0ab6485baff88876ba55cd190edf730970875f75522010e40f8c28e4872a2065c96390041bef9273a6a1c05d2bd28193b205b2cf25e44c5290926a4d392450b3135a0db7cc2c0696384eee68a65a4280ac3c44207264243fd18795c69588f4e418a26d4e21d1cee894325a2fc869b03fec68fd3e86b31998f9f9a6402dd672227451b1b5419a89c90ae96b9292a1ca83848bc026dcd00ec740342496730a7ab8e48200c7ea240d0e34a07890a9203938ee188475b3d6dd2f50399019c249536955894917fa3acc400ce04ec42d5e89e2d48aa085ae129226d0ea2a4d0038db88fd5ec0688768cea449171280438e8f5164d8682c40b91a2dab042800b1f312b22460e4905dccee59842a2bc9f807d542e08388fec013696d281c0356880040b0610ac4cb148a95a5924875891b2217040bbab7bba21f14898203ae87153206601c20c484f072216c1714ac5ded41a6d213fc09962f195129ac09d85dc05501a773163646021100481cb385a0fdb1609e8d1bc042942f169884e60482ae2004924fc2eb0b7061855858b5e54a4517352084778f38c09f1f004431da4531059c1296436d4c89e8839d34506a27b07c94fa80d2a0a9b73208a79982f0a5d16e0b723d38816a6a666c09bceae5a46d8a032248302224ae43c7e4801004ea6671c6d08142b67e27269a4ac6418748d74f481fc2dbbac5852afc645026cb462f790347d32a26e0b88209f2168110eb4e88394dd0f3bc27958994803238059d581d8cda73493a994c433fad902e20093ad40b1570543af928bc4830c3976d2802635400c0ac5a25833008f00b8bb691c1d9ce026373d05ac03fa6851402e05c6f109fa1754da54a20aa9f4f4782e68966a5113ae141d495d2a53d64bb6a023616b243e0333e2e0c65f2078559a98f48e8637f7b2ff326572a32532e2ec9e9651c092c52a522a5120249a159fa49d56d304806b502c425e3981275409f38b20418bc8206d21e884401c05c3c7d0b7404cf2a97706092b5a818638122ce750ce8780812900f501f4f02cb90fd5ea615e611006e010920072d08ca01b535741460c9aa1ab567ac2f79a004400e523fdcf95320bc08a37f54aaa01b2a2d0aa343ec13205131124b445a2c1b9a7542c63c6ced549447462099c12a9c613838995d718849650300056845311b2c93a1d35a66622466e0a3cef68594faa11021751c0e5358027721d2a2362fc9353655680c80fa5cad35685a0454932251aa121cb50583ae987c2a6e8009f3342048019509760b7e233de62cdcb636344d8a012af9f61a539ec66801c46a56b3d8ea6825e95430d1cc71fcc0bc977e4ea27f83e284cab0aea0a5085e67039901252a722054e33168a89d160a5908a325b63654016da1e94450548bac84a1b22fcc92ce7e2018967755711480e9048f5ded20b5d3960f21b559f1a0be84a53721f7b0f283d7d1bc2bd7f5d7550d3213814eb56e13f0b106acc07b05ece2c518117e934409843f1f889c2d84845c540514badb4ca00864e8bde78e50b0837478104c018cd5996977196e4f064002480a2761489000984d44d0077df65696f306930c893c50b08516e9ea82e02eb0400bc3d1adade23161b45e5210e08e981568f8af232bdf0f3c460349a8800c9f2c510eecc8ccee39e8b0898d329560aaf4d9594a551186423f79aa6806ce8c541506283a54e8859a840814012cad0289627f8659658218f6e58926af0849b4b23b40ac76280061b90c940f71617e0397ea145968250b1060608e4002432021195635dc52e0495c69fa67768a4a89ec32206fa30f62a85503de8c79df940f808c0de2f1723c0c84d89f317c4c1287a40759946d9cc8c43044a817dd6bb8ed326e4ab800fd8815482910de3cc360d40080a8d956e049ec6d1000000000943a3102".parse().unwrap();
let message: types::FilterLoad = deserialize_payload(&payload, 70001).unwrap();
let message: types::FilterLoad = deserialize_payload(&payload, 70001, 0).unwrap();
// containing this address
let address: Bytes = "BA99435B59DEBDBB5E207C0B33FF55752DBC5EFF".parse().unwrap();
......
......@@ -245,9 +245,11 @@ impl<F> BlockHeaderBuilder<F> where F: Invoke<chain::BlockHeader> {
time: self.time,
previous_header_hash: self.parent,
bits: self.bits,
nonce: self.nonce,
nonce: self.nonce.into(),
merkle_root_hash: self.merkle_root,
version: self.version,
hash_final_sapling_root: None,
equihash_solution: None,
}
)
}
......@@ -335,6 +337,7 @@ impl<F> TransactionBuilder<F> where F: Invoke<chain::Transaction> {
version: self.version,
inputs: self.inputs,
outputs: self.outputs,
joint_split: None,
}
)
}
......
......@@ -9,6 +9,8 @@ lazy_static = "1.0"
log = "0.4"
rayon = "1.0"
parking_lot = "0.4"
blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", branch = "persona" }
byteorder = "1.2"
primitives = { path = "../primitives" }
chain = { path = "../chain" }
serialization = { path = "../serialization" }
......@@ -18,5 +20,6 @@ storage = { path = "../storage" }
bitcrypto = { path = "../crypto" }
[dev-dependencies]
rand = "0.4"
test-data = { path = "../test-data" }
db = { path = "../db" }
......@@ -293,7 +293,7 @@ impl<'a> BlockCoinbaseScript<'a> {
}
let prefix = script::Builder::default()
.push_num(self.height.into())
.push_i64(self.height.into())
.into_script();
let matches = self.block.transactions.first()
......
use network::ConsensusParams;
use network::{ConsensusParams, ConsensusFork};
use storage::BlockHeaderProvider;
use canon::CanonHeader;
use error::Error;
......@@ -8,6 +8,7 @@ use deployments::Deployments;
pub struct HeaderAcceptor<'a> {
pub version: HeaderVersion<'a>,
pub equihash: HeaderEquihashSolution<'a>,
pub work: HeaderWork<'a>,
pub median_timestamp: HeaderMedianTimestamp<'a>,
}
......@@ -22,6 +23,7 @@ impl<'a> HeaderAcceptor<'a> {
) -> Self {
let csv_active = deployments.as_ref().csv(height, store, consensus);
HeaderAcceptor {
equihash: HeaderEquihashSolution::new(header, consensus),
work: HeaderWork::new(header, store, height, consensus),
median_timestamp: HeaderMedianTimestamp::new(header, store, csv_active),
version: HeaderVersion::new(header, height, consensus),
......@@ -29,6 +31,7 @@ impl<'a> HeaderAcceptor<'a> {
}
pub fn check(&self) -> Result<(), Error> {
try!(self.equihash.check());
try!(self.version.check());
try!(self.work.check());
try!(self.median_timestamp.check());
......@@ -64,6 +67,39 @@ impl<'a> HeaderVersion<'a> {
}
}
pub struct HeaderEquihashSolution<'a> {
header: CanonHeader<'a>,
consensus: &'a ConsensusParams,
}
impl<'a> HeaderEquihashSolution<'a> {
fn new(header: CanonHeader<'a>, consensus: &'a ConsensusParams) -> Self {
HeaderEquihashSolution {
header: header,
consensus: consensus,
}
}
fn check(&self) -> Result<(), Error> {
match self.consensus.fork {
ConsensusFork::ZCash(_) => (),
_ => return Ok(()),
}
use equihash;
let is_solution_correct = equihash::verify_block_equihash_solution(&equihash::EquihashParams {
N: 200,
K: 9,
}, &self.header.raw);
if is_solution_correct {
Ok(())
} else {
Err(Error::InvalidEquihashSolution)
}
}
}
pub struct HeaderWork<'a> {
header: CanonHeader<'a>,
store: &'a BlockHeaderProvider,
......