Checkpoint commit: into warnings!

This commit is contained in:
Andrew Poelstra 2015-04-10 18:15:57 -05:00
parent 1d78dccb9e
commit 3117f95b62
13 changed files with 143 additions and 141 deletions

View File

@ -32,7 +32,7 @@ use blockdata::transaction::Transaction;
/// A block header, which contains all the block's information except
/// the actual transactions
#[derive(PartialEq, Eq, Clone, Debug)]
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub struct BlockHeader {
/// The protocol version. Should always be 1.
pub version: u32,

View File

@ -34,7 +34,7 @@ use network::encodable::{ConsensusDecodable, ConsensusEncodable};
// write an #[inline] helper function which casts to u8s.
/// A script Opcode
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum All {
/// Push an empty array onto the stack
@ -633,7 +633,7 @@ pub static OP_FALSE: All = All::OP_PUSHBYTES_0;
pub static OP_TRUE: All = All::OP_PUSHNUM_1;
/// Broad categories of opcodes with similar behavior
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Class {
/// Pushes the given number onto the stack
PushNum(i32),
@ -663,7 +663,7 @@ macro_rules! ordinary_opcode {
($($op:ident),*) => (
#[repr(u8)]
#[doc(hidden)]
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Ordinary {
$( $op = All::$op as u8 ),*
}

View File

@ -1628,10 +1628,10 @@ macro_rules! stack_opcode {
macro_rules! num_opcode {
($stack:ident($($var:ident),*): $op:expr) => ({
$(
let $var = try!(read_scriptint(match $stack.pop() {
Some(elem) => &elem[..],
let $var = try!(read_scriptint(&match $stack.pop() {
Some(elem) => elem,
None => { return Err(Error::PopEmptyStack); }
}));
}[..]));
)*
$stack.push(MaybeOwned::Owned(build_scriptint($op)));
// Return a tuple of all the variables

View File

@ -153,16 +153,15 @@ pub struct TransactionTrace {
impl TxIn {
/// Check an input's script for validity
pub fn validate(&self,
utxoset: &UtxoSet,
txn: &Transaction,
index: usize) -> Result<(), Error> {
utxoset: &UtxoSet,
txn: &Transaction,
index: usize) -> Result<(), Error> {
let txo = utxoset.get_utxo(self.prev_hash, self.prev_index);
match txo {
Some((_, txo)) => {
let mut p2sh_stack = Vec::new();
let mut p2sh_script = Script::new();
let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new());
let mut stack = Vec::with_capacity(6);
let mut stack = vec![];
match self.script_sig.evaluate(&mut stack, Some((txn, index)), None) {
Ok(_) => {}
Err(e) => { return Err(Error::InputScriptFailure(e)); }
@ -220,7 +219,7 @@ impl Transaction {
/// Produce a trace of a transaction's execution
pub fn trace(&self, utxoset: &UtxoSet) -> TransactionTrace {
let mut ret = TransactionTrace { txid: self.bitcoin_hash(),
inputs: Vec::with_capacity(self.input.len()) };
inputs: Vec::with_capacity(self.input.len()) };
for (n, input) in self.input.iter().enumerate() {
// Setup trace
let mut trace = InputTrace {
@ -240,8 +239,7 @@ impl Transaction {
let txo = utxoset.get_utxo(input.prev_hash, input.prev_index);
match txo {
Some((_, txo)) => {
let mut p2sh_stack = Vec::new();
let mut p2sh_script = Script::new();
let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new());
let mut stack = Vec::with_capacity(6);
trace.sig_trace = input.script_sig.trace(&mut stack, Some((self, n)));

View File

@ -196,7 +196,7 @@ impl UtxoSet {
};
// Check that this specific output is there
if vout as usize >= node.outputs.len() { return None; }
let replace = node.outputs[vout as usize];
let replace = &node.outputs[vout as usize];
Some((node.height as usize, replace.as_ref().unwrap()))
}
@ -283,7 +283,7 @@ impl UtxoSet {
// Return the last error since we need to finish every future before
// leaving this function, and given that, it's easier to return the last.
let mut last_err = Ok(());
for res in future_vec.iter_mut().map(|f| f.await().unwrap()) {
for res in future_vec.into_iter().map(|f| f.await().unwrap()) {
if res.is_err() { last_err = res; }
}
if last_err.is_err() { return last_err; }
@ -292,7 +292,7 @@ impl UtxoSet {
for tx in block.txdata.iter().skip(1) {
let txid = tx.bitcoin_hash();
// Put the removed utxos into the stxo cache, in case we need to rewind
(&self.spent_txos[spent_idx]).reserve(tx.input.len());
(&mut self.spent_txos[spent_idx]).reserve(tx.input.len());
for (n, input) in tx.input.iter().enumerate() {
let taken = self.take_utxo(input.prev_hash, input.prev_index);
match taken {

View File

@ -117,6 +117,8 @@ macro_rules! impl_array_newtype {
}
}
impl Copy for $thing {}
impl ::std::hash::Hash for $thing {
#[inline]
fn hash<H>(&self, state: &mut H)

View File

@ -56,9 +56,12 @@ extern crate rand;
extern crate rustc_serialize as serialize;
extern crate secp256k1;
extern crate serde;
extern crate test;
#[cfg(test)] extern crate test;
extern crate time;
#[cfg(test)]
#[macro_use]
mod test_macros;
#[macro_use]
mod internal_macros;
#[macro_use]

View File

@ -22,7 +22,7 @@ use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{SimpleEncoder, SimpleDecoder};
user_enum! {
#[derive(PartialEq, Eq, Clone, Hash)]
#[derive(Copy, PartialEq, Eq, Clone, Hash)]
#[doc="The cryptocurrency to act on"]
pub enum Network {
#[doc="Classic Bitcoin"]

View File

@ -35,9 +35,9 @@ use util::{self, propagate_err};
/// Format an IP address in the 16-byte bitcoin protocol serialization
fn ipaddr_to_bitcoin_addr(ipaddr: &net::IpAddr) -> [u16; 8] {
match *ipaddr {
net::IpAddr::V4(ref addr) => &addr.to_ipv6_mapped(),
net::IpAddr::V6(ref addr) => addr
}.segments()
net::IpAddr::V4(ref addr) => addr.to_ipv6_mapped().segments(),
net::IpAddr::V6(ref addr) => addr.segments()
}
}
/// A network socket along with information about the peer
@ -55,6 +55,31 @@ pub struct Socket {
pub magic: u32
}
macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({
use ::std::ops::DerefMut;
let mut sock_lock = $s.socket.lock();
match sock_lock {
Err(_) => {
let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: socket mutex was poisoned");
return Err(util::Error::Io(io_err));
}
Ok(mut guard) => {
match *guard.deref_mut() {
Some(ref mut $sock) => {
$body
}
None => {
let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: not connected to peer");
return Err(util::Error::Io(io_err));
}
}
}
}
}));
impl Socket {
// TODO: we fix services to 0
/// Construct a new socket
@ -85,55 +110,36 @@ impl Socket {
}
}
fn socket(&mut self) -> Result<&mut net::TcpStream, util::Error> {
let mut sock_lock = self.socket.lock();
match sock_lock {
Err(_) => {
let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: socket mutex was poisoned");
Err(util::Error::Io(io_err))
}
Ok(guard) => {
match *guard {
Some(ref mut sock) => Ok(sock),
None => {
let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: not connected to peer");
Err(util::Error::Io(io_err))
}
}
}
}
}
/// Peer address
pub fn receiver_address(&mut self) -> Result<Address, util::Error> {
let sock = try!(self.socket());
match sock.peer_addr() {
Ok(addr) => {
Ok(Address {
services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip()),
port: addr.port()
})
},
Err(e) => Err(util::Error::Io(e))
}
with_socket!(self, sock, {
match sock.peer_addr() {
Ok(addr) => {
Ok(Address {
services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip()),
port: addr.port()
})
},
Err(e) => Err(util::Error::Io(e))
}
})
}
/// Our own address
pub fn sender_address(&mut self) -> Result<Address, util::Error> {
let sock = try!(self.socket());
match sock.local_addr() {
Ok(addr) => {
Ok(Address {
services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip()),
port: addr.port()
})
},
Err(e) => Err(util::Error::Io(e))
}
with_socket!(self, sock, {
match sock.local_addr() {
Ok(addr) => {
Ok(Address {
services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip()),
port: addr.port()
})
},
Err(e) => Err(util::Error::Io(e))
}
})
}
/// Produce a version message appropriate for this socket
@ -157,35 +163,37 @@ impl Socket {
/// Send a general message across the line
pub fn send_message(&mut self, payload: NetworkMessage) -> Result<(), util::Error> {
let sock = try!(self.socket());
let message = RawNetworkMessage { magic: self.magic, payload: payload };
try!(message.consensus_encode(&mut RawEncoder::new(sock)));
sock.flush().map_err(util::Error::Io)
with_socket!(self, sock, {
let message = RawNetworkMessage { magic: self.magic, payload: payload };
try!(message.consensus_encode(&mut RawEncoder::new(&mut *sock)));
sock.flush().map_err(util::Error::Io)
})
}
/// 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> {
let sock = try!(self.socket());
// 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 decode: Result<RawNetworkMessage, _> = ConsensusDecodable::consensus_decode(&mut decoder);
match decode {
// Check for parse errors...
Err(e) => {
propagate_err("receive_message".to_string(), Err(e))
},
Ok(ret) => {
// Then for magic (this should come before parse error, but we can't
// get to it if the deserialization failed). TODO restructure this
if ret.magic != self.magic {
Err(util::Error::BadNetworkMagic(self.magic, ret.magic))
} else {
Ok(ret.payload)
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 decode: Result<RawNetworkMessage, _> = ConsensusDecodable::consensus_decode(&mut decoder);
match decode {
// Check for parse errors...
Err(e) => {
propagate_err("receive_message".to_string(), Err(e))
},
Ok(ret) => {
// Then for magic (this should come before parse error, but we can't
// get to it if the deserialization failed). TODO restructure this
if ret.magic != self.magic {
Err(util::Error::BadNetworkMagic(self.magic, ret.magic))
} else {
Ok(ret.payload)
}
}
}
}
})
}
}

View File

@ -48,15 +48,15 @@ pub struct Ripemd160Hash([u8; 20]);
impl_array_newtype!(Ripemd160Hash, u8, 20);
/// A 32-bit hash obtained by truncating a real hash
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Hash32((u8, u8, u8, u8));
/// A 48-bit hash obtained by truncating a real hash
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Hash48((u8, u8, u8, u8, u8, u8));
/// A 64-bit hash obtained by truncating a real hash
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8));
impl Ripemd160Hash {
@ -268,8 +268,7 @@ mod tests {
use std::io::Cursor;
use std::num::FromPrimitive;
use std::str::from_utf8;
use serialize::Encodable;
use serialize::json;
use serde::{json, Serialize, Deserialize};
use network::serialize::{serialize, deserialize};
use util::hash::Sha256dHash;
@ -296,15 +295,15 @@ mod tests {
#[test]
fn test_hash_encode_decode() {
let hash = Sha256dHash::from_data(&[]);
let mut writer = Cursor::new(vec![]);
let mut writer = vec![];
{
let mut encoder = json::Encoder::new(&mut writer);
assert!(hash.encode(&mut encoder).is_ok());
let mut serializer = json::ser::Serializer::new(&mut writer);
assert!(hash.serialize(&mut serializer).is_ok());
}
let res = writer.into_inner();
assert_eq!(&res[..],
assert_eq!(&writer[..],
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
assert_eq!(json::decode(from_utf8(res.as_slice()).unwrap()), Ok(hash));
let mut deserializer = json::de::Deserializer::new(writer.iter().map(|c| Ok(*c))).unwrap();
assert_eq!(hash, Deserialize::deserialize(&mut deserializer).unwrap());
}
#[test]

View File

@ -25,7 +25,7 @@ pub fn hex_bytes(s: &str) -> Result<Vec<u8>, Error> {
let mut v = vec![];
let mut iter = s.chars().pair();
// Do the parsing
try!(iter.fold(Ok(()), |e, (f, s)|
try!(iter.by_ref().fold(Ok(()), |e, (f, s)|
if e.is_err() { e }
else {
match (f.to_digit(16), s.to_digit(16)) {
@ -73,9 +73,8 @@ pub fn script_find_and_remove(haystack: &mut Vec<u8>, needle: &[u8]) -> usize {
let mut i = 0;
while i <= top {
if &haystack[i..(i + needle.len())] == needle {
let v = &mut haystack;
for j in i..top {
v.swap(j + needle.len(), j);
haystack.swap(j + needle.len(), j);
}
n_deleted += 1;
// This is ugly but prevents infinite loop in case of overflow

View File

@ -30,7 +30,7 @@ use network::serialize::{SimpleDecoder, SimpleEncoder};
use util::BitArray;
/// Patricia troo
pub struct PatriciaTree<K, V> {
pub struct PatriciaTree<K: Copy, V> {
data: Option<V>,
child_l: Option<Box<PatriciaTree<K, V>>>,
child_r: Option<Box<PatriciaTree<K, V>>>,
@ -39,7 +39,7 @@ pub struct PatriciaTree<K, V> {
}
impl<K, V> PatriciaTree<K, V>
where K: BitArray + cmp::Eq + Zero + One +
where K: Copy + BitArray + cmp::Eq + Zero + One +
ops::BitXor<K, Output=K> +
ops::Add<K, Output=K> +
ops::Shr<usize, Output=K> +
@ -221,7 +221,7 @@ impl<K, V> PatriciaTree<K, V>
/// Return value is (deletable, actual return value), where `deletable` is true
/// is true when the entire node can be deleted (i.e. it has no children)
fn recurse<K, V>(tree: &mut PatriciaTree<K, V>, key: &K, key_len: usize) -> (bool, Option<V>)
where K: BitArray + cmp::Eq + Zero + One +
where K: Copy + BitArray + cmp::Eq + Zero + One +
ops::Add<K, Output=K> +
ops::Shr<usize, Output=K> +
ops::Shl<usize, Output=K>
@ -333,7 +333,7 @@ impl<K, V> PatriciaTree<K, V>
/// Count all the nodes
pub fn node_count(&self) -> usize {
fn recurse<K, V>(node: &Option<Box<PatriciaTree<K, V>>>) -> usize {
fn recurse<K: Copy, V>(node: &Option<Box<PatriciaTree<K, V>>>) -> usize {
match node {
&Some(ref node) => { 1 + recurse(&node.child_l) + recurse(&node.child_r) }
&None => 0
@ -362,10 +362,12 @@ impl<K, V> PatriciaTree<K, V>
}
}
impl<K:BitArray, V:Debug> Debug for PatriciaTree<K, V> {
impl<K: Copy + BitArray, V: Debug> Debug for PatriciaTree<K, V> {
/// Print the entire tree
fn fmt<'a>(&'a self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn recurse<'a, K:BitArray, V:Debug>(tree: &'a PatriciaTree<K, V>, f: &mut fmt::Formatter, depth: usize) -> Result<(), fmt::Error> {
fn recurse<'a, K, V>(tree: &'a PatriciaTree<K, V>, f: &mut fmt::Formatter, depth: usize) -> Result<(), fmt::Error>
where K: Copy + BitArray, V: Debug
{
for i in 0..tree.skip_len as usize {
try!(write!(f, "{:}", if tree.skip_prefix.bit(i) { 1 } else { 0 }));
}
@ -400,7 +402,7 @@ impl<K:BitArray, V:Debug> Debug for PatriciaTree<K, V> {
impl<S, K, V> ConsensusEncodable<S> for PatriciaTree<K, V>
where S: SimpleEncoder,
K: ConsensusEncodable<S>,
K: Copy + ConsensusEncodable<S>,
V: ConsensusEncodable<S>
{
fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
@ -416,7 +418,7 @@ impl<S, K, V> ConsensusEncodable<S> for PatriciaTree<K, V>
impl<D, K, V> ConsensusDecodable<D> for PatriciaTree<K, V>
where D: SimpleDecoder,
K: ConsensusDecodable<D>,
K: Copy + ConsensusDecodable<D>,
V: ConsensusDecodable<D>
{
fn consensus_decode(d: &mut D) -> Result<PatriciaTree<K, V>, D::Error> {
@ -431,25 +433,25 @@ impl<D, K, V> ConsensusDecodable<D> for PatriciaTree<K, V>
}
/// Iterator
pub struct Items<'tree, K: 'tree, V: 'tree> {
pub struct Items<'tree, K: Copy + 'tree, V: 'tree> {
started: bool,
node: Option<&'tree PatriciaTree<K, V>>,
parents: Vec<&'tree PatriciaTree<K, V>>
}
/// Mutable iterator
pub struct MutItems<'tree, K: 'tree, V: 'tree> {
pub struct MutItems<'tree, K: Copy + 'tree, V: 'tree> {
started: bool,
node: *mut PatriciaTree<K, V>,
parents: Vec<*mut PatriciaTree<K, V>>,
marker: marker::PhantomData<&'tree PatriciaTree<K, V>>
}
impl<'a, K, V> Iterator for Items<'a, K, V> {
impl<'a, K: Copy, V> Iterator for Items<'a, K, V> {
type Item = &'a V;
fn next(&mut self) -> Option<&'a V> {
fn borrow_opt<'a, K, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> Option<&'a PatriciaTree<K, V>> {
fn borrow_opt<'a, K: Copy, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> Option<&'a PatriciaTree<K, V>> {
opt_ptr.as_ref().map(|b| &**b)
}
@ -491,11 +493,11 @@ impl<'a, K, V> Iterator for Items<'a, K, V> {
}
}
impl<'a, K, V> Iterator for MutItems<'a, K, V> {
impl<'a, K: Copy, V> Iterator for MutItems<'a, K, V> {
type Item = &'a mut V;
fn next(&mut self) -> Option<&'a mut V> {
fn borrow_opt<'a, K, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> *mut PatriciaTree<K, V> {
fn borrow_opt<'a, K: Copy, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> *mut PatriciaTree<K, V> {
match *opt_ptr {
Some(ref data) => &**data as *const _ as *mut _,
None => ptr::null_mut()

View File

@ -51,7 +51,7 @@ impl Default for Fingerprint {
}
/// Extended private key
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct ExtendedPrivKey {
/// The network this key is to be used on
pub network: Network,
@ -68,7 +68,7 @@ pub struct ExtendedPrivKey {
}
/// Extended public key
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct ExtendedPubKey {
/// The network this key is to be used on
pub network: Network,
@ -85,7 +85,7 @@ pub struct ExtendedPubKey {
}
/// A child number for a derived key
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ChildNumber {
/// Hardened key index, within [0, 2^31 - 1]
Hardened(u32),
@ -292,9 +292,9 @@ impl ExtendedPubKey {
impl ToBase58 for ExtendedPrivKey {
fn base58_layout(&self) -> Vec<u8> {
let mut ret = Vec::with_capacity(78);
ret.push_all(match self.network {
Network::Bitcoin => &[0x04, 0x88, 0xAD, 0xE4],
Network::Testnet => &[0x04, 0x35, 0x83, 0x94]
ret.push_all(&match self.network {
Network::Bitcoin => [0x04, 0x88, 0xAD, 0xE4],
Network::Testnet => [0x04, 0x35, 0x83, 0x94]
});
ret.push(self.depth as u8);
ret.push_all(&self.parent_fingerprint[..]);
@ -346,9 +346,9 @@ impl ToBase58 for ExtendedPubKey {
fn base58_layout(&self) -> Vec<u8> {
assert!(self.public_key.is_compressed());
let mut ret = Vec::with_capacity(78);
ret.push_all(match self.network {
Network::Bitcoin => &[0x04u8, 0x88, 0xB2, 0x1E],
Network::Testnet => &[0x04u8, 0x35, 0x87, 0xCF]
ret.push_all(&match self.network {
Network::Bitcoin => [0x04u8, 0x88, 0xB2, 0x1E],
Network::Testnet => [0x04u8, 0x35, 0x87, 0xCF]
});
ret.push(self.depth as u8);
ret.push_all(&self.parent_fingerprint[..]);
@ -510,21 +510,12 @@ mod tests {
#[test]
pub fn encode_decode_childnumber() {
use serialize::json;
let h1 = Hardened(1);
let n1 = Normal(1);
let h1_str = json::encode(&h1);
let n1_str = json::encode(&n1);
assert!(h1 != n1);
assert!(h1_str != n1_str);
let h1_dec = json::decode(&h1_str).unwrap();
let n1_dec = json::decode(&n1_str).unwrap();
assert_eq!(h1, h1_dec);
assert_eq!(n1, n1_dec);
serde_round_trip!(Normal(0));
serde_round_trip!(Normal(1));
serde_round_trip!(Normal((1 << 31) - 1));
serde_round_trip!(Hardened(0));
serde_round_trip!(Hardened(1));
serde_round_trip!(Hardened((1 << 31) - 1));
}
#[bench]