Changes for cargo-clippy warnings

This commit is contained in:
Andrew Poelstra 2015-10-28 11:27:23 -05:00
parent 8daf06cc1d
commit 5e03adc9aa
14 changed files with 127 additions and 117 deletions

View File

@ -39,7 +39,8 @@ using the same rules to validate data, and this library is simply unable
to implement the same rules as Core. to implement the same rules as Core.
Given the complexity of both C++ and Rust, it is unlikely that this will Given the complexity of both C++ and Rust, it is unlikely that this will
ever be fixed, and there are no plans to do so. ever be fixed, and there are no plans to do so. Of course, patches to
fix specific consensus incompatibilities are welcome.
## Memory Usage ## Memory Usage

View File

@ -80,7 +80,7 @@ impl BlockHeader {
let (mant, expt) = { let (mant, expt) = {
let unshifted_expt = self.bits >> 24; let unshifted_expt = self.bits >> 24;
if unshifted_expt <= 3 { if unshifted_expt <= 3 {
((self.bits & 0xFFFFFF) >> 8 * (3 - unshifted_expt as usize), 0) ((self.bits & 0xFFFFFF) >> (8 * (3 - unshifted_expt as usize)), 0)
} else { } else {
(self.bits & 0xFFFFFF, 8 * ((self.bits >> 24) - 3)) (self.bits & 0xFFFFFF, 8 * ((self.bits >> 24) - 3))
} }
@ -98,11 +98,11 @@ impl BlockHeader {
/// is correct, but does not verify that the transactions are valid or encoded /// is correct, but does not verify that the transactions are valid or encoded
/// correctly. /// correctly.
pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> { pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> {
let ref target = self.target(); let target = &self.target();
if target != required_target { if target != required_target {
return Err(SpvBadTarget); return Err(SpvBadTarget);
} }
let ref hash = self.bitcoin_hash().into_le(); let hash = &self.bitcoin_hash().into_le();
if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) } if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) }
} }

View File

@ -65,18 +65,19 @@ impl BlockchainNode {
/// Is the node on the main chain? /// Is the node on the main chain?
fn is_on_main_chain(&self, chain: &Blockchain) -> bool { fn is_on_main_chain(&self, chain: &Blockchain) -> bool {
if self.block.header == unsafe { (*chain.best_tip).block.header } { if self.block.header == unsafe { (*chain.best_tip).block.header } {
return true; true
} } else {
unsafe { unsafe {
let mut scan = self.next; let mut scan = self.next;
while !scan.is_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;
}
scan = (*scan).next;
} }
scan = (*scan).next;
} }
false
} }
return false;
} }
} }
@ -385,7 +386,7 @@ impl Blockchain {
} }
/// Looks up a block in the chain and returns the BlockchainNode containing it /// Looks up a block in the chain and returns the BlockchainNode containing it
pub fn get_block<'a>(&'a self, hash: Sha256dHash) -> Option<&'a BlockchainNode> { pub fn get_block(&self, hash: Sha256dHash) -> Option<&BlockchainNode> {
self.tree.lookup(&hash.into_le(), 256).map(|node| &**node) self.tree.lookup(&hash.into_le(), 256).map(|node| &**node)
} }
@ -412,7 +413,7 @@ impl Blockchain {
fn real_add_block(&mut self, block: Block, has_txdata: bool) -> Result<(), util::Error> { fn real_add_block(&mut self, block: Block, has_txdata: bool) -> Result<(), util::Error> {
// get_prev optimizes the common case where we are extending the best tip // get_prev optimizes the common case where we are extending the best tip
#[inline] #[inline]
fn get_prev<'a>(chain: &'a Blockchain, hash: Sha256dHash) -> Option<NodePtr> { fn get_prev(chain: &Blockchain, hash: Sha256dHash) -> Option<NodePtr> {
if hash == chain.best_hash { if hash == chain.best_hash {
Some(chain.best_tip) Some(chain.best_tip)
} else { } else {
@ -535,7 +536,7 @@ impl Blockchain {
} }
/// Returns the best tip /// Returns the best tip
pub fn best_tip<'a>(&'a self) -> &'a Block { pub fn best_tip(&self) -> &Block {
unsafe { &(*self.best_tip).block } unsafe { &(*self.best_tip).block }
} }

View File

@ -891,14 +891,14 @@ impl AbstractStackElem {
} }
/// Looks up another stack item by index /// Looks up another stack item by index
unsafe fn lookup<'a>(&'a self, idx: usize) -> &'a AbstractStackElem { unsafe fn lookup(&self, idx: usize) -> &AbstractStackElem {
let mypos = self as *const _; let mypos = self as *const _;
let myidx = self.alloc_index.unwrap() as isize; let myidx = self.alloc_index.unwrap() as isize;
&*mypos.offset(idx as isize - myidx) &*mypos.offset(idx as isize - myidx)
} }
/// Looks up another stack item by index /// Looks up another stack item by index
unsafe fn lookup_mut<'a>(&'a self, idx: usize) -> &'a mut AbstractStackElem { unsafe fn lookup_mut(&self, idx: usize) -> &mut AbstractStackElem {
let mypos = self as *const _ as *mut _; let mypos = self as *const _ as *mut _;
let myidx = self.alloc_index.unwrap() as isize; let myidx = self.alloc_index.unwrap() as isize;
&mut *mypos.offset(idx as isize - myidx) &mut *mypos.offset(idx as isize - myidx)
@ -910,7 +910,7 @@ impl AbstractStackElem {
} }
/// Retrieves the raw value of the stack element, if it can be determined /// Retrieves the raw value of the stack element, if it can be determined
pub fn raw_value<'a>(&'a self) -> Option<&'a [u8]> { pub fn raw_value(&self) -> Option<&[u8]> {
self.raw.as_ref().map(|x| &x[..]) self.raw.as_ref().map(|x| &x[..])
} }
@ -1177,9 +1177,7 @@ impl AbstractStack {
/// Construct the initial stack in the end /// Construct the initial stack in the end
pub fn build_initial_stack(&self) -> Vec<AbstractStackElem> { pub fn build_initial_stack(&self) -> Vec<AbstractStackElem> {
let res: Vec<AbstractStackElem> = self.initial_stack.iter().map(|&i| self.alloc[i].clone()).collect()
self.initial_stack.iter().map(|&i| self.alloc[i].clone()).collect();
res
} }
/// Increase the stack size to `n`, adding elements to the initial /// Increase the stack size to `n`, adding elements to the initial
@ -1196,7 +1194,7 @@ impl AbstractStack {
} }
/// Push a new element /// Push a new element
pub fn push_alloc<'a>(&'a mut self, elem: AbstractStackElem) -> &'a mut AbstractStackElem { pub fn push_alloc(&mut self, elem: AbstractStackElem) -> &mut AbstractStackElem {
let idx = self.allocate(elem); let idx = self.allocate(elem);
self.stack.push(idx); self.stack.push(idx);
&mut self.alloc[idx] &mut self.alloc[idx]
@ -1204,8 +1202,8 @@ impl AbstractStack {
/// Obtain a mutable element to the top stack element /// Obtain a mutable element to the top stack element
pub fn peek_mut<'a>(&'a mut self) -> &'a mut AbstractStackElem { pub fn peek_mut(&mut self) -> &mut AbstractStackElem {
if self.stack.len() == 0 { if self.stack.is_empty() {
self.push_initial(AbstractStackElem::new_unknown()); self.push_initial(AbstractStackElem::new_unknown());
} }
@ -1214,7 +1212,7 @@ impl AbstractStack {
/// Obtain a stackref to the current top element /// Obtain a stackref to the current top element
pub fn peek_index(&mut self) -> usize { pub fn peek_index(&mut self) -> usize {
if self.stack.len() == 0 { if self.stack.is_empty() {
self.push_initial(AbstractStackElem::new_unknown()); self.push_initial(AbstractStackElem::new_unknown());
} }
*self.stack.last().unwrap() *self.stack.last().unwrap()
@ -1222,15 +1220,15 @@ impl AbstractStack {
/// Drop the top stack item /// Drop the top stack item
fn pop(&mut self) -> usize { fn pop(&mut self) -> usize {
if self.stack.len() == 0 { if self.stack.is_empty() {
self.push_initial(AbstractStackElem::new_unknown()); self.push_initial(AbstractStackElem::new_unknown());
} }
self.stack.pop().unwrap() self.stack.pop().unwrap()
} }
/// Obtain a mutable reference to the top stack item, but remove it from the stack /// Obtain a mutable reference to the top stack item, but remove it from the stack
fn pop_mut<'a>(&'a mut self) -> &'a mut AbstractStackElem { fn pop_mut(&mut self) -> &mut AbstractStackElem {
if self.stack.len() == 0 { if self.stack.is_empty() {
self.push_initial(AbstractStackElem::new_unknown()); self.push_initial(AbstractStackElem::new_unknown());
} }
@ -1239,8 +1237,8 @@ impl AbstractStack {
/// Move the top stack item to the altstack /// Move the top stack item to the altstack
pub fn to_altstack(&mut self) { pub fn top_to_altstack(&mut self) {
if self.stack.len() == 0 { if self.stack.is_empty() {
self.push_initial(AbstractStackElem::new_unknown()); self.push_initial(AbstractStackElem::new_unknown());
} }
@ -1252,7 +1250,7 @@ impl AbstractStack {
/// altstack is empty. (Note that input scripts pass their /// altstack is empty. (Note that input scripts pass their
/// stack to the output script but /not/ the altstack, so /// stack to the output script but /not/ the altstack, so
/// there is no input that can make an empty altstack nonempty.) /// there is no input that can make an empty altstack nonempty.)
pub fn from_altstack(&mut self) -> Result<(), Error> { pub fn top_from_altstack(&mut self) -> Result<(), Error> {
match self.alt_stack.pop() { match self.alt_stack.pop() {
Some(x) => { self.stack.push(x); Ok(()) } Some(x) => { self.stack.push(x); Ok(()) }
None => Err(Error::PopEmptyStack) None => Err(Error::PopEmptyStack)
@ -1549,7 +1547,7 @@ pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
let (mut ret, sh) = v.iter() let (mut ret, sh) = v.iter()
.fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8)); .fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8));
if v[len - 1] & 0x80 != 0 { if v[len - 1] & 0x80 != 0 {
ret &= (1 << sh - 1) - 1; ret &= (1 << (sh - 1)) - 1;
ret = -ret; ret = -ret;
} }
Ok(ret) Ok(ret)
@ -1559,7 +1557,7 @@ pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
/// else as true", except that the overflow rules don't apply. /// else as true", except that the overflow rules don't apply.
#[inline] #[inline]
pub fn read_scriptbool(v: &[u8]) -> bool { pub fn read_scriptbool(v: &[u8]) -> bool {
!(v.len() == 0 || !(v.is_empty() ||
((v[v.len() - 1] == 0 || v[v.len() - 1] == 0x80) && ((v[v.len() - 1] == 0 || v[v.len() - 1] == 0x80) &&
v.iter().rev().skip(1).all(|&w| w == 0))) v.iter().rev().skip(1).all(|&w| w == 0)))
} }
@ -1809,6 +1807,9 @@ impl Script {
/// The length in bytes of the script /// The length in bytes of the script
pub fn len(&self) -> usize { self.0.len() } pub fn len(&self) -> usize { self.0.len() }
/// Whether the script is the empty script
pub fn is_empty(&self) -> bool { self.0.is_empty() }
/// Trace a script /// Trace a script
pub fn trace<'a>(&'a self, secp: &Secp256k1, stack: &mut Vec<MaybeOwned<'a>>, pub fn trace<'a>(&'a self, secp: &Secp256k1, stack: &mut Vec<MaybeOwned<'a>>,
input_context: Option<(&Transaction, usize)>) input_context: Option<(&Transaction, usize)>)
@ -1852,7 +1853,7 @@ impl Script {
errored: true, errored: true,
op_count: op_count, op_count: op_count,
effect: opcode.classify(), effect: opcode.classify(),
stack: vec!["<failed to execute opcode>".to_string()] stack: vec!["<failed to execute opcode>".to_owned()]
}); });
} }
None => {} None => {}
@ -1954,16 +1955,16 @@ impl Script {
} }
} }
opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): drop 1; drop 2), opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): drop 1; drop 2),
opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): copy 2; copy 1), opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): copy 2; copy 1),
opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): copy 3; copy 2; copy 1), opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): copy 3; copy 2; copy 1),
opcodes::Ordinary::OP_2OVER => stack_opcode!(stack(4): copy 4; copy 3), opcodes::Ordinary::OP_2OVER => stack_opcode!(stack(4): copy 4; copy 3),
opcodes::Ordinary::OP_2ROT => stack_opcode!(stack(6): perm (1, 3, 5); opcodes::Ordinary::OP_2ROT => stack_opcode!(stack(6): perm (1, 3, 5);
perm (2, 4, 6)), perm (2, 4, 6)),
opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack(4): swap (2, 4); swap (1, 3)), opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack(4): swap (2, 4); swap (1, 3)),
opcodes::Ordinary::OP_DROP => stack_opcode!(stack(1): drop 1), opcodes::Ordinary::OP_DROP => stack_opcode!(stack(1): drop 1),
opcodes::Ordinary::OP_DUP => stack_opcode!(stack(1): copy 1), opcodes::Ordinary::OP_DUP => stack_opcode!(stack(1): copy 1),
opcodes::Ordinary::OP_NIP => stack_opcode!(stack(2): drop 2), opcodes::Ordinary::OP_NIP => stack_opcode!(stack(2): drop 2),
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[..])),
@ -2009,7 +2010,7 @@ impl Script {
stack.push(MaybeOwned::Borrowed(if a == b { SCRIPT_TRUE } else { SCRIPT_FALSE })); stack.push(MaybeOwned::Borrowed(if a == b { SCRIPT_TRUE } else { SCRIPT_FALSE }));
if op == opcodes::Ordinary::OP_EQUALVERIFY { if op == opcodes::Ordinary::OP_EQUALVERIFY {
op_verify!(stack, Error::EqualVerifyFailed((&a[..]).to_hex(), op_verify!(stack, Error::EqualVerifyFailed((&a[..]).to_hex(),
(&b[..]).to_hex())); (&b[..]).to_hex()));
} }
} }
opcodes::Ordinary::OP_1ADD => { num_opcode!(stack(a): a + 1); } opcodes::Ordinary::OP_1ADD => { num_opcode!(stack(a): a + 1); }
@ -2108,7 +2109,7 @@ 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 = (&self.0[codeseparator_index..]).to_vec(); let mut script = (&self.0[codeseparator_index..]).to_vec();
for sig in sigs.iter() { for sig in &sigs {
let mut remove = Builder::new(); let mut remove = Builder::new();
remove.push_slice(&sig[..]); remove.push_slice(&sig[..]);
script_find_and_remove(&mut script, &remove[..]); script_find_and_remove(&mut script, &remove[..]);
@ -2185,10 +2186,10 @@ impl Script {
/// Evaluate the script to determine whether any possible input will cause it /// Evaluate the script to determine whether any possible input will cause it
/// to accept. Returns true if it is guaranteed to fail; false otherwise. /// to accept. Returns true if it is guaranteed to fail; false otherwise.
pub fn satisfy(&self) -> Result<Vec<AbstractStackElem>, Error> { pub fn satisfy(&self) -> Result<Vec<AbstractStackElem>, Error> {
fn recurse<'a>(script: &'a [u8], fn recurse(script: &[u8],
mut stack: AbstractStack, mut stack: AbstractStack,
mut exec_stack: Vec<bool>, mut exec_stack: Vec<bool>,
depth: usize) -> Result<Vec<AbstractStackElem>, Error> { depth: usize) -> Result<Vec<AbstractStackElem>, Error> {
// Avoid doing more than 64k forks // Avoid doing more than 64k forks
if depth > 16 { return Err(Error::InterpreterStackOverflow); } if depth > 16 { return Err(Error::InterpreterStackOverflow); }
@ -2334,8 +2335,8 @@ impl Script {
} }
} }
opcodes::Ordinary::OP_VERIFY => op_verify_satisfy!(stack), opcodes::Ordinary::OP_VERIFY => op_verify_satisfy!(stack),
opcodes::Ordinary::OP_TOALTSTACK => { stack.to_altstack(); } opcodes::Ordinary::OP_TOALTSTACK => { stack.top_to_altstack(); }
opcodes::Ordinary::OP_FROMALTSTACK => { try!(stack.from_altstack()); } opcodes::Ordinary::OP_FROMALTSTACK => { try!(stack.top_from_altstack()); }
opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): require 2 drop 1; drop 2), opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): require 2 drop 1; drop 2),
opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): require 2 copy 2; copy 1), opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): require 2 copy 2; copy 1),
opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): require 3 copy 3; copy 2; copy 1), opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): require 3 copy 3; copy 2; copy 1),
@ -2558,7 +2559,7 @@ impl<'a> Iterator for Instructions<'a> {
type Item = Instruction<'a>; type Item = Instruction<'a>;
fn next(&mut self) -> Option<Instruction<'a>> { fn next(&mut self) -> Option<Instruction<'a>> {
if self.data.len() == 0 { if self.data.is_empty() {
return None; return None;
} }
@ -2622,6 +2623,9 @@ impl Builder {
/// The length in bytes of the script /// The length in bytes of the script
pub fn len(&self) -> usize { self.0.len() } pub fn len(&self) -> usize { self.0.len() }
/// Whether the script is the empty script
pub fn is_empty(&self) -> bool { self.0.is_empty() }
/// Adds instructions to push an integer onto the stack. Integers are /// Adds instructions to push an integer onto the stack. Integers are
/// encoded as little-endian signed-magnitude numbers, but there are /// encoded as little-endian signed-magnitude numbers, but there are
/// dedicated opcodes to push some small integers. /// dedicated opcodes to push some small integers.
@ -2833,8 +2837,8 @@ mod test {
// before needing a transaction // before needing a transaction
assert_eq!(script_pk.evaluate(&s, &mut vec![], None, None), Err(Error::PopEmptyStack)); assert_eq!(script_pk.evaluate(&s, &mut vec![], None, None), Err(Error::PopEmptyStack));
assert_eq!(script_pk.evaluate(&s, &mut vec![Owned(vec![]), Owned(vec![])], None, None), assert_eq!(script_pk.evaluate(&s, &mut vec![Owned(vec![]), Owned(vec![])], None, None),
Err(Error::EqualVerifyFailed("e729dea4a3a81108e16376d1cc329c91db589994".to_string(), Err(Error::EqualVerifyFailed("e729dea4a3a81108e16376d1cc329c91db589994".to_owned(),
"b472a266d0bd89c13706a4132ccfb16f7c3b9fcb".to_string()))); "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb".to_owned())));
// But if the signature is there, we need a tx to check it // But if the signature is there, we need a tx to check it
assert_eq!(script_pk.evaluate(&s, &mut vec![Owned(vec![]), Owned("026d5d4cfef5f3d97d2263941b4d8e7aaa82910bf8e6f7c6cf1d8f0d755b9d2d1a".from_hex().unwrap())], None, None), Err(Error::NoTransaction)); assert_eq!(script_pk.evaluate(&s, &mut vec![Owned(vec![]), Owned("026d5d4cfef5f3d97d2263941b4d8e7aaa82910bf8e6f7c6cf1d8f0d755b9d2d1a".from_hex().unwrap())], None, None), Err(Error::NoTransaction));
assert_eq!(script_pk.evaluate(&s, &mut vec![Owned(vec![0]), Owned("026d5d4cfef5f3d97d2263941b4d8e7aaa82910bf8e6f7c6cf1d8f0d755b9d2d1a".from_hex().unwrap())], None, None), Err(Error::NoTransaction)); assert_eq!(script_pk.evaluate(&s, &mut vec![Owned(vec![0]), Owned("026d5d4cfef5f3d97d2263941b4d8e7aaa82910bf8e6f7c6cf1d8f0d755b9d2d1a".from_hex().unwrap())], None, None), Err(Error::NoTransaction));

View File

@ -145,7 +145,7 @@ impl TxIn {
Ok(_) => {} Ok(_) => {}
Err(e) => { return Err(Error::InputScriptFailure(e)); } Err(e) => { return Err(Error::InputScriptFailure(e)); }
} }
if txo.script_pubkey.is_p2sh() && stack.len() > 0 { if txo.script_pubkey.is_p2sh() && !stack.is_empty() {
p2sh_stack = stack.clone(); p2sh_stack = stack.clone();
p2sh_script = match p2sh_stack.pop() { p2sh_script = match p2sh_stack.pop() {
Some(script::MaybeOwned::Owned(v)) => Script::from(v), Some(script::MaybeOwned::Owned(v)) => Script::from(v),
@ -225,7 +225,7 @@ impl Transaction {
let err = trace.sig_trace.error.as_ref().map(|e| e.clone()); let err = trace.sig_trace.error.as_ref().map(|e| e.clone());
err.map(|e| trace.error = Some(Error::InputScriptFailure(e))); err.map(|e| trace.error = Some(Error::InputScriptFailure(e)));
if txo.script_pubkey.is_p2sh() && stack.len() > 0 { if txo.script_pubkey.is_p2sh() && !stack.is_empty() {
p2sh_stack = stack.clone(); p2sh_stack = stack.clone();
p2sh_script = match p2sh_stack.pop() { p2sh_script = match p2sh_stack.pop() {
Some(script::MaybeOwned::Owned(v)) => Script::from(v), Some(script::MaybeOwned::Owned(v)) => Script::from(v),

View File

@ -96,16 +96,19 @@ impl<'a> Iterator for UtxoIterator<'a> {
None => { self.current = None; } None => { self.current = None; }
} }
} }
return None; None
} }
} }
/// A mapping from a spent-txo to an actual txout ((txid, vout), (height, txout))
pub type StxoRef = ((Sha256dHash, u32), (u32, TxOut));
/// The UTXO set /// The UTXO set
pub struct UtxoSet { pub struct UtxoSet {
table: HashMap<Sha256dHash, UtxoNode>, 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<StxoRef>>,
// The last index into the above buffer that was assigned to // The last index into the above buffer that was assigned to
spent_idx: u64, spent_idx: u64,
n_utxos: u64, n_utxos: u64,
@ -137,7 +140,7 @@ impl UtxoSet {
// Locate node if it's already there // Locate node if it's already there
let new_node = { let new_node = {
let mut new_node = Vec::with_capacity(tx.output.len()); let mut new_node = Vec::with_capacity(tx.output.len());
for txo in tx.output.iter() { for txo in &tx.output {
if txo.script_pubkey.is_provably_unspendable() { if txo.script_pubkey.is_provably_unspendable() {
new_node.push(None); new_node.push(None);
self.n_utxos -= 1; self.n_utxos -= 1;
@ -188,7 +191,7 @@ 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(&self, txid: Sha256dHash, vout: u32) -> Option<(usize, &TxOut)> {
// Locate the UTXO, failing if not found // Locate the UTXO, failing if not found
let node = match self.table.get(&txid) { let node = match self.table.get(&txid) {
Some(node) => node, Some(node) => node,
@ -221,7 +224,7 @@ impl UtxoSet {
// same block. (Note that Bitcoin requires chained transactions to be in // same block. (Note that Bitcoin requires chained transactions to be in
// the correct order, which we do not check, so we are minorly too permissive. // the correct order, which we do not check, so we are minorly too permissive.
// TODO this is a consensus bug.) // TODO this is a consensus bug.)
for tx in block.txdata.iter() { for tx in &block.txdata {
let txid = tx.bitcoin_hash(); let txid = tx.bitcoin_hash();
// Add outputs -- add_utxos returns the original transaction if this is a dupe. // Add outputs -- add_utxos returns the original transaction if this is a dupe.
// Note that this can only happen with coinbases, and in this case the block // Note that this can only happen with coinbases, and in this case the block
@ -231,8 +234,8 @@ impl UtxoSet {
match self.add_utxos(tx, blockheight as u32) { match self.add_utxos(tx, blockheight as u32) {
Some(mut replace) => { Some(mut replace) => {
let blockhash = block.header.bitcoin_hash().be_hex_string(); let blockhash = block.header.bitcoin_hash().be_hex_string();
if blockhash == "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec".to_string() || if blockhash == "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec" ||
blockhash == "00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721".to_string() { blockhash == "00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721" {
// For these specific blocks, overwrite the old UTXOs. // For these specific blocks, overwrite the old UTXOs.
// (Actually add_utxos() already did this, so we do nothing.) // (Actually add_utxos() already did this, so we do nothing.)
} else { } else {
@ -330,7 +333,7 @@ impl UtxoSet {
// Delete added txouts // Delete added txouts
let mut skipped_genesis = false; let mut skipped_genesis = false;
for tx in block.txdata.iter() { for tx in &block.txdata {
let txhash = tx.bitcoin_hash(); let txhash = tx.bitcoin_hash();
for n in 0..tx.output.len() { for n in 0..tx.output.len() {
// Just bomb out the whole transaction // Just bomb out the whole transaction
@ -374,7 +377,7 @@ impl UtxoSet {
self.spent_idx = (self.spent_idx + self.spent_txos.len() as u64 - 1) % self.spent_idx = (self.spent_idx + self.spent_txos.len() as u64 - 1) %
self.spent_txos.len() as u64; self.spent_txos.len() as u64;
self.last_hash = block.header.prev_blockhash; self.last_hash = block.header.prev_blockhash;
return true; true
} }
/// Get the hash of the last block added to the utxo set /// Get the hash of the last block added to the utxo set

View File

@ -73,6 +73,10 @@ macro_rules! impl_array_newtype {
#[inline] #[inline]
/// Returns the length of the object as an array /// Returns the length of the object as an array
pub fn len(&self) -> usize { $len } pub fn len(&self) -> usize { $len }
#[inline]
/// Returns whether the object, as an array, is empty. Always false.
pub fn is_empty(&self) -> bool { false }
} }
impl<'a> From<&'a [$ty]> for $thing { impl<'a> From<&'a [$ty]> for $thing {

View File

@ -128,7 +128,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for String {
#[inline] #[inline]
fn consensus_decode(d: &mut D) -> Result<String, D::Error> { fn consensus_decode(d: &mut D) -> Result<String, D::Error> {
String::from_utf8(try!(ConsensusDecodable::consensus_decode(d))) String::from_utf8(try!(ConsensusDecodable::consensus_decode(d)))
.map_err(|_| d.error("String was not valid UTF8".to_string())) .map_err(|_| d.error("String was not valid UTF8".to_owned()))
} }
} }
@ -248,7 +248,7 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for CheckedData {
try!((self.0.len() as u32).consensus_encode(s)); try!((self.0.len() as u32).consensus_encode(s));
try!(sha2_checksum(&self.0).consensus_encode(s)); try!(sha2_checksum(&self.0).consensus_encode(s));
// We can't just pass to the slice encoder since it'll insert a length // We can't just pass to the slice encoder since it'll insert a length
for ch in self.0.iter() { for ch in &self.0 {
try!(ch.consensus_encode(s)); try!(ch.consensus_encode(s));
} }
Ok(()) Ok(())
@ -308,7 +308,7 @@ impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for Box<T
impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Box<T> { impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Box<T> {
#[inline] #[inline]
fn consensus_decode(d: &mut D) -> Result<Box<T>, D::Error> { fn consensus_decode(d: &mut D) -> Result<Box<T>, D::Error> {
ConsensusDecodable::consensus_decode(d).map(|res| Box::new(res)) ConsensusDecodable::consensus_decode(d).map(Box::new)
} }
} }

View File

@ -30,7 +30,7 @@ use util;
/// A message which can be sent on the Bitcoin network /// A message which can be sent on the Bitcoin network
pub trait Listener { pub trait Listener {
/// Return a string encoding of the peer's network address /// Return a string encoding of the peer's network address
fn peer<'a>(&'a self) -> &'a str; fn peer(&self) -> &str;
/// Return the port we have connected to the peer on /// Return the port we have connected to the peer on
fn port(&self) -> u16; fn port(&self) -> u16;
/// Return the network this `Listener` is operating on /// Return the network this `Listener` is operating on
@ -40,7 +40,7 @@ pub trait Listener {
// Open socket // Open socket
let mut ret_sock = Socket::new(self.network()); let mut ret_sock = Socket::new(self.network());
if let Err(e) = ret_sock.connect(self.peer(), self.port()) { if let Err(e) = ret_sock.connect(self.peer(), self.port()) {
return Err(util::Error::Detail("listener".to_string(), Box::new(e))); return Err(util::Error::Detail("listener".to_owned(), Box::new(e)));
} }
let mut sock = ret_sock.clone(); let mut sock = ret_sock.clone();
@ -59,18 +59,15 @@ pub trait Listener {
match sock.receive_message() { match sock.receive_message() {
Ok(payload) => { Ok(payload) => {
// React to any network messages that affect our state. // React to any network messages that affect our state.
match payload { if let Verack = payload {
// Make an exception for verack since there is no response required // Make an exception for verack since there is no response required
Verack => { // TODO: when the timeout stuff in std::io::net::tcp is sorted out we should
// TODO: when the timeout stuff in std::io::net::tcp is sorted out we should // actually time out if the verack doesn't come in in time
// actually time out if the verack doesn't come in in time if handshake_complete {
if handshake_complete { println!("Received second verack (peer is misbehaving)");
println!("Received second verack (peer is misbehaving)"); } else {
} else { handshake_complete = true;
handshake_complete = true;
}
} }
_ => {}
}; };
// We have to pass the message to the main thread for processing, // We have to pass the message to the main thread for processing,
// unfortunately, because sipa says we have to handle everything // unfortunately, because sipa says we have to handle everything

View File

@ -133,7 +133,7 @@ impl RawNetworkMessage {
NetworkMessage::Headers(_) => "headers", NetworkMessage::Headers(_) => "headers",
NetworkMessage::Ping(_) => "ping", NetworkMessage::Ping(_) => "ping",
NetworkMessage::Pong(_) => "pong", NetworkMessage::Pong(_) => "pong",
}.to_string() }.to_owned()
} }
} }
@ -170,19 +170,19 @@ impl<D: SimpleDecoder<Error=util::Error>> ConsensusDecodable<D> for RawNetworkMe
let mut mem_d = RawDecoder::new(Cursor::new(raw_payload)); let mut mem_d = RawDecoder::new(Cursor::new(raw_payload));
let payload = match &cmd[..] { let payload = match &cmd[..] {
"version" => NetworkMessage::Version(try!(propagate_err("version".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "version" => NetworkMessage::Version(try!(propagate_err("version".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"verack" => NetworkMessage::Verack, "verack" => NetworkMessage::Verack,
"addr" => NetworkMessage::Addr(try!(propagate_err("addr".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "addr" => NetworkMessage::Addr(try!(propagate_err("addr".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"inv" => NetworkMessage::Inv(try!(propagate_err("inv".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "inv" => NetworkMessage::Inv(try!(propagate_err("inv".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"getdata" => NetworkMessage::GetData(try!(propagate_err("getdata".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "getdata" => NetworkMessage::GetData(try!(propagate_err("getdata".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"notfound" => NetworkMessage::NotFound(try!(propagate_err("notfound".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "notfound" => NetworkMessage::NotFound(try!(propagate_err("notfound".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"getblocks" => NetworkMessage::GetBlocks(try!(propagate_err("getblocks".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "getblocks" => NetworkMessage::GetBlocks(try!(propagate_err("getblocks".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"getheaders" => NetworkMessage::GetHeaders(try!(propagate_err("getheaders".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "getheaders" => NetworkMessage::GetHeaders(try!(propagate_err("getheaders".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"block" => NetworkMessage::Block(try!(propagate_err("block".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "block" => NetworkMessage::Block(try!(propagate_err("block".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"headers" => NetworkMessage::Headers(try!(propagate_err("headers".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "headers" => NetworkMessage::Headers(try!(propagate_err("headers".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"ping" => NetworkMessage::Ping(try!(propagate_err("ping".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "ping" => NetworkMessage::Ping(try!(propagate_err("ping".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"pong" => NetworkMessage::Ping(try!(propagate_err("pong".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "pong" => NetworkMessage::Ping(try!(propagate_err("pong".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"tx" => NetworkMessage::Tx(try!(propagate_err("tx".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))), "tx" => NetworkMessage::Tx(try!(propagate_err("tx".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
cmd => return Err(d.error(format!("unrecognized network command `{}`", cmd))) cmd => return Err(d.error(format!("unrecognized network command `{}`", cmd)))
}; };
Ok(RawNetworkMessage { Ok(RawNetworkMessage {
@ -200,7 +200,7 @@ mod test {
#[test] #[test]
fn serialize_commandstring_test() { fn serialize_commandstring_test() {
let cs = CommandString("Andrew".to_string()); let cs = CommandString("Andrew".to_owned());
assert_eq!(serialize(&cs).ok(), Some(vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0])); assert_eq!(serialize(&cs).ok(), Some(vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]));
} }
@ -208,7 +208,7 @@ mod test {
fn deserialize_commandstring_test() { fn deserialize_commandstring_test() {
let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]); let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
assert!(cs.is_ok()); assert!(cs.is_ok());
assert_eq!(cs.unwrap(), CommandString("Andrew".to_string())); assert_eq!(cs.unwrap(), CommandString("Andrew".to_owned()));
let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]); let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
assert!(short_cs.is_err()); assert!(short_cs.is_err());

View File

@ -62,7 +62,7 @@ macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({
Err(_) => { Err(_) => {
let io_err = io::Error::new(io::ErrorKind::NotConnected, let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: socket mutex was poisoned"); "socket: socket mutex was poisoned");
return Err(util::Error::Io(io_err)); Err(util::Error::Io(io_err))
} }
Ok(mut guard) => { Ok(mut guard) => {
match *guard.deref_mut() { match *guard.deref_mut() {
@ -72,7 +72,7 @@ macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({
None => { None => {
let io_err = io::Error::new(io::ErrorKind::NotConnected, let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: not connected to peer"); "socket: not connected to peer");
return Err(util::Error::Io(io_err)); Err(util::Error::Io(io_err))
} }
} }
} }
@ -89,7 +89,7 @@ impl Socket {
socket: Arc::new(Mutex::new(None)), socket: Arc::new(Mutex::new(None)),
services: 0, services: 0,
version_nonce: rng.gen(), version_nonce: rng.gen(),
user_agent: constants::USER_AGENT.to_string(), user_agent: constants::USER_AGENT.to_owned(),
magic: constants::magic(network) magic: constants::magic(network)
} }
} }
@ -181,7 +181,7 @@ impl Socket {
match decode { match decode {
// Check for parse errors... // Check for parse errors...
Err(e) => { Err(e) => {
propagate_err("receive_message".to_string(), Err(e)) propagate_err("receive_message".to_owned(), Err(e))
}, },
Ok(ret) => { Ok(ret) => {
// Then for magic (this should come before parse error, but we can't // Then for magic (this should come before parse error, but we can't

View File

@ -144,7 +144,7 @@ pub fn base58_encode_slice(data: &[u8]) -> String {
// 7/5 is just over log_58(256) // 7/5 is just over log_58(256)
let mut scratch = vec![0u8; 1 + data.len() * 7 / 5]; let mut scratch = vec![0u8; 1 + data.len() * 7 / 5];
// Build in base 58 // Build in base 58
for &d256 in data.base58_layout().iter() { for &d256 in &data.base58_layout() {
// Compute "X = X * 256 + next_digit" in base 58 // Compute "X = X * 256 + next_digit" in base 58
let mut carry = d256 as u32; let mut carry = d256 as u32;
for d58 in scratch.iter_mut().rev() { for d58 in scratch.iter_mut().rev() {

View File

@ -57,7 +57,7 @@ impl<K, V> PatriciaTree<K, V>
} }
/// Lookup a value by exactly matching `key` and return a referenc /// Lookup a value by exactly matching `key` and return a referenc
pub fn lookup_mut<'a>(&'a mut self, key: &K, key_len: usize) -> Option<&'a mut V> { pub fn lookup_mut(&mut self, key: &K, key_len: usize) -> Option<&mut V> {
// Caution: `lookup_mut` never modifies its self parameter (in fact its // Caution: `lookup_mut` never modifies its self parameter (in fact its
// internal recursion uses a non-mutable self, so we are OK to just // internal recursion uses a non-mutable self, so we are OK to just
// transmute our self pointer into a mutable self before passing it in. // transmute our self pointer into a mutable self before passing it in.
@ -66,7 +66,7 @@ impl<K, V> PatriciaTree<K, V>
} }
/// Lookup a value by exactly matching `key` and return a mutable reference /// Lookup a value by exactly matching `key` and return a mutable reference
pub fn lookup<'a>(&'a self, key: &K, key_len: usize) -> Option<&'a V> { pub fn lookup(&self, key: &K, key_len: usize) -> Option<&V> {
let mut node = self; let mut node = self;
let mut key_idx = 0; let mut key_idx = 0;
@ -89,11 +89,11 @@ impl<K, V> PatriciaTree<K, V>
// Key matches prefix: search key longer than node key, recurse // Key matches prefix: search key longer than node key, recurse
key_idx += 1 + node.skip_len as usize; key_idx += 1 + node.skip_len as usize;
let subtree = if key.bit(key_idx - 1) { &node.child_r } else { &node.child_l }; let subtree = if key.bit(key_idx - 1) { &node.child_r } else { &node.child_l };
match subtree { match *subtree {
&Some(ref bx) => { Some(ref bx) => {
node = &**bx; // bx is a &Box<U> here, so &**bx gets &U node = &**bx; // bx is a &Box<U> here, so &**bx gets &U
} }
&None => { return None; } None => { return None; }
} }
} }
} // end loop } // end loop
@ -305,7 +305,7 @@ impl<K, V> PatriciaTree<K, V>
(_, Some(child_l), Some(child_r)) => { (_, Some(child_l), Some(child_r)) => {
tree.child_l = Some(child_l); tree.child_l = Some(child_l);
tree.child_r = Some(child_r); tree.child_r = Some(child_r);
return (false, ret); (false, ret)
} }
// One child? Consolidate // One child? Consolidate
(bit, Some(child), None) | (bit, None, Some(child)) => { (bit, Some(child), None) | (bit, None, Some(child)) => {
@ -321,11 +321,11 @@ impl<K, V> PatriciaTree<K, V>
new_bit + new_bit +
(skip_prefix << (1 + tree.skip_len as usize)); (skip_prefix << (1 + tree.skip_len as usize));
tree.skip_len += 1 + skip_len; tree.skip_len += 1 + skip_len;
return (false, ret); (false, ret)
} }
// No children? Delete // No children? Delete
(_, None, None) => { (_, None, None) => {
return (true, ret); (true, ret)
} }
} }
} }
@ -336,9 +336,9 @@ impl<K, V> PatriciaTree<K, V>
/// Count all the nodes /// Count all the nodes
pub fn node_count(&self) -> usize { pub fn node_count(&self) -> usize {
fn recurse<K: Copy, V>(node: &Option<Box<PatriciaTree<K, V>>>) -> usize { fn recurse<K: Copy, V>(node: &Option<Box<PatriciaTree<K, V>>>) -> usize {
match node { match *node {
&Some(ref node) => { 1 + recurse(&node.child_l) + recurse(&node.child_r) } Some(ref node) => { 1 + recurse(&node.child_l) + recurse(&node.child_r) }
&None => 0 None => 0
} }
} }
1 + recurse(&self.child_l) + recurse(&self.child_r) 1 + recurse(&self.child_l) + recurse(&self.child_r)
@ -366,8 +366,8 @@ impl<K, V> PatriciaTree<K, V>
impl<K: Copy + BitArray, V: Debug> Debug for PatriciaTree<K, V> { impl<K: Copy + BitArray, V: Debug> Debug for PatriciaTree<K, V> {
/// Print the entire tree /// Print the entire tree
fn fmt<'a>(&'a self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn recurse<'a, K, V>(tree: &'a PatriciaTree<K, V>, f: &mut fmt::Formatter, depth: usize) -> Result<(), fmt::Error> fn recurse<K, V>(tree: &PatriciaTree<K, V>, f: &mut fmt::Formatter, depth: usize) -> Result<(), fmt::Error>
where K: Copy + BitArray, V: Debug where K: Copy + BitArray, V: Debug
{ {
for i in 0..tree.skip_len as usize { for i in 0..tree.skip_len as usize {
@ -453,7 +453,7 @@ impl<'a, K: Copy, V> Iterator for Items<'a, K, V> {
type Item = &'a V; type Item = &'a V;
fn next(&mut self) -> Option<&'a V> { fn next(&mut self) -> Option<&'a V> {
fn borrow_opt<'a, K: Copy, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> Option<&'a PatriciaTree<K, V>> { fn borrow_opt<K: Copy, V>(opt_ptr: &Option<Box<PatriciaTree<K, V>>>) -> Option<&PatriciaTree<K, V>> {
opt_ptr.as_ref().map(|b| &**b) opt_ptr.as_ref().map(|b| &**b)
} }
@ -499,7 +499,7 @@ impl<'a, K: Copy, V> Iterator for MutItems<'a, K, V> {
type Item = &'a mut V; type Item = &'a mut V;
fn next(&mut self) -> Option<&'a mut V> { fn next(&mut self) -> Option<&'a mut V> {
fn borrow_opt<'a, K: Copy, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> *mut PatriciaTree<K, V> { fn borrow_opt<K: Copy, V>(opt_ptr: &Option<Box<PatriciaTree<K, V>>>) -> *mut PatriciaTree<K, V> {
match *opt_ptr { match *opt_ptr {
Some(ref data) => &**data as *const _ as *mut _, Some(ref data) => &**data as *const _ as *mut _,
None => ptr::null_mut() None => ptr::null_mut()

View File

@ -127,7 +127,7 @@ macro_rules! construct_uint {
let mut me = self; let mut me = self;
// TODO: be more efficient about this // TODO: be more efficient about this
for i in 0..(2 * $n_words) { for i in 0..(2 * $n_words) {
me = me + me.mul_u32((other >> (32 * i)).low_u32()) << (32 * i); me = (me + me.mul_u32((other >> (32 * i)).low_u32())) << (32 * i);
} }
me me
} }
@ -315,7 +315,7 @@ macro_rules! construct_uint {
if me[$n_words - 1 - i] < you[$n_words - 1 - i] { return ::std::cmp::Ordering::Less; } if me[$n_words - 1 - i] < you[$n_words - 1 - i] { return ::std::cmp::Ordering::Less; }
if me[$n_words - 1 - i] > you[$n_words - 1 - i] { return ::std::cmp::Ordering::Greater; } if me[$n_words - 1 - i] > you[$n_words - 1 - i] { return ::std::cmp::Ordering::Greater; }
} }
return ::std::cmp::Ordering::Equal; ::std::cmp::Ordering::Equal
} }
} }