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]
git = "https://github.com/apoelstra/bitcoin-secp256k1-rs.git"
[dependencies.eventual]
git = "https://github.com/carllerche/eventual"
[dependencies]
byteorder = "*"
num_cpus = "*"

View File

@ -112,7 +112,7 @@ impl BlockHeader {
let mut ret = !self.target();
let mut ret1 = self.target();
ret1.increment();
ret = ret.div(&ret1);
ret = ret / ret1;
ret.increment();
ret
}
@ -121,7 +121,7 @@ impl BlockHeader {
impl BitcoinHash for BlockHeader {
fn bitcoin_hash(&self) -> Sha256dHash {
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 {
let mut scan = self.next;
while scan.is_not_null() {
while !scan.is_null() {
if (*scan).block.header == (*chain.best_tip).block.header {
return true;
}
@ -145,15 +145,15 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Blockchain {
let best = match tree.lookup(&best_hash.into_le(), 256) {
Some(node) => &**node as NodePtr,
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
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
let raw_tree = &tree as *const _;
let raw_tree = &tree as *const BlockTree;
for node in tree.mut_iter() {
let hash = node.block.header.prev_blockhash.into_le();
let prevptr =
@ -166,7 +166,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Blockchain {
// Reconnect next pointers on the main chain
unsafe {
let mut scan = best;
while (*scan).prev.is_not_null() {
while !(*scan).prev.is_null() {
let prev = (*scan).prev as *mut BlockchainNode;
(*prev).next = scan;
scan = prev as NodePtr;
@ -175,7 +175,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Blockchain {
// Check that "genesis" is the genesis
if (*scan).bitcoin_hash() != genesis_hash {
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)
self.index = unsafe { (*self.index).prev };
// 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 {
unsafe {
if (*self.index).prev.is_null() {
@ -318,7 +318,7 @@ impl<'tree> Iterator for RevStaleBlockIter<'tree> {
let ret = Some(&(*self.index).block);
let next_index = (*self.index).prev;
// 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).is_on_main_chain(self.chain) {
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
/// the nBits block header field. Savour the perversity. This is in Bitcoin
/// 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
let bits = 8 * ((n.bits() + 7) / 8 - 3);
let mut ret = n >> bits;
@ -475,16 +475,16 @@ impl Blockchain {
let max = max_target(self.network);
if target > max { target = max };
// 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
// 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 {
max_target(self.network)
// 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
// 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
unsafe {
let mut scan = prev;
@ -500,7 +500,7 @@ impl Blockchain {
};
// Create node
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,
required_difficulty: difficulty,
height: unsafe { (*prev).height + 1 },
@ -538,7 +538,7 @@ impl Blockchain {
unsafe {
let mut scan = self.best_tip;
// 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 scan == self.best_tip { break; }
// Otherwise set the next-ptr and carry on

View File

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

View File

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

View File

@ -35,7 +35,7 @@ use crypto::digest::Digest;
use crypto::ripemd160::Ripemd160;
use crypto::sha1::Sha1;
use crypto::sha2::Sha256;
use secp256k1::Secp256k1;
use secp256k1::{self, Secp256k1};
use secp256k1::key::PublicKey;
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 {
#[inline]
fn hash<H>(&self, state: &mut H)
where H: hash::Hasher
{
let &Script(ref raw) = self;
(&raw[..]).hash(state);
(&self.0[..]).hash(state);
}
#[inline]
@ -70,8 +73,7 @@ impl hash::Hash for Script {
where H: hash::Hasher
{
for s in data.iter() {
let &Script(ref raw) = s;
(&raw[..]).hash(state);
(&s.0[..]).hash(state);
}
}
}
@ -95,7 +97,7 @@ pub enum Error {
/// OP_CHECKSIG was called with a bad signature
BadSignature,
/// An ECDSA error
Ecdsa(::secp256k1::Error),
Ecdsa(secp256k1::Error),
/// An OP_ELSE happened while not in an OP_IF tree
ElseWithoutIf,
/// 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 {
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;
} else {
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()
};
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.
@ -1719,70 +1724,7 @@ impl Script {
pub fn from_vec(v: Vec<u8>) -> Script { Script(v.into_boxed_slice()) }
/// The length in bytes of the script
pub fn len(&self) -> usize {
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);
}
pub fn len(&self) -> usize { self.0.len() }
/// Trace a script
pub fn trace<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>,
@ -1807,21 +1749,19 @@ impl Script {
input_context: Option<(&Transaction, usize)>,
mut trace: Option<&mut Vec<TraceIteration>>)
-> Result<(), Error> {
let &Script(ref raw) = self;
let mut codeseparator_index = 0;
let mut exec_stack = vec![];
let mut alt_stack = vec![];
let mut index = 0;
let mut op_count = 0;
while index < raw.len() {
while index < self.0.len() {
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
match trace {
Some(ref mut t) => {
let opcode = opcodes::All::Opcode::from_u8(byte);
let opcode = opcodes::All::from_u8(byte);
t.push(TraceIteration {
index: index,
opcode: opcode,
@ -1837,7 +1777,7 @@ impl Script {
op_count += 1;
index += 1;
// 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
(_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode),
// Push number
@ -1846,29 +1786,30 @@ impl Script {
(true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn),
// Data-reading statements still need to read, even when not executing
(_, opcodes::Class::PushBytes(n)) => {
if raw.len() < index + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index, index + n))); }
let n = n as usize;
if self.0.len() < index + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(&self.0[index..index + n])); }
index += n;
}
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => {
if raw.len() < index + 1 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&raw[index..], 1));
if raw.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 1, index + n + 1))); }
if self.0.len() < index + 1 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&self.0[index..], 1));
if self.0.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 1..index + n + 1])); }
index += 1 + n;
}
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => {
if raw.len() < index + 2 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&raw[index..], 2));
if raw.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 2, index + n + 2))); }
if self.0.len() < index + 2 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&self.0[index..], 2));
if self.0.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 2..index + n + 2])); }
index += 2 + n;
}
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => {
if raw.len() < index + 4 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&raw[index..], 4));
if raw.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 4, index + n + 4))); }
if self.0.len() < index + 4 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(&self.0[index..], 4));
if self.0.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 4..index + n + 4])); }
index += 4 + n;
}
// 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_PICK => {
let n = match stack.pop() {
Some(data) => try!(read_scriptint(&data)),
Some(data) => try!(read_scriptint(&data[..])),
None => { return Err(Error::PopEmptyStack); }
};
if n < 0 { return Err(Error::NegativePick); }
@ -1951,7 +1892,7 @@ impl Script {
}
opcodes::Ordinary::OP_ROLL => {
let n = match stack.pop() {
Some(data) => try!(read_scriptint(&data)),
Some(data) => try!(read_scriptint(&data[..])),
None => { return Err(Error::PopEmptyStack); }
};
if n < 0 { return Err(Error::NegativeRoll); }
@ -2033,11 +1974,12 @@ impl Script {
// Compute the section of script that needs to be hashed: everything
// from the last CODESEPARATOR, except the signature itself.
let mut script = (&raw[codeseparator_index..]).to_vec();
let mut remove = Script::new();
let mut script = (&self.0[codeseparator_index..]).to_vec();
let mut remove = ScriptBuilder::new();
remove.push_slice(sig_slice);
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, &remove[..]);
// 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
if input_context.is_none() { return Err(Error::NoTransaction); }
@ -2053,7 +1995,7 @@ impl Script {
opcodes::Ordinary::OP_CHECKMULTISIG | opcodes::Ordinary::OP_CHECKMULTISIGVERIFY => {
// Read all the keys
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 {
return Err(Error::MultisigBadKeyCount(n_keys as isize));
}
@ -2066,7 +2008,7 @@ impl Script {
// Read all the signatures
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 {
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
// 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() {
let mut remove = Script::new();
remove.push_slice(&sig);
script_find_and_remove(&mut script, &remove);
script_find_and_remove(&mut script, [opcodes::Ordinary::OP_CODESEPARATOR as u8]);
let mut remove = ScriptBuilder::new();
remove.push_slice(&sig[..]);
script_find_and_remove(&mut script, &remove[..]);
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
@ -2105,7 +2047,7 @@ impl Script {
// Try to validate the signature with the given key
(Some(k), Some(s)) => {
// 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();
}
// Move to the next key in any case
@ -2142,12 +2084,11 @@ impl Script {
/// Checks whether a script pubkey is a p2sh output
#[inline]
pub fn is_p2sh(&self) -> bool {
let &Script(ref raw) = self;
unsafe {
raw.len() == 23 &&
*raw.get(0) == opcodes::All::OP_HASH160 as u8 &&
*raw.get(1) == opcodes::All::OP_PUSHBYTES_20 as u8 &&
*raw.get(22) == opcodes::All::OP_EQUAL as u8
self.0.len() == 23 &&
self.0[0] == opcodes::All::OP_HASH160 as u8 &&
self.0[1] == opcodes::All::OP_PUSHBYTES_20 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),
// Data-reading statements still need to read, even when not executing
(_, opcodes::Class::PushBytes(n)) => {
let n = n as usize;
if script.len() < index + n { return Err(Error::EarlyEndOfScript); }
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;
}
@ -2200,7 +2142,7 @@ impl Script {
};
if script.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); }
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;
}
@ -2212,7 +2154,7 @@ impl Script {
};
if script.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); }
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;
}
@ -2223,7 +2165,7 @@ impl Script {
};
if script.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); }
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;
}
@ -2495,8 +2437,7 @@ impl Script {
}
}
let &Script(ref raw) = self;
recurse(&raw, AbstractStack::new(), vec![], 1)
recurse(&self.0, AbstractStack::new(), vec![], 1)
}
}
@ -2504,62 +2445,93 @@ impl Default for Script {
fn default() -> Script { Script(vec![].into_boxed_slice()) }
}
impl_index_newtype!(Script, u8);
impl ops::Index<usize> for Script {
type Output = u8;
#[inline]
fn index(&self, index: usize) -> &u8 {
let &Script(ref raw) = self;
&raw[index]
impl ScriptBuilder {
/// Creates a new empty script
pub fn new() -> ScriptBuilder { ScriptBuilder(vec![]) }
/// Creates a new script from an existing vector
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 {
type Output = [u8];
#[inline]
fn index(&self, index: ops::Range<usize>) -> &[u8] {
let &Script(ref raw) = self;
&raw[index]
}
/// Adds an individual opcode to the script
impl Default for ScriptBuilder {
fn default() -> ScriptBuilder { ScriptBuilder(vec![]) }
}
impl ops::Index<ops::RangeTo<usize>> for Script {
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[..]
}
}
impl_index_newtype!(ScriptBuilder, u8);
// User-facing serialization
impl serde::Serialize for Script {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer,
{
let &Script(ref raw) = self;
for dat in raw.iter() {
serializer.visit_char(from_digit((dat / 0x10) as u32, 16).unwrap());
serializer.visit_char(from_digit((dat & 0x0f) as u32, 16).unwrap());
for dat in self.0.iter() {
try!(serializer.visit_char(from_digit((dat / 0x10) as u32, 16).unwrap()));
try!(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 {
#[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
let &Script(ref data) = self;
data.consensus_encode(s)
self.0.consensus_encode(s)
}
}

View File

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

View File

@ -21,11 +21,11 @@
use std::cmp;
use std::collections::HashMap;
use std::collections::hash::map::Iter;
use std::hash::SipHasher;
use std::default::Default;
use std::mem;
use eventual;
use eventual::Async;
use num_cpus;
use std::sync::Future;
use blockdata::transaction::{self, Transaction, TxOut};
use blockdata::constants::genesis_block;
@ -78,15 +78,12 @@ impl<'a> Iterator for UtxoIterator<'a> {
type Item = (Sha256dHash, u32, &'a TxOut, u32);
fn next(&mut self) -> Option<(Sha256dHash, u32, &'a TxOut, u32)> {
while self.current.is_some() {
let current = &self.current.unwrap().outputs;
while self.tx_index < current.len() as u32 {
while let Some(current) = self.current {
while self.tx_index < current.outputs.len() as u32 {
self.tx_index += 1;
if unsafe { current.get(self.tx_index as usize - 1) }.is_some() {
return Some((self.current_key,
self.tx_index,
unsafe { current.get(self.tx_index as usize - 1) }.as_ref().unwrap(),
self.current.unwrap().height));
if let Some(ref cur) = current.outputs[self.tx_index as usize - 1] {
return Some((self.current_key, self.tx_index,
cur, current.height));
}
}
match self.tx_iter.next() {
@ -104,7 +101,7 @@ impl<'a> Iterator for UtxoIterator<'a> {
/// The UTXO set
pub struct UtxoSet {
table: HashMap<Sha256dHash, UtxoNode, SipHasher>,
table: HashMap<Sha256dHash, UtxoNode>,
last_hash: Sha256dHash,
// A circular buffer of deleted utxos, grouped by block
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
// while the reference client won't, causing us to fork off the network.
UtxoSet {
table: HashMap::with_hasher(SipHasher::new()),
table: HashMap::new(),
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,
n_utxos: 0,
n_pruned: 0
@ -153,7 +150,7 @@ impl UtxoSet {
};
// Get the old value, if any (this is suprisingly possible, c.f. BIP30
// 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() {
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 :(
let (height, ret, should_delete) = {
// 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,
None => return None
};
@ -173,7 +170,7 @@ impl UtxoSet {
let ret = {
// Check that this specific output is there
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()
};
@ -193,13 +190,13 @@ impl UtxoSet {
/// Get a reference to a UTXO in the set
pub fn get_utxo<'a>(&'a self, txid: Sha256dHash, vout: u32) -> Option<(usize, &'a TxOut)> {
// Locate the UTXO, failing if not found
let node = match self.table.find(&txid) {
let node = match self.table.get(&txid) {
Some(node) => node,
None => return None
};
// Check that this specific output is there
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()))
}
@ -217,7 +214,7 @@ impl UtxoSet {
self.last_hash = block.header.bitcoin_hash();
let spent_idx = self.spent_idx as usize;
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
// same block. (Note that Bitcoin requires chained transactions to be in
@ -240,10 +237,10 @@ impl UtxoSet {
} else {
// Otherwise put the replaced txouts into the `deleted` cache
// 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() {
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 => {}
}
}
@ -268,12 +265,14 @@ impl UtxoSet {
let start = 1 + j * 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;
let txes = &block.txdata as *const _;
future_vec.push(Future::spawn(move || {
let txes = unsafe {&*txes};
for tx in txes.slice(start, end).iter() {
match tx.validate(unsafe {&*s}) {
// WARNING: we are asserting that these variables will outlive the Futures;
// this means that we need to await all Futures before leaving the
// function or else risk use-after-free in the async threads.
let static_txes = unsafe { &*(&block.txdata as *const Vec<Transaction>) };
let static_self = unsafe { &*(self as *const UtxoSet) };
future_vec.push(eventual::Future::spawn(move || {
for tx in static_txes[start..end].iter() {
match tx.validate(static_self) {
Ok(_) => {},
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
// leaving this function, and given that, it's easier to return the last.
let mut last_error = Ok(());
for res in future_vec.iter_mut().map(|f| f.get()) {
if res.is_err() {
last_error = res;
}
}
if last_error.is_err() {
return last_error;
let mut last_err = Ok(());
for res in future_vec.iter_mut().map(|f| f.await().unwrap()) {
if res.is_err() { last_err = res; }
}
if last_err.is_err() { return last_err; }
}
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.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() {
let taken = self.take_utxo(input.prev_hash, input.prev_index);
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 => {
if validation >= ValidationLevel::Inputs {
self.rewind(block);
@ -349,18 +344,17 @@ impl UtxoSet {
// Read deleted txouts
if skipped_genesis {
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() {
// Remove the tx's utxo list and patch the txo into place
let new_node =
match self.table.pop(&txid) {
let new_node = match self.table.remove(&txid) {
Some(mut node) => {
node.outputs[n as usize] = Some(txo);
node
}
None => {
unsafe {
let mut thinvec = Vec::with_capacity(n + 1);
let mut thinvec = Vec::with_capacity(n as usize + 1);
for _ in 0..n {
thinvec.push(None);
}

View File

@ -99,45 +99,7 @@ macro_rules! impl_array_newtype {
}
}
impl ::std::ops::Index<::std::ops::Range<usize>> for $thing {
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_index_newtype!($thing, $ty);
impl PartialEq for $thing {
#[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 {
($thing:ident) => {
impl ::std::fmt::Display for $thing {

View File

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

View File

@ -34,7 +34,6 @@ macro_rules! nu_select {
}
)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.

View File

@ -59,7 +59,7 @@ static BASE58_DIGITS: [Option<u8>; 128] = [
];
/// 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)
/// representation of its base58 format
fn from_base58_layout(data: Vec<u8>) -> Result<Self, Error>;
@ -67,7 +67,7 @@ pub trait FromBase58 {
/// Obtain an object from its base58 encoding
fn from_base58(data: &str) -> Result<Self, Error> {
// 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
for d58 in data.bytes() {
// 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
unsafe {
// 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])
.collect()).unwrap();
.collect();
// 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]));
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![]));
data[idx1].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)
}

View File

@ -84,7 +84,7 @@ pub fn script_find_and_remove(haystack: &mut Vec<u8>, needle: &[u8]) -> usize {
if overflow { break; }
} else {
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_PUSHDATA2) => 3,
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => 5,

View File

@ -21,7 +21,7 @@ use crypto::digest::Digest;
use crypto::sha2::Sha256;
use std::ops;
use blockdata::script::Script;
use blockdata::script::{Script, ScriptBuilder};
use blockdata::opcodes;
use network::constants::Network;
use util::hash::Ripemd160Hash;
@ -53,13 +53,13 @@ impl Address {
/// Generates a script pubkey spending to this address
#[inline]
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_HASH160);
script.push_slice(&self.hash[..]);
script.push_opcode(opcodes::All::OP_EQUALVERIFY);
script.push_opcode(opcodes::All::OP_CHECKSIG);
script
script.into_script()
}
}