<commit_before>// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Bitcoin Transaction
//!
//! A transaction describes a transfer of money. It consumes previously-unspent
//! transaction outputs and produces new ones, satisfying the condition to spend
//! the old outputs (typically a digital signature with a specific key must be
//! provided) and defining the condition to spend the new ones. The use of digital
//! signatures ensures that coins cannot be spent by unauthorized parties.
//!
//! This module provides the structures and functions needed to support transactions.
//!

use std::default::Default;
use std::fmt;
use serde;
use secp256k1::Secp256k1;

use util::hash::Sha256dHash;
use blockdata::script::{self, Script, ScriptTrace, read_scriptbool};
use blockdata::utxoset::UtxoSet;
use network::encodable::ConsensusEncodable;
use network::serialize::BitcoinHash;

/// A reference to a transaction output
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct TxOutRef {
    /// The referenced transaction's txid
    pub txid: Sha256dHash,
    /// The index of the referenced output in its transaction's vout
    pub index: usize
}

impl fmt::Display for TxOutRef {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.txid, self.index)
    }
}

/// A transaction input, which defines old coins to be consumed
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TxIn {
    /// The hash of the transaction whose output is being used an an input
    pub prev_hash: Sha256dHash,
    /// The index of the output in the previous transaction, which may have several
    pub prev_index: u32,
    /// The script which pushes values on the stack which will cause
    /// the referenced output's script to accept
    pub script_sig: Script,
    /// The sequence number, which suggests to miners which of two
    /// conflicting transactions should be preferred, or 0xFFFFFFFF
    /// to ignore this feature. This is generally never used since
    /// the miner behaviour cannot be enforced.
    pub sequence: u32,
}

/// A transaction output, which defines new coins to be created from old ones.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TxOut {
    /// The value of the output, in satoshis
    pub value: u64,
    /// The script which must satisfy for the output to be spent
    pub script_pubkey: Script
}

// This is used as a "null txout" in consensus signing code
impl Default for TxOut {
    fn default() -> TxOut {
        TxOut { value: 0xffffffffffffffff, script_pubkey: Script::new() }
    }
}

/// A Bitcoin transaction, which describes an authenticated movement of coins
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Transaction {
    /// The protocol version, should always be 1.
    pub version: u32,
    /// Block number before which this transaction is valid, or 0 for
    /// valid immediately.
    pub lock_time: u32,
    /// List of inputs
    pub input: Vec<TxIn>,
    /// List of outputs
    pub output: Vec<TxOut>
}

/// A transaction error
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Error {
    /// Concatenated script failed in the input half (script error)
    InputScriptFailure(script::Error),
    /// Concatenated script failed in the output half (script error)
    OutputScriptFailure(script::Error),
    /// P2SH serialized script failed (script error)
    P2shScriptFailure(script::Error),
    /// P2SH serialized script ended with false at the top of the stack
    P2shScriptReturnedFalse,
    /// P2SH serialized script ended with nothing in the stack
    P2shScriptReturnedEmptyStack,
    /// Script ended with false at the top of the stack
    ScriptReturnedFalse,
    /// Script ended with nothing in the stack
    ScriptReturnedEmptyStack,
    /// 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>
        where S: serde::Serializer,
    {
        serializer.visit_str(&self.to_string())
    }
}

/// A trace of a transaction input's script execution
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct InputTrace {
    input_txid: Sha256dHash,
    input_vout: usize,
    sig_trace: ScriptTrace,
    pubkey_trace: Option<ScriptTrace>,
    p2sh_trace: Option<ScriptTrace>,
    error: Option<Error>
}

/// A trace of a transaction's execution
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct TransactionTrace {
    txid: Sha256dHash,
    inputs: Vec<InputTrace>
}

impl TxIn {
    /// Check an input's script for validity
    pub fn validate(&self,
                    secp: &Secp256k1,
                    utxoset: &UtxoSet,
                    txn: &Transaction,
                    index: usize) -> Result<(), Error> {
        let txo = utxoset.get_utxo(self.prev_hash, self.prev_index);
        match txo {
            Some((_, txo)) => {
                let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new());

                let mut stack = vec![];
                match self.script_sig.evaluate(secp, &mut stack, Some((txn, index)), None) {
                    Ok(_) => {}
                    Err(e) => { return Err(Error::InputScriptFailure(e)); }
                }
                if txo.script_pubkey.is_p2sh() && !stack.is_empty() {
                    p2sh_stack = stack.clone();
                    p2sh_script = match p2sh_stack.pop() {
                        Some(script::MaybeOwned::Owned(v)) => Script::from(v),
                        Some(script::MaybeOwned::Borrowed(s)) => Script::from(s.to_vec()),
                        None => unreachable!()
                    };
                }
                match txo.script_pubkey.evaluate(secp, &mut stack, Some((txn, index)), None) {
                    Ok(_) => {}
                    Err(e) => { return Err(Error::OutputScriptFailure(e)); }
                }
                match stack.pop() {
                    Some(v) => {
                        if !read_scriptbool(&v[..]) {
                            return Err(Error::ScriptReturnedFalse);
                        }
                     }
                    None => { return Err(Error::ScriptReturnedEmptyStack); }
                }
                if txo.script_pubkey.is_p2sh() {
                    match p2sh_script.evaluate(secp, &mut p2sh_stack, Some((txn, index)), None) {
                        Ok(_) => {}
                        Err(e) => { return Err(Error::P2shScriptFailure(e)); }
                    }
                    match p2sh_stack.pop() {
                        Some(v) => {
                            if !read_scriptbool(&v[..]) {
                                return Err(Error::P2shScriptReturnedFalse);
                            }
                        }
                        None => { return Err(Error::P2shScriptReturnedEmptyStack); }
                    }
                }
            }
            None => { return Err(Error::InputNotFound(self.prev_hash, self.prev_index)); }
        }
        Ok(())
    }
}

impl Transaction {
    /// Check a transaction for validity
    pub fn validate(&self, secp: &Secp256k1, utxoset: &UtxoSet) -> Result<(), Error> {
        for (n, input) in self.input.iter().enumerate() {
            try!(input.validate(secp, utxoset, self, n));
        }
        Ok(())
    }

    /// Produce a trace of a transaction's execution
    pub fn trace(&self, secp: &Secp256k1, utxoset: &UtxoSet) -> TransactionTrace {
        let mut ret = TransactionTrace { txid: self.bitcoin_hash(),
                                         inputs: Vec::with_capacity(self.input.len()) };
        for (n, input) in self.input.iter().enumerate() {
            // Setup trace
            let mut trace = InputTrace {
                input_txid: input.prev_hash,
                input_vout: input.prev_index as usize,
                sig_trace: ScriptTrace {
                    script: Script::new(),
                    initial_stack: vec![],
                    iterations: vec![],
                    error: None
                },
                pubkey_trace: None,
                p2sh_trace: None,
                error: None
            };
            // Run through the input
            let txo = utxoset.get_utxo(input.prev_hash, input.prev_index);
            match txo {
                Some((_, txo)) => {
                    let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new());

                    let mut stack = Vec::with_capacity(6);
                    trace.sig_trace = input.script_sig.trace(secp, &mut stack, Some((self, n)));
                    let err = trace.sig_trace.error.as_ref().map(|e| e.clone());
                    err.map(|e| trace.error = Some(Error::InputScriptFailure(e)));

                    if txo.script_pubkey.is_p2sh() && !stack.is_empty() {
                        p2sh_stack = stack.clone();
                        p2sh_script = match p2sh_stack.pop() {
                            Some(script::MaybeOwned::Owned(v)) => Script::from(v),
                            Some(script::MaybeOwned::Borrowed(s)) => Script::from(s.to_vec()),
                            None => unreachable!()
                        };
                    }
                    if trace.error.is_none() {
                        trace.pubkey_trace = Some(txo.script_pubkey.trace(secp, &mut stack, Some((self, n))));
                        let err = trace.pubkey_trace.as_ref().unwrap().error.as_ref().map(|e| e.clone());
                        err.map(|e| trace.error = Some(Error::OutputScriptFailure(e)));
                        match stack.pop() {
                            Some(v) => {
                                if !read_scriptbool(&v[..]) {
                                    trace.error = Some(Error::ScriptReturnedFalse);
                                }
                            }
                            None => { trace.error = Some(Error::ScriptReturnedEmptyStack); }
                        }
                        if trace.error.is_none() && txo.script_pubkey.is_p2sh() {
                            trace.p2sh_trace = Some(p2sh_script.trace(secp, &mut p2sh_stack, Some((self, n))));
                            let err = trace.p2sh_trace.as_ref().unwrap().error.as_ref().map(|e| e.clone());
                            err.map(|e| trace.error = Some(Error::P2shScriptFailure(e)));
                            match p2sh_stack.pop() {
                                Some(v) => {
                                    if !read_scriptbool(&v[..]) {
                                        trace.error = Some(Error::P2shScriptReturnedFalse);
                                    }
                                }
                                None => { trace.error = Some(Error::P2shScriptReturnedEmptyStack); }
                            }
                        }
                    }
                }
                None => {
                    trace.error = Some(Error::InputNotFound(input.prev_hash, input.prev_index));
                }
            }
            ret.inputs.push(trace);
        }
        ret
    }
}

impl BitcoinHash for Transaction {
    fn bitcoin_hash(&self) -> Sha256dHash {
        use network::serialize::serialize;
        Sha256dHash::from_data(&serialize(self).unwrap())
    }
}

impl_consensus_encoding!(TxIn, prev_hash, prev_index, script_sig, sequence);
impl_consensus_encoding!(TxOut, value, script_pubkey);
impl_consensus_encoding!(Transaction, version, input, output, lock_time);

#[cfg(test)]
mod tests {
    use super::{Transaction, TxIn};

    use network::serialize::BitcoinHash;
    use network::serialize::deserialize;
    use util::misc::hex_bytes;

    #[test]
    fn test_txin() {
        let txin: Result<TxIn, _> = deserialize(&hex_bytes("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap());
        assert!(txin.is_ok());
    }

    #[test]
    fn test_transaction() {
        let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
        let tx: Result<Transaction, _> = deserialize(&hex_tx);
        assert!(tx.is_ok());
        let realtx = tx.unwrap();
        // All these tests aren't really needed because if they fail, the hash check at the end
        // will also fail. But these will show you where the failure is so I'll leave them in.
        assert_eq!(realtx.version, 1);
        assert_eq!(realtx.input.len(), 1);
        // In particular this one is easy to get backward -- in bitcoin hashes are encoded
        // as little-endian 256-bit numbers rather than as data strings.
        assert_eq!(realtx.input[0].prev_hash.be_hex_string(),
                   "ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string());
        assert_eq!(realtx.input[0].prev_index, 1);
        assert_eq!(realtx.output.len(), 1);
        assert_eq!(realtx.lock_time, 0);

        assert_eq!(realtx.bitcoin_hash().be_hex_string(),
                   "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string());
    }
}

<commit_msg>Add Hash derived impls for all the transaction types<commit_after>// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Bitcoin Transaction
//!
//! A transaction describes a transfer of money. It consumes previously-unspent
//! transaction outputs and produces new ones, satisfying the condition to spend
//! the old outputs (typically a digital signature with a specific key must be
//! provided) and defining the condition to spend the new ones. The use of digital
//! signatures ensures that coins cannot be spent by unauthorized parties.
//!
//! This module provides the structures and functions needed to support transactions.
//!

use std::default::Default;
use std::fmt;
use serde;
use secp256k1::Secp256k1;

use util::hash::Sha256dHash;
use blockdata::script::{self, Script, ScriptTrace, read_scriptbool};
use blockdata::utxoset::UtxoSet;
use network::encodable::ConsensusEncodable;
use network::serialize::BitcoinHash;

/// A reference to a transaction output
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct TxOutRef {
    /// The referenced transaction's txid
    pub txid: Sha256dHash,
    /// The index of the referenced output in its transaction's vout
    pub index: usize
}

impl fmt::Display for TxOutRef {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.txid, self.index)
    }
}

/// A transaction input, which defines old coins to be consumed
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TxIn {
    /// The hash of the transaction whose output is being used an an input
    pub prev_hash: Sha256dHash,
    /// The index of the output in the previous transaction, which may have several
    pub prev_index: u32,
    /// The script which pushes values on the stack which will cause
    /// the referenced output's script to accept
    pub script_sig: Script,
    /// The sequence number, which suggests to miners which of two
    /// conflicting transactions should be preferred, or 0xFFFFFFFF
    /// to ignore this feature. This is generally never used since
    /// the miner behaviour cannot be enforced.
    pub sequence: u32,
}

/// A transaction output, which defines new coins to be created from old ones.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TxOut {
    /// The value of the output, in satoshis
    pub value: u64,
    /// The script which must satisfy for the output to be spent
    pub script_pubkey: Script
}

// This is used as a "null txout" in consensus signing code
impl Default for TxOut {
    fn default() -> TxOut {
        TxOut { value: 0xffffffffffffffff, script_pubkey: Script::new() }
    }
}

/// A Bitcoin transaction, which describes an authenticated movement of coins
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Transaction {
    /// The protocol version, should always be 1.
    pub version: u32,
    /// Block number before which this transaction is valid, or 0 for
    /// valid immediately.
    pub lock_time: u32,
    /// List of inputs
    pub input: Vec<TxIn>,
    /// List of outputs
    pub output: Vec<TxOut>
}

/// A transaction error
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Error {
    /// Concatenated script failed in the input half (script error)
    InputScriptFailure(script::Error),
    /// Concatenated script failed in the output half (script error)
    OutputScriptFailure(script::Error),
    /// P2SH serialized script failed (script error)
    P2shScriptFailure(script::Error),
    /// P2SH serialized script ended with false at the top of the stack
    P2shScriptReturnedFalse,
    /// P2SH serialized script ended with nothing in the stack
    P2shScriptReturnedEmptyStack,
    /// Script ended with false at the top of the stack
    ScriptReturnedFalse,
    /// Script ended with nothing in the stack
    ScriptReturnedEmptyStack,
    /// 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>
        where S: serde::Serializer,
    {
        serializer.visit_str(&self.to_string())
    }
}

/// A trace of a transaction input's script execution
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct InputTrace {
    input_txid: Sha256dHash,
    input_vout: usize,
    sig_trace: ScriptTrace,
    pubkey_trace: Option<ScriptTrace>,
    p2sh_trace: Option<ScriptTrace>,
    error: Option<Error>
}

/// A trace of a transaction's execution
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct TransactionTrace {
    txid: Sha256dHash,
    inputs: Vec<InputTrace>
}

impl TxIn {
    /// Check an input's script for validity
    pub fn validate(&self,
                    secp: &Secp256k1,
                    utxoset: &UtxoSet,
                    txn: &Transaction,
                    index: usize) -> Result<(), Error> {
        let txo = utxoset.get_utxo(self.prev_hash, self.prev_index);
        match txo {
            Some((_, txo)) => {
                let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new());

                let mut stack = vec![];
                match self.script_sig.evaluate(secp, &mut stack, Some((txn, index)), None) {
                    Ok(_) => {}
                    Err(e) => { return Err(Error::InputScriptFailure(e)); }
                }
                if txo.script_pubkey.is_p2sh() && !stack.is_empty() {
                    p2sh_stack = stack.clone();
                    p2sh_script = match p2sh_stack.pop() {
                        Some(script::MaybeOwned::Owned(v)) => Script::from(v),
                        Some(script::MaybeOwned::Borrowed(s)) => Script::from(s.to_vec()),
                        None => unreachable!()
                    };
                }
                match txo.script_pubkey.evaluate(secp, &mut stack, Some((txn, index)), None) {
                    Ok(_) => {}
                    Err(e) => { return Err(Error::OutputScriptFailure(e)); }
                }
                match stack.pop() {
                    Some(v) => {
                        if !read_scriptbool(&v[..]) {
                            return Err(Error::ScriptReturnedFalse);
                        }
                     }
                    None => { return Err(Error::ScriptReturnedEmptyStack); }
                }
                if txo.script_pubkey.is_p2sh() {
                    match p2sh_script.evaluate(secp, &mut p2sh_stack, Some((txn, index)), None) {
                        Ok(_) => {}
                        Err(e) => { return Err(Error::P2shScriptFailure(e)); }
                    }
                    match p2sh_stack.pop() {
                        Some(v) => {
                            if !read_scriptbool(&v[..]) {
                                return Err(Error::P2shScriptReturnedFalse);
                            }
                        }
                        None => { return Err(Error::P2shScriptReturnedEmptyStack); }
                    }
                }
            }
            None => { return Err(Error::InputNotFound(self.prev_hash, self.prev_index)); }
        }
        Ok(())
    }
}

impl Transaction {
    /// Check a transaction for validity
    pub fn validate(&self, secp: &Secp256k1, utxoset: &UtxoSet) -> Result<(), Error> {
        for (n, input) in self.input.iter().enumerate() {
            try!(input.validate(secp, utxoset, self, n));
        }
        Ok(())
    }

    /// Produce a trace of a transaction's execution
    pub fn trace(&self, secp: &Secp256k1, utxoset: &UtxoSet) -> TransactionTrace {
        let mut ret = TransactionTrace { txid: self.bitcoin_hash(),
                                         inputs: Vec::with_capacity(self.input.len()) };
        for (n, input) in self.input.iter().enumerate() {
            // Setup trace
            let mut trace = InputTrace {
                input_txid: input.prev_hash,
                input_vout: input.prev_index as usize,
                sig_trace: ScriptTrace {
                    script: Script::new(),
                    initial_stack: vec![],
                    iterations: vec![],
                    error: None
                },
                pubkey_trace: None,
                p2sh_trace: None,
                error: None
            };
            // Run through the input
            let txo = utxoset.get_utxo(input.prev_hash, input.prev_index);
            match txo {
                Some((_, txo)) => {
                    let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new());

                    let mut stack = Vec::with_capacity(6);
                    trace.sig_trace = input.script_sig.trace(secp, &mut stack, Some((self, n)));
                    let err = trace.sig_trace.error.as_ref().map(|e| e.clone());
                    err.map(|e| trace.error = Some(Error::InputScriptFailure(e)));

                    if txo.script_pubkey.is_p2sh() && !stack.is_empty() {
                        p2sh_stack = stack.clone();
                        p2sh_script = match p2sh_stack.pop() {
                            Some(script::MaybeOwned::Owned(v)) => Script::from(v),
                            Some(script::MaybeOwned::Borrowed(s)) => Script::from(s.to_vec()),
                            None => unreachable!()
                        };
                    }
                    if trace.error.is_none() {
                        trace.pubkey_trace = Some(txo.script_pubkey.trace(secp, &mut stack, Some((self, n))));
                        let err = trace.pubkey_trace.as_ref().unwrap().error.as_ref().map(|e| e.clone());
                        err.map(|e| trace.error = Some(Error::OutputScriptFailure(e)));
                        match stack.pop() {
                            Some(v) => {
                                if !read_scriptbool(&v[..]) {
                                    trace.error = Some(Error::ScriptReturnedFalse);
                                }
                            }
                            None => { trace.error = Some(Error::ScriptReturnedEmptyStack); }
                        }
                        if trace.error.is_none() && txo.script_pubkey.is_p2sh() {
                            trace.p2sh_trace = Some(p2sh_script.trace(secp, &mut p2sh_stack, Some((self, n))));
                            let err = trace.p2sh_trace.as_ref().unwrap().error.as_ref().map(|e| e.clone());
                            err.map(|e| trace.error = Some(Error::P2shScriptFailure(e)));
                            match p2sh_stack.pop() {
                                Some(v) => {
                                    if !read_scriptbool(&v[..]) {
                                        trace.error = Some(Error::P2shScriptReturnedFalse);
                                    }
                                }
                                None => { trace.error = Some(Error::P2shScriptReturnedEmptyStack); }
                            }
                        }
                    }
                }
                None => {
                    trace.error = Some(Error::InputNotFound(input.prev_hash, input.prev_index));
                }
            }
            ret.inputs.push(trace);
        }
        ret
    }
}

impl BitcoinHash for Transaction {
    fn bitcoin_hash(&self) -> Sha256dHash {
        use network::serialize::serialize;
        Sha256dHash::from_data(&serialize(self).unwrap())
    }
}

impl_consensus_encoding!(TxIn, prev_hash, prev_index, script_sig, sequence);
impl_consensus_encoding!(TxOut, value, script_pubkey);
impl_consensus_encoding!(Transaction, version, input, output, lock_time);

#[cfg(test)]
mod tests {
    use super::{Transaction, TxIn};

    use network::serialize::BitcoinHash;
    use network::serialize::deserialize;
    use util::misc::hex_bytes;

    #[test]
    fn test_txin() {
        let txin: Result<TxIn, _> = deserialize(&hex_bytes("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap());
        assert!(txin.is_ok());
    }

    #[test]
    fn test_transaction() {
        let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
        let tx: Result<Transaction, _> = deserialize(&hex_tx);
        assert!(tx.is_ok());
        let realtx = tx.unwrap();
        // All these tests aren't really needed because if they fail, the hash check at the end
        // will also fail. But these will show you where the failure is so I'll leave them in.
        assert_eq!(realtx.version, 1);
        assert_eq!(realtx.input.len(), 1);
        // In particular this one is easy to get backward -- in bitcoin hashes are encoded
        // as little-endian 256-bit numbers rather than as data strings.
        assert_eq!(realtx.input[0].prev_hash.be_hex_string(),
                   "ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string());
        assert_eq!(realtx.input[0].prev_index, 1);
        assert_eq!(realtx.output.len(), 1);
        assert_eq!(realtx.lock_time, 0);

        assert_eq!(realtx.bitcoin_hash().be_hex_string(),
                   "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string());
    }
}

<|endoftext|>


<commit_before>#[feature(globs)];
#[feature(struct_variant)];
#[feature(macro_rules)];
extern mod std;
extern mod extra;
use extra::getopts;
use basics::*;
use policies::TimingPolicy;

mod basics;
mod policies;
mod raft;
mod sim;

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("samples"),
        getopts::optopt("servers"),
        getopts::optopt("tasks"),
        getopts::optopt("timing"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println!("-h, --help       Print this help message");
        println!("--samples=N      Number of simulations (default 10,000)");
        println!("--servers=N      Simulate cluster with N servers");
        println!("--tasks=N        Number of parallel jobs (default {})",
                 std::rt::default_sched_threads() - 1);
        println!("--timing=POLICY  Number of timing policy (default LAN)");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let num_samples : uint = match matches.opt_str("samples") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of samples from '{}'", s));
            },
        }},
        None => { 10000 },
    };
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let num_tasks : uint = match matches.opt_str("tasks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of tasks from '{}'", s));
            },
        }},
        None => { std::rt::default_sched_threads() - 1 },
    };
    let timing : ~str = match matches.opt_str("timing") {
        Some(s) => { s },
        None => { ~"LAN" },
    };

    println!("Servers: {}", num_servers)
    println!("Tasks:   {}", num_tasks)
    println!("Trials:  {}", num_samples)
    println!("Timing:  {}", timing)

    let start_ns = extra::time::precise_time_ns();

    let samples = if num_tasks <= 1 {
        run_task(num_samples, num_servers, timing)
    } else {
        let (port, chan): (Port<~[Time]>, Chan<~[Time]>) = stream();
        let chan = std::comm::SharedChan::new(chan);
        for tid in range(0, num_tasks) {
            let child_chan = chan.clone();
            let child_timing = timing.clone();
            do spawn || {
                let n = if tid == 0 {
                    // get the odd one left over
                    num_samples - (num_samples / num_tasks) * (num_tasks - 1)
                } else {
                    num_samples / num_tasks
                };
                child_chan.send(run_task(n, num_servers, child_timing));
            }
        }

        let mut samples = ~[];
        samples.reserve(num_samples);
        do num_tasks.times {
            samples.push_all(port.recv());
        }
        extra::sort::tim_sort(samples);
        samples
    };

    let end_ns = extra::time::precise_time_ns();
    let elapsed_ns = end_ns - start_ns;

    println!("Min:     {} ticks", samples[0]);
    println!("Median:  {} ticks", samples[samples.len()/2]);
    println!("Max:     {} ticks", samples[samples.len()-1]);
    println!("Wall:    {:.2f} s",     elapsed_ns as f64 / 1e9);
}

fn run_task(n: uint, num_servers: uint, timing: &str) -> ~[Time] {
    let mut samples = ~[];
    samples.reserve(n);
    do n.times {
        // TODO: may be better to reuse these timing policies.
        let p = policies::make(timing);
        let sample = sim::simulate(num_servers, p);
        samples.push(sample);
    }
    extra::sort::tim_sort(samples);
    return samples;
}
<commit_msg>output csv<commit_after>#[feature(globs)];
#[feature(struct_variant)];
#[feature(macro_rules)];
extern mod std;
extern mod extra;
use extra::getopts;
use basics::*;
use policies::TimingPolicy;
use std::rt::io::File;

mod basics;
mod policies;
mod raft;
mod sim;

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("samples"),
        getopts::optopt("servers"),
        getopts::optopt("tasks"),
        getopts::optopt("timing"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println!("-h, --help       Print this help message");
        println!("--samples=N      Number of simulations (default 10,000)");
        println!("--servers=N      Simulate cluster with N servers");
        println!("--tasks=N        Number of parallel jobs (default {})",
                 std::rt::default_sched_threads() - 1);
        println!("--timing=POLICY  Number of timing policy (default LAN)");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let num_samples : uint = match matches.opt_str("samples") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of samples from '{}'", s));
            },
        }},
        None => { 10000 },
    };
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let num_tasks : uint = match matches.opt_str("tasks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of tasks from '{}'", s));
            },
        }},
        None => { std::rt::default_sched_threads() - 1 },
    };
    let timing : ~str = match matches.opt_str("timing") {
        Some(s) => { s },
        None => { ~"LAN" },
    };

    let mut meta : ~[(~str, ~str)] = ~[];
    meta.push((~"servers", format!("{}", num_servers)));
    meta.push((~"tasks",   format!("{}", num_tasks)));
    meta.push((~"trials",  format!("{}", num_samples)));
    meta.push((~"timing",  timing.clone()));

    println!("Servers: {}", num_servers)
    println!("Tasks:   {}", num_tasks)
    println!("Trials:  {}", num_samples)
    println!("Timing:  {}", timing)

    let start_ns = extra::time::precise_time_ns();

    let samples = if num_tasks <= 1 {
        run_task(num_samples, num_servers, timing)
    } else {
        let (port, chan): (Port<~[Time]>, Chan<~[Time]>) = stream();
        let chan = std::comm::SharedChan::new(chan);
        for tid in range(0, num_tasks) {
            let child_chan = chan.clone();
            let child_timing = timing.clone();
            do spawn || {
                let n = if tid == 0 {
                    // get the odd one left over
                    num_samples - (num_samples / num_tasks) * (num_tasks - 1)
                } else {
                    num_samples / num_tasks
                };
                child_chan.send(run_task(n, num_servers, child_timing));
            }
        }

        let mut samples = ~[];
        samples.reserve(num_samples);
        do num_tasks.times {
            samples.push_all(port.recv());
        }
        extra::sort::tim_sort(samples);
        samples
    };

    let end_ns = extra::time::precise_time_ns();
    let elapsed_ns = end_ns - start_ns;
    meta.push((~"wall",  format!("{}", elapsed_ns as f64 / 1e9)));

    println!("Min:     {} ticks", samples[0]);
    println!("Median:  {} ticks", samples[samples.len()/2]);
    println!("Max:     {} ticks", samples[samples.len()-1]);
    println!("Wall:    {:.2f} s",     elapsed_ns as f64 / 1e9);

    let metaf = &mut File::create(&Path::new("meta.csv")).unwrap() as &mut Writer;
    for &(ref k, ref _v) in meta.iter() {
        write!(metaf, "{}, ", *k);
    }
    write!(metaf, "\n");
    for &(ref _k, ref v) in meta.iter() {
        write!(metaf, "{}, ", *v);
    }
    write!(metaf, "\n");

    let runf = &mut File::create(&Path::new("samples.csv")).unwrap() as &mut Writer;
    writeln!(runf, "election_time");
    for sample in samples.iter() {
        writeln!(runf, "{}", *sample);
    }
}

fn run_task(n: uint, num_servers: uint, timing: &str) -> ~[Time] {
    let mut samples = ~[];
    samples.reserve(n);
    do n.times {
        // TODO: may be better to reuse these timing policies.
        let p = policies::make(timing);
        let sample = sim::simulate(num_servers, p);
        samples.push(sample);
    }
    extra::sort::tim_sort(samples);
    return samples;
}
<|endoftext|>


<commit_before>use beacon_chain::{
    fork_choice::BitwiseLMDGhost,
    slot_clock::SystemTimeSlotClock,
    store::{DiskStore, MemoryStore, Store},
    BeaconChain, BeaconChainTypes,
};
use fork_choice::ForkChoice;
use slog::{info, Logger};
use slot_clock::SlotClock;
use std::sync::Arc;
use tree_hash::TreeHash;
use types::{
    test_utils::TestingBeaconStateBuilder, BeaconBlock, EthSpec, Hash256, LighthouseTestnetEthSpec,
};

/// The number initial validators when starting the `LighthouseTestnet`.
const TESTNET_VALIDATOR_COUNT: usize = 16;

/// Provides a new, initialized `BeaconChain`
pub trait InitialiseBeaconChain<T: BeaconChainTypes> {
    fn initialise_beacon_chain(store: Arc<T::Store>, log: Logger) -> BeaconChain<T>;
}

/// A testnet-suitable BeaconChainType, using `MemoryStore`.
#[derive(Clone)]
pub struct TestnetMemoryBeaconChainTypes;

impl BeaconChainTypes for TestnetMemoryBeaconChainTypes {
    type Store = MemoryStore;
    type SlotClock = SystemTimeSlotClock;
    type ForkChoice = BitwiseLMDGhost<Self::Store, Self::EthSpec>;
    type EthSpec = LighthouseTestnetEthSpec;
}

impl<T: BeaconChainTypes> InitialiseBeaconChain<T> for TestnetMemoryBeaconChainTypes {
    fn initialise_beacon_chain(store: Arc<T::Store>, log: Logger) -> BeaconChain<T> {
        maybe_load_from_store_for_testnet::<_, T::Store, T::EthSpec>(store, log)
    }
}

/// A testnet-suitable BeaconChainType, using `DiskStore`.
#[derive(Clone)]
pub struct TestnetDiskBeaconChainTypes;

impl BeaconChainTypes for TestnetDiskBeaconChainTypes {
    type Store = DiskStore;
    type SlotClock = SystemTimeSlotClock;
    type ForkChoice = BitwiseLMDGhost<Self::Store, Self::EthSpec>;
    type EthSpec = LighthouseTestnetEthSpec;
}

impl<T: BeaconChainTypes> InitialiseBeaconChain<T> for TestnetDiskBeaconChainTypes {
    fn initialise_beacon_chain(store: Arc<T::Store>, log: Logger) -> BeaconChain<T> {
        maybe_load_from_store_for_testnet::<_, T::Store, T::EthSpec>(store, log)
    }
}

/// Loads a `BeaconChain` from `store`, if it exists. Otherwise, create a new chain from genesis.
fn maybe_load_from_store_for_testnet<T, U: Store, V: EthSpec>(
    store: Arc<U>,
    log: Logger,
) -> BeaconChain<T>
where
    T: BeaconChainTypes<Store = U>,
    T::ForkChoice: ForkChoice<U>,
{
    if let Ok(Some(beacon_chain)) = BeaconChain::from_store(store.clone()) {
        info!(
            log,
            "Loaded BeaconChain from store";
            "slot" => beacon_chain.head().beacon_state.slot,
            "best_slot" => beacon_chain.best_slot(),
        );

        beacon_chain
    } else {
        info!(log, "Initializing new BeaconChain from genesis");
        let spec = T::EthSpec::spec();

        let state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(
            TESTNET_VALIDATOR_COUNT,
            &spec,
        );
        let (genesis_state, _keypairs) = state_builder.build();

        let mut genesis_block = BeaconBlock::empty(&spec);
        genesis_block.state_root = Hash256::from_slice(&genesis_state.tree_hash_root());

        // Slot clock
        let slot_clock = T::SlotClock::new(
            spec.genesis_slot,
            genesis_state.genesis_time,
            spec.seconds_per_slot,
        );
        // Choose the fork choice
        let fork_choice = T::ForkChoice::new(store.clone());

        // Genesis chain
        //TODO: Handle error correctly
        BeaconChain::from_genesis(
            store,
            slot_clock,
            genesis_state,
            genesis_block,
            spec.clone(),
            fork_choice,
        )
        .expect("Terminate if beacon chain generation fails")
    }
}
<commit_msg>Switch runtime fork choice to optimized<commit_after>use beacon_chain::{
    fork_choice::OptimizedLMDGhost,
    slot_clock::SystemTimeSlotClock,
    store::{DiskStore, MemoryStore, Store},
    BeaconChain, BeaconChainTypes,
};
use fork_choice::ForkChoice;
use slog::{info, Logger};
use slot_clock::SlotClock;
use std::sync::Arc;
use tree_hash::TreeHash;
use types::{
    test_utils::TestingBeaconStateBuilder, BeaconBlock, EthSpec, Hash256, LighthouseTestnetEthSpec,
};

/// The number initial validators when starting the `LighthouseTestnet`.
const TESTNET_VALIDATOR_COUNT: usize = 16;

/// Provides a new, initialized `BeaconChain`
pub trait InitialiseBeaconChain<T: BeaconChainTypes> {
    fn initialise_beacon_chain(store: Arc<T::Store>, log: Logger) -> BeaconChain<T>;
}

/// A testnet-suitable BeaconChainType, using `MemoryStore`.
#[derive(Clone)]
pub struct TestnetMemoryBeaconChainTypes;

impl BeaconChainTypes for TestnetMemoryBeaconChainTypes {
    type Store = MemoryStore;
    type SlotClock = SystemTimeSlotClock;
    type ForkChoice = OptimizedLMDGhost<Self::Store, Self::EthSpec>;
    type EthSpec = LighthouseTestnetEthSpec;
}

impl<T: BeaconChainTypes> InitialiseBeaconChain<T> for TestnetMemoryBeaconChainTypes {
    fn initialise_beacon_chain(store: Arc<T::Store>, log: Logger) -> BeaconChain<T> {
        maybe_load_from_store_for_testnet::<_, T::Store, T::EthSpec>(store, log)
    }
}

/// A testnet-suitable BeaconChainType, using `DiskStore`.
#[derive(Clone)]
pub struct TestnetDiskBeaconChainTypes;

impl BeaconChainTypes for TestnetDiskBeaconChainTypes {
    type Store = DiskStore;
    type SlotClock = SystemTimeSlotClock;
    type ForkChoice = OptimizedLMDGhost<Self::Store, Self::EthSpec>;
    type EthSpec = LighthouseTestnetEthSpec;
}

impl<T: BeaconChainTypes> InitialiseBeaconChain<T> for TestnetDiskBeaconChainTypes {
    fn initialise_beacon_chain(store: Arc<T::Store>, log: Logger) -> BeaconChain<T> {
        maybe_load_from_store_for_testnet::<_, T::Store, T::EthSpec>(store, log)
    }
}

/// Loads a `BeaconChain` from `store`, if it exists. Otherwise, create a new chain from genesis.
fn maybe_load_from_store_for_testnet<T, U: Store, V: EthSpec>(
    store: Arc<U>,
    log: Logger,
) -> BeaconChain<T>
where
    T: BeaconChainTypes<Store = U>,
    T::ForkChoice: ForkChoice<U>,
{
    if let Ok(Some(beacon_chain)) = BeaconChain::from_store(store.clone()) {
        info!(
            log,
            "Loaded BeaconChain from store";
            "slot" => beacon_chain.head().beacon_state.slot,
            "best_slot" => beacon_chain.best_slot(),
        );

        beacon_chain
    } else {
        info!(log, "Initializing new BeaconChain from genesis");
        let spec = T::EthSpec::spec();

        let state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(
            TESTNET_VALIDATOR_COUNT,
            &spec,
        );
        let (genesis_state, _keypairs) = state_builder.build();

        let mut genesis_block = BeaconBlock::empty(&spec);
        genesis_block.state_root = Hash256::from_slice(&genesis_state.tree_hash_root());

        // Slot clock
        let slot_clock = T::SlotClock::new(
            spec.genesis_slot,
            genesis_state.genesis_time,
            spec.seconds_per_slot,
        );
        // Choose the fork choice
        let fork_choice = T::ForkChoice::new(store.clone());

        // Genesis chain
        //TODO: Handle error correctly
        BeaconChain::from_genesis(
            store,
            slot_clock,
            genesis_state,
            genesis_block,
            spec.clone(),
            fork_choice,
        )
        .expect("Terminate if beacon chain generation fails")
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{context::XContext, Result};
use anyhow::Context;
use determinator::Determinator;
use guppy::graph::{DependencyDirection, PackageSet};
use log::trace;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
pub struct Args {
    /// List packages changed since this commit
    pub(crate) base: String,
}

pub fn run(args: Args, xctx: XContext) -> Result<()> {
    let affected_set = changed_since_impl(&xctx, &args.base)?;
    for package in affected_set.packages(DependencyDirection::Forward) {
        println!("{}", package.name());
    }
    Ok(())
}

pub(crate) fn changed_since_impl<'g>(xctx: &'g XContext, base: &str) -> Result<PackageSet<'g>> {
    let git_cli = xctx.core().git_cli();
    let merge_base = git_cli
        .merge_base(&base)
        .with_context(|| "failed to get merge base with HEAD")?;
    let (old_graph, (new_graph, files_changed)) = rayon::join(
        || {
            trace!("building old graph");
            git_cli
                .package_graph_at(&merge_base)
                .with_context(|| "failed to build old package graph")
                .map(|old_graph| {
                    // Initialize the feature graph since it will be required later on.
                    old_graph.feature_graph();
                    old_graph
                })
        },
        || {
            rayon::join(
                || {
                    trace!("building new graph");
                    xctx.core().package_graph().map(|new_graph| {
                        // Initialize the feature graph since it will be required later on.
                        new_graph.feature_graph();
                        new_graph
                    })
                },
                || {
                    // Get the list of files changed between the merge base and the current dir.
                    // diff_filter = "d" means "skip over deleted files".
                    trace!("getting files changed");
                    git_cli
                        .files_changed_between(&merge_base, None, Some("d"))
                        .with_context(|| "error while getting files changed from merge base")
                },
            )
        },
    );
    let (old_graph, new_graph, files_changed) = (old_graph?, new_graph?, files_changed?);

    trace!("running determinator");
    let mut determinator = Determinator::new(&old_graph, new_graph);
    determinator
        .add_changed_paths(&files_changed)
        .set_rules(xctx.config().determinator_rules())
        .with_context(|| "failed to set determinator rules")?;

    let determinator_set = determinator.compute();
    Ok(determinator_set.affected_set)
}
<commit_msg>[x] don't ignore deleted files in changed-since<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{context::XContext, Result};
use anyhow::Context;
use determinator::Determinator;
use guppy::graph::{DependencyDirection, PackageSet};
use log::trace;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
pub struct Args {
    /// List packages changed since this commit
    pub(crate) base: String,
}

pub fn run(args: Args, xctx: XContext) -> Result<()> {
    let affected_set = changed_since_impl(&xctx, &args.base)?;
    for package in affected_set.packages(DependencyDirection::Forward) {
        println!("{}", package.name());
    }
    Ok(())
}

pub(crate) fn changed_since_impl<'g>(xctx: &'g XContext, base: &str) -> Result<PackageSet<'g>> {
    let git_cli = xctx.core().git_cli();
    let merge_base = git_cli
        .merge_base(&base)
        .with_context(|| "failed to get merge base with HEAD")?;
    let (old_graph, (new_graph, files_changed)) = rayon::join(
        || {
            trace!("building old graph");
            git_cli
                .package_graph_at(&merge_base)
                .with_context(|| "failed to build old package graph")
                .map(|old_graph| {
                    // Initialize the feature graph since it will be required later on.
                    old_graph.feature_graph();
                    old_graph
                })
        },
        || {
            rayon::join(
                || {
                    trace!("building new graph");
                    xctx.core().package_graph().map(|new_graph| {
                        // Initialize the feature graph since it will be required later on.
                        new_graph.feature_graph();
                        new_graph
                    })
                },
                || {
                    // Get the list of files changed between the merge base and the current dir.
                    trace!("getting files changed");
                    git_cli
                        .files_changed_between(&merge_base, None, None)
                        .with_context(|| "error while getting files changed from merge base")
                },
            )
        },
    );
    let (old_graph, new_graph, files_changed) = (old_graph?, new_graph?, files_changed?);

    trace!("running determinator");
    let mut determinator = Determinator::new(&old_graph, new_graph);
    determinator
        .add_changed_paths(&files_changed)
        .set_rules(xctx.config().determinator_rules())
        .with_context(|| "failed to set determinator rules")?;

    let determinator_set = determinator.compute();
    Ok(determinator_set.affected_set)
}
<|endoftext|>


<commit_before>#![allow(clippy::too_many_arguments)]

extern crate pq_sys;

use self::pq_sys::*;
use std::ffi::{CStr, CString};
use std::os::raw as libc;
use std::ptr::NonNull;
use std::{ptr, str};

use crate::result::*;

#[allow(missing_debug_implementations, missing_copy_implementations)]
pub struct RawConnection {
    internal_connection: NonNull<PGconn>,
}

impl RawConnection {
    pub fn establish(database_url: &str) -> ConnectionResult<Self> {
        use self::ConnStatusType::*;

        let connection_string = CString::new(database_url)?;
        let connection_ptr = unsafe { PQconnectdb(connection_string.as_ptr()) };
        let connection_status = unsafe { PQstatus(connection_ptr) };

        match connection_status {
            CONNECTION_OK => {
                let connection_ptr = unsafe { NonNull::new_unchecked(connection_ptr) };
                Ok(RawConnection {
                    internal_connection: connection_ptr,
                })
            }
            _ => {
                let message = last_error_message(connection_ptr);
                Err(ConnectionError::BadConnection(message))
            }
        }
    }

    pub fn last_error_message(&self) -> String {
        last_error_message(self.internal_connection.as_ptr())
    }

    pub fn set_notice_processor(&self, notice_processor: NoticeProcessor) {
        unsafe {
            PQsetNoticeProcessor(
                self.internal_connection.as_ptr(),
                Some(notice_processor),
                ptr::null_mut(),
            );
        }
    }

    pub unsafe fn exec(&self, query: *const libc::c_char) -> QueryResult<RawResult> {
        RawResult::new(PQexec(self.internal_connection.as_ptr(), query), self)
    }

    pub unsafe fn exec_prepared(
        &self,
        stmt_name: *const libc::c_char,
        param_count: libc::c_int,
        param_values: *const *const libc::c_char,
        param_lengths: *const libc::c_int,
        param_formats: *const libc::c_int,
        result_format: libc::c_int,
    ) -> QueryResult<RawResult> {
        let ptr = PQexecPrepared(
            self.internal_connection.as_ptr(),
            stmt_name,
            param_count,
            param_values,
            param_lengths,
            param_formats,
            result_format,
        );
        RawResult::new(ptr, self)
    }

    pub unsafe fn prepare(
        &self,
        stmt_name: *const libc::c_char,
        query: *const libc::c_char,
        param_count: libc::c_int,
        param_types: *const Oid,
    ) -> QueryResult<RawResult> {
        let ptr = PQprepare(
            self.internal_connection.as_ptr(),
            stmt_name,
            query,
            param_count,
            param_types,
        );
        RawResult::new(ptr, self)
    }
}

pub type NoticeProcessor = extern "C" fn(arg: *mut libc::c_void, message: *const libc::c_char);

impl Drop for RawConnection {
    fn drop(&mut self) {
        unsafe { PQfinish(self.internal_connection.as_ptr()) };
    }
}

fn last_error_message(conn: *const PGconn) -> String {
    unsafe {
        let error_ptr = PQerrorMessage(conn);
        let bytes = CStr::from_ptr(error_ptr).to_bytes();
        String::from_utf8_lossy(bytes).to_string()
    }
}

/// Internal wrapper around a `*mut PGresult` which is known to be not-null, and
/// have no aliases.  This wrapper is to ensure that it's always properly
/// dropped.
///
/// If `Unique` is ever stabilized, we should use it here.
#[allow(missing_debug_implementations)]
pub struct RawResult(NonNull<PGresult>);

unsafe impl Send for RawResult {}
unsafe impl Sync for RawResult {}

impl RawResult {
    #[allow(clippy::new_ret_no_self)]
    fn new(ptr: *mut PGresult, conn: &RawConnection) -> QueryResult<Self> {
        NonNull::new(ptr).map(RawResult).ok_or_else(|| {
            Error::DatabaseError(
                DatabaseErrorKind::UnableToSendCommand,
                Box::new(conn.last_error_message()),
            )
        })
    }

    pub fn as_ptr(&self) -> *mut PGresult {
        self.0.as_ptr()
    }

    pub fn error_message(&self) -> &str {
        let ptr = unsafe { PQresultErrorMessage(self.0.as_ptr()) };
        let cstr = unsafe { CStr::from_ptr(ptr) };
        cstr.to_str().unwrap_or_default()
    }
}

impl Drop for RawResult {
    fn drop(&mut self) {
        unsafe { PQclear(self.0.as_ptr()) }
    }
}
<commit_msg>Properly call PQFinish after failed connection attempts to stop leaking socket file descriptors<commit_after>#![allow(clippy::too_many_arguments)]

extern crate pq_sys;

use self::pq_sys::*;
use std::ffi::{CStr, CString};
use std::os::raw as libc;
use std::ptr::NonNull;
use std::{ptr, str};

use crate::result::*;

#[allow(missing_debug_implementations, missing_copy_implementations)]
pub struct RawConnection {
    internal_connection: NonNull<PGconn>,
}

impl RawConnection {
    pub fn establish(database_url: &str) -> ConnectionResult<Self> {
        use self::ConnStatusType::*;

        let connection_string = CString::new(database_url)?;
        let connection_ptr = unsafe { PQconnectdb(connection_string.as_ptr()) };
        let connection_status = unsafe { PQstatus(connection_ptr) };

        match connection_status {
            CONNECTION_OK => {
                let connection_ptr = unsafe { NonNull::new_unchecked(connection_ptr) };
                Ok(RawConnection {
                    internal_connection: connection_ptr,
                })
            }
            _ => {
                let message = last_error_message(connection_ptr);

                unsafe { PQfinish(connection_ptr) }

                Err(ConnectionError::BadConnection(message))
            }
        }
    }

    pub fn last_error_message(&self) -> String {
        last_error_message(self.internal_connection.as_ptr())
    }

    pub fn set_notice_processor(&self, notice_processor: NoticeProcessor) {
        unsafe {
            PQsetNoticeProcessor(
                self.internal_connection.as_ptr(),
                Some(notice_processor),
                ptr::null_mut(),
            );
        }
    }

    pub unsafe fn exec(&self, query: *const libc::c_char) -> QueryResult<RawResult> {
        RawResult::new(PQexec(self.internal_connection.as_ptr(), query), self)
    }

    pub unsafe fn exec_prepared(
        &self,
        stmt_name: *const libc::c_char,
        param_count: libc::c_int,
        param_values: *const *const libc::c_char,
        param_lengths: *const libc::c_int,
        param_formats: *const libc::c_int,
        result_format: libc::c_int,
    ) -> QueryResult<RawResult> {
        let ptr = PQexecPrepared(
            self.internal_connection.as_ptr(),
            stmt_name,
            param_count,
            param_values,
            param_lengths,
            param_formats,
            result_format,
        );
        RawResult::new(ptr, self)
    }

    pub unsafe fn prepare(
        &self,
        stmt_name: *const libc::c_char,
        query: *const libc::c_char,
        param_count: libc::c_int,
        param_types: *const Oid,
    ) -> QueryResult<RawResult> {
        let ptr = PQprepare(
            self.internal_connection.as_ptr(),
            stmt_name,
            query,
            param_count,
            param_types,
        );
        RawResult::new(ptr, self)
    }
}

pub type NoticeProcessor = extern "C" fn(arg: *mut libc::c_void, message: *const libc::c_char);

impl Drop for RawConnection {
    fn drop(&mut self) {
        unsafe { PQfinish(self.internal_connection.as_ptr()) };
    }
}

fn last_error_message(conn: *const PGconn) -> String {
    unsafe {
        let error_ptr = PQerrorMessage(conn);
        let bytes = CStr::from_ptr(error_ptr).to_bytes();
        String::from_utf8_lossy(bytes).to_string()
    }
}

/// Internal wrapper around a `*mut PGresult` which is known to be not-null, and
/// have no aliases.  This wrapper is to ensure that it's always properly
/// dropped.
///
/// If `Unique` is ever stabilized, we should use it here.
#[allow(missing_debug_implementations)]
pub struct RawResult(NonNull<PGresult>);

unsafe impl Send for RawResult {}
unsafe impl Sync for RawResult {}

impl RawResult {
    #[allow(clippy::new_ret_no_self)]
    fn new(ptr: *mut PGresult, conn: &RawConnection) -> QueryResult<Self> {
        NonNull::new(ptr).map(RawResult).ok_or_else(|| {
            Error::DatabaseError(
                DatabaseErrorKind::UnableToSendCommand,
                Box::new(conn.last_error_message()),
            )
        })
    }

    pub fn as_ptr(&self) -> *mut PGresult {
        self.0.as_ptr()
    }

    pub fn error_message(&self) -> &str {
        let ptr = unsafe { PQresultErrorMessage(self.0.as_ptr()) };
        let cstr = unsafe { CStr::from_ptr(ptr) };
        cstr.to_str().unwrap_or_default()
    }
}

impl Drop for RawResult {
    fn drop(&mut self) {
        unsafe { PQclear(self.0.as_ptr()) }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use hir::def_id::DefId;
use rustc_data_structures::veccell::VecCell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;
use super::shadow::ShadowGraph;

#[derive(Debug)]
pub enum DepMessage {
    Read(DepNode<DefId>),
    Write(DepNode<DefId>),
    PushTask(DepNode<DefId>),
    PopTask(DepNode<DefId>),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // The "shadow graph" is a debugging aid. We give it each message
    // in real time as it arrives and it checks for various errors
    // (for example, a read/write when there is no current task; it
    // can also apply user-defined filters; see `shadow` module for
    // details). This only occurs if debug-assertions are enabled.
    //
    // Note that in some cases the same errors will occur when the
    // data is processed off the main thread, but that's annoying
    // because it lacks precision about the source of the error.
    shadow_graph: ShadowGraph,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // whence to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery<DefId>>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();

        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }

        DepGraphThreadData {
            enabled: enabled,
            shadow_graph: ShadowGraph::new(),
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    /// True if we are actually building the full dep-graph.
    #[inline]
    pub fn is_fully_enabled(&self) -> bool {
        self.enabled
    }

    /// True if (a) we are actually building the full dep-graph, or (b) we are
    /// only enqueuing messages in order to sanity-check them (which happens
    /// when debug assertions are enabled).
    #[inline]
    pub fn is_enqueue_enabled(&self) -> bool {
        self.is_fully_enabled() || self.shadow_graph.enabled()
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.is_fully_enabled(), "should never swap if not fully enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery<DefId> {
        assert!(self.is_fully_enabled(), "should never query if not fully enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        assert!(self.is_enqueue_enabled(), "should never enqueue if not enqueue-enabled");
        self.shadow_graph.enqueue(&message);
        if self.is_fully_enabled() {
            self.enqueue_enabled(message);
        }
    }

    // Outline this fn since I expect it may want to be inlined
    // separately.
    fn enqueue_enabled(&self, message: DepMessage) {
        let len = self.messages.push(message);
        if len == INITIAL_CAPACITY {
            self.swap();
        }
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery<DefId>>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        if let Err(_) = swap_out.send(messages) {
            // the receiver must have been dropped already
            break;
        }
    }
}
<commit_msg>Rollup merge of #39115 - king6cong:master, r=nikomatsakis<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use hir::def_id::DefId;
use rustc_data_structures::veccell::VecCell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;
use super::shadow::ShadowGraph;

#[derive(Debug)]
pub enum DepMessage {
    Read(DepNode<DefId>),
    Write(DepNode<DefId>),
    PushTask(DepNode<DefId>),
    PopTask(DepNode<DefId>),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // The "shadow graph" is a debugging aid. We give it each message
    // in real time as it arrives and it checks for various errors
    // (for example, a read/write when there is no current task; it
    // can also apply user-defined filters; see `shadow` module for
    // details). This only occurs if debug-assertions are enabled.
    //
    // Note that in some cases the same errors will occur when the
    // data is processed off the main thread, but that's annoying
    // because it lacks precision about the source of the error.
    shadow_graph: ShadowGraph,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // where to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery<DefId>>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();

        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }

        DepGraphThreadData {
            enabled: enabled,
            shadow_graph: ShadowGraph::new(),
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    /// True if we are actually building the full dep-graph.
    #[inline]
    pub fn is_fully_enabled(&self) -> bool {
        self.enabled
    }

    /// True if (a) we are actually building the full dep-graph, or (b) we are
    /// only enqueuing messages in order to sanity-check them (which happens
    /// when debug assertions are enabled).
    #[inline]
    pub fn is_enqueue_enabled(&self) -> bool {
        self.is_fully_enabled() || self.shadow_graph.enabled()
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.is_fully_enabled(), "should never swap if not fully enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery<DefId> {
        assert!(self.is_fully_enabled(), "should never query if not fully enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        assert!(self.is_enqueue_enabled(), "should never enqueue if not enqueue-enabled");
        self.shadow_graph.enqueue(&message);
        if self.is_fully_enabled() {
            self.enqueue_enabled(message);
        }
    }

    // Outline this fn since I expect it may want to be inlined
    // separately.
    fn enqueue_enabled(&self, message: DepMessage) {
        let len = self.messages.push(message);
        if len == INITIAL_CAPACITY {
            self.swap();
        }
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery<DefId>>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        if let Err(_) = swap_out.send(messages) {
            // the receiver must have been dropped already
            break;
        }
    }
}
<|endoftext|>


<commit_before>use ty::{self, Ty, TyCtxt};
use ty::fold::{TypeFolder, TypeFoldable};

pub(super) fn provide(providers: &mut ty::query::Providers<'_>) {
    *providers = ty::query::Providers {
        erase_regions_ty,
        ..*providers
    };
}

fn erase_regions_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
    // N.B., use `super_fold_with` here. If we used `fold_with`, it
    // could invoke the `erase_regions_ty` query recursively.
    ty.super_fold_with(&mut RegionEraserVisitor { tcx })
}

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
    /// Returns an equivalent value with all free regions removed (note
    /// that late-bound regions remain, because they are important for
    /// subtyping, but they are anonymized and normalized as well)..
    pub fn erase_regions<T>(self, value: &T) -> T
        where T : TypeFoldable<'tcx>
    {
        let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
        debug!("erase_regions({:?}) = {:?}", value, value1);
        value1
    }
}

struct RegionEraserVisitor<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
}

impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
        self.tcx
    }

    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
        if let Some(ty_lifted) = self.tcx.lift_to_global(&ty) {
            self.tcx.erase_regions_ty(ty_lifted)
        } else {
            ty.super_fold_with(self)
        }
    }

    fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
        where T : TypeFoldable<'tcx>
    {
        let u = self.tcx.anonymize_late_bound_regions(t);
        u.super_fold_with(self)
    }

    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
        // because late-bound regions affect subtyping, we can't
        // erase the bound/free distinction, but we can replace
        // all free regions with 'erased.
        //
        // Note that we *CAN* replace early-bound regions -- the
        // type system never "sees" those, they get substituted
        // away. In codegen, they will always be erased to 'erased
        // whenever a substitution occurs.
        match *r {
            ty::ReLateBound(..) => r,
            _ => self.tcx.types.re_erased
        }
    }
}
<commit_msg>Avoid erase_regions_ty queries if there are no regions to erase<commit_after>use ty::{self, Ty, TyCtxt, TypeFlags};
use ty::fold::{TypeFolder, TypeFoldable};

pub(super) fn provide(providers: &mut ty::query::Providers<'_>) {
    *providers = ty::query::Providers {
        erase_regions_ty,
        ..*providers
    };
}

fn erase_regions_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
    // N.B., use `super_fold_with` here. If we used `fold_with`, it
    // could invoke the `erase_regions_ty` query recursively.
    ty.super_fold_with(&mut RegionEraserVisitor { tcx })
}

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
    /// Returns an equivalent value with all free regions removed (note
    /// that late-bound regions remain, because they are important for
    /// subtyping, but they are anonymized and normalized as well)..
    pub fn erase_regions<T>(self, value: &T) -> T
        where T : TypeFoldable<'tcx>
    {
        // If there's nothing to erase avoid performing the query at all
        if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
            return value.clone();
        }

        let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
        debug!("erase_regions({:?}) = {:?}", value, value1);
        value1
    }
}

struct RegionEraserVisitor<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
}

impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
        self.tcx
    }

    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
        if let Some(ty_lifted) = self.tcx.lift_to_global(&ty) {
            self.tcx.erase_regions_ty(ty_lifted)
        } else {
            ty.super_fold_with(self)
        }
    }

    fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
        where T : TypeFoldable<'tcx>
    {
        let u = self.tcx.anonymize_late_bound_regions(t);
        u.super_fold_with(self)
    }

    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
        // because late-bound regions affect subtyping, we can't
        // erase the bound/free distinction, but we can replace
        // all free regions with 'erased.
        //
        // Note that we *CAN* replace early-bound regions -- the
        // type system never "sees" those, they get substituted
        // away. In codegen, they will always be erased to 'erased
        // whenever a substitution occurs.
        match *r {
            ty::ReLateBound(..) => r,
            _ => self.tcx.types.re_erased
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ncurses-compatible database discovery
//!
//! Does not support hashed database, only filesystem!

use std::env;
use std::fs;
use std::path::PathBuf;

/// Return path to database entry for `term`
#[allow(deprecated)]
pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
    let mut dirs_to_search = Vec::new();
    let first_char = match term.chars().next() {
        Some(c) => c,
        None => return None,
    };

    // Find search directory
    match env::var_os("TERMINFO") {
        Some(dir) => dirs_to_search.push(PathBuf::from(dir)),
        None => {
            if let Some(mut homedir) = env::home_dir() {
                // ncurses compatibility;
                homedir.push(".terminfo");
                dirs_to_search.push(homedir)
            }
            match env::var("TERMINFO_DIRS") {
                Ok(dirs) => {
                    for i in dirs.split(':') {
                        if i == "" {
                            dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
                        } else {
                            dirs_to_search.push(PathBuf::from(i));
                        }
                    }
                }
                // Found nothing in TERMINFO_DIRS, use the default paths:
                // According to  /etc/terminfo/README, after looking at
                // ~/.terminfo, ncurses will search /etc/terminfo, then
                // /lib/terminfo, and eventually /usr/share/terminfo.
                // On Haiku the database can be found at /boot/system/data/terminfo
                Err(..) => {
                    dirs_to_search.push(PathBuf::from("/etc/terminfo"));
                    dirs_to_search.push(PathBuf::from("/lib/terminfo"));
                    dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
                    dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo"));
                }
            }
        }
    };

    // Look for the terminal in all of the search directories
    for mut p in dirs_to_search {
        if fs::metadata(&p).is_ok() {
            p.push(&first_char.to_string());
            p.push(&term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
            p.pop();
            p.pop();

            // on some installations the dir is named after the hex of the char
            // (e.g. OS X)
            p.push(&format!("{:x}", first_char as usize));
            p.push(term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
        }
    }
    None
}

#[test]
#[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")]
fn test_get_dbpath_for_term() {
    // woefully inadequate test coverage
    // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's)
    use std::env;
    // FIXME (#9639): This needs to handle non-utf8 paths
    fn x(t: &str) -> String {
        let p = get_dbpath_for_term(t).expect("no terminfo entry found");
        p.to_str().unwrap().to_string()
    }
    assert!(x("screen") == "/usr/share/terminfo/s/screen");
    assert!(get_dbpath_for_term("") == None);
    env::set_var("TERMINFO_DIRS", ":");
    assert!(x("screen") == "/usr/share/terminfo/s/screen");
    env::remove_var("TERMINFO_DIRS");
}
<commit_msg>Auto merge of #37469 - meh:fix-term, r=alexcrichton<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ncurses-compatible database discovery
//!
//! Does not support hashed database, only filesystem!

use std::env;
use std::fs;
use std::path::PathBuf;

/// Return path to database entry for `term`
#[allow(deprecated)]
pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
    let mut dirs_to_search = Vec::new();
    let first_char = match term.chars().next() {
        Some(c) => c,
        None => return None,
    };

    // Find search directory
    if let Some(dir) = env::var_os("TERMINFO") {
        dirs_to_search.push(PathBuf::from(dir));
    }

    if let Ok(dirs) = env::var("TERMINFO_DIRS") {
        for i in dirs.split(':') {
            if i == "" {
                dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
            } else {
                dirs_to_search.push(PathBuf::from(i));
            }
        }
    } else {
        // Found nothing in TERMINFO_DIRS, use the default paths:
        // According to  /etc/terminfo/README, after looking at
        // ~/.terminfo, ncurses will search /etc/terminfo, then
        // /lib/terminfo, and eventually /usr/share/terminfo.
        // On Haiku the database can be found at /boot/system/data/terminfo
        if let Some(mut homedir) = env::home_dir() {
            homedir.push(".terminfo");
            dirs_to_search.push(homedir)
        }

        dirs_to_search.push(PathBuf::from("/etc/terminfo"));
        dirs_to_search.push(PathBuf::from("/lib/terminfo"));
        dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
        dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo"));
    }

    // Look for the terminal in all of the search directories
    for mut p in dirs_to_search {
        if fs::metadata(&p).is_ok() {
            p.push(&first_char.to_string());
            p.push(&term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
            p.pop();
            p.pop();

            // on some installations the dir is named after the hex of the char
            // (e.g. OS X)
            p.push(&format!("{:x}", first_char as usize));
            p.push(term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
        }
    }
    None
}

#[test]
#[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")]
fn test_get_dbpath_for_term() {
    // woefully inadequate test coverage
    // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's)
    use std::env;
    // FIXME (#9639): This needs to handle non-utf8 paths
    fn x(t: &str) -> String {
        let p = get_dbpath_for_term(t).expect("no terminfo entry found");
        p.to_str().unwrap().to_string()
    }
    assert!(x("screen") == "/usr/share/terminfo/s/screen");
    assert!(get_dbpath_for_term("") == None);
    env::set_var("TERMINFO_DIRS", ":");
    assert!(x("screen") == "/usr/share/terminfo/s/screen");
    env::remove_var("TERMINFO_DIRS");
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

extern crate coinnect;

use coinnect::kraken::KrakenApi;

fn main() {
    // We create a KrakenApi by providing API key/secret
    let path = PathBuf::from("keys_real.json");
    let mut my_api = KrakenApi::new_from_file("account_kraken", path);

    println!("return {:?}", my_api.get_deposit_methods("", ""));
}
<commit_msg>Update kraken_trading example.<commit_after>// This example shows how to implement a simple trading strategy.
// We are looking for the pair with the highest rise in price over the last 24 hours and we
// add a buy order to buy it.

// Please do NOT run this example with your real account unless you know what you're doing.

extern crate coinnect;

use std::path::PathBuf;

use coinnect::kraken::KrakenApi;

fn main() {
    // We create a KrakenApi by loading a json file containing API configuration
    // (see documentation for more info)
    let path = PathBuf::from("keys_real.json");
    let mut my_api = KrakenApi::new_from_file("account_kraken", path);

    // First, get the list of all pair we can trade with EUR€ as quote
    let pairs_request = my_api.get_tradable_asset_pairs("", "").unwrap();
    let list_all_pairs = pairs_request.get("result").unwrap().as_object().unwrap();

    let mut list_pairs_eur = Vec::new();

    for pair in list_all_pairs {
        // The map structure is explained in documentation
        let quote = pair.1.as_object().unwrap().get("quote").unwrap().as_str().unwrap();
        if quote == "ZEUR" {
            let name = pair.0;
            list_pairs_eur.push(name);
        }
    }

    println!("List {:?}", list_pairs_eur);

    // Now that we have the pairs, we choose the one with the highest price variation.
    // We query the ticker to get the opening and closing price over the last 24 hours for each
    // pairs in list_pairs_eur. KrakenApi has a blocking timer which prevents from ban if you
    // make rapid succession of requests (inside a for loop for example). Here, the ticker function
    // can take a list of pairs as parameter, so 1 request should suffice.

    // Convert Vec into comma separated values String
    let eur_pairs = format!("{:?}", list_pairs_eur);
    let eur_pairs = eur_pairs.replace("\"", "").replace("[", "").replace("]", "").replace(" ", "");

    // Get ticker
    let ticker_request = my_api.get_ticker_information(&eur_pairs).unwrap();
    let list_ticker = ticker_request.get("result").unwrap().as_object().unwrap();

    let mut pair_to_buy = "";
    let mut pair_price_var = 0.0;
    let mut current_price = 0.0;

    for pair in list_ticker {
        let name = pair.0;

        // WARNING: Kraken uses quotes to encapsulate floating value
        let pair_info = pair.1.as_object().unwrap();
        let open_price = pair_info.get("o").unwrap().as_str().unwrap().parse::<f64>().unwrap();
        let close_price_array = pair_info.get("c").unwrap().as_array().unwrap();
        let close_price = close_price_array[0].as_str().unwrap().parse::<f64>().unwrap();

        let price_var = (close_price / open_price - 1.0) * 100.0;

        if price_var > pair_price_var {
            pair_price_var = price_var;
            pair_to_buy = name;
            current_price = close_price;
        }
    }

    println!("{} has the highest price variation ({:.2}%).",
             pair_to_buy,
             pair_price_var);

    // Add a buy limit order for an amount of 100€ for a price of: current_price - 2%
    let buying_price = current_price - (current_price * 2.0 / 100.0);
    let volume = 100.0 / buying_price;

    // Specify optional parameters with an empty str ("")
    // See documentation for more informations
    my_api.add_standard_order(pair_to_buy,                  // name of the pair
                              "buy",                        // type : buy/sell
                              "limit",                      // order type : market/limit/...
                              &buying_price.to_string(),    // price 1
                              "",                           // price 2
                              &volume.to_string(),          // volume
                              "",                           // leverage
                              "",                           // oflags (see doc)
                              "",                           // starttm
                              "",                           // expiretm
                              "",                           // userref
                              "");                          // validate
    // In a real case example, you should check if any error occurs.
}
<|endoftext|>