Merge pull request #156 from dongcarl/2018-8-network-cleanup
Ready for Review: Clean up `network::encodable` and `network::serialize`
This commit is contained in:
commit
45140a3251
|
@ -1,7 +1,7 @@
|
||||||
extern crate bitcoin;
|
extern crate bitcoin;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let _: Result<bitcoin::blockdata::block::Block, _>= bitcoin::network::serialize::deserialize(data);
|
let _: Result<bitcoin::blockdata::block::Block, _>= bitcoin::consensus::encode::deserialize(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "afl")]
|
#[cfg(feature = "afl")]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
extern crate bitcoin;
|
extern crate bitcoin;
|
||||||
|
|
||||||
use bitcoin::blockdata::script;
|
use bitcoin::blockdata::script;
|
||||||
use bitcoin::network::serialize;
|
use bitcoin::consensus::encode;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let s: Result<script::Script, _> = serialize::deserialize(data);
|
let s: Result<script::Script, _> = encode::deserialize(data);
|
||||||
if let Ok(script) = s {
|
if let Ok(script) = s {
|
||||||
let _: Vec<script::Instruction> = script.iter(false).collect();
|
let _: Vec<script::Instruction> = script.iter(false).collect();
|
||||||
let enforce_min: Vec<script::Instruction> = script.iter(true).collect();
|
let enforce_min: Vec<script::Instruction> = script.iter(true).collect();
|
||||||
|
@ -31,7 +31,7 @@ fn do_test(data: &[u8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(b.into_script(), script);
|
assert_eq!(b.into_script(), script);
|
||||||
assert_eq!(data, &serialize::serialize(&script).unwrap()[..]);
|
assert_eq!(data, &encode::serialize(&script)[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
extern crate bitcoin;
|
extern crate bitcoin;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let tx_result: Result<bitcoin::blockdata::transaction::Transaction, _> = bitcoin::network::serialize::deserialize(data);
|
let tx_result: Result<bitcoin::blockdata::transaction::Transaction, _> = bitcoin::consensus::encode::deserialize(data);
|
||||||
match tx_result {
|
match tx_result {
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
Ok(mut tx) => {
|
Ok(mut tx) => {
|
||||||
let len = bitcoin::network::serialize::serialize(&tx).unwrap().len() as u64;
|
let len = bitcoin::consensus::encode::serialize(&tx).len() as u64;
|
||||||
let calculated_weight = tx.get_weight();
|
let calculated_weight = tx.get_weight();
|
||||||
for input in &mut tx.input {
|
for input in &mut tx.input {
|
||||||
input.witness = vec![];
|
input.witness = vec![];
|
||||||
}
|
}
|
||||||
let no_witness_len = bitcoin::network::serialize::serialize(&tx).unwrap().len() as u64;
|
let no_witness_len = bitcoin::consensus::encode::serialize(&tx).len() as u64;
|
||||||
assert_eq!(no_witness_len * 3 + len, calculated_weight);
|
assert_eq!(no_witness_len * 3 + len, calculated_weight);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,9 @@
|
||||||
|
|
||||||
use util;
|
use util;
|
||||||
use util::Error::{SpvBadTarget, SpvBadProofOfWork};
|
use util::Error::{SpvBadTarget, SpvBadProofOfWork};
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::{BitcoinHash, Sha256dHash};
|
||||||
use util::uint::Uint256;
|
use util::uint::Uint256;
|
||||||
use network::encodable::VarInt;
|
use consensus::encode::VarInt;
|
||||||
use network::serialize::BitcoinHash;
|
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use blockdata::transaction::Transaction;
|
use blockdata::transaction::Transaction;
|
||||||
use blockdata::constants::max_target;
|
use blockdata::constants::max_target;
|
||||||
|
@ -143,8 +142,8 @@ impl BlockHeader {
|
||||||
|
|
||||||
impl BitcoinHash for BlockHeader {
|
impl BitcoinHash for BlockHeader {
|
||||||
fn bitcoin_hash(&self) -> Sha256dHash {
|
fn bitcoin_hash(&self) -> Sha256dHash {
|
||||||
use network::serialize::serialize;
|
use consensus::encode::serialize;
|
||||||
Sha256dHash::from_data(&serialize(self).unwrap())
|
Sha256dHash::from_data(&serialize(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +162,7 @@ mod tests {
|
||||||
use hex::decode as hex_decode;
|
use hex::decode as hex_decode;
|
||||||
|
|
||||||
use blockdata::block::{Block, BlockHeader};
|
use blockdata::block::{Block, BlockHeader};
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_test() {
|
fn block_test() {
|
||||||
|
@ -180,15 +179,15 @@ mod tests {
|
||||||
assert!(bad_decode.is_err());
|
assert!(bad_decode.is_err());
|
||||||
let real_decode = decode.unwrap();
|
let real_decode = decode.unwrap();
|
||||||
assert_eq!(real_decode.header.version, 1);
|
assert_eq!(real_decode.header.version, 1);
|
||||||
assert_eq!(serialize(&real_decode.header.prev_blockhash).ok(), Some(prevhash));
|
assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash);
|
||||||
// [test] TODO: actually compute the merkle root
|
// [test] TODO: actually compute the merkle root
|
||||||
assert_eq!(serialize(&real_decode.header.merkle_root).ok(), Some(merkle));
|
assert_eq!(serialize(&real_decode.header.merkle_root), merkle);
|
||||||
assert_eq!(real_decode.header.time, 1231965655);
|
assert_eq!(real_decode.header.time, 1231965655);
|
||||||
assert_eq!(real_decode.header.bits, 486604799);
|
assert_eq!(real_decode.header.bits, 486604799);
|
||||||
assert_eq!(real_decode.header.nonce, 2067413810);
|
assert_eq!(real_decode.header.nonce, 2067413810);
|
||||||
// [test] TODO: check the transaction data
|
// [test] TODO: check the transaction data
|
||||||
|
|
||||||
assert_eq!(serialize(&real_decode).ok(), Some(some_block));
|
assert_eq!(serialize(&real_decode), some_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b
|
// Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b
|
||||||
|
@ -204,14 +203,14 @@ mod tests {
|
||||||
assert!(decode.is_ok());
|
assert!(decode.is_ok());
|
||||||
let real_decode = decode.unwrap();
|
let real_decode = decode.unwrap();
|
||||||
assert_eq!(real_decode.header.version, 0x20000000); // VERSIONBITS but no bits set
|
assert_eq!(real_decode.header.version, 0x20000000); // VERSIONBITS but no bits set
|
||||||
assert_eq!(serialize(&real_decode.header.prev_blockhash).ok(), Some(prevhash));
|
assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash);
|
||||||
assert_eq!(serialize(&real_decode.header.merkle_root).ok(), Some(merkle));
|
assert_eq!(serialize(&real_decode.header.merkle_root), merkle);
|
||||||
assert_eq!(real_decode.header.time, 1472004949);
|
assert_eq!(real_decode.header.time, 1472004949);
|
||||||
assert_eq!(real_decode.header.bits, 0x1a06d450);
|
assert_eq!(real_decode.header.bits, 0x1a06d450);
|
||||||
assert_eq!(real_decode.header.nonce, 1879759182);
|
assert_eq!(real_decode.header.nonce, 1879759182);
|
||||||
// [test] TODO: check the transaction data
|
// [test] TODO: check the transaction data
|
||||||
|
|
||||||
assert_eq!(serialize(&real_decode).ok(), Some(segwit_block));
|
assert_eq!(serialize(&real_decode), segwit_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -143,9 +143,10 @@ mod test {
|
||||||
use hex::decode as hex_decode;
|
use hex::decode as hex_decode;
|
||||||
|
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use network::serialize::{BitcoinHash, serialize};
|
use consensus::encode::serialize;
|
||||||
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
|
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
|
||||||
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
|
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
|
||||||
|
use util::hash::BitcoinHash;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bitcoin_genesis_first_transaction() {
|
fn bitcoin_genesis_first_transaction() {
|
||||||
|
@ -155,13 +156,13 @@ mod test {
|
||||||
assert_eq!(gen.input.len(), 1);
|
assert_eq!(gen.input.len(), 1);
|
||||||
assert_eq!(gen.input[0].previous_output.txid, Default::default());
|
assert_eq!(gen.input[0].previous_output.txid, Default::default());
|
||||||
assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF);
|
assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF);
|
||||||
assert_eq!(serialize(&gen.input[0].script_sig).ok(),
|
assert_eq!(serialize(&gen.input[0].script_sig),
|
||||||
Some(hex_decode("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73").unwrap()));
|
hex_decode("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73").unwrap());
|
||||||
|
|
||||||
assert_eq!(gen.input[0].sequence, MAX_SEQUENCE);
|
assert_eq!(gen.input[0].sequence, MAX_SEQUENCE);
|
||||||
assert_eq!(gen.output.len(), 1);
|
assert_eq!(gen.output.len(), 1);
|
||||||
assert_eq!(serialize(&gen.output[0].script_pubkey).ok(),
|
assert_eq!(serialize(&gen.output[0].script_pubkey),
|
||||||
Some(hex_decode("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap()));
|
hex_decode("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap());
|
||||||
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
|
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
|
||||||
assert_eq!(gen.lock_time, 0);
|
assert_eq!(gen.lock_time, 0);
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
// Heavy stick to translate between opcode types
|
// Heavy stick to translate between opcode types
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
|
|
||||||
use network::serialize::{self, SimpleDecoder, SimpleEncoder};
|
use consensus::encode::{self, Decoder, Encoder};
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
|
|
||||||
// Note: I am deliberately not implementing PartialOrd or Ord on the
|
// Note: I am deliberately not implementing PartialOrd or Ord on the
|
||||||
// opcode enum. If you want to check ranges of opcodes, etc.,
|
// opcode enum. If you want to check ranges of opcodes, etc.,
|
||||||
|
@ -606,16 +606,16 @@ impl From<u8> for All {
|
||||||
|
|
||||||
display_from_debug!(All);
|
display_from_debug!(All);
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for All {
|
impl<D: Decoder> Decodable<D> for All {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<All, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<All, encode::Error> {
|
||||||
Ok(All::from(d.read_u8()?))
|
Ok(All::from(d.read_u8()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for All {
|
impl<S: Encoder> Encodable<S> for All {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
s.emit_u8(*self as u8)
|
s.emit_u8(*self as u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,8 @@ use crypto::digest::Digest;
|
||||||
#[cfg(feature = "serde")] use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
use network::serialize::{self, SimpleDecoder, SimpleEncoder};
|
use consensus::encode::{self, Decoder, Encoder};
|
||||||
use util::hash::Hash160;
|
use util::hash::Hash160;
|
||||||
#[cfg(feature="bitcoinconsensus")] use bitcoinconsensus;
|
#[cfg(feature="bitcoinconsensus")] use bitcoinconsensus;
|
||||||
#[cfg(feature="bitcoinconsensus")] use std::convert;
|
#[cfg(feature="bitcoinconsensus")] use std::convert;
|
||||||
|
@ -671,17 +671,17 @@ impl serde::Serialize for Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network serialization
|
// Network serialization
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for Script {
|
impl<S: Encoder> Encodable<S> for Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
self.0.consensus_encode(s)
|
self.0.consensus_encode(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for Script {
|
impl<D: Decoder> Decodable<D> for Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<Script, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<Script, encode::Error> {
|
||||||
Ok(Script(ConsensusDecodable::consensus_decode(d)?))
|
Ok(Script(Decodable::consensus_decode(d)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,7 +692,7 @@ mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::build_scriptint;
|
use super::build_scriptint;
|
||||||
|
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -740,7 +740,7 @@ mod test {
|
||||||
let hex_script = hex_decode("6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52").unwrap();
|
let hex_script = hex_decode("6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52").unwrap();
|
||||||
let script: Result<Script, _> = deserialize(&hex_script);
|
let script: Result<Script, _> = deserialize(&hex_script);
|
||||||
assert!(script.is_ok());
|
assert!(script.is_ok());
|
||||||
assert_eq!(serialize(&script.unwrap()).ok(), Some(hex_script));
|
assert_eq!(serialize(&script.unwrap()), hex_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -28,11 +28,11 @@ use std::default::Default;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature="bitcoinconsensus")] use std::collections::HashMap;
|
#[cfg(feature="bitcoinconsensus")] use std::collections::HashMap;
|
||||||
|
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::{BitcoinHash, Sha256dHash};
|
||||||
#[cfg(feature="bitcoinconsensus")] use blockdata::script;
|
#[cfg(feature="bitcoinconsensus")] use blockdata::script;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use network::serialize::{self, serialize, BitcoinHash, SimpleEncoder, SimpleDecoder};
|
use consensus::encode::{self, serialize, Encoder, Decoder};
|
||||||
use network::encodable::{ConsensusEncodable, ConsensusDecodable, VarInt};
|
use consensus::encode::{Encodable, Decodable, VarInt};
|
||||||
|
|
||||||
/// A reference to a transaction output
|
/// A reference to a transaction output
|
||||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||||
|
@ -104,9 +104,9 @@ pub struct TxIn {
|
||||||
pub sequence: u32,
|
pub sequence: u32,
|
||||||
/// Witness data: an array of byte-arrays.
|
/// Witness data: an array of byte-arrays.
|
||||||
/// Note that this field is *not* (de)serialized with the rest of the TxIn in
|
/// Note that this field is *not* (de)serialized with the rest of the TxIn in
|
||||||
/// ConsensusEncodable/ConsennsusDecodable, as it is (de)serialized at the end of the full
|
/// Encodable/Decodable, as it is (de)serialized at the end of the full
|
||||||
/// Transaction. It *is* (de)serialized with the rest of the TxIn in other (de)serializationn
|
/// Transaction. It *is* (de)serialized with the rest of the TxIn in other
|
||||||
/// routines.
|
/// (de)serialization routines.
|
||||||
pub witness: Vec<Vec<u8>>
|
pub witness: Vec<Vec<u8>>
|
||||||
}
|
}
|
||||||
serde_struct_impl!(TxIn, previous_output, script_sig, sequence, witness);
|
serde_struct_impl!(TxIn, previous_output, script_sig, sequence, witness);
|
||||||
|
@ -238,7 +238,7 @@ impl Transaction {
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
// hash the result
|
// hash the result
|
||||||
let mut raw_vec = serialize(&tx).unwrap();
|
let mut raw_vec = serialize(&tx);
|
||||||
raw_vec.write_u32::<LittleEndian>(sighash_u32).unwrap();
|
raw_vec.write_u32::<LittleEndian>(sighash_u32).unwrap();
|
||||||
Sha256dHash::from_data(&raw_vec)
|
Sha256dHash::from_data(&raw_vec)
|
||||||
}
|
}
|
||||||
|
@ -288,23 +288,19 @@ impl Transaction {
|
||||||
#[cfg(feature="bitcoinconsensus")]
|
#[cfg(feature="bitcoinconsensus")]
|
||||||
/// Verify that this transaction is able to spend some outputs of spent transactions
|
/// Verify that this transaction is able to spend some outputs of spent transactions
|
||||||
pub fn verify(&self, spent: &HashMap<Sha256dHash, Transaction>) -> Result<(), script::Error> {
|
pub fn verify(&self, spent: &HashMap<Sha256dHash, Transaction>) -> Result<(), script::Error> {
|
||||||
if let Ok(tx) = serialize(&*self) {
|
let tx = serialize(&*self);
|
||||||
for (idx, input) in self.input.iter().enumerate() {
|
for (idx, input) in self.input.iter().enumerate() {
|
||||||
if let Some(ref s) = spent.get(&input.previous_output.txid) {
|
if let Some(ref s) = spent.get(&input.previous_output.txid) {
|
||||||
if let Some(ref output) = s.output.get(input.previous_output.vout as usize) {
|
if let Some(ref output) = s.output.get(input.previous_output.vout as usize) {
|
||||||
output.script_pubkey.verify(idx, output.value, tx.as_slice())?;
|
output.script_pubkey.verify(idx, output.value, tx.as_slice())?;
|
||||||
} else {
|
|
||||||
return Err(script::Error::WrongSpentOutputIndex(input.previous_output.vout as usize));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Err(script::Error::UnknownSpentTransaction(input.previous_output.txid));
|
return Err(script::Error::WrongSpentOutputIndex(input.previous_output.vout as usize));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Err(script::Error::UnknownSpentTransaction(input.previous_output.txid));
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Err(script::Error::SerializationError)
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this a coin base transaction?
|
/// Is this a coin base transaction?
|
||||||
|
@ -325,41 +321,41 @@ impl BitcoinHash for Transaction {
|
||||||
|
|
||||||
impl_consensus_encoding!(TxOut, value, script_pubkey);
|
impl_consensus_encoding!(TxOut, value, script_pubkey);
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for OutPoint {
|
impl<S: Encoder> Encodable<S> for OutPoint {
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result <(), encode::Error> {
|
||||||
self.txid.consensus_encode(s)?;
|
self.txid.consensus_encode(s)?;
|
||||||
self.vout.consensus_encode(s)
|
self.vout.consensus_encode(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for OutPoint {
|
impl<D: Decoder> Decodable<D> for OutPoint {
|
||||||
fn consensus_decode(d: &mut D) -> Result<OutPoint, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<OutPoint, encode::Error> {
|
||||||
Ok(OutPoint {
|
Ok(OutPoint {
|
||||||
txid: ConsensusDecodable::consensus_decode(d)?,
|
txid: Decodable::consensus_decode(d)?,
|
||||||
vout: ConsensusDecodable::consensus_decode(d)?,
|
vout: Decodable::consensus_decode(d)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for TxIn {
|
impl<S: Encoder> Encodable<S> for TxIn {
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result <(), encode::Error> {
|
||||||
self.previous_output.consensus_encode(s)?;
|
self.previous_output.consensus_encode(s)?;
|
||||||
self.script_sig.consensus_encode(s)?;
|
self.script_sig.consensus_encode(s)?;
|
||||||
self.sequence.consensus_encode(s)
|
self.sequence.consensus_encode(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for TxIn {
|
impl<D: Decoder> Decodable<D> for TxIn {
|
||||||
fn consensus_decode(d: &mut D) -> Result<TxIn, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<TxIn, encode::Error> {
|
||||||
Ok(TxIn {
|
Ok(TxIn {
|
||||||
previous_output: ConsensusDecodable::consensus_decode(d)?,
|
previous_output: Decodable::consensus_decode(d)?,
|
||||||
script_sig: ConsensusDecodable::consensus_decode(d)?,
|
script_sig: Decodable::consensus_decode(d)?,
|
||||||
sequence: ConsensusDecodable::consensus_decode(d)?,
|
sequence: Decodable::consensus_decode(d)?,
|
||||||
witness: vec![],
|
witness: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for Transaction {
|
impl<S: Encoder> Encodable<S> for Transaction {
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result <(), encode::Error> {
|
||||||
self.version.consensus_encode(s)?;
|
self.version.consensus_encode(s)?;
|
||||||
let mut have_witness = false;
|
let mut have_witness = false;
|
||||||
for input in &self.input {
|
for input in &self.input {
|
||||||
|
@ -384,13 +380,13 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for Transaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for Transaction {
|
impl<D: Decoder> Decodable<D> for Transaction {
|
||||||
fn consensus_decode(d: &mut D) -> Result<Transaction, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<Transaction, encode::Error> {
|
||||||
let version: u32 = ConsensusDecodable::consensus_decode(d)?;
|
let version: u32 = Decodable::consensus_decode(d)?;
|
||||||
let input: Vec<TxIn> = ConsensusDecodable::consensus_decode(d)?;
|
let input: Vec<TxIn> = Decodable::consensus_decode(d)?;
|
||||||
// segwit
|
// segwit
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
let segwit_flag: u8 = ConsensusDecodable::consensus_decode(d)?;
|
let segwit_flag: u8 = Decodable::consensus_decode(d)?;
|
||||||
match segwit_flag {
|
match segwit_flag {
|
||||||
// Empty tx
|
// Empty tx
|
||||||
0 => {
|
0 => {
|
||||||
|
@ -398,30 +394,30 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Transaction {
|
||||||
version: version,
|
version: version,
|
||||||
input: input,
|
input: input,
|
||||||
output: vec![],
|
output: vec![],
|
||||||
lock_time: ConsensusDecodable::consensus_decode(d)?,
|
lock_time: Decodable::consensus_decode(d)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// BIP144 input witnesses
|
// BIP144 input witnesses
|
||||||
1 => {
|
1 => {
|
||||||
let mut input: Vec<TxIn> = ConsensusDecodable::consensus_decode(d)?;
|
let mut input: Vec<TxIn> = Decodable::consensus_decode(d)?;
|
||||||
let output: Vec<TxOut> = ConsensusDecodable::consensus_decode(d)?;
|
let output: Vec<TxOut> = Decodable::consensus_decode(d)?;
|
||||||
for txin in input.iter_mut() {
|
for txin in input.iter_mut() {
|
||||||
txin.witness = ConsensusDecodable::consensus_decode(d)?;
|
txin.witness = Decodable::consensus_decode(d)?;
|
||||||
}
|
}
|
||||||
if !input.is_empty() && input.iter().all(|input| input.witness.is_empty()) {
|
if !input.is_empty() && input.iter().all(|input| input.witness.is_empty()) {
|
||||||
Err(serialize::Error::ParseFailed("witness flag set but no witnesses present"))
|
Err(encode::Error::ParseFailed("witness flag set but no witnesses present"))
|
||||||
} else {
|
} else {
|
||||||
Ok(Transaction {
|
Ok(Transaction {
|
||||||
version: version,
|
version: version,
|
||||||
input: input,
|
input: input,
|
||||||
output: output,
|
output: output,
|
||||||
lock_time: ConsensusDecodable::consensus_decode(d)?,
|
lock_time: Decodable::consensus_decode(d)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We don't support anything else
|
// We don't support anything else
|
||||||
x => {
|
x => {
|
||||||
Err(serialize::Error::UnsupportedSegwitFlag(x))
|
Err(encode::Error::UnsupportedSegwitFlag(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// non-segwit
|
// non-segwit
|
||||||
|
@ -429,8 +425,8 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Transaction {
|
||||||
Ok(Transaction {
|
Ok(Transaction {
|
||||||
version: version,
|
version: version,
|
||||||
input: input,
|
input: input,
|
||||||
output: ConsensusDecodable::consensus_decode(d)?,
|
output: Decodable::consensus_decode(d)?,
|
||||||
lock_time: ConsensusDecodable::consensus_decode(d)?,
|
lock_time: Decodable::consensus_decode(d)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -499,11 +495,10 @@ mod tests {
|
||||||
use super::{Transaction, TxIn};
|
use super::{Transaction, TxIn};
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use network::serialize::BitcoinHash;
|
|
||||||
#[cfg(all(feature = "serde", feature = "strason"))]
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
use network::serialize::serialize;
|
use consensus::encode::serialize;
|
||||||
use network::serialize::deserialize;
|
use consensus::encode::deserialize;
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::{BitcoinHash, Sha256dHash};
|
||||||
use util::misc::hex_bytes;
|
use util::misc::hex_bytes;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -651,7 +646,7 @@ mod tests {
|
||||||
let decoded = encoded.into_deserialize().unwrap();
|
let decoded = encoded.into_deserialize().unwrap();
|
||||||
assert_eq!(tx, decoded);
|
assert_eq!(tx, decoded);
|
||||||
|
|
||||||
let consensus_encoded = serialize(&tx).unwrap();
|
let consensus_encoded = serialize(&tx);
|
||||||
assert_eq!(consensus_encoded, hex_tx);
|
assert_eq!(consensus_encoded, hex_tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,889 @@
|
||||||
|
// Rust Bitcoin Library
|
||||||
|
// Written in 2014 by
|
||||||
|
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
||||||
|
//
|
||||||
|
// To the extent possible under law, the author(s) have dedicated all
|
||||||
|
// copyright and related and neighboring rights to this software to
|
||||||
|
// the public domain worldwide. This software is distributed without
|
||||||
|
// any warranty.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the CC0 Public Domain Dedication
|
||||||
|
// along with this software.
|
||||||
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
//! Consensus-encodable types
|
||||||
|
//!
|
||||||
|
//! This is basically a replacement of the `Encodable` trait which does
|
||||||
|
//! normalization for endianness, etc., to ensure that the encoding
|
||||||
|
//! matches for endianness, etc., to ensure that the encoding matches
|
||||||
|
//! the network consensus encoding.
|
||||||
|
//!
|
||||||
|
//! Essentially, anything that must go on the -disk- or -network- must
|
||||||
|
//! be encoded using the `Encodable` trait, since this data
|
||||||
|
//! must be the same for all systems. Any data going to the -user-, e.g.
|
||||||
|
//! over JSONRPC, should use the ordinary `Encodable` trait. (This
|
||||||
|
//! should also be the same across systems, of course, but has some
|
||||||
|
//! critical differences from the network format, e.g. scripts come
|
||||||
|
//! with an opcode decode, hashes are big-endian, numbers are typically
|
||||||
|
//! big-endian decimals, etc.)
|
||||||
|
//!
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::{mem, u32};
|
||||||
|
|
||||||
|
use util::hash::Sha256dHash;
|
||||||
|
|
||||||
|
use std::error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::io;
|
||||||
|
use std::io::{Cursor, Read, Write};
|
||||||
|
use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
use hex::encode as hex_encode;
|
||||||
|
|
||||||
|
use bitcoin_bech32;
|
||||||
|
|
||||||
|
use util::base58;
|
||||||
|
|
||||||
|
/// Encoding error
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// And I/O error
|
||||||
|
Io(io::Error),
|
||||||
|
/// Base58 encoding error
|
||||||
|
Base58(base58::Error),
|
||||||
|
/// Bech32 encoding error
|
||||||
|
Bech32(bitcoin_bech32::Error),
|
||||||
|
/// Error from the `byteorder` crate
|
||||||
|
ByteOrder(io::Error),
|
||||||
|
/// Network magic was not expected
|
||||||
|
UnexpectedNetworkMagic {
|
||||||
|
/// The expected network magic
|
||||||
|
expected: u32,
|
||||||
|
/// The unexpected network magic
|
||||||
|
actual: u32,
|
||||||
|
},
|
||||||
|
/// Tried to allocate an oversized vector
|
||||||
|
OversizedVectorAllocation{
|
||||||
|
/// The capacity requested
|
||||||
|
requested: usize,
|
||||||
|
/// The maximum capacity
|
||||||
|
max: usize,
|
||||||
|
},
|
||||||
|
/// Checksum was invalid
|
||||||
|
InvalidChecksum {
|
||||||
|
/// The expected checksum
|
||||||
|
expected: [u8; 4],
|
||||||
|
/// The invalid checksum
|
||||||
|
actual: [u8; 4],
|
||||||
|
},
|
||||||
|
/// Network magic was unknown
|
||||||
|
UnknownNetworkMagic(u32),
|
||||||
|
/// Parsing error
|
||||||
|
ParseFailed(&'static str),
|
||||||
|
/// Unsupported witness version
|
||||||
|
UnsupportedWitnessVersion(u8),
|
||||||
|
/// Unsupported Segwit flag
|
||||||
|
UnsupportedSegwitFlag(u8),
|
||||||
|
/// Unrecognized network command
|
||||||
|
UnrecognizedNetworkCommand(String),
|
||||||
|
/// Unexpected hex digit
|
||||||
|
UnexpectedHexDigit(char),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Error::Io(ref e) => fmt::Display::fmt(e, f),
|
||||||
|
Error::Base58(ref e) => fmt::Display::fmt(e, f),
|
||||||
|
Error::Bech32(ref e) => fmt::Display::fmt(e, f),
|
||||||
|
Error::ByteOrder(ref e) => fmt::Display::fmt(e, f),
|
||||||
|
Error::UnexpectedNetworkMagic { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), e, a),
|
||||||
|
Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f, "{}: requested {}, maximum {}", error::Error::description(self), r, m),
|
||||||
|
Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), hex_encode(e), hex_encode(a)),
|
||||||
|
Error::UnknownNetworkMagic(ref m) => write!(f, "{}: {}", error::Error::description(self), m),
|
||||||
|
Error::ParseFailed(ref e) => write!(f, "{}: {}", error::Error::description(self), e),
|
||||||
|
Error::UnsupportedWitnessVersion(ref wver) => write!(f, "{}: {}", error::Error::description(self), wver),
|
||||||
|
Error::UnsupportedSegwitFlag(ref swflag) => write!(f, "{}: {}", error::Error::description(self), swflag),
|
||||||
|
Error::UnrecognizedNetworkCommand(ref nwcmd) => write!(f, "{}: {}", error::Error::description(self), nwcmd),
|
||||||
|
Error::UnexpectedHexDigit(ref d) => write!(f, "{}: {}", error::Error::description(self), d),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error {
|
||||||
|
fn cause(&self) -> Option<&error::Error> {
|
||||||
|
match *self {
|
||||||
|
Error::Io(ref e) => Some(e),
|
||||||
|
Error::Base58(ref e) => Some(e),
|
||||||
|
Error::Bech32(ref e) => Some(e),
|
||||||
|
Error::ByteOrder(ref e) => Some(e),
|
||||||
|
Error::UnexpectedNetworkMagic { .. }
|
||||||
|
| Error::OversizedVectorAllocation { .. }
|
||||||
|
| Error::InvalidChecksum { .. }
|
||||||
|
| Error::UnknownNetworkMagic(..)
|
||||||
|
| Error::ParseFailed(..)
|
||||||
|
| Error::UnsupportedWitnessVersion(..)
|
||||||
|
| Error::UnsupportedSegwitFlag(..)
|
||||||
|
| Error::UnrecognizedNetworkCommand(..)
|
||||||
|
| Error::UnexpectedHexDigit(..) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
Error::Io(ref e) => e.description(),
|
||||||
|
Error::Base58(ref e) => e.description(),
|
||||||
|
Error::Bech32(ref e) => e.description(),
|
||||||
|
Error::ByteOrder(ref e) => e.description(),
|
||||||
|
Error::UnexpectedNetworkMagic { .. } => "unexpected network magic",
|
||||||
|
Error::OversizedVectorAllocation { .. } => "allocation of oversized vector requested",
|
||||||
|
Error::InvalidChecksum { .. } => "invalid checksum",
|
||||||
|
Error::UnknownNetworkMagic(..) => "unknown network magic",
|
||||||
|
Error::ParseFailed(..) => "parse failed",
|
||||||
|
Error::UnsupportedWitnessVersion(..) => "unsupported witness version",
|
||||||
|
Error::UnsupportedSegwitFlag(..) => "unsupported segwit version",
|
||||||
|
Error::UnrecognizedNetworkCommand(..) => "unrecognized network command",
|
||||||
|
Error::UnexpectedHexDigit(..) => "unexpected hex digit",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
impl From<base58::Error> for Error {
|
||||||
|
fn from(e: base58::Error) -> Error {
|
||||||
|
Error::Base58(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
impl From<bitcoin_bech32::Error> for Error {
|
||||||
|
fn from(e: bitcoin_bech32::Error) -> Error {
|
||||||
|
Error::Bech32(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(error: io::Error) -> Self {
|
||||||
|
Error::Io(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode an object into a vector
|
||||||
|
pub fn serialize<T: ?Sized>(data: &T) -> Vec<u8>
|
||||||
|
where T: Encodable<Cursor<Vec<u8>>>,
|
||||||
|
{
|
||||||
|
let mut encoder = Cursor::new(vec![]);
|
||||||
|
data.consensus_encode(&mut encoder).unwrap();
|
||||||
|
encoder.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode an object into a hex-encoded string
|
||||||
|
pub fn serialize_hex<T: ?Sized>(data: &T) -> String
|
||||||
|
where T: Encodable<Cursor<Vec<u8>>>
|
||||||
|
{
|
||||||
|
hex_encode(serialize(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize an object from a vector, will error if said deserialization
|
||||||
|
/// doesn't consume the entire vector.
|
||||||
|
pub fn deserialize<'a, T>(data: &'a [u8]) -> Result<T, Error>
|
||||||
|
where T: Decodable<Cursor<&'a [u8]>>
|
||||||
|
{
|
||||||
|
let mut decoder = Cursor::new(data);
|
||||||
|
let rv = Decodable::consensus_decode(&mut decoder)?;
|
||||||
|
|
||||||
|
// Fail if data is not consumed entirely.
|
||||||
|
if decoder.position() == data.len() as u64 {
|
||||||
|
Ok(rv)
|
||||||
|
} else {
|
||||||
|
Err(Error::ParseFailed("data not consumed entirely when explicitly deserializing"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple Encoder trait
|
||||||
|
pub trait Encoder {
|
||||||
|
/// Output a 64-bit uint
|
||||||
|
fn emit_u64(&mut self, v: u64) -> Result<(), Error>;
|
||||||
|
/// Output a 32-bit uint
|
||||||
|
fn emit_u32(&mut self, v: u32) -> Result<(), Error>;
|
||||||
|
/// Output a 16-bit uint
|
||||||
|
fn emit_u16(&mut self, v: u16) -> Result<(), Error>;
|
||||||
|
/// Output a 8-bit uint
|
||||||
|
fn emit_u8(&mut self, v: u8) -> Result<(), Error>;
|
||||||
|
|
||||||
|
/// Output a 64-bit int
|
||||||
|
fn emit_i64(&mut self, v: i64) -> Result<(), Error>;
|
||||||
|
/// Output a 32-bit int
|
||||||
|
fn emit_i32(&mut self, v: i32) -> Result<(), Error>;
|
||||||
|
/// Output a 16-bit int
|
||||||
|
fn emit_i16(&mut self, v: i16) -> Result<(), Error>;
|
||||||
|
/// Output a 8-bit int
|
||||||
|
fn emit_i8(&mut self, v: i8) -> Result<(), Error>;
|
||||||
|
|
||||||
|
/// Output a boolean
|
||||||
|
fn emit_bool(&mut self, v: bool) -> Result<(), Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple Decoder trait
|
||||||
|
pub trait Decoder {
|
||||||
|
/// Read a 64-bit uint
|
||||||
|
fn read_u64(&mut self) -> Result<u64, Error>;
|
||||||
|
/// Read a 32-bit uint
|
||||||
|
fn read_u32(&mut self) -> Result<u32, Error>;
|
||||||
|
/// Read a 16-bit uint
|
||||||
|
fn read_u16(&mut self) -> Result<u16, Error>;
|
||||||
|
/// Read a 8-bit uint
|
||||||
|
fn read_u8(&mut self) -> Result<u8, Error>;
|
||||||
|
|
||||||
|
/// Read a 64-bit int
|
||||||
|
fn read_i64(&mut self) -> Result<i64, Error>;
|
||||||
|
/// Read a 32-bit int
|
||||||
|
fn read_i32(&mut self) -> Result<i32, Error>;
|
||||||
|
/// Read a 16-bit int
|
||||||
|
fn read_i16(&mut self) -> Result<i16, Error>;
|
||||||
|
/// Read a 8-bit int
|
||||||
|
fn read_i8(&mut self) -> Result<i8, Error>;
|
||||||
|
|
||||||
|
/// Read a boolean
|
||||||
|
fn read_bool(&mut self) -> Result<bool, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! encoder_fn {
|
||||||
|
($name:ident, $val_type:ty, $writefn:ident) => {
|
||||||
|
#[inline]
|
||||||
|
fn $name(&mut self, v: $val_type) -> Result<(), Error> {
|
||||||
|
WriteBytesExt::$writefn::<LittleEndian>(self, v).map_err(Error::Io)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! decoder_fn {
|
||||||
|
($name:ident, $val_type:ty, $readfn:ident) => {
|
||||||
|
#[inline]
|
||||||
|
fn $name(&mut self) -> Result<$val_type, Error> {
|
||||||
|
ReadBytesExt::$readfn::<LittleEndian>(self).map_err(Error::Io)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> Encoder for W {
|
||||||
|
encoder_fn!(emit_u64, u64, write_u64);
|
||||||
|
encoder_fn!(emit_u32, u32, write_u32);
|
||||||
|
encoder_fn!(emit_u16, u16, write_u16);
|
||||||
|
encoder_fn!(emit_i64, i64, write_i64);
|
||||||
|
encoder_fn!(emit_i32, i32, write_i32);
|
||||||
|
encoder_fn!(emit_i16, i16, write_i16);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn emit_i8(&mut self, v: i8) -> Result<(), Error> {
|
||||||
|
self.write_i8(v).map_err(Error::Io)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn emit_u8(&mut self, v: u8) -> Result<(), Error> {
|
||||||
|
self.write_u8(v).map_err(Error::Io)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn emit_bool(&mut self, v: bool) -> Result<(), Error> {
|
||||||
|
self.write_i8(if v {1} else {0}).map_err(Error::Io)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Read> Decoder for R {
|
||||||
|
decoder_fn!(read_u64, u64, read_u64);
|
||||||
|
decoder_fn!(read_u32, u32, read_u32);
|
||||||
|
decoder_fn!(read_u16, u16, read_u16);
|
||||||
|
decoder_fn!(read_i64, i64, read_i64);
|
||||||
|
decoder_fn!(read_i32, i32, read_i32);
|
||||||
|
decoder_fn!(read_i16, i16, read_i16);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn read_u8(&mut self) -> Result<u8, Error> {
|
||||||
|
ReadBytesExt::read_u8(self).map_err(Error::Io)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn read_i8(&mut self) -> Result<i8, Error> {
|
||||||
|
ReadBytesExt::read_i8(self).map_err(Error::Io)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn read_bool(&mut self) -> Result<bool, Error> {
|
||||||
|
Decoder::read_i8(self).map(|bit| bit != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maximum size, in bytes, of a vector we are allowed to decode
|
||||||
|
pub const MAX_VEC_SIZE: usize = 32 * 1024 * 1024;
|
||||||
|
|
||||||
|
/// Data which can be encoded in a consensus-consistent way
|
||||||
|
pub trait Encodable<S: Encoder> {
|
||||||
|
/// Encode an object with a well-defined format, should only ever error if
|
||||||
|
/// the underlying Encoder errors.
|
||||||
|
fn consensus_encode(&self, e: &mut S) -> Result<(), self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data which can be encoded in a consensus-consistent way
|
||||||
|
pub trait Decodable<D: Decoder>: Sized {
|
||||||
|
/// Decode an object with a well-defined format
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<Self, self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variable-length unsigned integer
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
|
||||||
|
pub struct VarInt(pub u64);
|
||||||
|
|
||||||
|
/// Data which must be preceded by a 4-byte checksum
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub struct CheckedData(pub Vec<u8>);
|
||||||
|
|
||||||
|
// Primitive types
|
||||||
|
macro_rules! impl_int_encodable{
|
||||||
|
($ty:ident, $meth_dec:ident, $meth_enc:ident) => (
|
||||||
|
impl<D: Decoder> Decodable<D> for $ty {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<$ty, self::Error> { d.$meth_dec().map($ty::from_le) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Encoder> Encodable<S> for $ty {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { s.$meth_enc(self.to_le()) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_int_encodable!(u8, read_u8, emit_u8);
|
||||||
|
impl_int_encodable!(u16, read_u16, emit_u16);
|
||||||
|
impl_int_encodable!(u32, read_u32, emit_u32);
|
||||||
|
impl_int_encodable!(u64, read_u64, emit_u64);
|
||||||
|
impl_int_encodable!(i8, read_i8, emit_i8);
|
||||||
|
impl_int_encodable!(i16, read_i16, emit_i16);
|
||||||
|
impl_int_encodable!(i32, read_i32, emit_i32);
|
||||||
|
impl_int_encodable!(i64, read_i64, emit_i64);
|
||||||
|
|
||||||
|
impl VarInt {
|
||||||
|
/// Gets the length of this VarInt when encoded.
|
||||||
|
/// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1),
|
||||||
|
/// and 9 otherwise.
|
||||||
|
#[inline]
|
||||||
|
pub fn encoded_length(&self) -> u64 {
|
||||||
|
match self.0 {
|
||||||
|
0...0xFC => { 1 }
|
||||||
|
0xFD...0xFFFF => { 3 }
|
||||||
|
0x10000...0xFFFFFFFF => { 5 }
|
||||||
|
_ => { 9 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Encoder> Encodable<S> for VarInt {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
match self.0 {
|
||||||
|
0...0xFC => { (self.0 as u8).consensus_encode(s) }
|
||||||
|
0xFD...0xFFFF => { s.emit_u8(0xFD)?; (self.0 as u16).consensus_encode(s) }
|
||||||
|
0x10000...0xFFFFFFFF => { s.emit_u8(0xFE)?; (self.0 as u32).consensus_encode(s) }
|
||||||
|
_ => { s.emit_u8(0xFF)?; (self.0 as u64).consensus_encode(s) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder> Decodable<D> for VarInt {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<VarInt, self::Error> {
|
||||||
|
let n = d.read_u8()?;
|
||||||
|
match n {
|
||||||
|
0xFF => {
|
||||||
|
let x = d.read_u64()?;
|
||||||
|
if x < 0x100000000 {
|
||||||
|
Err(self::Error::ParseFailed("non-minimal varint"))
|
||||||
|
} else {
|
||||||
|
Ok(VarInt(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0xFE => {
|
||||||
|
let x = d.read_u32()?;
|
||||||
|
if x < 0x10000 {
|
||||||
|
Err(self::Error::ParseFailed("non-minimal varint"))
|
||||||
|
} else {
|
||||||
|
Ok(VarInt(x as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0xFD => {
|
||||||
|
let x = d.read_u16()?;
|
||||||
|
if x < 0xFD {
|
||||||
|
Err(self::Error::ParseFailed("non-minimal varint"))
|
||||||
|
} else {
|
||||||
|
Ok(VarInt(x as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n => Ok(VarInt(n as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Booleans
|
||||||
|
impl<S: Encoder> Encodable<S> for bool {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { s.emit_u8(if *self {1} else {0}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder> Decodable<D> for bool {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<bool, self::Error> { d.read_u8().map(|n| n != 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings
|
||||||
|
impl<S: Encoder> Encodable<S> for String {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
self.as_bytes().consensus_encode(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder> Decodable<D> for String {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<String, self::Error> {
|
||||||
|
String::from_utf8(Decodable::consensus_decode(d)?)
|
||||||
|
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
macro_rules! impl_array {
|
||||||
|
( $size:expr ) => (
|
||||||
|
impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T; $size] {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
for i in self.iter() { i.consensus_encode(s)?; }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder, T:Decodable<D> + Copy> Decodable<D> for [T; $size] {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<[T; $size], self::Error> {
|
||||||
|
// Set everything to the first decode
|
||||||
|
let mut ret = [Decodable::consensus_decode(d)?; $size];
|
||||||
|
// Set the rest
|
||||||
|
for item in ret.iter_mut().take($size).skip(1) { *item = Decodable::consensus_decode(d)?; }
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_array!(2);
|
||||||
|
impl_array!(4);
|
||||||
|
impl_array!(8);
|
||||||
|
impl_array!(12);
|
||||||
|
impl_array!(16);
|
||||||
|
impl_array!(32);
|
||||||
|
|
||||||
|
impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
VarInt(self.len() as u64).consensus_encode(s)?;
|
||||||
|
for c in self.iter() { c.consensus_encode(s)?; }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot decode a slice
|
||||||
|
|
||||||
|
// Vectors
|
||||||
|
impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (&self[..]).consensus_encode(s) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<Vec<T>, self::Error> {
|
||||||
|
let len = VarInt::consensus_decode(d)?.0;
|
||||||
|
let byte_size = (len as usize)
|
||||||
|
.checked_mul(mem::size_of::<T>())
|
||||||
|
.ok_or(self::Error::ParseFailed("Invalid length"))?;
|
||||||
|
if byte_size > MAX_VEC_SIZE {
|
||||||
|
return Err(self::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE })
|
||||||
|
}
|
||||||
|
let mut ret = Vec::with_capacity(len as usize);
|
||||||
|
for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); }
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Encoder, T: Encodable<S>> Encodable<S> for Box<[T]> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (&self[..]).consensus_encode(s) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<Box<[T]>, self::Error> {
|
||||||
|
let len = VarInt::consensus_decode(d)?.0;
|
||||||
|
let len = len as usize;
|
||||||
|
if len > MAX_VEC_SIZE {
|
||||||
|
return Err(self::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE })
|
||||||
|
}
|
||||||
|
let mut ret = Vec::with_capacity(len);
|
||||||
|
for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); }
|
||||||
|
Ok(ret.into_boxed_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options (encoded as vectors of length 0 or 1)
|
||||||
|
impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
match *self {
|
||||||
|
Some(ref data) => {
|
||||||
|
1u8.consensus_encode(s)?;
|
||||||
|
data.consensus_encode(s)?;
|
||||||
|
}
|
||||||
|
None => { 0u8.consensus_encode(s)?; }
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder, T:Decodable<D>> Decodable<D> for Option<T> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<Option<T>, self::Error> {
|
||||||
|
let bit: u8 = Decodable::consensus_decode(d)?;
|
||||||
|
Ok(if bit != 0 {
|
||||||
|
Some(Decodable::consensus_decode(d)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Do a double-SHA256 on some data and return the first 4 bytes
|
||||||
|
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
||||||
|
let checksum = Sha256dHash::from_data(data);
|
||||||
|
[checksum[0], checksum[1], checksum[2], checksum[3]]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checked data
|
||||||
|
impl<S: Encoder> Encodable<S> for CheckedData {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
(self.0.len() as u32).consensus_encode(s)?;
|
||||||
|
sha2_checksum(&self.0).consensus_encode(s)?;
|
||||||
|
// We can't just pass to the slice encoder since it'll insert a length
|
||||||
|
for ch in &self.0 {
|
||||||
|
ch.consensus_encode(s)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder> Decodable<D> for CheckedData {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<CheckedData, self::Error> {
|
||||||
|
let len: u32 = Decodable::consensus_decode(d)?;
|
||||||
|
let checksum: [u8; 4] = Decodable::consensus_decode(d)?;
|
||||||
|
let mut ret = Vec::with_capacity(len as usize);
|
||||||
|
for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); }
|
||||||
|
let expected_checksum = sha2_checksum(&ret);
|
||||||
|
if expected_checksum != checksum {
|
||||||
|
Err(self::Error::InvalidChecksum {
|
||||||
|
expected: expected_checksum,
|
||||||
|
actual: checksum,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(CheckedData(ret))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tuples
|
||||||
|
macro_rules! tuple_encode {
|
||||||
|
($($x:ident),*) => (
|
||||||
|
impl <S: Encoder, $($x: Encodable<S>),*> Encodable<S> for ($($x),*) {
|
||||||
|
#[inline]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
let &($(ref $x),*) = self;
|
||||||
|
$( $x.consensus_encode(s)?; )*
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder, $($x: Decodable<D>),*> Decodable<D> for ($($x),*) {
|
||||||
|
#[inline]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<($($x),*), self::Error> {
|
||||||
|
Ok(($({let $x = Decodable::consensus_decode(d)?; $x }),*))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple_encode!(T0, T1);
|
||||||
|
tuple_encode!(T0, T1, T2, T3);
|
||||||
|
tuple_encode!(T0, T1, T2, T3, T4, T5);
|
||||||
|
tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
|
||||||
|
|
||||||
|
// References
|
||||||
|
impl<S: Encoder, T: Encodable<S>> Encodable<S> for Box<T> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (**self).consensus_encode(s) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<Box<T>, self::Error> {
|
||||||
|
Decodable::consensus_decode(d).map(Box::new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashMap
|
||||||
|
impl<S, K, V> Encodable<S> for HashMap<K, V>
|
||||||
|
where S: Encoder,
|
||||||
|
K: Encodable<S> + Eq + Hash,
|
||||||
|
V: Encodable<S>
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
VarInt(self.len() as u64).consensus_encode(s)?;
|
||||||
|
for (key, value) in self.iter() {
|
||||||
|
key.consensus_encode(s)?;
|
||||||
|
value.consensus_encode(s)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, K, V> Decodable<D> for HashMap<K, V>
|
||||||
|
where D: Decoder,
|
||||||
|
K: Decodable<D> + Eq + Hash,
|
||||||
|
V: Decodable<D>
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<HashMap<K, V>, self::Error> {
|
||||||
|
let len = VarInt::consensus_decode(d)?.0;
|
||||||
|
|
||||||
|
let mut ret = HashMap::with_capacity(len as usize);
|
||||||
|
for _ in 0..len {
|
||||||
|
ret.insert(Decodable::consensus_decode(d)?,
|
||||||
|
Decodable::consensus_decode(d)?);
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{CheckedData, VarInt};
|
||||||
|
|
||||||
|
use super::{deserialize, serialize, Error};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_int_test() {
|
||||||
|
// bool
|
||||||
|
assert_eq!(serialize(&false), vec![0u8]);
|
||||||
|
assert_eq!(serialize(&true), vec![1u8]);
|
||||||
|
// u8
|
||||||
|
assert_eq!(serialize(&1u8), vec![1u8]);
|
||||||
|
assert_eq!(serialize(&0u8), vec![0u8]);
|
||||||
|
assert_eq!(serialize(&255u8), vec![255u8]);
|
||||||
|
// u16
|
||||||
|
assert_eq!(serialize(&1u16), vec![1u8, 0]);
|
||||||
|
assert_eq!(serialize(&256u16), vec![0u8, 1]);
|
||||||
|
assert_eq!(serialize(&5000u16), vec![136u8, 19]);
|
||||||
|
// u32
|
||||||
|
assert_eq!(serialize(&1u32), vec![1u8, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&256u32), vec![0u8, 1, 0, 0]);
|
||||||
|
assert_eq!(serialize(&5000u32), vec![136u8, 19, 0, 0]);
|
||||||
|
assert_eq!(serialize(&500000u32), vec![32u8, 161, 7, 0]);
|
||||||
|
assert_eq!(serialize(&168430090u32), vec![10u8, 10, 10, 10]);
|
||||||
|
// TODO: test negative numbers
|
||||||
|
assert_eq!(serialize(&1i32), vec![1u8, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&256i32), vec![0u8, 1, 0, 0]);
|
||||||
|
assert_eq!(serialize(&5000i32), vec![136u8, 19, 0, 0]);
|
||||||
|
assert_eq!(serialize(&500000i32), vec![32u8, 161, 7, 0]);
|
||||||
|
assert_eq!(serialize(&168430090i32), vec![10u8, 10, 10, 10]);
|
||||||
|
// u64
|
||||||
|
assert_eq!(serialize(&1u64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&256u64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&5000u64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&500000u64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&723401728380766730u64), vec![10u8, 10, 10, 10, 10, 10, 10, 10]);
|
||||||
|
// TODO: test negative numbers
|
||||||
|
assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&500000i64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(serialize(&723401728380766730i64), vec![10u8, 10, 10, 10, 10, 10, 10, 10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_varint_test() {
|
||||||
|
assert_eq!(serialize(&VarInt(10)), vec![10u8]);
|
||||||
|
assert_eq!(serialize(&VarInt(0xFC)), vec![0xFCu8]);
|
||||||
|
assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]);
|
||||||
|
assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]);
|
||||||
|
assert_eq!(serialize(&VarInt(0xF0F0F0F)), vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]);
|
||||||
|
assert_eq!(serialize(&VarInt(0xF0F0F0F0F0E0)), vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_nonminimal_vec() {
|
||||||
|
match deserialize::<Vec<u8>>(&[0xfd, 0x00, 0x00]) {
|
||||||
|
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||||
|
x => panic!(x)
|
||||||
|
}
|
||||||
|
match deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]) {
|
||||||
|
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||||
|
x => panic!(x)
|
||||||
|
}
|
||||||
|
match deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]) {
|
||||||
|
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||||
|
x => panic!(x)
|
||||||
|
}
|
||||||
|
match deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]) {
|
||||||
|
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||||
|
x => panic!(x)
|
||||||
|
}
|
||||||
|
match deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) {
|
||||||
|
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||||
|
x => panic!(x)
|
||||||
|
}
|
||||||
|
match deserialize::<Vec<u8>>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) {
|
||||||
|
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||||
|
x => panic!(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut vec_256 = vec![0; 259];
|
||||||
|
vec_256[0] = 0xfd;
|
||||||
|
vec_256[1] = 0x00;
|
||||||
|
vec_256[2] = 0x01;
|
||||||
|
assert!(deserialize::<Vec<u8>>(&vec_256).is_ok());
|
||||||
|
|
||||||
|
let mut vec_253 = vec![0; 256];
|
||||||
|
vec_253[0] = 0xfd;
|
||||||
|
vec_253[1] = 0xfd;
|
||||||
|
vec_253[2] = 0x00;
|
||||||
|
assert!(deserialize::<Vec<u8>>(&vec_253).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_checkeddata_test() {
|
||||||
|
let cd = CheckedData(vec![1u8, 2, 3, 4, 5]);
|
||||||
|
assert_eq!(serialize(&cd), vec![5, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_vector_test() {
|
||||||
|
assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]);
|
||||||
|
assert_eq!(serialize(&[1u8, 2, 3][..]), vec![3u8, 1, 2, 3]);
|
||||||
|
// TODO: test vectors of more interesting objects
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_strbuf_test() {
|
||||||
|
assert_eq!(serialize(&"Andrew".to_string()), vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_box_test() {
|
||||||
|
assert_eq!(serialize(&Box::new(1u8)), vec![1u8]);
|
||||||
|
assert_eq!(serialize(&Box::new(1u16)), vec![1u8, 0]);
|
||||||
|
assert_eq!(serialize(&Box::new(1u64)), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_option_test() {
|
||||||
|
assert_eq!(serialize(&None::<u8>), vec![0]);
|
||||||
|
assert_eq!(serialize(&Some(0xFFu8)), vec![1, 0xFF]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_int_test() {
|
||||||
|
// bool
|
||||||
|
assert!((deserialize(&[58u8, 0]) as Result<bool, _>).is_err());
|
||||||
|
assert_eq!(deserialize(&[58u8]).ok(), Some(true));
|
||||||
|
assert_eq!(deserialize(&[1u8]).ok(), Some(true));
|
||||||
|
assert_eq!(deserialize(&[0u8]).ok(), Some(false));
|
||||||
|
assert!((deserialize(&[0u8, 1]) as Result<bool, _>).is_err());
|
||||||
|
|
||||||
|
// u8
|
||||||
|
assert_eq!(deserialize(&[58u8]).ok(), Some(58u8));
|
||||||
|
|
||||||
|
// u16
|
||||||
|
assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16));
|
||||||
|
assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16));
|
||||||
|
assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16));
|
||||||
|
let failure16: Result<u16, _> = deserialize(&[1u8]);
|
||||||
|
assert!(failure16.is_err());
|
||||||
|
|
||||||
|
// u32
|
||||||
|
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32));
|
||||||
|
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(), Some(0xCDAB0DA0u32));
|
||||||
|
let failure32: Result<u32, _> = deserialize(&[1u8, 2, 3]);
|
||||||
|
assert!(failure32.is_err());
|
||||||
|
// TODO: test negative numbers
|
||||||
|
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32));
|
||||||
|
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(), Some(0x2DAB0DA0i32));
|
||||||
|
let failurei32: Result<i32, _> = deserialize(&[1u8, 2, 3]);
|
||||||
|
assert!(failurei32.is_err());
|
||||||
|
|
||||||
|
// u64
|
||||||
|
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABu64));
|
||||||
|
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(0x99000099CDAB0DA0u64));
|
||||||
|
let failure64: Result<u64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
||||||
|
assert!(failure64.is_err());
|
||||||
|
// TODO: test negative numbers
|
||||||
|
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABi64));
|
||||||
|
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(-0x66ffff663254f260i64));
|
||||||
|
let failurei64: Result<i64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
||||||
|
assert!(failurei64.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_vec_test() {
|
||||||
|
assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4]));
|
||||||
|
assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result<Vec<u8>, _>).is_err());
|
||||||
|
// found by cargo fuzz
|
||||||
|
assert!(deserialize::<Vec<u64>>(&[0xff,0xff,0xff,0xff,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0xa,0xa,0x3a]).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_strbuf_test() {
|
||||||
|
assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_checkeddata_test() {
|
||||||
|
let cd: Result<CheckedData, _> = deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]);
|
||||||
|
assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5])));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_option_test() {
|
||||||
|
let none: Result<Option<u8>, _> = deserialize(&[0u8]);
|
||||||
|
let good: Result<Option<u8>, _> = deserialize(&[1u8, 0xFF]);
|
||||||
|
let bad: Result<Option<u8>, _> = deserialize(&[2u8]);
|
||||||
|
assert!(bad.is_err());
|
||||||
|
assert_eq!(none.ok(), Some(None));
|
||||||
|
assert_eq!(good.ok(), Some(Some(0xFF)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_box_test() {
|
||||||
|
let zero: Result<Box<u8>, _> = deserialize(&[0u8]);
|
||||||
|
let one: Result<Box<u8>, _> = deserialize(&[1u8]);
|
||||||
|
assert_eq!(zero.ok(), Some(Box::new(0)));
|
||||||
|
assert_eq!(one.ok(), Some(Box::new(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Rust Bitcoin Library
|
||||||
|
// Written by
|
||||||
|
// The Rust Bitcoin developers
|
||||||
|
//
|
||||||
|
// To the extent possible under law, the author(s) have dedicated all
|
||||||
|
// copyright and related and neighboring rights to this software to
|
||||||
|
// the public domain worldwide. This software is distributed without
|
||||||
|
// any warranty.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the CC0 Public Domain Dedication
|
||||||
|
// along with this software.
|
||||||
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
//! Consensus
|
||||||
|
//!
|
||||||
|
//! This module defines structures, functions, and traits which are needed to
|
||||||
|
//! conform to Bitcoin consensus.
|
||||||
|
//!
|
||||||
|
|
||||||
|
pub mod encode;
|
||||||
|
pub mod params;
|
||||||
|
|
||||||
|
pub use self::encode::{Encodable, Decodable, Encoder, Decoder, serialize, deserialize};
|
||||||
|
pub use self::params::Params;
|
|
@ -44,7 +44,7 @@ const MAX_BITS_REGTEST: Uint256 = Uint256([
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
/// Parameters that influence chain consensus.
|
/// Parameters that influence chain consensus.
|
||||||
pub struct ConsensusParams {
|
pub struct Params {
|
||||||
/// Network for which parameters are valid.
|
/// Network for which parameters are valid.
|
||||||
pub network: Network,
|
pub network: Network,
|
||||||
/// Time when BIP16 becomes active.
|
/// Time when BIP16 becomes active.
|
||||||
|
@ -73,11 +73,11 @@ pub struct ConsensusParams {
|
||||||
pub no_pow_retargeting: bool,
|
pub no_pow_retargeting: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsensusParams {
|
impl Params {
|
||||||
/// Creates parameters set for the given network.
|
/// Creates parameters set for the given network.
|
||||||
pub fn new(network: Network) -> Self {
|
pub fn new(network: Network) -> Self {
|
||||||
match network {
|
match network {
|
||||||
Network::Bitcoin => ConsensusParams {
|
Network::Bitcoin => Params {
|
||||||
network: Network::Bitcoin,
|
network: Network::Bitcoin,
|
||||||
bip16_time: 1333238400, // Apr 1 2012
|
bip16_time: 1333238400, // Apr 1 2012
|
||||||
bip34_height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
|
bip34_height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
|
||||||
|
@ -91,7 +91,7 @@ impl ConsensusParams {
|
||||||
allow_min_difficulty_blocks: false,
|
allow_min_difficulty_blocks: false,
|
||||||
no_pow_retargeting: false,
|
no_pow_retargeting: false,
|
||||||
},
|
},
|
||||||
Network::Testnet => ConsensusParams {
|
Network::Testnet => Params {
|
||||||
network: Network::Testnet,
|
network: Network::Testnet,
|
||||||
bip16_time: 1333238400, // Apr 1 2012
|
bip16_time: 1333238400, // Apr 1 2012
|
||||||
bip34_height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
|
bip34_height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
|
||||||
|
@ -105,7 +105,7 @@ impl ConsensusParams {
|
||||||
allow_min_difficulty_blocks: true,
|
allow_min_difficulty_blocks: true,
|
||||||
no_pow_retargeting: false,
|
no_pow_retargeting: false,
|
||||||
},
|
},
|
||||||
Network::Regtest => ConsensusParams {
|
Network::Regtest => Params {
|
||||||
network: Network::Regtest,
|
network: Network::Regtest,
|
||||||
bip16_time: 1333238400, // Apr 1 2012
|
bip16_time: 1333238400, // Apr 1 2012
|
||||||
bip34_height: 100000000, // not activated on regtest
|
bip34_height: 100000000, // not activated on regtest
|
|
@ -14,20 +14,20 @@
|
||||||
|
|
||||||
macro_rules! impl_consensus_encoding {
|
macro_rules! impl_consensus_encoding {
|
||||||
($thing:ident, $($field:ident),+) => (
|
($thing:ident, $($field:ident),+) => (
|
||||||
impl<S: ::network::serialize::SimpleEncoder> ::network::encodable::ConsensusEncodable<S> for $thing {
|
impl<S: ::consensus::encode::Encoder> ::consensus::encode::Encodable<S> for $thing {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), ::network::serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), ::consensus::encode::Error> {
|
||||||
$( self.$field.consensus_encode(s)?; )+
|
$( self.$field.consensus_encode(s)?; )+
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: ::network::serialize::SimpleDecoder> ::network::encodable::ConsensusDecodable<D> for $thing {
|
impl<D: ::consensus::encode::Decoder> ::consensus::encode::Decodable<D> for $thing {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<$thing, ::network::serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<$thing, ::consensus::encode::Error> {
|
||||||
use network::encodable::ConsensusDecodable;
|
use consensus::encode::Decodable;
|
||||||
Ok($thing {
|
Ok($thing {
|
||||||
$( $field: ConsensusDecodable::consensus_decode(d)?, )+
|
$( $field: Decodable::consensus_decode(d)?, )+
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,18 +36,18 @@ macro_rules! impl_consensus_encoding {
|
||||||
|
|
||||||
macro_rules! impl_newtype_consensus_encoding {
|
macro_rules! impl_newtype_consensus_encoding {
|
||||||
($thing:ident) => (
|
($thing:ident) => (
|
||||||
impl<S: ::network::serialize::SimpleEncoder> ::network::encodable::ConsensusEncodable<S> for $thing {
|
impl<S: ::consensus::encode::Encoder> ::consensus::encode::Encodable<S> for $thing {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), ::network::serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), ::consensus::encode::Error> {
|
||||||
let &$thing(ref data) = self;
|
let &$thing(ref data) = self;
|
||||||
data.consensus_encode(s)
|
data.consensus_encode(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: ::network::serialize::SimpleDecoder> ::network::encodable::ConsensusDecodable<D> for $thing {
|
impl<D: ::consensus::encode::Decoder> ::consensus::encode::Decodable<D> for $thing {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<$thing, ::network::serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<$thing, ::consensus::encode::Error> {
|
||||||
Ok($thing(ConsensusDecodable::consensus_decode(d)?))
|
Ok($thing(Decodable::consensus_decode(d)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -62,6 +62,7 @@ pub mod macros;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod blockdata;
|
pub mod blockdata;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
pub mod consensus;
|
||||||
|
|
||||||
pub use blockdata::block::Block;
|
pub use blockdata::block::Block;
|
||||||
pub use blockdata::block::BlockHeader;
|
pub use blockdata::block::BlockHeader;
|
||||||
|
@ -71,11 +72,10 @@ pub use blockdata::transaction::TxIn;
|
||||||
pub use blockdata::transaction::TxOut;
|
pub use blockdata::transaction::TxOut;
|
||||||
pub use blockdata::transaction::OutPoint;
|
pub use blockdata::transaction::OutPoint;
|
||||||
pub use blockdata::transaction::SigHashType;
|
pub use blockdata::transaction::SigHashType;
|
||||||
pub use network::encodable::VarInt;
|
pub use consensus::encode::VarInt;
|
||||||
pub use network::serialize::BitcoinHash;
|
|
||||||
pub use util::Error;
|
pub use util::Error;
|
||||||
pub use util::address::Address;
|
pub use util::address::Address;
|
||||||
|
pub use util::hash::BitcoinHash;
|
||||||
pub use util::privkey::Privkey;
|
pub use util::privkey::Privkey;
|
||||||
pub use util::decimal::Decimal;
|
pub use util::decimal::Decimal;
|
||||||
pub use util::decimal::UDecimal;
|
pub use util::decimal::UDecimal;
|
||||||
|
|
||||||
|
|
|
@ -16,71 +16,6 @@
|
||||||
//!
|
//!
|
||||||
//! Macros available to users of the Bitcoin library
|
//! Macros available to users of the Bitcoin library
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! nu_select {
|
|
||||||
($($name:pat = $rx:expr => $code:expr),+) => ({
|
|
||||||
nu_select!{ $($name = $rx, recv => $code),+ }
|
|
||||||
});
|
|
||||||
($($name:pat = $rx:expr, $meth:ident => $code:expr),+) => ({
|
|
||||||
use rustrt::local::Local;
|
|
||||||
use rustrt::task::Task;
|
|
||||||
use sync::comm::Packet;
|
|
||||||
|
|
||||||
// Is anything already ready to receive? Grab it without waiting.
|
|
||||||
$(
|
|
||||||
if (&$rx as &Packet).can_recv() {
|
|
||||||
let $name = $rx.$meth();
|
|
||||||
$code
|
|
||||||
}
|
|
||||||
)else+
|
|
||||||
else {
|
|
||||||
// Start selecting on as many as we need to before getting a bite.
|
|
||||||
// Keep count of how many, since we need to abort every selection
|
|
||||||
// that we started.
|
|
||||||
let mut started_count = 0;
|
|
||||||
// Restrict lifetime of borrows in `packets`
|
|
||||||
{
|
|
||||||
let packets = [ $( &$rx as &Packet, )+ ];
|
|
||||||
|
|
||||||
let task: Box<Task> = Local::take();
|
|
||||||
task.deschedule(packets.len(), |task| {
|
|
||||||
match packets[started_count].start_selection(task) {
|
|
||||||
Ok(()) => {
|
|
||||||
started_count += 1;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(task) => Err(task)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
let ret = $(
|
|
||||||
// Abort the receivers, stopping at the first ready one to get its data.
|
|
||||||
if { i += 1; i <= started_count } &&
|
|
||||||
// If start_selection() failed, abort_selection() will fail too,
|
|
||||||
// but it still counts as "data available".
|
|
||||||
($rx.abort_selection() || i == started_count) {
|
|
||||||
// React to the first
|
|
||||||
let $name = $rx.$meth();
|
|
||||||
$code
|
|
||||||
})else+
|
|
||||||
else {
|
|
||||||
fail!("we didn't find the ready receiver, but we should have had one");
|
|
||||||
};
|
|
||||||
// At this point, the first i receivers have been aborted. We need to abort the rest:
|
|
||||||
$(if i > 0 {
|
|
||||||
i -= 1;
|
|
||||||
} else {
|
|
||||||
$rx.abort_selection();
|
|
||||||
})+
|
|
||||||
let _ = i; // Shut up `i -= 1 but i is never read` warning
|
|
||||||
// Return
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! user_enum {
|
macro_rules! user_enum {
|
||||||
(
|
(
|
||||||
|
|
|
@ -22,8 +22,8 @@ use std::io;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||||
|
|
||||||
use network::serialize::{self, SimpleEncoder, SimpleDecoder};
|
use consensus::encode::{self, Encoder, Decoder};
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
|
|
||||||
/// A message which can be sent on the Bitcoin network
|
/// A message which can be sent on the Bitcoin network
|
||||||
pub struct Address {
|
pub struct Address {
|
||||||
|
@ -72,22 +72,22 @@ fn addr_to_be(addr: [u16; 8]) -> [u16; 8] {
|
||||||
addr[4].to_be(), addr[5].to_be(), addr[6].to_be(), addr[7].to_be()]
|
addr[4].to_be(), addr[5].to_be(), addr[6].to_be(), addr[7].to_be()]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for Address {
|
impl<S: Encoder> Encodable<S> for Address {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
self.services.consensus_encode(s)?;
|
self.services.consensus_encode(s)?;
|
||||||
addr_to_be(self.address).consensus_encode(s)?;
|
addr_to_be(self.address).consensus_encode(s)?;
|
||||||
self.port.to_be().consensus_encode(s)
|
self.port.to_be().consensus_encode(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for Address {
|
impl<D: Decoder> Decodable<D> for Address {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<Address, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<Address, encode::Error> {
|
||||||
Ok(Address {
|
Ok(Address {
|
||||||
services: ConsensusDecodable::consensus_decode(d)?,
|
services: Decodable::consensus_decode(d)?,
|
||||||
address: addr_to_be(ConsensusDecodable::consensus_decode(d)?),
|
address: addr_to_be(Decodable::consensus_decode(d)?),
|
||||||
port: u16::from_be(ConsensusDecodable::consensus_decode(d)?)
|
port: u16::from_be(Decodable::consensus_decode(d)?)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ mod test {
|
||||||
use super::Address;
|
use super::Address;
|
||||||
use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
|
use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_address_test() {
|
fn serialize_address_test() {
|
||||||
|
@ -134,9 +134,9 @@ mod test {
|
||||||
services: 1,
|
services: 1,
|
||||||
address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001],
|
address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001],
|
||||||
port: 8333
|
port: 8333
|
||||||
}).ok(),
|
}),
|
||||||
Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1, 0x20, 0x8d]));
|
0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1, 0x20, 0x8d]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -17,28 +17,28 @@
|
||||||
//! This module provides various constants relating to the Bitcoin network
|
//! This module provides various constants relating to the Bitcoin network
|
||||||
//! protocol, such as protocol versioning and magic header bytes.
|
//! protocol, such as protocol versioning and magic header bytes.
|
||||||
//!
|
//!
|
||||||
//! The [`Network`][1] type implements the [`ConsensusDecodable`][2] and
|
//! The [`Network`][1] type implements the [`Decodable`][2] and
|
||||||
//! [`ConsensusEncodable`][3] and encodes the magic bytes of the given
|
//! [`Encodable`][3] traits and encodes the magic bytes of the given
|
||||||
//! network
|
//! network
|
||||||
//!
|
//!
|
||||||
//! [1]: enum.Network.html
|
//! [1]: enum.Network.html
|
||||||
//! [2]: ../encodable/trait.ConsensusDecodable.html
|
//! [2]: ../../consensus/encode/trait.Decodable.html
|
||||||
//! [3]: ../encodable/trait.ConsensusEncodable.html
|
//! [3]: ../../consensus/encode/trait.Encodable.html
|
||||||
//!
|
//!
|
||||||
//! # Example: encoding a network's magic bytes
|
//! # Example: encoding a network's magic bytes
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use bitcoin::network::constants::Network;
|
//! use bitcoin::network::constants::Network;
|
||||||
//! use bitcoin::network::serialize::serialize;
|
//! use bitcoin::consensus::encode::serialize;
|
||||||
//!
|
//!
|
||||||
//! let network = Network::Bitcoin;
|
//! let network = Network::Bitcoin;
|
||||||
//! let bytes = serialize(&network).unwrap();
|
//! let bytes = serialize(&network);
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
|
//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
use network::serialize::{self, SimpleEncoder, SimpleDecoder};
|
use consensus::encode::{self, Encoder, Decoder};
|
||||||
|
|
||||||
/// Version of the protocol as appearing in network message headers
|
/// Version of the protocol as appearing in network message headers
|
||||||
pub const PROTOCOL_VERSION: u32 = 70001;
|
pub const PROTOCOL_VERSION: u32 = 70001;
|
||||||
|
@ -102,22 +102,22 @@ impl Network {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for Network {
|
impl<S: Encoder> Encodable<S> for Network {
|
||||||
/// Encodes the magic bytes of `Network`.
|
/// Encodes the magic bytes of `Network`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
self.magic().consensus_encode(s)
|
self.magic().consensus_encode(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for Network {
|
impl<D: Decoder> Decodable<D> for Network {
|
||||||
/// Decodes the magic bytes of `Network`.
|
/// Decodes the magic bytes of `Network`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<Network, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<Network, encode::Error> {
|
||||||
u32::consensus_decode(d)
|
u32::consensus_decode(d)
|
||||||
.and_then(|m| {
|
.and_then(|m| {
|
||||||
Network::from_magic(m)
|
Network::from_magic(m)
|
||||||
.ok_or(serialize::Error::UnknownNetworkMagic(m))
|
.ok_or(encode::Error::UnknownNetworkMagic(m))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,13 +125,13 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Network {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Network;
|
use super::Network;
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_test() {
|
fn serialize_test() {
|
||||||
assert_eq!(serialize(&Network::Bitcoin).unwrap(), vec![0xf9, 0xbe, 0xb4, 0xd9]);
|
assert_eq!(serialize(&Network::Bitcoin), vec![0xf9, 0xbe, 0xb4, 0xd9]);
|
||||||
assert_eq!(serialize(&Network::Testnet).unwrap(), vec![0x0b, 0x11, 0x09, 0x07]);
|
assert_eq!(serialize(&Network::Testnet), vec![0x0b, 0x11, 0x09, 0x07]);
|
||||||
assert_eq!(serialize(&Network::Regtest).unwrap(), vec![0xfa, 0xbf, 0xb5, 0xda]);
|
assert_eq!(serialize(&Network::Regtest), vec![0xfa, 0xbf, 0xb5, 0xda]);
|
||||||
|
|
||||||
assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin));
|
assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin));
|
||||||
assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet));
|
assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet));
|
||||||
|
|
|
@ -1,612 +0,0 @@
|
||||||
// Rust Bitcoin Library
|
|
||||||
// Written in 2014 by
|
|
||||||
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
|
||||||
//
|
|
||||||
// To the extent possible under law, the author(s) have dedicated all
|
|
||||||
// copyright and related and neighboring rights to this software to
|
|
||||||
// the public domain worldwide. This software is distributed without
|
|
||||||
// any warranty.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the CC0 Public Domain Dedication
|
|
||||||
// along with this software.
|
|
||||||
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//! Consensus-encodable types
|
|
||||||
//!
|
|
||||||
//! This is basically a replacement of the `Encodable` trait which does
|
|
||||||
//! normalization for endianness, etc., to ensure that the encoding
|
|
||||||
//! matches for endianness, etc., to ensure that the encoding matches
|
|
||||||
//! the network consensus encoding.
|
|
||||||
//!
|
|
||||||
//! Essentially, anything that must go on the -disk- or -network- must
|
|
||||||
//! be encoded using the `ConsensusEncodable` trait, since this data
|
|
||||||
//! must be the same for all systems. Any data going to the -user-, e.g.
|
|
||||||
//! over JSONRPC, should use the ordinary `Encodable` trait. (This
|
|
||||||
//! should also be the same across systems, of course, but has some
|
|
||||||
//! critical differences from the network format, e.g. scripts come
|
|
||||||
//! with an opcode decode, hashes are big-endian, numbers are typically
|
|
||||||
//! big-endian decimals, etc.)
|
|
||||||
//!
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::hash::Hash;
|
|
||||||
use std::{mem, u32};
|
|
||||||
|
|
||||||
use util::hash::Sha256dHash;
|
|
||||||
use network::serialize::{self, SimpleDecoder, SimpleEncoder};
|
|
||||||
|
|
||||||
/// Maximum size, in bytes, of a vector we are allowed to decode
|
|
||||||
pub const MAX_VEC_SIZE: usize = 32 * 1024 * 1024;
|
|
||||||
|
|
||||||
/// Data which can be encoded in a consensus-consistent way
|
|
||||||
pub trait ConsensusEncodable<S: SimpleEncoder> {
|
|
||||||
/// Encode an object with a well-defined format
|
|
||||||
fn consensus_encode(&self, e: &mut S) -> Result<(), serialize::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Data which can be encoded in a consensus-consistent way
|
|
||||||
pub trait ConsensusDecodable<D: SimpleDecoder>: Sized {
|
|
||||||
/// Decode an object with a well-defined format
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<Self, serialize::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A variable-length unsigned integer
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
|
|
||||||
pub struct VarInt(pub u64);
|
|
||||||
|
|
||||||
/// Data which must be preceded by a 4-byte checksum
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
|
||||||
pub struct CheckedData(pub Vec<u8>);
|
|
||||||
|
|
||||||
// Primitive types
|
|
||||||
macro_rules! impl_int_encodable{
|
|
||||||
($ty:ident, $meth_dec:ident, $meth_enc:ident) => (
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for $ty {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<$ty, serialize::Error> { d.$meth_dec().map($ty::from_le) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for $ty {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { s.$meth_enc(self.to_le()) }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_int_encodable!(u8, read_u8, emit_u8);
|
|
||||||
impl_int_encodable!(u16, read_u16, emit_u16);
|
|
||||||
impl_int_encodable!(u32, read_u32, emit_u32);
|
|
||||||
impl_int_encodable!(u64, read_u64, emit_u64);
|
|
||||||
impl_int_encodable!(i8, read_i8, emit_i8);
|
|
||||||
impl_int_encodable!(i16, read_i16, emit_i16);
|
|
||||||
impl_int_encodable!(i32, read_i32, emit_i32);
|
|
||||||
impl_int_encodable!(i64, read_i64, emit_i64);
|
|
||||||
|
|
||||||
impl VarInt {
|
|
||||||
/// Gets the length of this VarInt when encoded.
|
|
||||||
/// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1),
|
|
||||||
/// and 9 otherwise.
|
|
||||||
#[inline]
|
|
||||||
pub fn encoded_length(&self) -> u64 {
|
|
||||||
match self.0 {
|
|
||||||
0...0xFC => { 1 }
|
|
||||||
0xFD...0xFFFF => { 3 }
|
|
||||||
0x10000...0xFFFFFFFF => { 5 }
|
|
||||||
_ => { 9 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for VarInt {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
match self.0 {
|
|
||||||
0...0xFC => { (self.0 as u8).consensus_encode(s) }
|
|
||||||
0xFD...0xFFFF => { s.emit_u8(0xFD)?; (self.0 as u16).consensus_encode(s) }
|
|
||||||
0x10000...0xFFFFFFFF => { s.emit_u8(0xFE)?; (self.0 as u32).consensus_encode(s) }
|
|
||||||
_ => { s.emit_u8(0xFF)?; (self.0 as u64).consensus_encode(s) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for VarInt {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<VarInt, serialize::Error> {
|
|
||||||
let n = d.read_u8()?;
|
|
||||||
match n {
|
|
||||||
0xFF => {
|
|
||||||
let x = d.read_u64()?;
|
|
||||||
if x < 0x100000000 {
|
|
||||||
Err(serialize::Error::ParseFailed("non-minimal varint"))
|
|
||||||
} else {
|
|
||||||
Ok(VarInt(x))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0xFE => {
|
|
||||||
let x = d.read_u32()?;
|
|
||||||
if x < 0x10000 {
|
|
||||||
Err(serialize::Error::ParseFailed("non-minimal varint"))
|
|
||||||
} else {
|
|
||||||
Ok(VarInt(x as u64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0xFD => {
|
|
||||||
let x = d.read_u16()?;
|
|
||||||
if x < 0xFD {
|
|
||||||
Err(serialize::Error::ParseFailed("non-minimal varint"))
|
|
||||||
} else {
|
|
||||||
Ok(VarInt(x as u64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n => Ok(VarInt(n as u64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Booleans
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for bool {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { s.emit_u8(if *self {1} else {0}) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for bool {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<bool, serialize::Error> { d.read_u8().map(|n| n != 0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strings
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for String {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
self.as_bytes().consensus_encode(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for String {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<String, serialize::Error> {
|
|
||||||
String::from_utf8(ConsensusDecodable::consensus_decode(d)?)
|
|
||||||
.map_err(|_| serialize::Error::ParseFailed("String was not valid UTF8"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Arrays
|
|
||||||
macro_rules! impl_array {
|
|
||||||
( $size:expr ) => (
|
|
||||||
impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for [T; $size] {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
for i in self.iter() { i.consensus_encode(s)?; }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder, T:ConsensusDecodable<D> + Copy> ConsensusDecodable<D> for [T; $size] {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<[T; $size], serialize::Error> {
|
|
||||||
// Set everything to the first decode
|
|
||||||
let mut ret = [ConsensusDecodable::consensus_decode(d)?; $size];
|
|
||||||
// Set the rest
|
|
||||||
for item in ret.iter_mut().take($size).skip(1) { *item = ConsensusDecodable::consensus_decode(d)?; }
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_array!(2);
|
|
||||||
impl_array!(4);
|
|
||||||
impl_array!(8);
|
|
||||||
impl_array!(12);
|
|
||||||
impl_array!(16);
|
|
||||||
impl_array!(32);
|
|
||||||
|
|
||||||
impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for [T] {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
VarInt(self.len() as u64).consensus_encode(s)?;
|
|
||||||
for c in self.iter() { c.consensus_encode(s)?; }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot decode a slice
|
|
||||||
|
|
||||||
// Vectors
|
|
||||||
impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for Vec<T> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { (&self[..]).consensus_encode(s) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Vec<T> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<Vec<T>, serialize::Error> {
|
|
||||||
let len = VarInt::consensus_decode(d)?.0;
|
|
||||||
let byte_size = (len as usize)
|
|
||||||
.checked_mul(mem::size_of::<T>())
|
|
||||||
.ok_or(serialize::Error::ParseFailed("Invalid length"))?;
|
|
||||||
if byte_size > MAX_VEC_SIZE {
|
|
||||||
return Err(serialize::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE })
|
|
||||||
}
|
|
||||||
let mut ret = Vec::with_capacity(len as usize);
|
|
||||||
for _ in 0..len { ret.push(ConsensusDecodable::consensus_decode(d)?); }
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for Box<[T]> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { (&self[..]).consensus_encode(s) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Box<[T]> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<Box<[T]>, serialize::Error> {
|
|
||||||
let len = VarInt::consensus_decode(d)?.0;
|
|
||||||
let len = len as usize;
|
|
||||||
if len > MAX_VEC_SIZE {
|
|
||||||
return Err(serialize::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE })
|
|
||||||
}
|
|
||||||
let mut ret = Vec::with_capacity(len);
|
|
||||||
for _ in 0..len { ret.push(ConsensusDecodable::consensus_decode(d)?); }
|
|
||||||
Ok(ret.into_boxed_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options (encoded as vectors of length 0 or 1)
|
|
||||||
impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for Option<T> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
match *self {
|
|
||||||
Some(ref data) => {
|
|
||||||
1u8.consensus_encode(s)?;
|
|
||||||
data.consensus_encode(s)?;
|
|
||||||
}
|
|
||||||
None => { 0u8.consensus_encode(s)?; }
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder, T:ConsensusDecodable<D>> ConsensusDecodable<D> for Option<T> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<Option<T>, serialize::Error> {
|
|
||||||
let bit: u8 = ConsensusDecodable::consensus_decode(d)?;
|
|
||||||
Ok(if bit != 0 {
|
|
||||||
Some(ConsensusDecodable::consensus_decode(d)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Do a double-SHA256 on some data and return the first 4 bytes
|
|
||||||
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
|
||||||
let checksum = Sha256dHash::from_data(data);
|
|
||||||
[checksum[0], checksum[1], checksum[2], checksum[3]]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checked data
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for CheckedData {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
(self.0.len() as u32).consensus_encode(s)?;
|
|
||||||
sha2_checksum(&self.0).consensus_encode(s)?;
|
|
||||||
// We can't just pass to the slice encoder since it'll insert a length
|
|
||||||
for ch in &self.0 {
|
|
||||||
ch.consensus_encode(s)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for CheckedData {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<CheckedData, serialize::Error> {
|
|
||||||
let len: u32 = ConsensusDecodable::consensus_decode(d)?;
|
|
||||||
let checksum: [u8; 4] = ConsensusDecodable::consensus_decode(d)?;
|
|
||||||
let mut ret = Vec::with_capacity(len as usize);
|
|
||||||
for _ in 0..len { ret.push(ConsensusDecodable::consensus_decode(d)?); }
|
|
||||||
let expected_checksum = sha2_checksum(&ret);
|
|
||||||
if expected_checksum != checksum {
|
|
||||||
Err(serialize::Error::InvalidChecksum {
|
|
||||||
expected: expected_checksum,
|
|
||||||
actual: checksum,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(CheckedData(ret))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tuples
|
|
||||||
macro_rules! tuple_encode {
|
|
||||||
($($x:ident),*) => (
|
|
||||||
impl <S: SimpleEncoder, $($x: ConsensusEncodable<S>),*> ConsensusEncodable<S> for ($($x),*) {
|
|
||||||
#[inline]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
let &($(ref $x),*) = self;
|
|
||||||
$( $x.consensus_encode(s)?; )*
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder, $($x: ConsensusDecodable<D>),*> ConsensusDecodable<D> for ($($x),*) {
|
|
||||||
#[inline]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<($($x),*), serialize::Error> {
|
|
||||||
Ok(($({let $x = ConsensusDecodable::consensus_decode(d)?; $x }),*))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple_encode!(T0, T1);
|
|
||||||
tuple_encode!(T0, T1, T2, T3);
|
|
||||||
tuple_encode!(T0, T1, T2, T3, T4, T5);
|
|
||||||
tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
|
|
||||||
|
|
||||||
// References
|
|
||||||
impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for Box<T> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { (**self).consensus_encode(s) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Box<T> {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<Box<T>, serialize::Error> {
|
|
||||||
ConsensusDecodable::consensus_decode(d).map(Box::new)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HashMap
|
|
||||||
impl<S, K, V> ConsensusEncodable<S> for HashMap<K, V>
|
|
||||||
where S: SimpleEncoder,
|
|
||||||
K: ConsensusEncodable<S> + Eq + Hash,
|
|
||||||
V: ConsensusEncodable<S>
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
|
||||||
VarInt(self.len() as u64).consensus_encode(s)?;
|
|
||||||
for (key, value) in self.iter() {
|
|
||||||
key.consensus_encode(s)?;
|
|
||||||
value.consensus_encode(s)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D, K, V> ConsensusDecodable<D> for HashMap<K, V>
|
|
||||||
where D: SimpleDecoder,
|
|
||||||
K: ConsensusDecodable<D> + Eq + Hash,
|
|
||||||
V: ConsensusDecodable<D>
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn consensus_decode(d: &mut D) -> Result<HashMap<K, V>, serialize::Error> {
|
|
||||||
let len = VarInt::consensus_decode(d)?.0;
|
|
||||||
|
|
||||||
let mut ret = HashMap::with_capacity(len as usize);
|
|
||||||
for _ in 0..len {
|
|
||||||
ret.insert(ConsensusDecodable::consensus_decode(d)?,
|
|
||||||
ConsensusDecodable::consensus_decode(d)?);
|
|
||||||
}
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Tests
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{CheckedData, VarInt};
|
|
||||||
|
|
||||||
use network::serialize::{deserialize, serialize, Error};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_int_test() {
|
|
||||||
// bool
|
|
||||||
assert_eq!(serialize(&false).ok(), Some(vec![0u8]));
|
|
||||||
assert_eq!(serialize(&true).ok(), Some(vec![1u8]));
|
|
||||||
// u8
|
|
||||||
assert_eq!(serialize(&1u8).ok(), Some(vec![1u8]));
|
|
||||||
assert_eq!(serialize(&0u8).ok(), Some(vec![0u8]));
|
|
||||||
assert_eq!(serialize(&255u8).ok(), Some(vec![255u8]));
|
|
||||||
// u16
|
|
||||||
assert_eq!(serialize(&1u16).ok(), Some(vec![1u8, 0]));
|
|
||||||
assert_eq!(serialize(&256u16).ok(), Some(vec![0u8, 1]));
|
|
||||||
assert_eq!(serialize(&5000u16).ok(), Some(vec![136u8, 19]));
|
|
||||||
// u32
|
|
||||||
assert_eq!(serialize(&1u32).ok(), Some(vec![1u8, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&256u32).ok(), Some(vec![0u8, 1, 0, 0]));
|
|
||||||
assert_eq!(serialize(&5000u32).ok(), Some(vec![136u8, 19, 0, 0]));
|
|
||||||
assert_eq!(serialize(&500000u32).ok(), Some(vec![32u8, 161, 7, 0]));
|
|
||||||
assert_eq!(serialize(&168430090u32).ok(), Some(vec![10u8, 10, 10, 10]));
|
|
||||||
// TODO: test negative numbers
|
|
||||||
assert_eq!(serialize(&1i32).ok(), Some(vec![1u8, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&256i32).ok(), Some(vec![0u8, 1, 0, 0]));
|
|
||||||
assert_eq!(serialize(&5000i32).ok(), Some(vec![136u8, 19, 0, 0]));
|
|
||||||
assert_eq!(serialize(&500000i32).ok(), Some(vec![32u8, 161, 7, 0]));
|
|
||||||
assert_eq!(serialize(&168430090i32).ok(), Some(vec![10u8, 10, 10, 10]));
|
|
||||||
// u64
|
|
||||||
assert_eq!(serialize(&1u64).ok(), Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&256u64).ok(), Some(vec![0u8, 1, 0, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&5000u64).ok(), Some(vec![136u8, 19, 0, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&500000u64).ok(), Some(vec![32u8, 161, 7, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&723401728380766730u64).ok(), Some(vec![10u8, 10, 10, 10, 10, 10, 10, 10]));
|
|
||||||
// TODO: test negative numbers
|
|
||||||
assert_eq!(serialize(&1i64).ok(), Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&256i64).ok(), Some(vec![0u8, 1, 0, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&5000i64).ok(), Some(vec![136u8, 19, 0, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&500000i64).ok(), Some(vec![32u8, 161, 7, 0, 0, 0, 0, 0]));
|
|
||||||
assert_eq!(serialize(&723401728380766730i64).ok(), Some(vec![10u8, 10, 10, 10, 10, 10, 10, 10]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_varint_test() {
|
|
||||||
assert_eq!(serialize(&VarInt(10)).ok(), Some(vec![10u8]));
|
|
||||||
assert_eq!(serialize(&VarInt(0xFC)).ok(), Some(vec![0xFCu8]));
|
|
||||||
assert_eq!(serialize(&VarInt(0xFD)).ok(), Some(vec![0xFDu8, 0xFD, 0]));
|
|
||||||
assert_eq!(serialize(&VarInt(0xFFF)).ok(), Some(vec![0xFDu8, 0xFF, 0xF]));
|
|
||||||
assert_eq!(serialize(&VarInt(0xF0F0F0F)).ok(), Some(vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]));
|
|
||||||
assert_eq!(serialize(&VarInt(0xF0F0F0F0F0E0)).ok(), Some(vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_nonminimal_vec() {
|
|
||||||
match deserialize::<Vec<u8>>(&[0xfd, 0x00, 0x00]) {
|
|
||||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
|
||||||
x => panic!(x)
|
|
||||||
}
|
|
||||||
match deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]) {
|
|
||||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
|
||||||
x => panic!(x)
|
|
||||||
}
|
|
||||||
match deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]) {
|
|
||||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
|
||||||
x => panic!(x)
|
|
||||||
}
|
|
||||||
match deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]) {
|
|
||||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
|
||||||
x => panic!(x)
|
|
||||||
}
|
|
||||||
match deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) {
|
|
||||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
|
||||||
x => panic!(x)
|
|
||||||
}
|
|
||||||
match deserialize::<Vec<u8>>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) {
|
|
||||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
|
||||||
x => panic!(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut vec_256 = vec![0; 259];
|
|
||||||
vec_256[0] = 0xfd;
|
|
||||||
vec_256[1] = 0x00;
|
|
||||||
vec_256[2] = 0x01;
|
|
||||||
assert!(deserialize::<Vec<u8>>(&vec_256).is_ok());
|
|
||||||
|
|
||||||
let mut vec_253 = vec![0; 256];
|
|
||||||
vec_253[0] = 0xfd;
|
|
||||||
vec_253[1] = 0xfd;
|
|
||||||
vec_253[2] = 0x00;
|
|
||||||
assert!(deserialize::<Vec<u8>>(&vec_253).is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_checkeddata_test() {
|
|
||||||
let cd = CheckedData(vec![1u8, 2, 3, 4, 5]);
|
|
||||||
assert_eq!(serialize(&cd).ok(), Some(vec![5, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_vector_test() {
|
|
||||||
assert_eq!(serialize(&vec![1u8, 2, 3]).ok(), Some(vec![3u8, 1, 2, 3]));
|
|
||||||
assert_eq!(serialize(&[1u8, 2, 3][..]).ok(), Some(vec![3u8, 1, 2, 3]));
|
|
||||||
// TODO: test vectors of more interesting objects
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_strbuf_test() {
|
|
||||||
assert_eq!(serialize(&"Andrew".to_string()).ok(), Some(vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_box_test() {
|
|
||||||
assert_eq!(serialize(&Box::new(1u8)).ok(), Some(vec![1u8]));
|
|
||||||
assert_eq!(serialize(&Box::new(1u16)).ok(), Some(vec![1u8, 0]));
|
|
||||||
assert_eq!(serialize(&Box::new(1u64)).ok(), Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_option_test() {
|
|
||||||
let none_ser = serialize(&None::<u8>);
|
|
||||||
let some_ser = serialize(&Some(0xFFu8));
|
|
||||||
assert_eq!(none_ser.ok(), Some(vec![0]));
|
|
||||||
assert_eq!(some_ser.ok(), Some(vec![1, 0xFF]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_int_test() {
|
|
||||||
// bool
|
|
||||||
assert!((deserialize(&[58u8, 0]) as Result<bool, _>).is_err());
|
|
||||||
assert_eq!(deserialize(&[58u8]).ok(), Some(true));
|
|
||||||
assert_eq!(deserialize(&[1u8]).ok(), Some(true));
|
|
||||||
assert_eq!(deserialize(&[0u8]).ok(), Some(false));
|
|
||||||
assert!((deserialize(&[0u8, 1]) as Result<bool, _>).is_err());
|
|
||||||
|
|
||||||
// u8
|
|
||||||
assert_eq!(deserialize(&[58u8]).ok(), Some(58u8));
|
|
||||||
|
|
||||||
// u16
|
|
||||||
assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16));
|
|
||||||
assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16));
|
|
||||||
assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16));
|
|
||||||
let failure16: Result<u16, _> = deserialize(&[1u8]);
|
|
||||||
assert!(failure16.is_err());
|
|
||||||
|
|
||||||
// u32
|
|
||||||
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32));
|
|
||||||
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(), Some(0xCDAB0DA0u32));
|
|
||||||
let failure32: Result<u32, _> = deserialize(&[1u8, 2, 3]);
|
|
||||||
assert!(failure32.is_err());
|
|
||||||
// TODO: test negative numbers
|
|
||||||
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32));
|
|
||||||
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(), Some(0x2DAB0DA0i32));
|
|
||||||
let failurei32: Result<i32, _> = deserialize(&[1u8, 2, 3]);
|
|
||||||
assert!(failurei32.is_err());
|
|
||||||
|
|
||||||
// u64
|
|
||||||
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABu64));
|
|
||||||
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(0x99000099CDAB0DA0u64));
|
|
||||||
let failure64: Result<u64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
|
||||||
assert!(failure64.is_err());
|
|
||||||
// TODO: test negative numbers
|
|
||||||
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABi64));
|
|
||||||
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(-0x66ffff663254f260i64));
|
|
||||||
let failurei64: Result<i64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
|
||||||
assert!(failurei64.is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_vec_test() {
|
|
||||||
assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4]));
|
|
||||||
assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result<Vec<u8>, _>).is_err());
|
|
||||||
// found by cargo fuzz
|
|
||||||
assert!(deserialize::<Vec<u64>>(&[0xff,0xff,0xff,0xff,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0xa,0xa,0x3a]).is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_strbuf_test() {
|
|
||||||
assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_checkeddata_test() {
|
|
||||||
let cd: Result<CheckedData, _> = deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]);
|
|
||||||
assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5])));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_option_test() {
|
|
||||||
let none: Result<Option<u8>, _> = deserialize(&[0u8]);
|
|
||||||
let good: Result<Option<u8>, _> = deserialize(&[1u8, 0xFF]);
|
|
||||||
let bad: Result<Option<u8>, _> = deserialize(&[2u8]);
|
|
||||||
assert!(bad.is_err());
|
|
||||||
assert_eq!(none.ok(), Some(None));
|
|
||||||
assert_eq!(good.ok(), Some(Some(0xFF)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_box_test() {
|
|
||||||
let zero: Result<Box<u8>, _> = deserialize(&[0u8]);
|
|
||||||
let one: Result<Box<u8>, _> = deserialize(&[1u8]);
|
|
||||||
assert_eq!(zero.ok(), Some(Box::new(0)));
|
|
||||||
assert_eq!(one.ok(), Some(Box::new(1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
// Rust Bitcoin Library
|
|
||||||
// Written in 2014 by
|
|
||||||
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
|
||||||
//
|
|
||||||
// To the extent possible under law, the author(s) have dedicated all
|
|
||||||
// copyright and related and neighboring rights to this software to
|
|
||||||
// the public domain worldwide. This software is distributed without
|
|
||||||
// any warranty.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the CC0 Public Domain Dedication
|
|
||||||
// along with this software.
|
|
||||||
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//! Abstract Bitcoin listener
|
|
||||||
//!
|
|
||||||
//! This module defines a listener on the Bitcoin network which is able
|
|
||||||
//! to connect to a peer, send network messages, and receive Bitcoin data.
|
|
||||||
//!
|
|
||||||
|
|
||||||
use std::thread;
|
|
||||||
use std::sync::mpsc::{channel, Receiver};
|
|
||||||
|
|
||||||
use network::constants::Network;
|
|
||||||
use network::message;
|
|
||||||
use network::message::NetworkMessage::Verack;
|
|
||||||
use network::socket::Socket;
|
|
||||||
use util;
|
|
||||||
|
|
||||||
/// A message which can be sent on the Bitcoin network
|
|
||||||
pub trait Listener {
|
|
||||||
/// Return a string encoding of the peer's network address
|
|
||||||
fn peer(&self) -> &str;
|
|
||||||
/// Return the port we have connected to the peer on
|
|
||||||
fn port(&self) -> u16;
|
|
||||||
/// Return the network this `Listener` is operating on
|
|
||||||
fn network(&self) -> Network;
|
|
||||||
/// Main listen loop
|
|
||||||
fn start(&self) -> Result<(Receiver<message::SocketResponse>, Socket), util::Error> {
|
|
||||||
// Open socket
|
|
||||||
let mut ret_sock = Socket::new(self.network());
|
|
||||||
ret_sock.connect(self.peer(), self.port())?;
|
|
||||||
let mut sock = ret_sock.clone();
|
|
||||||
|
|
||||||
let (recv_tx, recv_rx) = channel();
|
|
||||||
|
|
||||||
// Send version message to peer
|
|
||||||
let version_message = sock.version_message(0)?;
|
|
||||||
sock.send_message(version_message)?;
|
|
||||||
|
|
||||||
// Message loop
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut handshake_complete = false;
|
|
||||||
loop {
|
|
||||||
// Receive new message
|
|
||||||
match sock.receive_message() {
|
|
||||||
Ok(payload) => {
|
|
||||||
// React to any network messages that affect our state.
|
|
||||||
if let Verack = payload {
|
|
||||||
// Make an exception for verack since there is no response required
|
|
||||||
// TODO: when the timeout stuff in std::io::net::tcp is sorted out we should
|
|
||||||
// actually time out if the verack doesn't come in in time
|
|
||||||
if handshake_complete {
|
|
||||||
println!("Received second verack (peer is misbehaving)");
|
|
||||||
} else {
|
|
||||||
handshake_complete = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// We have to pass the message to the main thread for processing,
|
|
||||||
// unfortunately, because sipa says we have to handle everything
|
|
||||||
// in order.
|
|
||||||
recv_tx.send(message::SocketResponse::MessageReceived(payload)).unwrap();
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// On failure we send an error message to the main thread, along with
|
|
||||||
// a channel to receive an acknowledgement that we may tear down this
|
|
||||||
// thread. (If we simply exited immediately, the channel would be torn
|
|
||||||
// down and the main thread would never see the error message.)
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
recv_tx.send(message::SocketResponse::ConnectionFailed(e, tx)).unwrap();
|
|
||||||
rx.recv().unwrap();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok((recv_rx, ret_sock))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,18 +28,18 @@ use blockdata::transaction;
|
||||||
use network::address::Address;
|
use network::address::Address;
|
||||||
use network::message_network;
|
use network::message_network;
|
||||||
use network::message_blockdata;
|
use network::message_blockdata;
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
use network::encodable::CheckedData;
|
use consensus::encode::CheckedData;
|
||||||
use network::serialize::{self, serialize, RawDecoder, SimpleEncoder, SimpleDecoder};
|
use consensus::encode::{self, serialize, Encoder, Decoder};
|
||||||
use util;
|
use util;
|
||||||
|
|
||||||
/// Serializer for command string
|
/// Serializer for command string
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct CommandString(pub String);
|
pub struct CommandString(pub String);
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for CommandString {
|
impl<S: Encoder> Encodable<S> for CommandString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
let &CommandString(ref inner_str) = self;
|
let &CommandString(ref inner_str) = self;
|
||||||
let mut rawbytes = [0u8; 12];
|
let mut rawbytes = [0u8; 12];
|
||||||
let strbytes = inner_str.as_bytes();
|
let strbytes = inner_str.as_bytes();
|
||||||
|
@ -53,10 +53,10 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for CommandString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for CommandString {
|
impl<D: Decoder> Decodable<D> for CommandString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<CommandString, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<CommandString, encode::Error> {
|
||||||
let rawbytes: [u8; 12] = ConsensusDecodable::consensus_decode(d)?;
|
let rawbytes: [u8; 12] = Decodable::consensus_decode(d)?;
|
||||||
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
|
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
|
||||||
Ok(CommandString(rv))
|
Ok(CommandString(rv))
|
||||||
}
|
}
|
||||||
|
@ -146,57 +146,56 @@ impl RawNetworkMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for RawNetworkMessage {
|
impl<S: Encoder> Encodable<S> for RawNetworkMessage {
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
self.magic.consensus_encode(s)?;
|
self.magic.consensus_encode(s)?;
|
||||||
CommandString(self.command()).consensus_encode(s)?;
|
CommandString(self.command()).consensus_encode(s)?;
|
||||||
CheckedData(match self.payload {
|
CheckedData(match self.payload {
|
||||||
NetworkMessage::Version(ref dat) => serialize(dat),
|
NetworkMessage::Version(ref dat) => serialize(dat),
|
||||||
NetworkMessage::Verack => Ok(vec![]),
|
|
||||||
NetworkMessage::Addr(ref dat) => serialize(dat),
|
NetworkMessage::Addr(ref dat) => serialize(dat),
|
||||||
NetworkMessage::Inv(ref dat) => serialize(dat),
|
NetworkMessage::Inv(ref dat) => serialize(dat),
|
||||||
NetworkMessage::GetData(ref dat) => serialize(dat),
|
NetworkMessage::GetData(ref dat) => serialize(dat),
|
||||||
NetworkMessage::NotFound(ref dat) => serialize(dat),
|
NetworkMessage::NotFound(ref dat) => serialize(dat),
|
||||||
NetworkMessage::GetBlocks(ref dat) => serialize(dat),
|
NetworkMessage::GetBlocks(ref dat) => serialize(dat),
|
||||||
NetworkMessage::GetHeaders(ref dat) => serialize(dat),
|
NetworkMessage::GetHeaders(ref dat) => serialize(dat),
|
||||||
NetworkMessage::MemPool => Ok(vec![]),
|
|
||||||
NetworkMessage::Tx(ref dat) => serialize(dat),
|
NetworkMessage::Tx(ref dat) => serialize(dat),
|
||||||
NetworkMessage::Block(ref dat) => serialize(dat),
|
NetworkMessage::Block(ref dat) => serialize(dat),
|
||||||
NetworkMessage::Headers(ref dat) => serialize(dat),
|
NetworkMessage::Headers(ref dat) => serialize(dat),
|
||||||
NetworkMessage::GetAddr => Ok(vec![]),
|
|
||||||
NetworkMessage::Ping(ref dat) => serialize(dat),
|
NetworkMessage::Ping(ref dat) => serialize(dat),
|
||||||
NetworkMessage::Pong(ref dat) => serialize(dat),
|
NetworkMessage::Pong(ref dat) => serialize(dat),
|
||||||
NetworkMessage::Alert(ref dat) => serialize(dat)
|
NetworkMessage::Alert(ref dat) => serialize(dat),
|
||||||
}.unwrap()).consensus_encode(s)?;
|
NetworkMessage::Verack
|
||||||
Ok(())
|
| NetworkMessage::MemPool
|
||||||
|
| NetworkMessage::GetAddr => vec![],
|
||||||
|
}).consensus_encode(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for RawNetworkMessage {
|
impl<D: Decoder> Decodable<D> for RawNetworkMessage {
|
||||||
fn consensus_decode(d: &mut D) -> Result<RawNetworkMessage, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<RawNetworkMessage, encode::Error> {
|
||||||
let magic = ConsensusDecodable::consensus_decode(d)?;
|
let magic = Decodable::consensus_decode(d)?;
|
||||||
let CommandString(cmd): CommandString= ConsensusDecodable::consensus_decode(d)?;
|
let CommandString(cmd): CommandString= Decodable::consensus_decode(d)?;
|
||||||
let CheckedData(raw_payload): CheckedData = ConsensusDecodable::consensus_decode(d)?;
|
let CheckedData(raw_payload): CheckedData = Decodable::consensus_decode(d)?;
|
||||||
|
|
||||||
let mut mem_d = RawDecoder::new(Cursor::new(raw_payload));
|
let mut mem_d = Cursor::new(raw_payload);
|
||||||
let payload = match &cmd[..] {
|
let payload = match &cmd[..] {
|
||||||
"version" => NetworkMessage::Version(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"version" => NetworkMessage::Version(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"verack" => NetworkMessage::Verack,
|
"verack" => NetworkMessage::Verack,
|
||||||
"addr" => NetworkMessage::Addr(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"addr" => NetworkMessage::Addr(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"inv" => NetworkMessage::Inv(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"inv" => NetworkMessage::Inv(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"getdata" => NetworkMessage::GetData(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"getdata" => NetworkMessage::GetData(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"notfound" => NetworkMessage::NotFound(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"notfound" => NetworkMessage::NotFound(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"getblocks" => NetworkMessage::GetBlocks(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"getblocks" => NetworkMessage::GetBlocks(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"getheaders" => NetworkMessage::GetHeaders(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"getheaders" => NetworkMessage::GetHeaders(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"mempool" => NetworkMessage::MemPool,
|
"mempool" => NetworkMessage::MemPool,
|
||||||
"block" => NetworkMessage::Block(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"block" => NetworkMessage::Block(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"headers" => NetworkMessage::Headers(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"headers" => NetworkMessage::Headers(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"getaddr" => NetworkMessage::GetAddr,
|
"getaddr" => NetworkMessage::GetAddr,
|
||||||
"ping" => NetworkMessage::Ping(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"ping" => NetworkMessage::Ping(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"pong" => NetworkMessage::Pong(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"pong" => NetworkMessage::Pong(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"tx" => NetworkMessage::Tx(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"tx" => NetworkMessage::Tx(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"alert" => NetworkMessage::Alert(ConsensusDecodable::consensus_decode(&mut mem_d)?),
|
"alert" => NetworkMessage::Alert(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
_ => return Err(serialize::Error::UnrecognizedNetworkCommand(cmd)),
|
_ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd)),
|
||||||
};
|
};
|
||||||
Ok(RawNetworkMessage {
|
Ok(RawNetworkMessage {
|
||||||
magic: magic,
|
magic: magic,
|
||||||
|
@ -209,12 +208,12 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for RawNetworkMessage {
|
||||||
mod test {
|
mod test {
|
||||||
use super::{RawNetworkMessage, NetworkMessage, CommandString};
|
use super::{RawNetworkMessage, NetworkMessage, CommandString};
|
||||||
|
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_commandstring_test() {
|
fn serialize_commandstring_test() {
|
||||||
let cs = CommandString("Andrew".to_owned());
|
let cs = CommandString("Andrew".to_owned());
|
||||||
assert_eq!(serialize(&cs).ok(), Some(vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]));
|
assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -229,36 +228,36 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_verack_test() {
|
fn serialize_verack_test() {
|
||||||
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }).ok(),
|
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }),
|
||||||
Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
|
||||||
0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
|
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_ping_test() {
|
fn serialize_ping_test() {
|
||||||
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }).ok(),
|
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }),
|
||||||
Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
|
0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
|
||||||
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_mempool_test() {
|
fn serialize_mempool_test() {
|
||||||
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }).ok(),
|
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }),
|
||||||
Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
|
||||||
0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
|
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_getaddr_test() {
|
fn serialize_getaddr_test() {
|
||||||
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }).ok(),
|
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }),
|
||||||
Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
|
||||||
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
|
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use network::constants;
|
use network::constants;
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
use network::serialize::{self, SimpleDecoder, SimpleEncoder};
|
use consensus::encode::{self, Decoder, Encoder};
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::Sha256dHash;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
@ -101,9 +101,9 @@ impl GetHeadersMessage {
|
||||||
|
|
||||||
impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash);
|
impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash);
|
||||||
|
|
||||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for Inventory {
|
impl<S: Encoder> Encodable<S> for Inventory {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
match self.inv_type {
|
match self.inv_type {
|
||||||
InvType::Error => 0u32,
|
InvType::Error => 0u32,
|
||||||
InvType::Transaction => 1,
|
InvType::Transaction => 1,
|
||||||
|
@ -115,10 +115,10 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for Inventory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for Inventory {
|
impl<D: Decoder> Decodable<D> for Inventory {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<Inventory, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<Inventory, encode::Error> {
|
||||||
let int_type: u32 = ConsensusDecodable::consensus_decode(d)?;
|
let int_type: u32 = Decodable::consensus_decode(d)?;
|
||||||
Ok(Inventory {
|
Ok(Inventory {
|
||||||
inv_type: match int_type {
|
inv_type: match int_type {
|
||||||
0 => InvType::Error,
|
0 => InvType::Error,
|
||||||
|
@ -127,7 +127,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Inventory {
|
||||||
// TODO do not fail here
|
// TODO do not fail here
|
||||||
_ => { panic!("bad inventory type field") }
|
_ => { panic!("bad inventory type field") }
|
||||||
},
|
},
|
||||||
hash: ConsensusDecodable::consensus_decode(d)?
|
hash: Decodable::consensus_decode(d)?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ mod tests {
|
||||||
|
|
||||||
use hex::decode as hex_decode;
|
use hex::decode as hex_decode;
|
||||||
|
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -151,10 +151,10 @@ mod tests {
|
||||||
let real_decode = decode.unwrap();
|
let real_decode = decode.unwrap();
|
||||||
assert_eq!(real_decode.version, 70002);
|
assert_eq!(real_decode.version, 70002);
|
||||||
assert_eq!(real_decode.locator_hashes.len(), 1);
|
assert_eq!(real_decode.locator_hashes.len(), 1);
|
||||||
assert_eq!(serialize(&real_decode.locator_hashes[0]).ok(), Some(genhash));
|
assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash);
|
||||||
assert_eq!(real_decode.stop_hash, Default::default());
|
assert_eq!(real_decode.stop_hash, Default::default());
|
||||||
|
|
||||||
assert_eq!(serialize(&real_decode).ok(), Some(from_sat));
|
assert_eq!(serialize(&real_decode), from_sat);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -167,10 +167,10 @@ mod tests {
|
||||||
let real_decode = decode.unwrap();
|
let real_decode = decode.unwrap();
|
||||||
assert_eq!(real_decode.version, 70002);
|
assert_eq!(real_decode.version, 70002);
|
||||||
assert_eq!(real_decode.locator_hashes.len(), 1);
|
assert_eq!(real_decode.locator_hashes.len(), 1);
|
||||||
assert_eq!(serialize(&real_decode.locator_hashes[0]).ok(), Some(genhash));
|
assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash);
|
||||||
assert_eq!(real_decode.stop_hash, Default::default());
|
assert_eq!(real_decode.stop_hash, Default::default());
|
||||||
|
|
||||||
assert_eq!(serialize(&real_decode).ok(), Some(from_sat));
|
assert_eq!(serialize(&real_decode), from_sat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,8 @@
|
||||||
//! capabilities
|
//! capabilities
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use network::constants;
|
|
||||||
use network::address::Address;
|
use network::address::Address;
|
||||||
use network::socket::Socket;
|
use network::constants;
|
||||||
use util;
|
|
||||||
|
|
||||||
/// Some simple messages
|
/// Some simple messages
|
||||||
|
|
||||||
|
@ -53,21 +51,26 @@ pub struct VersionMessage {
|
||||||
impl VersionMessage {
|
impl VersionMessage {
|
||||||
// TODO: we have fixed services and relay to 0
|
// TODO: we have fixed services and relay to 0
|
||||||
/// Constructs a new `version` message
|
/// Constructs a new `version` message
|
||||||
pub fn new(timestamp: i64, mut socket: Socket, nonce: u64, start_height: i32) -> Result<VersionMessage, util::Error> {
|
pub fn new(
|
||||||
let recv_addr = socket.receiver_address()?;
|
services: u64,
|
||||||
let send_addr = socket.sender_address()?;
|
timestamp: i64,
|
||||||
|
receiver: Address,
|
||||||
Ok(VersionMessage {
|
sender: Address,
|
||||||
|
nonce: u64,
|
||||||
|
user_agent: String,
|
||||||
|
start_height: i32,
|
||||||
|
) -> VersionMessage {
|
||||||
|
VersionMessage {
|
||||||
version: constants::PROTOCOL_VERSION,
|
version: constants::PROTOCOL_VERSION,
|
||||||
services: socket.services,
|
services: services,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
receiver: recv_addr,
|
receiver: receiver,
|
||||||
sender: send_addr,
|
sender: sender,
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
user_agent: socket.user_agent,
|
user_agent: user_agent,
|
||||||
start_height: start_height,
|
start_height: start_height,
|
||||||
relay: false
|
relay: false,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +84,7 @@ mod tests {
|
||||||
|
|
||||||
use hex::decode as hex_decode;
|
use hex::decode as hex_decode;
|
||||||
|
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn version_message_test() {
|
fn version_message_test() {
|
||||||
|
@ -100,9 +103,6 @@ mod tests {
|
||||||
assert_eq!(real_decode.start_height, 302892);
|
assert_eq!(real_decode.start_height, 302892);
|
||||||
assert_eq!(real_decode.relay, true);
|
assert_eq!(real_decode.relay, true);
|
||||||
|
|
||||||
assert_eq!(serialize(&real_decode).ok(), Some(from_sat));
|
assert_eq!(serialize(&real_decode), from_sat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,8 @@ use std::io;
|
||||||
use std::error;
|
use std::error;
|
||||||
|
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod consensus_params;
|
|
||||||
pub mod encodable;
|
|
||||||
pub mod socket;
|
|
||||||
pub mod serialize;
|
|
||||||
|
|
||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod listener;
|
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod message_blockdata;
|
pub mod message_blockdata;
|
||||||
pub mod message_network;
|
pub mod message_network;
|
||||||
|
|
|
@ -1,347 +0,0 @@
|
||||||
// Rust Bitcoin Library
|
|
||||||
// Written in 2014 by
|
|
||||||
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
|
||||||
//
|
|
||||||
// To the extent possible under law, the author(s) have dedicated all
|
|
||||||
// copyright and related and neighboring rights to this software to
|
|
||||||
// the public domain worldwide. This software is distributed without
|
|
||||||
// any warranty.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the CC0 Public Domain Dedication
|
|
||||||
// along with this software.
|
|
||||||
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//! Network Serialization
|
|
||||||
//!
|
|
||||||
//! This module defines the `Serializable` trait which is used for
|
|
||||||
//! (de)serializing Bitcoin objects for transmission on the network.
|
|
||||||
//! It also defines (de)serialization routines for many primitives.
|
|
||||||
//!
|
|
||||||
|
|
||||||
use std::error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::io;
|
|
||||||
use std::io::{Cursor, Read, Write};
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};
|
|
||||||
use hex::encode as hex_encode;
|
|
||||||
|
|
||||||
use bitcoin_bech32;
|
|
||||||
|
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
|
||||||
use util::base58;
|
|
||||||
use util::hash::Sha256dHash;
|
|
||||||
|
|
||||||
/// Serialization error
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
/// And I/O error
|
|
||||||
Io(io::Error),
|
|
||||||
/// Base58 encoding error
|
|
||||||
Base58(base58::Error),
|
|
||||||
/// Bech32 encoding error
|
|
||||||
Bech32(bitcoin_bech32::Error),
|
|
||||||
/// Error from the `byteorder` crate
|
|
||||||
ByteOrder(io::Error),
|
|
||||||
/// Network magic was not expected
|
|
||||||
UnexpectedNetworkMagic {
|
|
||||||
/// The expected network magic
|
|
||||||
expected: u32,
|
|
||||||
/// The unexpected network magic
|
|
||||||
actual: u32,
|
|
||||||
},
|
|
||||||
/// Tried to allocate an oversized vector
|
|
||||||
OversizedVectorAllocation{
|
|
||||||
/// The capacity requested
|
|
||||||
requested: usize,
|
|
||||||
/// The maximum capacity
|
|
||||||
max: usize,
|
|
||||||
},
|
|
||||||
/// Checksum was invalid
|
|
||||||
InvalidChecksum {
|
|
||||||
/// The expected checksum
|
|
||||||
expected: [u8; 4],
|
|
||||||
/// The invalid checksum
|
|
||||||
actual: [u8; 4],
|
|
||||||
},
|
|
||||||
/// Network magic was unknown
|
|
||||||
UnknownNetworkMagic(u32),
|
|
||||||
/// Parsing error
|
|
||||||
ParseFailed(&'static str),
|
|
||||||
/// Unsupported witness version
|
|
||||||
UnsupportedWitnessVersion(u8),
|
|
||||||
/// Unsupported Segwit flag
|
|
||||||
UnsupportedSegwitFlag(u8),
|
|
||||||
/// Unrecognized network command
|
|
||||||
UnrecognizedNetworkCommand(String),
|
|
||||||
/// Unexpected hex digit
|
|
||||||
UnexpectedHexDigit(char),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Error::Io(ref e) => fmt::Display::fmt(e, f),
|
|
||||||
Error::Base58(ref e) => fmt::Display::fmt(e, f),
|
|
||||||
Error::Bech32(ref e) => fmt::Display::fmt(e, f),
|
|
||||||
Error::ByteOrder(ref e) => fmt::Display::fmt(e, f),
|
|
||||||
Error::UnexpectedNetworkMagic { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), e, a),
|
|
||||||
Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f, "{}: requested {}, maximum {}", error::Error::description(self), r, m),
|
|
||||||
Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), hex_encode(e), hex_encode(a)),
|
|
||||||
Error::UnknownNetworkMagic(ref m) => write!(f, "{}: {}", error::Error::description(self), m),
|
|
||||||
Error::ParseFailed(ref e) => write!(f, "{}: {}", error::Error::description(self), e),
|
|
||||||
Error::UnsupportedWitnessVersion(ref wver) => write!(f, "{}: {}", error::Error::description(self), wver),
|
|
||||||
Error::UnsupportedSegwitFlag(ref swflag) => write!(f, "{}: {}", error::Error::description(self), swflag),
|
|
||||||
Error::UnrecognizedNetworkCommand(ref nwcmd) => write!(f, "{}: {}", error::Error::description(self), nwcmd),
|
|
||||||
Error::UnexpectedHexDigit(ref d) => write!(f, "{}: {}", error::Error::description(self), d),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn cause(&self) -> Option<&error::Error> {
|
|
||||||
match *self {
|
|
||||||
Error::Io(ref e) => Some(e),
|
|
||||||
Error::Base58(ref e) => Some(e),
|
|
||||||
Error::Bech32(ref e) => Some(e),
|
|
||||||
Error::ByteOrder(ref e) => Some(e),
|
|
||||||
Error::UnexpectedNetworkMagic { .. }
|
|
||||||
| Error::OversizedVectorAllocation { .. }
|
|
||||||
| Error::InvalidChecksum { .. }
|
|
||||||
| Error::UnknownNetworkMagic(..)
|
|
||||||
| Error::ParseFailed(..)
|
|
||||||
| Error::UnsupportedWitnessVersion(..)
|
|
||||||
| Error::UnsupportedSegwitFlag(..)
|
|
||||||
| Error::UnrecognizedNetworkCommand(..)
|
|
||||||
| Error::UnexpectedHexDigit(..) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
Error::Io(ref e) => e.description(),
|
|
||||||
Error::Base58(ref e) => e.description(),
|
|
||||||
Error::Bech32(ref e) => e.description(),
|
|
||||||
Error::ByteOrder(ref e) => e.description(),
|
|
||||||
Error::UnexpectedNetworkMagic { .. } => "unexpected network magic",
|
|
||||||
Error::OversizedVectorAllocation { .. } => "allocation of oversized vector requested",
|
|
||||||
Error::InvalidChecksum { .. } => "invalid checksum",
|
|
||||||
Error::UnknownNetworkMagic(..) => "unknown network magic",
|
|
||||||
Error::ParseFailed(..) => "parse failed",
|
|
||||||
Error::UnsupportedWitnessVersion(..) => "unsupported witness version",
|
|
||||||
Error::UnsupportedSegwitFlag(..) => "unsupported segwit version",
|
|
||||||
Error::UnrecognizedNetworkCommand(..) => "unrecognized network command",
|
|
||||||
Error::UnexpectedHexDigit(..) => "unexpected hex digit",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
impl From<base58::Error> for Error {
|
|
||||||
fn from(e: base58::Error) -> Error {
|
|
||||||
Error::Base58(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
impl From<bitcoin_bech32::Error> for Error {
|
|
||||||
fn from(e: bitcoin_bech32::Error) -> Error {
|
|
||||||
Error::Bech32(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
impl From<io::Error> for Error {
|
|
||||||
fn from(error: io::Error) -> Self {
|
|
||||||
Error::Io(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Objects which are referred to by hash
|
|
||||||
pub trait BitcoinHash {
|
|
||||||
/// Produces a Sha256dHash which can be used to refer to the object
|
|
||||||
fn bitcoin_hash(&self) -> Sha256dHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitcoinHash for Vec<u8> {
|
|
||||||
#[inline]
|
|
||||||
fn bitcoin_hash(&self) -> Sha256dHash {
|
|
||||||
Sha256dHash::from_data(&self[..])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode an object into a vector
|
|
||||||
pub fn serialize<T: ?Sized>(data: &T) -> Result<Vec<u8>, Error>
|
|
||||||
where T: ConsensusEncodable<RawEncoder<Cursor<Vec<u8>>>>,
|
|
||||||
{
|
|
||||||
let mut encoder = RawEncoder::new(Cursor::new(vec![]));
|
|
||||||
data.consensus_encode(&mut encoder)?;
|
|
||||||
Ok(encoder.into_inner().into_inner())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode an object into a hex-encoded string
|
|
||||||
pub fn serialize_hex<T: ?Sized>(data: &T) -> Result<String, Error>
|
|
||||||
where T: ConsensusEncodable<RawEncoder<Cursor<Vec<u8>>>>
|
|
||||||
{
|
|
||||||
let serial = serialize(data)?;
|
|
||||||
Ok(hex_encode(serial))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserialize an object from a vector, will error if said deserialization
|
|
||||||
/// doesn't consume the entire vector.
|
|
||||||
pub fn deserialize<'a, T>(data: &'a [u8]) -> Result<T, Error>
|
|
||||||
where T: ConsensusDecodable<RawDecoder<Cursor<&'a [u8]>>>
|
|
||||||
{
|
|
||||||
let mut decoder = RawDecoder::new(Cursor::new(data));
|
|
||||||
let rv = ConsensusDecodable::consensus_decode(&mut decoder)?;
|
|
||||||
|
|
||||||
// Fail if data is not consumed entirely.
|
|
||||||
if decoder.into_inner().position() == data.len() as u64 {
|
|
||||||
Ok(rv)
|
|
||||||
} else {
|
|
||||||
Err(Error::ParseFailed("data not consumed entirely when explicitly deserializing"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An encoder for raw binary data
|
|
||||||
pub struct RawEncoder<W> {
|
|
||||||
writer: W
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An decoder for raw binary data
|
|
||||||
pub struct RawDecoder<R> {
|
|
||||||
reader: R
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write> RawEncoder<W> {
|
|
||||||
/// Constructor
|
|
||||||
pub fn new(writer: W) -> RawEncoder<W> { RawEncoder { writer: writer } }
|
|
||||||
/// Returns the underlying Writer
|
|
||||||
pub fn into_inner(self) -> W { self.writer }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Read> RawDecoder<R> {
|
|
||||||
/// Constructor
|
|
||||||
pub fn new(reader: R) -> RawDecoder<R> { RawDecoder { reader: reader } }
|
|
||||||
/// Returns the underlying Reader
|
|
||||||
pub fn into_inner(self) -> R { self.reader }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple Encoder trait
|
|
||||||
pub trait SimpleEncoder {
|
|
||||||
/// Output a 64-bit uint
|
|
||||||
fn emit_u64(&mut self, v: u64) -> Result<(), Error>;
|
|
||||||
/// Output a 32-bit uint
|
|
||||||
fn emit_u32(&mut self, v: u32) -> Result<(), Error>;
|
|
||||||
/// Output a 16-bit uint
|
|
||||||
fn emit_u16(&mut self, v: u16) -> Result<(), Error>;
|
|
||||||
/// Output a 8-bit uint
|
|
||||||
fn emit_u8(&mut self, v: u8) -> Result<(), Error>;
|
|
||||||
|
|
||||||
/// Output a 64-bit int
|
|
||||||
fn emit_i64(&mut self, v: i64) -> Result<(), Error>;
|
|
||||||
/// Output a 32-bit int
|
|
||||||
fn emit_i32(&mut self, v: i32) -> Result<(), Error>;
|
|
||||||
/// Output a 16-bit int
|
|
||||||
fn emit_i16(&mut self, v: i16) -> Result<(), Error>;
|
|
||||||
/// Output a 8-bit int
|
|
||||||
fn emit_i8(&mut self, v: i8) -> Result<(), Error>;
|
|
||||||
|
|
||||||
/// Output a boolean
|
|
||||||
fn emit_bool(&mut self, v: bool) -> Result<(), Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple Decoder trait
|
|
||||||
pub trait SimpleDecoder {
|
|
||||||
/// Read a 64-bit uint
|
|
||||||
fn read_u64(&mut self) -> Result<u64, Error>;
|
|
||||||
/// Read a 32-bit uint
|
|
||||||
fn read_u32(&mut self) -> Result<u32, Error>;
|
|
||||||
/// Read a 16-bit uint
|
|
||||||
fn read_u16(&mut self) -> Result<u16, Error>;
|
|
||||||
/// Read a 8-bit uint
|
|
||||||
fn read_u8(&mut self) -> Result<u8, Error>;
|
|
||||||
|
|
||||||
/// Read a 64-bit int
|
|
||||||
fn read_i64(&mut self) -> Result<i64, Error>;
|
|
||||||
/// Read a 32-bit int
|
|
||||||
fn read_i32(&mut self) -> Result<i32, Error>;
|
|
||||||
/// Read a 16-bit int
|
|
||||||
fn read_i16(&mut self) -> Result<i16, Error>;
|
|
||||||
/// Read a 8-bit int
|
|
||||||
fn read_i8(&mut self) -> Result<i8, Error>;
|
|
||||||
|
|
||||||
/// Read a boolean
|
|
||||||
fn read_bool(&mut self) -> Result<bool, Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! encoder_fn {
|
|
||||||
($name:ident, $val_type:ty, $writefn:ident) => {
|
|
||||||
#[inline]
|
|
||||||
fn $name(&mut self, v: $val_type) -> Result<(), Error> {
|
|
||||||
self.writer.$writefn::<LittleEndian>(v).map_err(Error::Io)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! decoder_fn {
|
|
||||||
($name:ident, $val_type:ty, $readfn:ident) => {
|
|
||||||
#[inline]
|
|
||||||
fn $name(&mut self) -> Result<$val_type, Error> {
|
|
||||||
self.reader.$readfn::<LittleEndian>().map_err(Error::Io)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write> SimpleEncoder for RawEncoder<W> {
|
|
||||||
encoder_fn!(emit_u64, u64, write_u64);
|
|
||||||
encoder_fn!(emit_u32, u32, write_u32);
|
|
||||||
encoder_fn!(emit_u16, u16, write_u16);
|
|
||||||
encoder_fn!(emit_i64, i64, write_i64);
|
|
||||||
encoder_fn!(emit_i32, i32, write_i32);
|
|
||||||
encoder_fn!(emit_i16, i16, write_i16);
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn emit_i8(&mut self, v: i8) -> Result<(), Error> {
|
|
||||||
self.writer.write_i8(v).map_err(Error::Io)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn emit_u8(&mut self, v: u8) -> Result<(), Error> {
|
|
||||||
self.writer.write_u8(v).map_err(Error::Io)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn emit_bool(&mut self, v: bool) -> Result<(), Error> {
|
|
||||||
self.writer.write_i8(if v {1} else {0}).map_err(Error::Io)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Read> SimpleDecoder for RawDecoder<R> {
|
|
||||||
decoder_fn!(read_u64, u64, read_u64);
|
|
||||||
decoder_fn!(read_u32, u32, read_u32);
|
|
||||||
decoder_fn!(read_u16, u16, read_u16);
|
|
||||||
decoder_fn!(read_i64, i64, read_i64);
|
|
||||||
decoder_fn!(read_i32, i32, read_i32);
|
|
||||||
decoder_fn!(read_i16, i16, read_i16);
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_u8(&mut self) -> Result<u8, Error> {
|
|
||||||
self.reader.read_u8().map_err(Error::Io)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn read_i8(&mut self) -> Result<i8, Error> {
|
|
||||||
self.reader.read_i8().map_err(Error::Io)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn read_bool(&mut self) -> Result<bool, Error> {
|
|
||||||
match self.reader.read_i8() {
|
|
||||||
Ok(bit) => Ok(bit != 0),
|
|
||||||
Err(e) => Err(Error::Io(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aren't really any tests here.. the main functions are serialize and
|
|
||||||
// deserialize, which get the crap tested out of them it every other
|
|
||||||
// module.
|
|
||||||
|
|
|
@ -1,195 +0,0 @@
|
||||||
// Rust Bitcoin Library
|
|
||||||
// Written in 2014 by
|
|
||||||
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
|
||||||
//
|
|
||||||
// To the extent possible under law, the author(s) have dedicated all
|
|
||||||
// copyright and related and neighboring rights to this software to
|
|
||||||
// the public domain worldwide. This software is distributed without
|
|
||||||
// any warranty.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the CC0 Public Domain Dedication
|
|
||||||
// along with this software.
|
|
||||||
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//! Sockets
|
|
||||||
//!
|
|
||||||
//! This module provides support for low-level network communication.
|
|
||||||
//!
|
|
||||||
|
|
||||||
use std::time::{UNIX_EPOCH, SystemTime};
|
|
||||||
use rand::{thread_rng, Rng};
|
|
||||||
use std::io::Write;
|
|
||||||
use std::net;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use network;
|
|
||||||
use network::constants;
|
|
||||||
use network::address::Address;
|
|
||||||
use network::encodable::{ConsensusEncodable, ConsensusDecodable};
|
|
||||||
use network::message::{RawNetworkMessage, NetworkMessage};
|
|
||||||
use network::message::NetworkMessage::Version;
|
|
||||||
use network::message_network::VersionMessage;
|
|
||||||
use network::serialize::{self, RawEncoder, RawDecoder};
|
|
||||||
use util;
|
|
||||||
|
|
||||||
/// Format an IP address in the 16-byte bitcoin protocol serialization
|
|
||||||
fn ipaddr_to_bitcoin_addr(addr: &net::SocketAddr) -> [u16; 8] {
|
|
||||||
match *addr {
|
|
||||||
net::SocketAddr::V4(ref addr) => addr.ip().to_ipv6_mapped().segments(),
|
|
||||||
net::SocketAddr::V6(ref addr) => addr.ip().segments()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A network socket along with information about the peer
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Socket {
|
|
||||||
/// The underlying TCP socket
|
|
||||||
socket: Arc<Mutex<Option<net::TcpStream>>>,
|
|
||||||
/// Services supported by us
|
|
||||||
pub services: u64,
|
|
||||||
/// Our user agent
|
|
||||||
pub user_agent: String,
|
|
||||||
/// Nonce to identify our `version` messages
|
|
||||||
pub version_nonce: u64,
|
|
||||||
/// Network magic
|
|
||||||
pub magic: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({
|
|
||||||
use ::std::ops::DerefMut;
|
|
||||||
let sock_lock = $s.socket.lock();
|
|
||||||
match sock_lock {
|
|
||||||
Err(_) => {
|
|
||||||
Err(network::Error::SocketMutexPoisoned.into())
|
|
||||||
}
|
|
||||||
Ok(mut guard) => {
|
|
||||||
match *guard.deref_mut() {
|
|
||||||
Some(ref mut $sock) => {
|
|
||||||
$body
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Err(network::Error::SocketNotConnectedToPeer.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
impl Socket {
|
|
||||||
// TODO: we fix services to 0
|
|
||||||
/// Construct a new socket
|
|
||||||
pub fn new(network: constants::Network) -> Socket {
|
|
||||||
let mut rng = thread_rng();
|
|
||||||
Socket {
|
|
||||||
socket: Arc::new(Mutex::new(None)),
|
|
||||||
services: 0,
|
|
||||||
version_nonce: rng.gen(),
|
|
||||||
user_agent: constants::USER_AGENT.to_owned(),
|
|
||||||
magic: network.magic(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// (Re)connect to the peer
|
|
||||||
pub fn connect(&mut self, host: &str, port: u16) -> Result<(), network::Error> {
|
|
||||||
// Entirely replace the Mutex, in case it was poisoned;
|
|
||||||
// this will also drop any preexisting socket that might be open
|
|
||||||
match net::TcpStream::connect((host, port)) {
|
|
||||||
Ok(s) => {
|
|
||||||
self.socket = Arc::new(Mutex::new(Some(s)));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
self.socket = Arc::new(Mutex::new(None));
|
|
||||||
Err(network::Error::Io(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Peer address
|
|
||||||
pub fn receiver_address(&mut self) -> Result<Address, network::Error> {
|
|
||||||
with_socket!(self, sock, {
|
|
||||||
match sock.peer_addr() {
|
|
||||||
Ok(addr) => {
|
|
||||||
Ok(Address {
|
|
||||||
services: self.services,
|
|
||||||
address: ipaddr_to_bitcoin_addr(&addr),
|
|
||||||
port: addr.port()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
Err(e) => Err(network::Error::Io(e))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Our own address
|
|
||||||
pub fn sender_address(&mut self) -> Result<Address, network::Error> {
|
|
||||||
with_socket!(self, sock, {
|
|
||||||
match sock.local_addr() {
|
|
||||||
Ok(addr) => {
|
|
||||||
Ok(Address {
|
|
||||||
services: self.services,
|
|
||||||
address: ipaddr_to_bitcoin_addr(&addr),
|
|
||||||
port: addr.port()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
Err(e) => Err(network::Error::Io(e))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Produce a version message appropriate for this socket
|
|
||||||
pub fn version_message(&mut self, start_height: i32) -> Result<NetworkMessage, network::Error> {
|
|
||||||
let recv_addr = self.receiver_address()?;
|
|
||||||
let send_addr = self.sender_address()?;
|
|
||||||
let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
|
||||||
Ok(dur) => dur,
|
|
||||||
Err(err) => err.duration(),
|
|
||||||
}.as_secs() as i64;
|
|
||||||
|
|
||||||
Ok(Version(VersionMessage {
|
|
||||||
version: constants::PROTOCOL_VERSION,
|
|
||||||
services: constants::SERVICES,
|
|
||||||
timestamp: timestamp,
|
|
||||||
receiver: recv_addr,
|
|
||||||
sender: send_addr,
|
|
||||||
nonce: self.version_nonce,
|
|
||||||
user_agent: self.user_agent.clone(),
|
|
||||||
start_height: start_height,
|
|
||||||
relay: false
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a general message across the line
|
|
||||||
pub fn send_message(&mut self, payload: NetworkMessage) -> Result<(), util::Error> {
|
|
||||||
with_socket!(self, sock, {
|
|
||||||
let message = RawNetworkMessage { magic: self.magic, payload: payload };
|
|
||||||
message.consensus_encode(&mut RawEncoder::new(&mut *sock))?;
|
|
||||||
sock.flush().map_err(network::Error::Io).map_err(util::Error::Network)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive the next message from the peer, decoding the network header
|
|
||||||
/// and verifying its correctness. Returns the undecoded payload.
|
|
||||||
pub fn receive_message(&mut self) -> Result<NetworkMessage, util::Error> {
|
|
||||||
with_socket!(self, sock, {
|
|
||||||
// We need a new scope since the closure in here borrows read_err,
|
|
||||||
// and we try to read it afterward. Letting `iter` go out fixes it.
|
|
||||||
let mut decoder = RawDecoder::new(sock);
|
|
||||||
|
|
||||||
let decoded: RawNetworkMessage = ConsensusDecodable::consensus_decode(&mut decoder)?;
|
|
||||||
|
|
||||||
// Then for magic (this should come before parse error, but we can't
|
|
||||||
// get to it if the deserialization failed). TODO restructure this
|
|
||||||
if decoded.magic != self.magic {
|
|
||||||
Err(serialize::Error::UnexpectedNetworkMagic {
|
|
||||||
expected: self.magic,
|
|
||||||
actual: decoded.magic,
|
|
||||||
}.into())
|
|
||||||
} else {
|
|
||||||
Ok(decoded.payload)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ use serde;
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use blockdata::script;
|
use blockdata::script;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use network::serialize;
|
use consensus::encode;
|
||||||
use util::hash::Hash160;
|
use util::hash::Hash160;
|
||||||
use util::base58;
|
use util::base58;
|
||||||
|
|
||||||
|
@ -246,9 +246,9 @@ impl Display for Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Address {
|
impl FromStr for Address {
|
||||||
type Err = serialize::Error;
|
type Err = encode::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Address, serialize::Error> {
|
fn from_str(s: &str) -> Result<Address, encode::Error> {
|
||||||
// bech32 (note that upper or lowercase is allowed but NOT mixed case)
|
// bech32 (note that upper or lowercase is allowed but NOT mixed case)
|
||||||
if s.starts_with("bc1") || s.starts_with("BC1") ||
|
if s.starts_with("bc1") || s.starts_with("BC1") ||
|
||||||
s.starts_with("tb1") || s.starts_with("TB1") ||
|
s.starts_with("tb1") || s.starts_with("TB1") ||
|
||||||
|
@ -262,7 +262,7 @@ impl FromStr for Address {
|
||||||
_ => panic!("unknown network")
|
_ => panic!("unknown network")
|
||||||
};
|
};
|
||||||
if witprog.version().to_u8() != 0 {
|
if witprog.version().to_u8() != 0 {
|
||||||
return Err(serialize::Error::UnsupportedWitnessVersion(witprog.version().to_u8()));
|
return Err(encode::Error::UnsupportedWitnessVersion(witprog.version().to_u8()));
|
||||||
}
|
}
|
||||||
return Ok(Address {
|
return Ok(Address {
|
||||||
network: network,
|
network: network,
|
||||||
|
@ -271,14 +271,14 @@ impl FromStr for Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.len() > 50 {
|
if s.len() > 50 {
|
||||||
return Err(serialize::Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15)));
|
return Err(encode::Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base 58
|
// Base 58
|
||||||
let data = base58::from_check(s)?;
|
let data = base58::from_check(s)?;
|
||||||
|
|
||||||
if data.len() != 21 {
|
if data.len() != 21 {
|
||||||
return Err(serialize::Error::Base58(base58::Error::InvalidLength(data.len())));
|
return Err(encode::Error::Base58(base58::Error::InvalidLength(data.len())));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (network, payload) = match data[0] {
|
let (network, payload) = match data[0] {
|
||||||
|
@ -298,7 +298,7 @@ impl FromStr for Address {
|
||||||
Network::Testnet,
|
Network::Testnet,
|
||||||
Payload::ScriptHash(Hash160::from(&data[1..]))
|
Payload::ScriptHash(Hash160::from(&data[1..]))
|
||||||
),
|
),
|
||||||
x => return Err(serialize::Error::Base58(base58::Error::InvalidVersion(vec![x])))
|
x => return Err(encode::Error::Base58(base58::Error::InvalidVersion(vec![x])))
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Address {
|
Ok(Address {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{Transaction, TxIn};
|
use blockdata::transaction::{Transaction, TxIn};
|
||||||
use network::encodable::ConsensusEncodable;
|
use consensus::encode::Encodable;
|
||||||
use util::hash::{Sha256dHash, Sha256dEncoder};
|
use util::hash::{Sha256dHash, Sha256dEncoder};
|
||||||
|
|
||||||
/// Parts of a sighash which are common across inputs or signatures, and which are
|
/// Parts of a sighash which are common across inputs or signatures, and which are
|
||||||
|
@ -101,7 +101,7 @@ impl SighashComponents {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use blockdata::transaction::Transaction;
|
use blockdata::transaction::Transaction;
|
||||||
use network::serialize::deserialize;
|
use consensus::encode::deserialize;
|
||||||
use util::misc::hex_bytes;
|
use util::misc::hex_bytes;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -20,16 +20,14 @@ use std::cmp::min;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Cursor;
|
use std::io::{self, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
#[cfg(feature = "serde")] use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use crypto::ripemd160::Ripemd160;
|
use crypto::ripemd160::Ripemd160;
|
||||||
|
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use consensus::encode::{Encodable, Decodable};
|
||||||
use network::serialize::{self, SimpleEncoder, RawEncoder, BitcoinHash};
|
|
||||||
use util::uint::Uint256;
|
use util::uint::Uint256;
|
||||||
|
|
||||||
#[cfg(feature="fuzztarget")] use util::sha2::Sha256;
|
#[cfg(feature="fuzztarget")] use util::sha2::Sha256;
|
||||||
|
@ -108,61 +106,13 @@ impl Sha256dEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleEncoder for Sha256dEncoder {
|
impl Write for Sha256dEncoder {
|
||||||
fn emit_u64(&mut self, v: u64) -> Result<(), serialize::Error> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
let mut data = [0; 8];
|
self.0.input(buf);
|
||||||
(&mut data[..]).write_u64::<LittleEndian>(v).unwrap();
|
Ok(buf.len())
|
||||||
self.0.input(&data);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_u32(&mut self, v: u32) -> Result<(), serialize::Error> {
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
let mut data = [0; 4];
|
|
||||||
(&mut data[..]).write_u32::<LittleEndian>(v).unwrap();
|
|
||||||
self.0.input(&data);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_u16(&mut self, v: u16) -> Result<(), serialize::Error> {
|
|
||||||
let mut data = [0; 2];
|
|
||||||
(&mut data[..]).write_u16::<LittleEndian>(v).unwrap();
|
|
||||||
self.0.input(&data);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_i64(&mut self, v: i64) -> Result<(), serialize::Error> {
|
|
||||||
let mut data = [0; 8];
|
|
||||||
(&mut data[..]).write_i64::<LittleEndian>(v).unwrap();
|
|
||||||
self.0.input(&data);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_i32(&mut self, v: i32) -> Result<(), serialize::Error> {
|
|
||||||
let mut data = [0; 4];
|
|
||||||
(&mut data[..]).write_i32::<LittleEndian>(v).unwrap();
|
|
||||||
self.0.input(&data);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_i16(&mut self, v: i16) -> Result<(), serialize::Error> {
|
|
||||||
let mut data = [0; 2];
|
|
||||||
(&mut data[..]).write_i16::<LittleEndian>(v).unwrap();
|
|
||||||
self.0.input(&data);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_i8(&mut self, v: i8) -> Result<(), serialize::Error> {
|
|
||||||
self.0.input(&[v as u8]);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_u8(&mut self, v: u8) -> Result<(), serialize::Error> {
|
|
||||||
self.0.input(&[v]);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_bool(&mut self, v: bool) -> Result<(), serialize::Error> {
|
|
||||||
self.0.input(&[if v {1} else {0}]);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,9 +306,9 @@ impl serde::Serialize for Sha256dHash {
|
||||||
/// Note that this outputs hashes as big endian hex numbers, so this should be
|
/// Note that this outputs hashes as big endian hex numbers, so this should be
|
||||||
/// used only for user-facing stuff. Internal and network serialization is
|
/// used only for user-facing stuff. Internal and network serialization is
|
||||||
/// little-endian and should be done using the consensus
|
/// little-endian and should be done using the consensus
|
||||||
/// [`ConsensusEncodable`][1] interface.
|
/// [`Encodable`][1] interface.
|
||||||
///
|
///
|
||||||
/// [1]: ../../network/encodable/trait.ConsensusEncodable.html
|
/// [1]: ../../network/encodable/trait.Encodable.html
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
|
@ -462,10 +412,10 @@ pub fn bitcoin_merkle_root(data: Vec<Sha256dHash>) -> Sha256dHash {
|
||||||
for idx in 0..((data.len() + 1) / 2) {
|
for idx in 0..((data.len() + 1) / 2) {
|
||||||
let idx1 = 2 * idx;
|
let idx1 = 2 * idx;
|
||||||
let idx2 = min(idx1 + 1, data.len() - 1);
|
let idx2 = min(idx1 + 1, data.len() - 1);
|
||||||
let mut encoder = RawEncoder::new(Cursor::new(vec![]));
|
let mut encoder = Sha256dEncoder::new();
|
||||||
data[idx1].consensus_encode(&mut encoder).unwrap();
|
data[idx1].consensus_encode(&mut encoder).unwrap();
|
||||||
data[idx2].consensus_encode(&mut encoder).unwrap();
|
data[idx2].consensus_encode(&mut encoder).unwrap();
|
||||||
next.push(encoder.into_inner().into_inner().bitcoin_hash());
|
next.push(encoder.into_hash());
|
||||||
}
|
}
|
||||||
bitcoin_merkle_root(next)
|
bitcoin_merkle_root(next)
|
||||||
}
|
}
|
||||||
|
@ -482,14 +432,19 @@ impl <T: BitcoinHash> MerkleRoot for Vec<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Objects which are referred to by hash
|
||||||
|
pub trait BitcoinHash {
|
||||||
|
/// Produces a Sha256dHash which can be used to refer to the object
|
||||||
|
fn bitcoin_hash(&self) -> Sha256dHash;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[cfg(all(feature = "serde", feature = "strason"))]
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
use strason::Json;
|
use strason::Json;
|
||||||
|
|
||||||
use network::encodable::{ConsensusEncodable, VarInt};
|
use consensus::encode::{Encodable, VarInt};
|
||||||
use network::serialize::{serialize, deserialize};
|
use consensus::encode::{serialize, deserialize};
|
||||||
use util::uint::{Uint128, Uint256};
|
use util::uint::{Uint128, Uint256};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -541,7 +496,7 @@ mod tests {
|
||||||
let test = vec![true, false, true, true, false];
|
let test = vec![true, false, true, true, false];
|
||||||
let mut enc = Sha256dEncoder::new();
|
let mut enc = Sha256dEncoder::new();
|
||||||
assert!(test.consensus_encode(&mut enc).is_ok());
|
assert!(test.consensus_encode(&mut enc).is_ok());
|
||||||
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test).unwrap()));
|
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test)));
|
||||||
|
|
||||||
macro_rules! array_encode_test (
|
macro_rules! array_encode_test (
|
||||||
($ty:ty) => ({
|
($ty:ty) => ({
|
||||||
|
@ -549,7 +504,7 @@ mod tests {
|
||||||
let test: [$ty; 1000] = [1; 1000];
|
let test: [$ty; 1000] = [1; 1000];
|
||||||
let mut enc = Sha256dEncoder::new();
|
let mut enc = Sha256dEncoder::new();
|
||||||
assert!((&test[..]).consensus_encode(&mut enc).is_ok());
|
assert!((&test[..]).consensus_encode(&mut enc).is_ok());
|
||||||
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]).unwrap()));
|
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..])));
|
||||||
|
|
||||||
// try doing it just one object at a time
|
// try doing it just one object at a time
|
||||||
let mut enc = Sha256dEncoder::new();
|
let mut enc = Sha256dEncoder::new();
|
||||||
|
@ -557,7 +512,7 @@ mod tests {
|
||||||
for obj in &test[..] {
|
for obj in &test[..] {
|
||||||
assert!(obj.consensus_encode(&mut enc).is_ok());
|
assert!(obj.consensus_encode(&mut enc).is_ok());
|
||||||
}
|
}
|
||||||
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]).unwrap()));
|
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..])));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -574,7 +529,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_consenus_encode_roundtrip() {
|
fn test_consenus_encode_roundtrip() {
|
||||||
let hash = Sha256dHash::from_data(&[]);
|
let hash = Sha256dHash::from_data(&[]);
|
||||||
let serial = serialize(&hash).unwrap();
|
let serial = serialize(&hash);
|
||||||
let deserial = deserialize(&serial).unwrap();
|
let deserial = deserialize(&serial).unwrap();
|
||||||
assert_eq!(hash, deserial);
|
assert_eq!(hash, deserial);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
|
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use util::iter::Pairable;
|
use util::iter::Pairable;
|
||||||
use network::serialize;
|
use consensus::encode;
|
||||||
|
|
||||||
/// Convert a hexadecimal-encoded string to its corresponding bytes
|
/// Convert a hexadecimal-encoded string to its corresponding bytes
|
||||||
pub fn hex_bytes(s: &str) -> Result<Vec<u8>, serialize::Error> {
|
pub fn hex_bytes(s: &str) -> Result<Vec<u8>, encode::Error> {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
let mut iter = s.chars().pair();
|
let mut iter = s.chars().pair();
|
||||||
// Do the parsing
|
// Do the parsing
|
||||||
|
@ -29,15 +29,15 @@ pub fn hex_bytes(s: &str) -> Result<Vec<u8>, serialize::Error> {
|
||||||
if e.is_err() { e }
|
if e.is_err() { e }
|
||||||
else {
|
else {
|
||||||
match (f.to_digit(16), s.to_digit(16)) {
|
match (f.to_digit(16), s.to_digit(16)) {
|
||||||
(None, _) => Err(serialize::Error::UnexpectedHexDigit(f)),
|
(None, _) => Err(encode::Error::UnexpectedHexDigit(f)),
|
||||||
(_, None) => Err(serialize::Error::UnexpectedHexDigit(s)),
|
(_, None) => Err(encode::Error::UnexpectedHexDigit(s)),
|
||||||
(Some(f), Some(s)) => { v.push((f * 0x10 + s) as u8); Ok(()) }
|
(Some(f), Some(s)) => { v.push((f * 0x10 + s) as u8); Ok(()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)?;
|
)?;
|
||||||
// Check that there was no remainder
|
// Check that there was no remainder
|
||||||
match iter.remainder() {
|
match iter.remainder() {
|
||||||
Some(_) => Err(serialize::Error::ParseFailed("hexstring of odd length")),
|
Some(_) => Err(encode::Error::ParseFailed("hexstring of odd length")),
|
||||||
None => Ok(v)
|
None => Ok(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ use std::{error, fmt};
|
||||||
use secp256k1;
|
use secp256k1;
|
||||||
|
|
||||||
use network;
|
use network;
|
||||||
use network::serialize;
|
use consensus::encode;
|
||||||
|
|
||||||
/// A trait which allows numbers to act as fixed-size bit arrays
|
/// A trait which allows numbers to act as fixed-size bit arrays
|
||||||
pub trait BitArray {
|
pub trait BitArray {
|
||||||
|
@ -65,8 +65,8 @@ pub trait BitArray {
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// secp-related error
|
/// secp-related error
|
||||||
Secp256k1(secp256k1::Error),
|
Secp256k1(secp256k1::Error),
|
||||||
/// Serialization error
|
/// Encoding error
|
||||||
Serialize(serialize::Error),
|
Encode(encode::Error),
|
||||||
/// Network error
|
/// Network error
|
||||||
Network(network::Error),
|
Network(network::Error),
|
||||||
/// The header hash is not below the target
|
/// The header hash is not below the target
|
||||||
|
@ -79,7 +79,7 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Secp256k1(ref e) => fmt::Display::fmt(e, f),
|
Error::Secp256k1(ref e) => fmt::Display::fmt(e, f),
|
||||||
Error::Serialize(ref e) => fmt::Display::fmt(e, f),
|
Error::Encode(ref e) => fmt::Display::fmt(e, f),
|
||||||
Error::Network(ref e) => fmt::Display::fmt(e, f),
|
Error::Network(ref e) => fmt::Display::fmt(e, f),
|
||||||
Error::SpvBadProofOfWork | Error::SpvBadTarget => f.write_str(error::Error::description(self)),
|
Error::SpvBadProofOfWork | Error::SpvBadTarget => f.write_str(error::Error::description(self)),
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ impl error::Error for Error {
|
||||||
fn cause(&self) -> Option<&error::Error> {
|
fn cause(&self) -> Option<&error::Error> {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Secp256k1(ref e) => Some(e),
|
Error::Secp256k1(ref e) => Some(e),
|
||||||
Error::Serialize(ref e) => Some(e),
|
Error::Encode(ref e) => Some(e),
|
||||||
Error::Network(ref e) => Some(e),
|
Error::Network(ref e) => Some(e),
|
||||||
Error::SpvBadProofOfWork | Error::SpvBadTarget => None
|
Error::SpvBadProofOfWork | Error::SpvBadTarget => None
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ impl error::Error for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Secp256k1(ref e) => e.description(),
|
Error::Secp256k1(ref e) => e.description(),
|
||||||
Error::Serialize(ref e) => e.description(),
|
Error::Encode(ref e) => e.description(),
|
||||||
Error::Network(ref e) => e.description(),
|
Error::Network(ref e) => e.description(),
|
||||||
Error::SpvBadProofOfWork => "target correct but not attained",
|
Error::SpvBadProofOfWork => "target correct but not attained",
|
||||||
Error::SpvBadTarget => "target incorrect",
|
Error::SpvBadTarget => "target incorrect",
|
||||||
|
@ -115,9 +115,9 @@ impl From<secp256k1::Error> for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl From<serialize::Error> for Error {
|
impl From<encode::Error> for Error {
|
||||||
fn from(e: serialize::Error) -> Error {
|
fn from(e: encode::Error) -> Error {
|
||||||
Error::Serialize(e)
|
Error::Encode(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::str::FromStr;
|
||||||
use secp256k1::{self, Secp256k1};
|
use secp256k1::{self, Secp256k1};
|
||||||
use secp256k1::key::{PublicKey, SecretKey};
|
use secp256k1::key::{PublicKey, SecretKey};
|
||||||
use util::address::Address;
|
use util::address::Address;
|
||||||
use network::serialize;
|
use consensus::encode;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use util::base58;
|
use util::base58;
|
||||||
|
|
||||||
|
@ -113,21 +113,21 @@ impl Display for Privkey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Privkey {
|
impl FromStr for Privkey {
|
||||||
type Err = serialize::Error;
|
type Err = encode::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Privkey, serialize::Error> {
|
fn from_str(s: &str) -> Result<Privkey, encode::Error> {
|
||||||
let data = base58::from_check(s)?;
|
let data = base58::from_check(s)?;
|
||||||
|
|
||||||
let compressed = match data.len() {
|
let compressed = match data.len() {
|
||||||
33 => false,
|
33 => false,
|
||||||
34 => true,
|
34 => true,
|
||||||
_ => { return Err(serialize::Error::Base58(base58::Error::InvalidLength(data.len()))); }
|
_ => { return Err(encode::Error::Base58(base58::Error::InvalidLength(data.len()))); }
|
||||||
};
|
};
|
||||||
|
|
||||||
let network = match data[0] {
|
let network = match data[0] {
|
||||||
128 => Network::Bitcoin,
|
128 => Network::Bitcoin,
|
||||||
239 => Network::Testnet,
|
239 => Network::Testnet,
|
||||||
x => { return Err(serialize::Error::Base58(base58::Error::InvalidVersion(vec![x]))); }
|
x => { return Err(encode::Error::Base58(base58::Error::InvalidVersion(vec![x]))); }
|
||||||
};
|
};
|
||||||
|
|
||||||
let secp = Secp256k1::without_caps();
|
let secp = Secp256k1::without_caps();
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use network::serialize;
|
use consensus::encode;
|
||||||
use util::BitArray;
|
use util::BitArray;
|
||||||
|
|
||||||
macro_rules! construct_uint {
|
macro_rules! construct_uint {
|
||||||
|
@ -336,19 +336,19 @@ macro_rules! construct_uint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: ::network::serialize::SimpleEncoder> ::network::encodable::ConsensusEncodable<S> for $name {
|
impl<S: ::consensus::encode::Encoder> ::consensus::encode::Encodable<S> for $name {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
|
||||||
let &$name(ref data) = self;
|
let &$name(ref data) = self;
|
||||||
for word in data.iter() { word.consensus_encode(s)?; }
|
for word in data.iter() { word.consensus_encode(s)?; }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: ::network::serialize::SimpleDecoder> ::network::encodable::ConsensusDecodable<D> for $name {
|
impl<D: ::consensus::encode::Decoder> ::consensus::encode::Decodable<D> for $name {
|
||||||
fn consensus_decode(d: &mut D) -> Result<$name, serialize::Error> {
|
fn consensus_decode(d: &mut D) -> Result<$name, encode::Error> {
|
||||||
use network::encodable::ConsensusDecodable;
|
use consensus::encode::Decodable;
|
||||||
let ret: [u64; $n_words] = ConsensusDecodable::consensus_decode(d)?;
|
let ret: [u64; $n_words] = Decodable::consensus_decode(d)?;
|
||||||
Ok($name(ret))
|
Ok($name(ret))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,7 @@ impl Uint256 {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use network::serialize::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
use util::uint::Uint256;
|
use util::uint::Uint256;
|
||||||
use util::BitArray;
|
use util::BitArray;
|
||||||
|
|
||||||
|
@ -535,8 +535,8 @@ mod tests {
|
||||||
pub fn uint256_serialize_test() {
|
pub fn uint256_serialize_test() {
|
||||||
let start1 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]);
|
let start1 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]);
|
||||||
let start2 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0xABCD, 0xFFFF]);
|
let start2 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0xABCD, 0xFFFF]);
|
||||||
let serial1 = serialize(&start1).unwrap();
|
let serial1 = serialize(&start1);
|
||||||
let serial2 = serialize(&start2).unwrap();
|
let serial2 = serialize(&start2);
|
||||||
let end1: Result<Uint256, _> = deserialize(&serial1);
|
let end1: Result<Uint256, _> = deserialize(&serial1);
|
||||||
let end2: Result<Uint256, _> = deserialize(&serial2);
|
let end2: Result<Uint256, _> = deserialize(&serial2);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue