Checkpoint commit

Work is stalled on some other library work (to give better lifetime
requirements on `eventual::Future` and avoid some unsafety), so
committing here.

There are only three errors left in this round :)

Also all the indenting is done, so there should be no more massive
rewrite commits. Depending how invasive the lifetime-error fixes
are, I may even be able to do sanely sized commits from here on.
This commit is contained in:
Andrew Poelstra 2015-04-07 17:51:57 -05:00
parent 200e0fe8e3
commit 08a20f8764
24 changed files with 4174 additions and 4202 deletions

View File

@ -11,6 +11,9 @@ path = "src/lib.rs"
[dependencies.secp256k1] [dependencies.secp256k1]
git = "https://github.com/apoelstra/bitcoin-secp256k1-rs.git" git = "https://github.com/apoelstra/bitcoin-secp256k1-rs.git"
[dependencies.eventual]
git = "https://github.com/carllerche/eventual"
[dependencies] [dependencies]
byteorder = "*" byteorder = "*"
num_cpus = "*" num_cpus = "*"

View File

@ -112,7 +112,7 @@ impl BlockHeader {
let mut ret = !self.target(); let mut ret = !self.target();
let mut ret1 = self.target(); let mut ret1 = self.target();
ret1.increment(); ret1.increment();
ret = ret.div(&ret1); ret = ret / ret1;
ret.increment(); ret.increment();
ret ret
} }
@ -121,7 +121,7 @@ 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 network::serialize::serialize;
Sha256dHash::from_data(serialize(self).unwrap().as_slice()) Sha256dHash::from_data(&serialize(self).unwrap())
} }
} }

View File

@ -69,7 +69,7 @@ impl BlockchainNode {
} }
unsafe { unsafe {
let mut scan = self.next; let mut scan = self.next;
while scan.is_not_null() { while !scan.is_null() {
if (*scan).block.header == (*chain.best_tip).block.header { if (*scan).block.header == (*chain.best_tip).block.header {
return true; return true;
} }
@ -145,15 +145,15 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Blockchain {
let best = match tree.lookup(&best_hash.into_le(), 256) { let best = match tree.lookup(&best_hash.into_le(), 256) {
Some(node) => &**node as NodePtr, Some(node) => &**node as NodePtr,
None => { None => {
return Err(d.error(format!("best tip {:x} not in tree", best_hash).as_slice())); return Err(d.error(format!("best tip {:x} not in tree", best_hash)));
} }
}; };
// Lookup genesis // Lookup genesis
if tree.lookup(&genesis_hash.into_le(), 256).is_none() { if tree.lookup(&genesis_hash.into_le(), 256).is_none() {
return Err(d.error(format!("genesis {:x} not in tree", genesis_hash).as_slice())); return Err(d.error(format!("genesis {:x} not in tree", genesis_hash)));
} }
// Reconnect all prev pointers // Reconnect all prev pointers
let raw_tree = &tree as *const _; let raw_tree = &tree as *const BlockTree;
for node in tree.mut_iter() { for node in tree.mut_iter() {
let hash = node.block.header.prev_blockhash.into_le(); let hash = node.block.header.prev_blockhash.into_le();
let prevptr = let prevptr =
@ -166,7 +166,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Blockchain {
// Reconnect next pointers on the main chain // Reconnect next pointers on the main chain
unsafe { unsafe {
let mut scan = best; let mut scan = best;
while (*scan).prev.is_not_null() { while !(*scan).prev.is_null() {
let prev = (*scan).prev as *mut BlockchainNode; let prev = (*scan).prev as *mut BlockchainNode;
(*prev).next = scan; (*prev).next = scan;
scan = prev as NodePtr; scan = prev as NodePtr;
@ -175,7 +175,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Blockchain {
// Check that "genesis" is the genesis // Check that "genesis" is the genesis
if (*scan).bitcoin_hash() != genesis_hash { if (*scan).bitcoin_hash() != genesis_hash {
return Err(d.error(format!("no path from tip {:x} to genesis {:x}", return Err(d.error(format!("no path from tip {:x} to genesis {:x}",
best_hash, genesis_hash).as_slice())); best_hash, genesis_hash)));
} }
} }
@ -216,7 +216,7 @@ impl Iterator for LocatorHashIter {
// Rewind once (if we are at the genesis, this will set self.index to None) // Rewind once (if we are at the genesis, this will set self.index to None)
self.index = unsafe { (*self.index).prev }; self.index = unsafe { (*self.index).prev };
// If we are not at the genesis, rewind `self.skip` times, or until we are. // If we are not at the genesis, rewind `self.skip` times, or until we are.
if self.index.is_not_null() { if !self.index.is_null() {
for _ in 1..self.skip { for _ in 1..self.skip {
unsafe { unsafe {
if (*self.index).prev.is_null() { if (*self.index).prev.is_null() {
@ -318,7 +318,7 @@ impl<'tree> Iterator for RevStaleBlockIter<'tree> {
let ret = Some(&(*self.index).block); let ret = Some(&(*self.index).block);
let next_index = (*self.index).prev; let next_index = (*self.index).prev;
// Check if the next block is going to be on the main chain // Check if the next block is going to be on the main chain
if next_index.is_not_null() && if !next_index.is_null() &&
(*next_index).next != self.index && (*next_index).next != self.index &&
(&*next_index).is_on_main_chain(self.chain) { (&*next_index).is_on_main_chain(self.chain) {
self.index = ptr::null(); self.index = ptr::null();
@ -334,7 +334,7 @@ impl<'tree> Iterator for RevStaleBlockIter<'tree> {
/// which drops the precision to something that can be encoded precisely in /// which drops the precision to something that can be encoded precisely in
/// the nBits block header field. Savour the perversity. This is in Bitcoin /// the nBits block header field. Savour the perversity. This is in Bitcoin
/// consensus code. What. Gaah! /// consensus code. What. Gaah!
fn satoshi_the_precision(n: &Uint256) -> Uint256 { fn satoshi_the_precision(n: Uint256) -> Uint256 {
// Shift by B bits right then left to turn the low bits to zero // Shift by B bits right then left to turn the low bits to zero
let bits = 8 * ((n.bits() + 7) / 8 - 3); let bits = 8 * ((n.bits() + 7) / 8 - 3);
let mut ret = n >> bits; let mut ret = n >> bits;
@ -475,16 +475,16 @@ impl Blockchain {
let max = max_target(self.network); let max = max_target(self.network);
if target > max { target = max }; if target > max { target = max };
// Compactify (make expressible in the 8+24 nBits float format // Compactify (make expressible in the 8+24 nBits float format
satoshi_the_precision(&target) satoshi_the_precision(target)
// On non-diffchange blocks, Testnet has a rule that any 20-minute-long // On non-diffchange blocks, Testnet has a rule that any 20-minute-long
// block intervals result the difficulty // block intervals result the difficulty
} else if self.network == Network::BitcoinTestnet && } else if self.network == Network::Testnet &&
block.header.time > unsafe { (*prev).block.header.time } + 2*TARGET_BLOCK_SPACING { block.header.time > unsafe { (*prev).block.header.time } + 2*TARGET_BLOCK_SPACING {
max_target(self.network) max_target(self.network)
// On the other hand, if we are in Testnet and the block interval is less // On the other hand, if we are in Testnet and the block interval is less
// than 20 minutes, we need to scan backward to find a block for which the // than 20 minutes, we need to scan backward to find a block for which the
// previous rule did not apply, to find the "real" difficulty. // previous rule did not apply, to find the "real" difficulty.
} else if self.network == Network::BitcoinTestnet { } else if self.network == Network::Testnet {
// Scan back DIFFCHANGE_INTERVAL blocks // Scan back DIFFCHANGE_INTERVAL blocks
unsafe { unsafe {
let mut scan = prev; let mut scan = prev;
@ -500,7 +500,7 @@ impl Blockchain {
}; };
// Create node // Create node
let ret = Box::new(BlockchainNode { let ret = Box::new(BlockchainNode {
total_work: block.header.work().add(unsafe { &(*prev).total_work }), total_work: block.header.work() + unsafe { (*prev).total_work },
block: block, block: block,
required_difficulty: difficulty, required_difficulty: difficulty,
height: unsafe { (*prev).height + 1 }, height: unsafe { (*prev).height + 1 },
@ -538,7 +538,7 @@ impl Blockchain {
unsafe { unsafe {
let mut scan = self.best_tip; let mut scan = self.best_tip;
// Scan backward // Scan backward
while (*scan).prev.is_not_null() { while !(*scan).prev.is_null() {
// If we hit the old best, there is no need to reorg. // If we hit the old best, there is no need to reorg.
if scan == self.best_tip { break; } if scan == self.best_tip { break; }
// Otherwise set the next-ptr and carry on // Otherwise set the next-ptr and carry on

View File

@ -23,7 +23,7 @@ use std::default::Default;
use std::num::from_u64; use std::num::from_u64;
use blockdata::opcodes; use blockdata::opcodes;
use blockdata::script::Script; use blockdata::script::ScriptBuilder;
use blockdata::transaction::{Transaction, TxOut, TxIn}; use blockdata::transaction::{Transaction, TxOut, TxIn};
use blockdata::block::{Block, BlockHeader}; use blockdata::block::{Block, BlockHeader};
use network::constants::Network; use network::constants::Network;
@ -60,24 +60,24 @@ fn bitcoin_genesis_tx() -> Transaction {
}; };
// Inputs // Inputs
let mut in_script = Script::new(); let mut in_script = ScriptBuilder::new();
in_script.push_scriptint(486604799); in_script.push_scriptint(486604799);
in_script.push_scriptint(4); in_script.push_scriptint(4);
in_script.push_slice("The Times 03/Jan/2009 Chancellor on brink of second bailout for banks".as_bytes()); in_script.push_slice("The Times 03/Jan/2009 Chancellor on brink of second bailout for banks".as_bytes());
ret.input.push(TxIn { ret.input.push(TxIn {
prev_hash: Default::default(), prev_hash: Default::default(),
prev_index: 0xFFFFFFFF, prev_index: 0xFFFFFFFF,
script_sig: in_script, script_sig: in_script.into_script(),
sequence: MAX_SEQUENCE sequence: MAX_SEQUENCE
}); });
// Outputs // Outputs
let mut out_script = Script::new(); let mut out_script = ScriptBuilder::new();
out_script.push_slice(hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap().as_slice()); out_script.push_slice(hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap().as_slice());
out_script.push_opcode(opcodes::All::OP_CHECKSIG); out_script.push_opcode(opcodes::All::OP_CHECKSIG);
ret.output.push(TxOut { ret.output.push(TxOut {
value: 50 * COIN_VALUE, value: 50 * COIN_VALUE,
script_pubkey: out_script script_pubkey: out_script.into_script()
}); });
// end // end

View File

@ -592,10 +592,10 @@ impl All {
// 16 opcodes // 16 opcodes
} else if All::OP_PUSHNUM_1 as u8 <= *self as u8 && } else if All::OP_PUSHNUM_1 as u8 <= *self as u8 &&
*self as u8 <= All::OP_PUSHNUM_16 as u8 { *self as u8 <= All::OP_PUSHNUM_16 as u8 {
Class::PushNum(1 + *self as isize - All::OP_PUSHNUM_1 as isize) Class::PushNum(1 + *self as i32 - All::OP_PUSHNUM_1 as i32)
// 76 opcodes // 76 opcodes
} else if *self as u8 <= All::OP_PUSHBYTES_75 as u8 { } else if *self as u8 <= All::OP_PUSHBYTES_75 as u8 {
Class::PushBytes(*self as usize) Class::PushBytes(*self as u32)
// 60 opcodes // 60 opcodes
} else { } else {
Class::Ordinary(unsafe { transmute(*self) }) Class::Ordinary(unsafe { transmute(*self) })
@ -636,9 +636,9 @@ pub static OP_TRUE: All = All::OP_PUSHNUM_1;
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub enum Class { pub enum Class {
/// Pushes the given number onto the stack /// Pushes the given number onto the stack
PushNum(isize), PushNum(i32),
/// Pushes the given number of bytes onto the stack /// Pushes the given number of bytes onto the stack
PushBytes(usize), PushBytes(u32),
/// Fails the script if executed /// Fails the script if executed
ReturnOp, ReturnOp,
/// Fails the script even if not executed /// Fails the script even if not executed

View File

@ -35,7 +35,7 @@ use crypto::digest::Digest;
use crypto::ripemd160::Ripemd160; use crypto::ripemd160::Ripemd160;
use crypto::sha1::Sha1; use crypto::sha1::Sha1;
use crypto::sha2::Sha256; use crypto::sha2::Sha256;
use secp256k1::Secp256k1; use secp256k1::{self, Secp256k1};
use secp256k1::key::PublicKey; use secp256k1::key::PublicKey;
use serde; use serde;
@ -56,13 +56,16 @@ impl Clone for Script {
} }
} }
#[derive(PartialEq, Eq, Debug, Clone, Display)]
/// An object which can be used to construct a script piece by piece
pub struct ScriptBuilder(Vec<u8>);
impl hash::Hash for Script { impl hash::Hash for Script {
#[inline] #[inline]
fn hash<H>(&self, state: &mut H) fn hash<H>(&self, state: &mut H)
where H: hash::Hasher where H: hash::Hasher
{ {
let &Script(ref raw) = self; (&self.0[..]).hash(state);
(&raw[..]).hash(state);
} }
#[inline] #[inline]
@ -70,8 +73,7 @@ impl hash::Hash for Script {
where H: hash::Hasher where H: hash::Hasher
{ {
for s in data.iter() { for s in data.iter() {
let &Script(ref raw) = s; (&s.0[..]).hash(state);
(&raw[..]).hash(state);
} }
} }
} }
@ -95,7 +97,7 @@ pub enum Error {
/// OP_CHECKSIG was called with a bad signature /// OP_CHECKSIG was called with a bad signature
BadSignature, BadSignature,
/// An ECDSA error /// An ECDSA error
Ecdsa(::secp256k1::Error), Ecdsa(secp256k1::Error),
/// An OP_ELSE happened while not in an OP_IF tree /// An OP_ELSE happened while not in an OP_IF tree
ElseWithoutIf, ElseWithoutIf,
/// An OP_ENDIF happened while not in an OP_IF tree /// An OP_ENDIF happened while not in an OP_IF tree
@ -1558,7 +1560,7 @@ fn check_signature(sig_slice: &[u8], pk_slice: &[u8], script: Vec<u8>,
for _ in 0..input_index { for _ in 0..input_index {
new_outs.push(Default::default()) new_outs.push(Default::default())
} }
new_outs.push(tx_copy.output.swap_remove(input_index).unwrap()); new_outs.push(tx_copy.output.swap_remove(input_index));
tx_copy.output = new_outs; tx_copy.output = new_outs;
} else { } else {
sighash_single_bug = true; sighash_single_bug = true;
@ -1581,7 +1583,10 @@ fn check_signature(sig_slice: &[u8], pk_slice: &[u8], script: Vec<u8>,
serialize(&Sha256dHash::from_data(&data_to_sign[..])).unwrap() serialize(&Sha256dHash::from_data(&data_to_sign[..])).unwrap()
}; };
Secp256k1::verify_raw(&signature_hash[..], sig_slice, &pubkey).map_err(Error::Ecdsa) // We can unwrap -- only failure mode is on length, which is fixed to 32
let msg = secp256k1::Message::from_slice(&signature_hash[..]).unwrap();
Secp256k1::verify_raw(&msg, sig_slice, &pubkey).map_err(Error::Ecdsa)
} }
// Macro to translate English stack instructions into Rust code. // Macro to translate English stack instructions into Rust code.
@ -1719,70 +1724,7 @@ impl Script {
pub fn from_vec(v: Vec<u8>) -> Script { Script(v.into_boxed_slice()) } pub fn from_vec(v: Vec<u8>) -> Script { Script(v.into_boxed_slice()) }
/// The length in bytes of the script /// The length in bytes of the script
pub fn len(&self) -> usize { pub fn len(&self) -> usize { self.0.len() }
let &Script(ref raw) = self;
raw.len()
}
/// Adds instructions to push an integer onto the stack. Integers are
/// encoded as little-endian signed-magnitude numbers, but there are
/// dedicated opcodes to push some small integers.
pub fn push_int(&mut self, data: i64) {
// We can special-case -1, 1-16
if data == -1 || (data >= 1 && data <=16) {
let &Script(ref mut raw) = self;
raw.push(data as u8 + opcodes::All::OP_TRUE as u8);
return;
}
// We can also special-case zero
if data == 0 {
let &Script(ref mut raw) = self;
raw.push(opcodes::All::OP_FALSE as u8);
return;
}
// Otherwise encode it as data
self.push_scriptint(data);
}
/// Adds instructions to push an integer onto the stack, using the explicit
/// encoding regardless of the availability of dedicated opcodes.
pub fn push_scriptint(&mut self, data: i64) {
self.push_slice(&build_scriptint(data));
}
/// Adds instructions to push some arbitrary data onto the stack
pub fn push_slice(&mut self, data: &[u8]) {
let &Script(ref mut raw) = self;
// Start with a PUSH opcode
match data.len() {
n if n < opcodes::Ordinary::OP_PUSHDATA1 as usize => { raw.push(n as u8); },
n if n < 0x100 => {
raw.push(opcodes::Ordinary::OP_PUSHDATA1 as u8);
raw.push(n as u8);
},
n if n < 0x10000 => {
raw.push(opcodes::Ordinary::OP_PUSHDATA2 as u8);
raw.push((n % 0x100) as u8);
raw.push((n / 0x100) as u8);
},
n if n < 0x100000000 => {
raw.push(opcodes::Ordinary::OP_PUSHDATA4 as u8);
raw.push((n % 0x100) as u8);
raw.push(((n / 0x100) % 0x100) as u8);
raw.push(((n / 0x10000) % 0x100) as u8);
raw.push((n / 0x1000000) as u8);
}
_ => panic!("tried to put a 4bn+ sized object into a script!")
}
// Then push the acraw
raw.extend(data.iter().map(|n| *n));
}
/// Adds an individual opcode to the script
pub fn push_opcode(&mut self, data: opcodes::All) {
let &Script(ref mut raw) = self;
raw.push(data as u8);
}
/// Trace a script /// Trace a script
pub fn trace<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>, pub fn trace<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>,
@ -1807,21 +1749,19 @@ impl Script {
input_context: Option<(&Transaction, usize)>, input_context: Option<(&Transaction, usize)>,
mut trace: Option<&mut Vec<TraceIteration>>) mut trace: Option<&mut Vec<TraceIteration>>)
-> Result<(), Error> { -> Result<(), Error> {
let &Script(ref raw) = self;
let mut codeseparator_index = 0; let mut codeseparator_index = 0;
let mut exec_stack = vec![]; let mut exec_stack = vec![];
let mut alt_stack = vec![]; let mut alt_stack = vec![];
let mut index = 0; let mut index = 0;
let mut op_count = 0; let mut op_count = 0;
while index < raw.len() { while index < self.0.len() {
let executing = exec_stack.iter().all(|e| *e); let executing = exec_stack.iter().all(|e| *e);
let byte = unsafe { *raw.get(index) }; let byte = self.0[index];
// Write out the trace, except the stack which we don't know yet // Write out the trace, except the stack which we don't know yet
match trace { match trace {
Some(ref mut t) => { Some(ref mut t) => {
let opcode = opcodes::All::Opcode::from_u8(byte); let opcode = opcodes::All::from_u8(byte);
t.push(TraceIteration { t.push(TraceIteration {
index: index, index: index,
opcode: opcode, opcode: opcode,
@ -1837,7 +1777,7 @@ impl Script {
op_count += 1; op_count += 1;
index += 1; index += 1;
// The definitions of all these categories are in opcodes.rs // The definitions of all these categories are in opcodes.rs
match (executing, opcodes::All::Opcode::from_u8(byte).classify()) { match (executing, opcodes::All::from_u8(byte).classify()) {
// Illegal operations mean failure regardless of execution state // Illegal operations mean failure regardless of execution state
(_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode), (_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode),
// Push number // Push number
@ -1846,29 +1786,30 @@ impl Script {
(true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn), (true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn),
// Data-reading statements still need to read, even when not executing // Data-reading statements still need to read, even when not executing
(_, opcodes::Class::PushBytes(n)) => { (_, opcodes::Class::PushBytes(n)) => {
if raw.len() < index + n { return Err(Error::EarlyEndOfScript); } let n = n as usize;
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index, index + n))); } if self.0.len() < index + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(&self.0[index..index + n])); }
index += n; index += n;
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => {
if raw.len() < index + 1 { return Err(Error::EarlyEndOfScript); } if self.0.len() < index + 1 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&raw[index..], 1)); let n = try!(read_uint(&self.0[index..], 1));
if raw.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } if self.0.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 1, index + n + 1))); } if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 1..index + n + 1])); }
index += 1 + n; index += 1 + n;
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => {
if raw.len() < index + 2 { return Err(Error::EarlyEndOfScript); } if self.0.len() < index + 2 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&raw[index..], 2)); let n = try!(read_uint(&self.0[index..], 2));
if raw.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } if self.0.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 2, index + n + 2))); } if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 2..index + n + 2])); }
index += 2 + n; index += 2 + n;
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => {
if raw.len() < index + 4 { return Err(Error::EarlyEndOfScript); } if self.0.len() < index + 4 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&raw[index..], 4)); let n = try!(read_uint(&self.0[index..], 4));
if raw.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } if self.0.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 4, index + n + 4))); } if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 4..index + n + 4])); }
index += 4 + n; index += 4 + n;
} }
// If-statements take effect when not executing // If-statements take effect when not executing
@ -1942,7 +1883,7 @@ impl Script {
opcodes::Ordinary::OP_OVER => stack_opcode!(stack(2): copy 2), opcodes::Ordinary::OP_OVER => stack_opcode!(stack(2): copy 2),
opcodes::Ordinary::OP_PICK => { opcodes::Ordinary::OP_PICK => {
let n = match stack.pop() { let n = match stack.pop() {
Some(data) => try!(read_scriptint(&data)), Some(data) => try!(read_scriptint(&data[..])),
None => { return Err(Error::PopEmptyStack); } None => { return Err(Error::PopEmptyStack); }
}; };
if n < 0 { return Err(Error::NegativePick); } if n < 0 { return Err(Error::NegativePick); }
@ -1951,7 +1892,7 @@ impl Script {
} }
opcodes::Ordinary::OP_ROLL => { opcodes::Ordinary::OP_ROLL => {
let n = match stack.pop() { let n = match stack.pop() {
Some(data) => try!(read_scriptint(&data)), Some(data) => try!(read_scriptint(&data[..])),
None => { return Err(Error::PopEmptyStack); } None => { return Err(Error::PopEmptyStack); }
}; };
if n < 0 { return Err(Error::NegativeRoll); } if n < 0 { return Err(Error::NegativeRoll); }
@ -2033,11 +1974,12 @@ impl Script {
// Compute the section of script that needs to be hashed: everything // Compute the section of script that needs to be hashed: everything
// from the last CODESEPARATOR, except the signature itself. // from the last CODESEPARATOR, except the signature itself.
let mut script = (&raw[codeseparator_index..]).to_vec(); let mut script = (&self.0[codeseparator_index..]).to_vec();
let mut remove = Script::new(); let mut remove = ScriptBuilder::new();
remove.push_slice(sig_slice); remove.push_slice(sig_slice);
script_find_and_remove(&mut script, &remove); script_find_and_remove(&mut script, &remove[..]);
script_find_and_remove(&mut script, [opcodes::Ordinary::OP_CODESEPARATOR as u8]); // Also all of the OP_CODESEPARATORS, even the unevaluated ones
script_find_and_remove(&mut script, &[opcodes::Ordinary::OP_CODESEPARATOR as u8]);
// This is as far as we can go without a transaction, so fail here // This is as far as we can go without a transaction, so fail here
if input_context.is_none() { return Err(Error::NoTransaction); } if input_context.is_none() { return Err(Error::NoTransaction); }
@ -2053,7 +1995,7 @@ impl Script {
opcodes::Ordinary::OP_CHECKMULTISIG | opcodes::Ordinary::OP_CHECKMULTISIGVERIFY => { opcodes::Ordinary::OP_CHECKMULTISIG | opcodes::Ordinary::OP_CHECKMULTISIGVERIFY => {
// Read all the keys // Read all the keys
if stack.len() < 1 { return Err(Error::PopEmptyStack); } if stack.len() < 1 { return Err(Error::PopEmptyStack); }
let n_keys = try!(read_scriptint(&stack.pop().unwrap())); let n_keys = try!(read_scriptint(&stack.pop().unwrap()[..]));
if n_keys < 0 || n_keys > 20 { if n_keys < 0 || n_keys > 20 {
return Err(Error::MultisigBadKeyCount(n_keys as isize)); return Err(Error::MultisigBadKeyCount(n_keys as isize));
} }
@ -2066,7 +2008,7 @@ impl Script {
// Read all the signatures // Read all the signatures
if stack.len() < 1 { return Err(Error::PopEmptyStack); } if stack.len() < 1 { return Err(Error::PopEmptyStack); }
let n_sigs = try!(read_scriptint(&stack.pop().unwrap())); let n_sigs = try!(read_scriptint(&stack.pop().unwrap()[..]));
if n_sigs < 0 || n_sigs > n_keys { if n_sigs < 0 || n_sigs > n_keys {
return Err(Error::MultisigBadSigCount(n_sigs as isize)); return Err(Error::MultisigBadSigCount(n_sigs as isize));
} }
@ -2082,12 +2024,12 @@ impl Script {
// Compute the section of script that needs to be hashed: everything // Compute the section of script that needs to be hashed: everything
// from the last CODESEPARATOR, except the signatures themselves. // from the last CODESEPARATOR, except the signatures themselves.
let mut script = (&raw[codeseparator_index..]).to_vec(); let mut script = (&self.0[codeseparator_index..]).to_vec();
for sig in sigs.iter() { for sig in sigs.iter() {
let mut remove = Script::new(); let mut remove = ScriptBuilder::new();
remove.push_slice(&sig); remove.push_slice(&sig[..]);
script_find_and_remove(&mut script, &remove); script_find_and_remove(&mut script, &remove[..]);
script_find_and_remove(&mut script, [opcodes::Ordinary::OP_CODESEPARATOR as u8]); script_find_and_remove(&mut script, &[opcodes::Ordinary::OP_CODESEPARATOR as u8]);
} }
// This is as far as we can go without a transaction, so fail here // This is as far as we can go without a transaction, so fail here
@ -2105,7 +2047,7 @@ impl Script {
// Try to validate the signature with the given key // Try to validate the signature with the given key
(Some(k), Some(s)) => { (Some(k), Some(s)) => {
// Move to the next signature if it is valid for the current key // Move to the next signature if it is valid for the current key
if check_signature(&s, &k, script.clone(), tx, input_index).is_ok() { if check_signature(&s[..], &k[..], script.clone(), tx, input_index).is_ok() {
sig = sig_iter.next(); sig = sig_iter.next();
} }
// Move to the next key in any case // Move to the next key in any case
@ -2142,12 +2084,11 @@ impl Script {
/// Checks whether a script pubkey is a p2sh output /// Checks whether a script pubkey is a p2sh output
#[inline] #[inline]
pub fn is_p2sh(&self) -> bool { pub fn is_p2sh(&self) -> bool {
let &Script(ref raw) = self;
unsafe { unsafe {
raw.len() == 23 && self.0.len() == 23 &&
*raw.get(0) == opcodes::All::OP_HASH160 as u8 && self.0[0] == opcodes::All::OP_HASH160 as u8 &&
*raw.get(1) == opcodes::All::OP_PUSHBYTES_20 as u8 && self.0[1] == opcodes::All::OP_PUSHBYTES_20 as u8 &&
*raw.get(22) == opcodes::All::OP_EQUAL as u8 self.0[22] == opcodes::All::OP_EQUAL as u8
} }
} }
@ -2186,9 +2127,10 @@ impl Script {
(true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn), (true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn),
// Data-reading statements still need to read, even when not executing // Data-reading statements still need to read, even when not executing
(_, opcodes::Class::PushBytes(n)) => { (_, opcodes::Class::PushBytes(n)) => {
let n = n as usize;
if script.len() < index + n { return Err(Error::EarlyEndOfScript); } if script.len() < index + n { return Err(Error::EarlyEndOfScript); }
if executing { if executing {
stack.push_alloc(AbstractStackElem::new_raw(script.slice(index, index + n))); stack.push_alloc(AbstractStackElem::new_raw(&script[index..index + n]));
} }
index += n; index += n;
} }
@ -2200,7 +2142,7 @@ impl Script {
}; };
if script.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } if script.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); }
if executing { if executing {
stack.push_alloc(AbstractStackElem::new_raw(script.slice(index + 1, index + n + 1))); stack.push_alloc(AbstractStackElem::new_raw(&script[index + 1..index + n + 1]));
} }
index += 1 + n; index += 1 + n;
} }
@ -2212,7 +2154,7 @@ impl Script {
}; };
if script.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } if script.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); }
if executing { if executing {
stack.push_alloc(AbstractStackElem::new_raw(script.slice(index + 2, index + n + 2))); stack.push_alloc(AbstractStackElem::new_raw(&script[index + 2..index + n + 2]));
} }
index += 2 + n; index += 2 + n;
} }
@ -2223,7 +2165,7 @@ impl Script {
}; };
if script.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } if script.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); }
if executing { if executing {
stack.push_alloc(AbstractStackElem::new_raw(script.slice(index + 4, index + n + 4))); stack.push_alloc(AbstractStackElem::new_raw(&script[index + 4..index + n + 4]));
} }
index += 4 + n; index += 4 + n;
} }
@ -2495,8 +2437,7 @@ impl Script {
} }
} }
let &Script(ref raw) = self; recurse(&self.0, AbstractStack::new(), vec![], 1)
recurse(&raw, AbstractStack::new(), vec![], 1)
} }
} }
@ -2504,62 +2445,93 @@ impl Default for Script {
fn default() -> Script { Script(vec![].into_boxed_slice()) } fn default() -> Script { Script(vec![].into_boxed_slice()) }
} }
impl_index_newtype!(Script, u8);
impl ops::Index<usize> for Script { impl ScriptBuilder {
type Output = u8; /// Creates a new empty script
#[inline] pub fn new() -> ScriptBuilder { ScriptBuilder(vec![]) }
fn index(&self, index: usize) -> &u8 {
let &Script(ref raw) = self; /// Creates a new script from an existing vector
&raw[index] pub fn from_vec(v: Vec<u8>) -> ScriptBuilder { ScriptBuilder(v) }
/// The length in bytes of the script
pub fn len(&self) -> usize { self.0.len() }
/// Adds instructions to push an integer onto the stack. Integers are
/// encoded as little-endian signed-magnitude numbers, but there are
/// dedicated opcodes to push some small integers.
pub fn push_int(&mut self, data: i64) {
// We can special-case -1, 1-16
if data == -1 || (data >= 1 && data <=16) {
self.0.push(data as u8 + opcodes::OP_TRUE as u8);
}
// We can also special-case zero
else if data == 0 {
self.0.push(opcodes::OP_FALSE as u8);
}
// Otherwise encode it as data
else { self.push_scriptint(data); }
}
/// Adds instructions to push an integer onto the stack, using the explicit
/// encoding regardless of the availability of dedicated opcodes.
pub fn push_scriptint(&mut self, data: i64) {
self.push_slice(&build_scriptint(data));
}
/// Adds instructions to push some arbitrary data onto the stack
pub fn push_slice(&mut self, data: &[u8]) {
// Start with a PUSH opcode
match data.len() {
n if n < opcodes::Ordinary::OP_PUSHDATA1 as usize => { self.0.push(n as u8); },
n if n < 0x100 => {
self.0.push(opcodes::Ordinary::OP_PUSHDATA1 as u8);
self.0.push(n as u8);
},
n if n < 0x10000 => {
self.0.push(opcodes::Ordinary::OP_PUSHDATA2 as u8);
self.0.push((n % 0x100) as u8);
self.0.push((n / 0x100) as u8);
},
n if n < 0x100000000 => {
self.0.push(opcodes::Ordinary::OP_PUSHDATA4 as u8);
self.0.push((n % 0x100) as u8);
self.0.push(((n / 0x100) % 0x100) as u8);
self.0.push(((n / 0x10000) % 0x100) as u8);
self.0.push((n / 0x1000000) as u8);
}
_ => panic!("tried to put a 4bn+ sized object into a script!")
}
// Then push the acraw
self.0.extend(data.iter().map(|n| *n));
}
pub fn push_opcode(&mut self, data: opcodes::All) {
self.0.push(data as u8);
}
pub fn into_script(self) -> Script {
Script(self.0.into_boxed_slice())
} }
} }
impl ops::Index<ops::Range<usize>> for Script { /// Adds an individual opcode to the script
type Output = [u8]; impl Default for ScriptBuilder {
#[inline] fn default() -> ScriptBuilder { ScriptBuilder(vec![]) }
fn index(&self, index: ops::Range<usize>) -> &[u8] {
let &Script(ref raw) = self;
&raw[index]
}
} }
impl ops::Index<ops::RangeTo<usize>> for Script { impl_index_newtype!(ScriptBuilder, u8);
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] {
let &Script(ref raw) = self;
&raw[index]
}
}
impl ops::Index<ops::RangeFrom<usize>> for Script {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
let &Script(ref raw) = self;
&raw[index]
}
}
impl ops::Index<ops::RangeFull> for Script {
type Output = [u8];
#[inline]
fn index(&self, _: ops::RangeFull) -> &[u8] {
let &Script(ref raw) = self;
&raw[..]
}
}
// User-facing serialization // User-facing serialization
impl serde::Serialize for Script { impl serde::Serialize for Script {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer, where S: serde::Serializer,
{ {
let &Script(ref raw) = self; for dat in self.0.iter() {
for dat in raw.iter() { try!(serializer.visit_char(from_digit((dat / 0x10) as u32, 16).unwrap()));
serializer.visit_char(from_digit((dat / 0x10) as u32, 16).unwrap()); try!(serializer.visit_char(from_digit((dat & 0x0f) as u32, 16).unwrap()));
serializer.visit_char(from_digit((dat & 0x0f) as u32, 16).unwrap());
} }
Ok(())
} }
} }
@ -2567,8 +2539,7 @@ impl serde::Serialize for Script {
impl<S: SimpleEncoder> ConsensusEncodable<S> for Script { impl<S: SimpleEncoder> ConsensusEncodable<S> for Script {
#[inline] #[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
let &Script(ref data) = self; self.0.consensus_encode(s)
data.consensus_encode(s)
} }
} }

View File

@ -32,7 +32,7 @@ use blockdata::utxoset::UtxoSet;
use network::encodable::ConsensusEncodable; use network::encodable::ConsensusEncodable;
use network::serialize::BitcoinHash; use network::serialize::BitcoinHash;
use network::constants::Network; use network::constants::Network;
use wallet::address::Address; use wallet::address::{Address, ToAddress};
/// A transaction input, which defines old coins to be consumed /// A transaction input, which defines old coins to be consumed
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
@ -79,9 +79,9 @@ impl TxOut {
/// Determines the template that this output adheres to, if any /// Determines the template that this output adheres to, if any
pub fn classify(&self, network: Network) -> ScriptPubkeyTemplate { pub fn classify(&self, network: Network) -> ScriptPubkeyTemplate {
if self.script_pubkey.len() == 25 && if self.script_pubkey.len() == 25 &&
self.script_pubkey.slice_to(3) == &[0x76, 0xa9, 0x14] && &self.script_pubkey[0..3] == &[0x76, 0xa9, 0x14] &&
self.script_pubkey.slice_from(23) == &[0x88, 0xac] { &self.script_pubkey[23..] == &[0x88, 0xac] {
ScriptPubkeyTemplate::PayToPubkeyHash(self.script_pubkey.slice(3, 23).to_address(network)) ScriptPubkeyTemplate::PayToPubkeyHash((&self.script_pubkey[3..23]).to_address(network))
} else { } else {
ScriptPubkeyTemplate::Unknown ScriptPubkeyTemplate::Unknown
} }
@ -122,6 +122,7 @@ pub enum Error {
/// Script ended with nothing in the stack (input txid, input vout) /// Script ended with nothing in the stack (input txid, input vout)
InputNotFound(Sha256dHash, u32), InputNotFound(Sha256dHash, u32),
} }
display_from_debug!(Error);
impl serde::Serialize for Error { impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>

View File

@ -21,11 +21,11 @@
use std::cmp; use std::cmp;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::hash::map::Iter; use std::collections::hash::map::Iter;
use std::hash::SipHasher;
use std::default::Default; use std::default::Default;
use std::mem; use std::mem;
use eventual;
use eventual::Async;
use num_cpus; use num_cpus;
use std::sync::Future;
use blockdata::transaction::{self, Transaction, TxOut}; use blockdata::transaction::{self, Transaction, TxOut};
use blockdata::constants::genesis_block; use blockdata::constants::genesis_block;
@ -78,15 +78,12 @@ impl<'a> Iterator for UtxoIterator<'a> {
type Item = (Sha256dHash, u32, &'a TxOut, u32); type Item = (Sha256dHash, u32, &'a TxOut, u32);
fn next(&mut self) -> Option<(Sha256dHash, u32, &'a TxOut, u32)> { fn next(&mut self) -> Option<(Sha256dHash, u32, &'a TxOut, u32)> {
while self.current.is_some() { while let Some(current) = self.current {
let current = &self.current.unwrap().outputs; while self.tx_index < current.outputs.len() as u32 {
while self.tx_index < current.len() as u32 {
self.tx_index += 1; self.tx_index += 1;
if unsafe { current.get(self.tx_index as usize - 1) }.is_some() { if let Some(ref cur) = current.outputs[self.tx_index as usize - 1] {
return Some((self.current_key, return Some((self.current_key, self.tx_index,
self.tx_index, cur, current.height));
unsafe { current.get(self.tx_index as usize - 1) }.as_ref().unwrap(),
self.current.unwrap().height));
} }
} }
match self.tx_iter.next() { match self.tx_iter.next() {
@ -104,7 +101,7 @@ impl<'a> Iterator for UtxoIterator<'a> {
/// The UTXO set /// The UTXO set
pub struct UtxoSet { pub struct UtxoSet {
table: HashMap<Sha256dHash, UtxoNode, SipHasher>, table: HashMap<Sha256dHash, UtxoNode>,
last_hash: Sha256dHash, last_hash: Sha256dHash,
// A circular buffer of deleted utxos, grouped by block // A circular buffer of deleted utxos, grouped by block
spent_txos: Vec<Vec<((Sha256dHash, u32), (u32, TxOut))>>, spent_txos: Vec<Vec<((Sha256dHash, u32), (u32, TxOut))>>,
@ -124,9 +121,9 @@ impl UtxoSet {
// must follow suit, otherwise we will accept a transaction spending it // must follow suit, otherwise we will accept a transaction spending it
// while the reference client won't, causing us to fork off the network. // while the reference client won't, causing us to fork off the network.
UtxoSet { UtxoSet {
table: HashMap::with_hasher(SipHasher::new()), table: HashMap::new(),
last_hash: genesis_block(network).header.bitcoin_hash(), last_hash: genesis_block(network).header.bitcoin_hash(),
spent_txos: Vec::from_elem(rewind_limit, vec![]), spent_txos: vec![vec![]; rewind_limit],
spent_idx: 0, spent_idx: 0,
n_utxos: 0, n_utxos: 0,
n_pruned: 0 n_pruned: 0
@ -153,7 +150,7 @@ impl UtxoSet {
}; };
// Get the old value, if any (this is suprisingly possible, c.f. BIP30 // Get the old value, if any (this is suprisingly possible, c.f. BIP30
// and the other comments in this file referring to it) // and the other comments in this file referring to it)
let ret = self.table.swap(txid, new_node.into_boxed_slice()); let ret = self.table.insert(txid, new_node);
if ret.is_none() { if ret.is_none() {
self.n_utxos += tx.output.len() as u64; self.n_utxos += tx.output.len() as u64;
} }
@ -165,7 +162,7 @@ impl UtxoSet {
// This whole function has awkward scoping thx to lexical borrow scoping :( // This whole function has awkward scoping thx to lexical borrow scoping :(
let (height, ret, should_delete) = { let (height, ret, should_delete) = {
// Locate the UTXO, failing if not found // Locate the UTXO, failing if not found
let node = match self.table.find_mut(&txid) { let node = match self.table.get_mut(&txid) {
Some(node) => node, Some(node) => node,
None => return None None => return None
}; };
@ -173,7 +170,7 @@ impl UtxoSet {
let ret = { let ret = {
// Check that this specific output is there // Check that this specific output is there
if vout as usize >= node.outputs.len() { return None; } if vout as usize >= node.outputs.len() { return None; }
let replace = unsafe { node.outputs.get_mut(vout as usize) }; let replace = &mut node.outputs[vout as usize];
replace.take() replace.take()
}; };
@ -193,13 +190,13 @@ impl UtxoSet {
/// Get a reference to a UTXO in the set /// Get a reference to a UTXO in the set
pub fn get_utxo<'a>(&'a self, txid: Sha256dHash, vout: u32) -> Option<(usize, &'a TxOut)> { pub fn get_utxo<'a>(&'a self, txid: Sha256dHash, vout: u32) -> Option<(usize, &'a TxOut)> {
// Locate the UTXO, failing if not found // Locate the UTXO, failing if not found
let node = match self.table.find(&txid) { let node = match self.table.get(&txid) {
Some(node) => node, Some(node) => node,
None => return None None => return None
}; };
// Check that this specific output is there // Check that this specific output is there
if vout as usize >= node.outputs.len() { return None; } if vout as usize >= node.outputs.len() { return None; }
let replace = unsafe { node.outputs.get(vout as usize) }; let replace = node.outputs[vout as usize];
Some((node.height as usize, replace.as_ref().unwrap())) Some((node.height as usize, replace.as_ref().unwrap()))
} }
@ -217,7 +214,7 @@ impl UtxoSet {
self.last_hash = block.header.bitcoin_hash(); self.last_hash = block.header.bitcoin_hash();
let spent_idx = self.spent_idx as usize; let spent_idx = self.spent_idx as usize;
self.spent_idx = (self.spent_idx + 1) % self.spent_txos.len() as u64; self.spent_idx = (self.spent_idx + 1) % self.spent_txos.len() as u64;
self.spent_txos.get_mut(spent_idx).clear(); (&mut self.spent_txos[spent_idx]).clear();
// Add all the utxos so that we can have chained transactions within the // Add all the utxos so that we can have chained transactions within the
// same block. (Note that Bitcoin requires chained transactions to be in // same block. (Note that Bitcoin requires chained transactions to be in
@ -240,10 +237,10 @@ impl UtxoSet {
} else { } else {
// Otherwise put the replaced txouts into the `deleted` cache // Otherwise put the replaced txouts into the `deleted` cache
// so that rewind will put them back. // so that rewind will put them back.
self.spent_txos.get_mut(spent_idx).reserve_additional(replace.outputs.len()); (&mut self.spent_txos[spent_idx]).reserve(replace.outputs.len());
for (n, input) in replace.outputs.iter_mut().enumerate() { for (n, input) in replace.outputs.iter_mut().enumerate() {
match input.take() { match input.take() {
Some(txo) => { self.spent_txos.get_mut(spent_idx).push(((txid, n as u32), (replace.height, txo))); } Some(txo) => { (&mut self.spent_txos[spent_idx]).push(((txid, n as u32), (replace.height, txo))); }
None => {} None => {}
} }
} }
@ -268,12 +265,14 @@ impl UtxoSet {
let start = 1 + j * n_elems / n_threads; let start = 1 + j * n_elems / n_threads;
let end = cmp::min(n_elems, 1 + (j + 1) * n_elems / n_threads); let end = cmp::min(n_elems, 1 + (j + 1) * n_elems / n_threads);
let s = self as *mut _ as *const UtxoSet; // WARNING: we are asserting that these variables will outlive the Futures;
let txes = &block.txdata as *const _; // this means that we need to await all Futures before leaving the
future_vec.push(Future::spawn(move || { // function or else risk use-after-free in the async threads.
let txes = unsafe {&*txes}; let static_txes = unsafe { &*(&block.txdata as *const Vec<Transaction>) };
for tx in txes.slice(start, end).iter() { let static_self = unsafe { &*(self as *const UtxoSet) };
match tx.validate(unsafe {&*s}) { future_vec.push(eventual::Future::spawn(move || {
for tx in static_txes[start..end].iter() {
match tx.validate(static_self) {
Ok(_) => {}, Ok(_) => {},
Err(e) => { return Err(Error::InvalidTx(tx.bitcoin_hash(), e)); } Err(e) => { return Err(Error::InvalidTx(tx.bitcoin_hash(), e)); }
} }
@ -283,25 +282,21 @@ impl UtxoSet {
} }
// Return the last error since we need to finish every future before // 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. // leaving this function, and given that, it's easier to return the last.
let mut last_error = Ok(()); let mut last_err = Ok(());
for res in future_vec.iter_mut().map(|f| f.get()) { for res in future_vec.iter_mut().map(|f| f.await().unwrap()) {
if res.is_err() { if res.is_err() { last_err = res; }
last_error = res;
}
}
if last_error.is_err() {
return last_error;
} }
if last_err.is_err() { return last_err; }
} }
for tx in block.txdata.iter().skip(1) { for tx in block.txdata.iter().skip(1) {
let txid = tx.bitcoin_hash(); let txid = tx.bitcoin_hash();
// Put the removed utxos into the stxo cache, in case we need to rewind // Put the removed utxos into the stxo cache, in case we need to rewind
self.spent_txos.get_mut(spent_idx).reserve_additional(tx.input.len()); (&self.spent_txos[spent_idx]).reserve(tx.input.len());
for (n, input) in tx.input.iter().enumerate() { for (n, input) in tx.input.iter().enumerate() {
let taken = self.take_utxo(input.prev_hash, input.prev_index); let taken = self.take_utxo(input.prev_hash, input.prev_index);
match taken { match taken {
Some(txo) => { self.spent_txos.get_mut(spent_idx).push(((txid, n as u32), txo)); } Some(txo) => { (&mut self.spent_txos[spent_idx]).push(((txid, n as u32), txo)); }
None => { None => {
if validation >= ValidationLevel::Inputs { if validation >= ValidationLevel::Inputs {
self.rewind(block); self.rewind(block);
@ -349,18 +344,17 @@ impl UtxoSet {
// Read deleted txouts // Read deleted txouts
if skipped_genesis { if skipped_genesis {
let mut extract_vec = vec![]; let mut extract_vec = vec![];
mem::swap(&mut extract_vec, self.spent_txos.get_mut(self.spent_idx as usize)); mem::swap(&mut extract_vec, (&mut self.spent_txos[self.spent_idx as usize]));
for ((txid, n), (height, txo)) in extract_vec.into_iter() { for ((txid, n), (height, txo)) in extract_vec.into_iter() {
// Remove the tx's utxo list and patch the txo into place // Remove the tx's utxo list and patch the txo into place
let new_node = let new_node = match self.table.remove(&txid) {
match self.table.pop(&txid) {
Some(mut node) => { Some(mut node) => {
node.outputs[n as usize] = Some(txo); node.outputs[n as usize] = Some(txo);
node node
} }
None => { None => {
unsafe { unsafe {
let mut thinvec = Vec::with_capacity(n + 1); let mut thinvec = Vec::with_capacity(n as usize + 1);
for _ in 0..n { for _ in 0..n {
thinvec.push(None); thinvec.push(None);
} }

View File

@ -99,45 +99,7 @@ macro_rules! impl_array_newtype {
} }
} }
impl ::std::ops::Index<::std::ops::Range<usize>> for $thing { impl_index_newtype!($thing, $ty);
type Output = [$ty];
#[inline]
fn index(&self, index: ::std::ops::Range<usize>) -> &[$ty] {
let &$thing(ref dat) = self;
&dat[index]
}
}
impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $thing {
type Output = [$ty];
#[inline]
fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[$ty] {
let &$thing(ref dat) = self;
&dat[index]
}
}
impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $thing {
type Output = [$ty];
#[inline]
fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[$ty] {
let &$thing(ref dat) = self;
&dat[index]
}
}
impl ::std::ops::Index<::std::ops::RangeFull> for $thing {
type Output = [$ty];
#[inline]
fn index(&self, _: ::std::ops::RangeFull) -> &[$ty] {
let &$thing(ref dat) = self;
&dat[..]
}
}
impl PartialEq for $thing { impl PartialEq for $thing {
#[inline] #[inline]
@ -234,6 +196,47 @@ macro_rules! impl_array_newtype_show {
} }
} }
macro_rules! impl_index_newtype {
($thing:ident, $ty:ty) => {
impl ::std::ops::Index<::std::ops::Range<usize>> for $thing {
type Output = [$ty];
#[inline]
fn index(&self, index: ::std::ops::Range<usize>) -> &[$ty] {
&self.0[index]
}
}
impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $thing {
type Output = [$ty];
#[inline]
fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[$ty] {
&self.0[index]
}
}
impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $thing {
type Output = [$ty];
#[inline]
fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[$ty] {
&self.0[index]
}
}
impl ::std::ops::Index<::std::ops::RangeFull> for $thing {
type Output = [$ty];
#[inline]
fn index(&self, _: ::std::ops::RangeFull) -> &[$ty] {
&self.0[..]
}
}
}
}
macro_rules! display_from_debug { macro_rules! display_from_debug {
($thing:ident) => { ($thing:ident) => {
impl ::std::fmt::Display for $thing { impl ::std::fmt::Display for $thing {

View File

@ -47,6 +47,7 @@
extern crate alloc; extern crate alloc;
extern crate byteorder; extern crate byteorder;
extern crate collections; extern crate collections;
extern crate eventual;
extern crate num_cpus; extern crate num_cpus;
extern crate rand; extern crate rand;
extern crate rustc_serialize as serialize; extern crate rustc_serialize as serialize;

View File

@ -34,7 +34,6 @@ macro_rules! nu_select {
} }
)else+ )else+
else { else {
// Start selecting on as many as we need to before getting a bite. // 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 // Keep count of how many, since we need to abort every selection
// that we started. // that we started.

View File

@ -59,7 +59,7 @@ static BASE58_DIGITS: [Option<u8>; 128] = [
]; ];
/// Trait for objects which can be read as base58 /// Trait for objects which can be read as base58
pub trait FromBase58 { pub trait FromBase58: Sized {
/// Constructs an object flrom the byte-encoding (base 256) /// Constructs an object flrom the byte-encoding (base 256)
/// representation of its base58 format /// representation of its base58 format
fn from_base58_layout(data: Vec<u8>) -> Result<Self, Error>; fn from_base58_layout(data: Vec<u8>) -> Result<Self, Error>;
@ -67,7 +67,7 @@ pub trait FromBase58 {
/// Obtain an object from its base58 encoding /// Obtain an object from its base58 encoding
fn from_base58(data: &str) -> Result<Self, Error> { fn from_base58(data: &str) -> Result<Self, Error> {
// 11/15 is just over log_256(58) // 11/15 is just over log_256(58)
let mut scratch = Vec::from_elem(1 + data.len() * 11 / 15, 0u8); let mut scratch = vec![0u8; 1 + data.len() * 11 / 15];
// Build in base 256 // Build in base 256
for d58 in data.bytes() { for d58 in data.bytes() {
// Compute "X = X * 58 + next_digit" in base 256 // Compute "X = X * 58 + next_digit" in base 256
@ -132,13 +132,13 @@ pub fn base58_encode_slice(data: &[u8]) -> String {
// Unsafely translate the bytes to a utf8 string // Unsafely translate the bytes to a utf8 string
unsafe { unsafe {
// Copy leading zeroes directly // Copy leading zeroes directly
let mut ret: Vec<u8> = str::from_utf8(data.iter().take_while(|&&x| x == 0) let mut ret: Vec<u8> = data.iter().take_while(|&&x| x == 0)
.map(|_| BASE58_CHARS[0]) .map(|_| BASE58_CHARS[0])
.collect()).unwrap(); .collect();
// Copy rest of string // Copy rest of string
ret.as_mut_vec().extend(scratch.into_iter().skip_while(|&x| x == 0) ret.extend(scratch.into_iter().skip_while(|&x| x == 0)
.map(|x| BASE58_CHARS[x as usize])); .map(|x| BASE58_CHARS[x as usize]));
ret String::from_utf8(ret).unwrap()
} }
} }

View File

@ -247,7 +247,7 @@ impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] {
let mut encoder = RawEncoder::new(Cursor::new(vec![])); let mut encoder = RawEncoder::new(Cursor::new(vec![]));
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.unwrap().into_inner().bitcoin_hash()); next.push(encoder.into_inner().into_inner().bitcoin_hash());
} }
merkle_root(next) merkle_root(next)
} }

View File

@ -84,7 +84,7 @@ pub fn script_find_and_remove(haystack: &mut Vec<u8>, needle: &[u8]) -> usize {
if overflow { break; } if overflow { break; }
} else { } else {
i += match opcodes::All::from_u8((*haystack)[i]).classify() { i += match opcodes::All::from_u8((*haystack)[i]).classify() {
opcodes::Class::PushBytes(n) => n + 1, opcodes::Class::PushBytes(n) => n as usize + 1,
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => 2, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => 2,
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => 3, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => 3,
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => 5, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => 5,

View File

@ -21,7 +21,7 @@ use crypto::digest::Digest;
use crypto::sha2::Sha256; use crypto::sha2::Sha256;
use std::ops; use std::ops;
use blockdata::script::Script; use blockdata::script::{Script, ScriptBuilder};
use blockdata::opcodes; use blockdata::opcodes;
use network::constants::Network; use network::constants::Network;
use util::hash::Ripemd160Hash; use util::hash::Ripemd160Hash;
@ -53,13 +53,13 @@ impl Address {
/// Generates a script pubkey spending to this address /// Generates a script pubkey spending to this address
#[inline] #[inline]
pub fn script_pubkey(&self) -> Script { pub fn script_pubkey(&self) -> Script {
let mut script = Script::new(); let mut script = ScriptBuilder::new();
script.push_opcode(opcodes::All::OP_DUP); script.push_opcode(opcodes::All::OP_DUP);
script.push_opcode(opcodes::All::OP_HASH160); script.push_opcode(opcodes::All::OP_HASH160);
script.push_slice(&self.hash[..]); script.push_slice(&self.hash[..]);
script.push_opcode(opcodes::All::OP_EQUALVERIFY); script.push_opcode(opcodes::All::OP_EQUALVERIFY);
script.push_opcode(opcodes::All::OP_CHECKSIG); script.push_opcode(opcodes::All::OP_CHECKSIG);
script script.into_script()
} }
} }