From c07bb4a4fbfa6a40278bf0e88e2993bc26ee9814 Mon Sep 17 00:00:00 2001 From: dallyshalla Date: Tue, 12 Apr 2016 15:58:22 +0200 Subject: [PATCH 01/29] add method P2SH --- examples/testkeys.rs | 2 ++ src/genesis/key_generation.rs | 29 +++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/examples/testkeys.rs b/examples/testkeys.rs index 10b60fe..1ad324d 100644 --- a/examples/testkeys.rs +++ b/examples/testkeys.rs @@ -21,6 +21,8 @@ fn main() { let the_string = KeyPair::address_base58(&the_keys.public); print!("your Hash160 Public Key: {:?} \n", the_string); + let the_string = KeyPair::scriptaddress_base58(&the_keys.public); + print!("your ScriptHash Hash160 Public Key: {:?} \n", the_string); let the_keys = KeyPair::from_secret(our_key.secret).unwrap(); diff --git a/src/genesis/key_generation.rs b/src/genesis/key_generation.rs index a30a924..d7cabad 100644 --- a/src/genesis/key_generation.rs +++ b/src/genesis/key_generation.rs @@ -11,7 +11,7 @@ use rand::os::OsRng; use bitcoin::util::hash::Hash160; use bitcoin::util::address::Address; use bitcoin::network::constants::Network::Bitcoin; -use bitcoin::util::address::Type::PubkeyHash; +use bitcoin::util::address::Type::{ScriptHash, PubkeyHash}; use bitcoin::util::hash::Sha256dHash; use bitcoin::util::base58::base58_encode_slice; @@ -68,6 +68,7 @@ impl KeyPair { public: pub_key, }) } + ///make a new random keypair pub fn create() -> KeyResult { let context = &SECP256K1; @@ -81,7 +82,8 @@ impl KeyPair { }; Ok(out_keys) } - ///convert secret key to base64 for ready import to wallets + + ///convert secret key to base64 for ready import to wallets **not working currently** pub fn private_key_towif(secret: SecretKey) -> String { let mut format_sk = format!("{:?}", secret); let string_len = format_sk.len() - 1; @@ -105,6 +107,7 @@ impl KeyPair { //figure out how to use this with the wif process base58_encode_slice } + ///convert secret key to base64 for ready import to wallets pub fn private_key_tobase64(secret: SecretKey) -> String { let mut format_sk = format!("{:?}", secret); @@ -116,6 +119,7 @@ impl KeyPair { let sec_key_base64 = format_sk.from_hex().ok().expect("error converting secret to base64").to_base64(STANDARD); sec_key_base64 } + ///keypair from base64 secret key pub fn keypair_frombase64(secret: String) -> KeyPair { let context = &SECP256K1; @@ -127,7 +131,8 @@ impl KeyPair { public: pub_key, } } - ///extract a bitcoin valid address in base58 + + ///extract a bitcoin valid address in base58 PubkeyHash pub fn address_base58(public: &PublicKey) -> String { let context = Secp256k1::without_caps(); let the_addr = Address { @@ -140,15 +145,28 @@ impl KeyPair { return_this } + ///extract a bitcoin valid address in base58 PubkeyHash + pub fn scriptaddress_base58(public: &PublicKey) -> String { + let context = Secp256k1::without_caps(); + let the_addr = Address { + ty: ScriptHash, + network: Bitcoin, + hash: Hash160::from_data(&public.serialize_vec(&context, false)[..]), + }; + + let return_this: String = format!("{:?}", the_addr); + return_this + } + /// Returns public key pub fn public(&self) -> &PublicKey { &self.public } + /// Returns private key pub fn secret(&self) -> &SecretKey { &self.secret } - //pub fn publick_key(&self) -> & /// Signs with a SecretKey and a message. pub fn sign(secret: &SecretKey, message: Vec) -> Vec { @@ -219,6 +237,9 @@ fn test() { let the_string = KeyPair::address_base58(&the_keys.public); print!("your Hash160 Public Key: {:?} \n", the_string); + let the_string = KeyPair::scriptaddress_base58(&the_keys.public); + print!("your ScriptHash Hash160 Public Key: {:?} \n", the_string); + let the_keys = KeyPair::from_secret(our_key.secret).unwrap(); let mut this_vec: Vec = Vec::new(); From 2deca82fc82a923053fd5ea3a5cf40c152d5c744 Mon Sep 17 00:00:00 2001 From: dallyshalla Date: Wed, 13 Apr 2016 17:01:04 +0200 Subject: [PATCH 02/29] move onto coin --- src/genesis/create_coin.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/genesis/create_coin.rs b/src/genesis/create_coin.rs index b84a025..35a912a 100644 --- a/src/genesis/create_coin.rs +++ b/src/genesis/create_coin.rs @@ -1 +1,13 @@ -//! Definies the methods for forming a cryptocurrency for use in the safex protocol \ No newline at end of file +//! Definies the methods for forming a cryptocurrency for use in the safex protocol + + +pub struct SafexCoin { +} + + +#[test] +fn test() { + + + + } \ No newline at end of file From 9f4e288b82d72e72b99c5cf0ec281e3b800c6d22 Mon Sep 17 00:00:00 2001 From: dallyshalla Date: Wed, 13 Apr 2016 17:02:02 +0200 Subject: [PATCH 03/29] clean up --- src/genesis/alias.rs | 37 ------------------------------------- src/genesis/btc_txn.rs | 4 ---- 2 files changed, 41 deletions(-) delete mode 100644 src/genesis/alias.rs delete mode 100644 src/genesis/btc_txn.rs diff --git a/src/genesis/alias.rs b/src/genesis/alias.rs deleted file mode 100644 index a4cd9de..0000000 --- a/src/genesis/alias.rs +++ /dev/null @@ -1,37 +0,0 @@ - - -use secp256k1::{Secp256k1}; -use secp256k1::key::{SecretKey, PublicKey}; - -use rand::{thread_rng}; - - -use genesis::key_generation::KeyPair; - -//every alias gets a keypair - -struct Account { - identities: Vec, -} - - -impl Account { - /*fn new_account() -> Account { - - }*/ -} - - - - -struct Alias { - name: String, - keys: Vec, - -} - - - - - - diff --git a/src/genesis/btc_txn.rs b/src/genesis/btc_txn.rs deleted file mode 100644 index cc09cc4..0000000 --- a/src/genesis/btc_txn.rs +++ /dev/null @@ -1,4 +0,0 @@ -//transaction and script usage - - -use bitcoin::blockdata::transaction::{TxIn, TxOut}; \ No newline at end of file From a8905c6591dc190149a264492a2d618e0d8f228a Mon Sep 17 00:00:00 2001 From: dallyshalla Date: Wed, 13 Apr 2016 17:03:39 +0200 Subject: [PATCH 04/29] mod --- src/genesis/mod.rs | 3 +-- src/genesis/txn_scripts.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/genesis/txn_scripts.rs diff --git a/src/genesis/mod.rs b/src/genesis/mod.rs index 15b2698..9456f54 100644 --- a/src/genesis/mod.rs +++ b/src/genesis/mod.rs @@ -7,9 +7,8 @@ //! -pub mod alias; pub mod create_coin; pub mod create_item; pub mod create_media; pub mod key_generation; -pub mod btc_txn; \ No newline at end of file +pub mod txn_scripts; \ No newline at end of file diff --git a/src/genesis/txn_scripts.rs b/src/genesis/txn_scripts.rs new file mode 100644 index 0000000..fb0d5fc --- /dev/null +++ b/src/genesis/txn_scripts.rs @@ -0,0 +1,22 @@ +//transaction and script usage + + +use bitcoin::blockdata::transaction::{TxIn, TxOut}; +use bitcoin::blockdata::opcodes; +use bitcoin::blockdata::script::{Script, Builder}; + +use rustc_serialize::hex::{ToHex, FromHex}; + +pub fn pubkey_script() { + +} + + + + +#[test] +fn test() { + + pubkey_script(); + +} \ No newline at end of file From 2405096527bb161142d24f6878bc3676307974b5 Mon Sep 17 00:00:00 2001 From: dallyshalla Date: Wed, 13 Apr 2016 21:03:26 +0200 Subject: [PATCH 05/29] remove bitcoin directory --- Cargo.toml | 9 +- bitcoin/.gitignore | 2 - bitcoin/.travis.yml | 12 - bitcoin/Cargo.toml | 31 - bitcoin/LICENSE | 122 - bitcoin/README.md | 76 - bitcoin/src/blockdata/block.rs | 171 -- bitcoin/src/blockdata/blockchain.rs | 617 ----- bitcoin/src/blockdata/constants.rs | 188 -- bitcoin/src/blockdata/mod.rs | 28 - bitcoin/src/blockdata/opcodes.rs | 699 ----- bitcoin/src/blockdata/script.rs | 3164 ---------------------- bitcoin/src/blockdata/transaction.rs | 239 -- bitcoin/src/internal_macros.rs | 286 -- bitcoin/src/lib.rs | 63 - bitcoin/src/macros.rs | 144 - bitcoin/src/network/address.rs | 126 - bitcoin/src/network/constants.rs | 88 - bitcoin/src/network/encodable.rs | 518 ---- bitcoin/src/network/listener.rs | 93 - bitcoin/src/network/message.rs | 248 -- bitcoin/src/network/message_blockdata.rs | 170 -- bitcoin/src/network/message_network.rs | 108 - bitcoin/src/network/mod.rs | 31 - bitcoin/src/network/serialize.rs | 226 -- bitcoin/src/network/socket.rs | 199 -- bitcoin/src/test_macros.rs | 31 - bitcoin/src/util/address.rs | 322 --- bitcoin/src/util/base58.rs | 254 -- bitcoin/src/util/contracthash.rs | 357 --- bitcoin/src/util/decimal.rs | 438 --- bitcoin/src/util/hash.rs | 397 --- bitcoin/src/util/iter.rs | 80 - bitcoin/src/util/misc.rs | 150 - bitcoin/src/util/mod.rs | 80 - bitcoin/src/util/patricia_tree.rs | 724 ----- bitcoin/src/util/uint.rs | 486 ---- src/genesis/create_coin.rs | 1 + 38 files changed, 9 insertions(+), 10969 deletions(-) delete mode 100644 bitcoin/.gitignore delete mode 100644 bitcoin/.travis.yml delete mode 100644 bitcoin/Cargo.toml delete mode 100644 bitcoin/LICENSE delete mode 100644 bitcoin/README.md delete mode 100644 bitcoin/src/blockdata/block.rs delete mode 100644 bitcoin/src/blockdata/blockchain.rs delete mode 100644 bitcoin/src/blockdata/constants.rs delete mode 100644 bitcoin/src/blockdata/mod.rs delete mode 100644 bitcoin/src/blockdata/opcodes.rs delete mode 100644 bitcoin/src/blockdata/script.rs delete mode 100644 bitcoin/src/blockdata/transaction.rs delete mode 100644 bitcoin/src/internal_macros.rs delete mode 100644 bitcoin/src/lib.rs delete mode 100644 bitcoin/src/macros.rs delete mode 100644 bitcoin/src/network/address.rs delete mode 100644 bitcoin/src/network/constants.rs delete mode 100644 bitcoin/src/network/encodable.rs delete mode 100644 bitcoin/src/network/listener.rs delete mode 100644 bitcoin/src/network/message.rs delete mode 100644 bitcoin/src/network/message_blockdata.rs delete mode 100644 bitcoin/src/network/message_network.rs delete mode 100644 bitcoin/src/network/mod.rs delete mode 100644 bitcoin/src/network/serialize.rs delete mode 100644 bitcoin/src/network/socket.rs delete mode 100644 bitcoin/src/test_macros.rs delete mode 100644 bitcoin/src/util/address.rs delete mode 100644 bitcoin/src/util/base58.rs delete mode 100644 bitcoin/src/util/contracthash.rs delete mode 100644 bitcoin/src/util/decimal.rs delete mode 100644 bitcoin/src/util/hash.rs delete mode 100644 bitcoin/src/util/iter.rs delete mode 100644 bitcoin/src/util/misc.rs delete mode 100644 bitcoin/src/util/mod.rs delete mode 100644 bitcoin/src/util/patricia_tree.rs delete mode 100644 bitcoin/src/util/uint.rs diff --git a/Cargo.toml b/Cargo.toml index ea135df..fe7bae2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,11 +21,18 @@ rand = "0.3" rustc-serialize = "0.3" lazy_static = "0.1" byteorder = "0.3" -bitcoin = { path = "bitcoin" } [dependencies.secp256k1] git = "https://github.com/safex/rust-secp256k1" + +[dependencies.bitcoin] +git = "https://github.com/safex/safex-bitcoin" + +[[example]] +name = "testscripts" +path = "examples/testscripts.rs" + [[example]] name = "testkeys" path = "examples/testkeys.rs" diff --git a/bitcoin/.gitignore b/bitcoin/.gitignore deleted file mode 100644 index d913617..0000000 --- a/bitcoin/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target - diff --git a/bitcoin/.travis.yml b/bitcoin/.travis.yml deleted file mode 100644 index 2f73a17..0000000 --- a/bitcoin/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: rust -rust: - - stable - - beta - - nightly - -install: - - git clone https://github.com/bitcoin/secp256k1.git - - cd secp256k1 - - ./autogen.sh && ./configure && make && sudo make install - - sudo ldconfig /usr/local/lib - diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml deleted file mode 100644 index dd55cdf..0000000 --- a/bitcoin/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ - -[package] -name = "bitcoin" -version = "0.5.4" -authors = ["Andrew Poelstra "] -license = "CC0-1.0" -homepage = "https://github.com/dallyshalla/rust-bitcoin/" -repository = "https://github.com/dallyshalla/rust-bitcoin/" -documentation = "https://www.wpsoftware.net/rustdoc/bitcoin/" -description = "General purpose library for using and interoperating with Bitcoin and other cryptocurrencies." -keywords = [ "crypto", "bitcoin" ] -readme = "README.md" - -[lib] -name = "bitcoin" -path = "src/lib.rs" - -[dependencies] -byteorder = "0.3" -jsonrpc = "0.7" # for serde macros -num = "0.1" -num_cpus = "0.2" -rand = "0.3" -rust-crypto = "0.2" -rustc-serialize = "0.3" -serde = "0.6" -strason = "0.3" -time = "0.1" - -[dependencies.secp256k1] -git = "https://github.com/safex/rust-secp256k1" \ No newline at end of file diff --git a/bitcoin/LICENSE b/bitcoin/LICENSE deleted file mode 100644 index 6ca207e..0000000 --- a/bitcoin/LICENSE +++ /dev/null @@ -1,122 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. - diff --git a/bitcoin/README.md b/bitcoin/README.md deleted file mode 100644 index b08604b..0000000 --- a/bitcoin/README.md +++ /dev/null @@ -1,76 +0,0 @@ -[![Status](https://travis-ci.org/apoelstra/rust-bitcoin.png?branch=master)](https://travis-ci.org/apoelstra/rust-bitcoin) - -# Rust Bitcoin Library - -Library with support for de/serialization, parsing and executing on data -structures and network messages related to Bitcoin and other blockchain-based -currencies. - -[Documentation](https://www.wpsoftware.net/rustdoc/bitcoin/) - -Supports (or should support) - -* De/serialization of Bitcoin protocol network messages -* De/serialization of blocks and transactions -* Script de/serialization and execution -* Blockchain validation and utxoset building -* Private keys and address creation, de/serialization and validation (including full BIP32 support) -* Pay-to-contract support as in Appendix A of the [Blockstream sidechains whitepaper](https://www.blockstream.com/sidechains.pdf) - -# Usage - -To use rust-bitcoin, just add the following to your Cargo.toml. - -```toml -[dependencies] -bitcoin = "0.3" -``` - -# Known limitations - -## Consensus - -This library **must not** be used for consensus code (i.e. fully validating -blockchain data). It technically supports doing this, but doing so is very -ill-advised because there are many deviations, known and unknown, between -this library and the Bitcoin Core reference implementation. In a consensus -based cryptocurrency such as Bitcoin it is critical that all parties are -using the same rules to validate data, and this library is simply unable -to implement the same rules as Core. - -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. Of course, patches to -fix specific consensus incompatibilities are welcome. - -## Memory Usage - -Currently this library's UTXO-set support is limited to an in-RAM hash tree. -It can be serialized and deserialized to disk to avoid recomputing it all -the time, but needs to be in memory to be used, which currently requires -several gigabytes of RAM. - -Patches are welcome. This is a priority but not a high one, due to lack of -developer time. - -## Documentation - -Currently the [documentation](https://www.wpsoftware.net/rustdoc/bitcoin/) -is very sparse. Patches to add usage examples and to expand on existing -docs would be extremely appreciated. - - -# Policy on Altcoins/Altchains - -Patches which add support for non-Bitcoin cryptocurrencies by adding constants -to existing enums (e.g. to set the network message magic-byte sequence) are -welcome. Anything more involved will be considered on a case-by-case basis, -as the altcoin landscape includes projects which [frequently appear and -disappear, and are poorly designed anyway](https://download.wpsoftware.net/bitcoin/alts.pdf) -and keeping the codebase maintainable is a large priority. - -In general, things that improve cross-chain compatibility (e.g. support for -cross-chain atomic swaps) are more likely to be accepted than things which -support only a single blockchain. - - - diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs deleted file mode 100644 index 7105ffc..0000000 --- a/bitcoin/src/blockdata/block.rs +++ /dev/null @@ -1,171 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// 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 . -// - -//! # Bitcoin Block -//! -//! A block is a bundle of transactions with a proof-of-work attached, -//! which attaches to an earlier block to form the blockchain. This -//! module describes structures and functions needed to describe -//! these blocks and the blockchain. -//! - -use num::{FromPrimitive, Zero}; - -use util; -use util::Error::{SpvBadTarget, SpvBadProofOfWork}; -use util::hash::Sha256dHash; -use util::uint::Uint256; -use network::encodable::{ConsensusEncodable, VarInt}; -use network::serialize::BitcoinHash; -use blockdata::transaction::Transaction; - -/// A block header, which contains all the block's information except -/// the actual transactions -#[derive(Copy, PartialEq, Eq, Clone, Debug)] -pub struct BlockHeader { - /// The protocol version. Should always be 1. - pub version: u32, - /// Reference to the previous block in the chain - pub prev_blockhash: Sha256dHash, - /// The root hash of the merkle tree of transactions in the block - pub merkle_root: Sha256dHash, - /// The timestamp of the block, as claimed by the mainer - pub time: u32, - /// The target value below which the blockhash must lie, encoded as a - /// a float (with well-defined rounding, of course) - pub bits: u32, - /// The nonce, selected to obtain a low enough blockhash - pub nonce: u32, -} - -/// A Bitcoin block, which is a collection of transactions with an attached -/// proof of work. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct Block { - /// The block header - pub header: BlockHeader, - /// List of transactions contained in the block - pub txdata: Vec -} - -/// A block header with txcount attached, which is given in the `headers` -/// network message. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct LoneBlockHeader { - /// The actual block header - pub header: BlockHeader, - /// The number of transactions in the block. This will always be zero - /// when the LoneBlockHeader is returned as part ef a `headers` message. - pub tx_count: VarInt -} - -impl BlockHeader { - /// Computes the target [0, T] that a blockhash must land in to be valid - pub fn target(&self) -> Uint256 { - // This is a floating-point "compact" encoding originally used by - // OpenSSL, which satoshi put into consensus code, so we're stuck - // with it. The exponent needs to have 3 subtracted from it, hence - // this goofy decoding code: - let (mant, expt) = { - let unshifted_expt = self.bits >> 24; - if unshifted_expt <= 3 { - ((self.bits & 0xFFFFFF) >> (8 * (3 - unshifted_expt as usize)), 0) - } else { - (self.bits & 0xFFFFFF, 8 * ((self.bits >> 24) - 3)) - } - }; - - // The mantissa is signed but may not be negative - if mant > 0x7FFFFF { - Zero::zero() - } else { - ::from_u64(mant as u64).unwrap() << (expt as usize) - } - } - - /// Performs an SPV validation of a block, which confirms that the proof-of-work - /// is correct, but does not verify that the transactions are valid or encoded - /// correctly. - pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> { - let target = &self.target(); - if target != required_target { - return Err(SpvBadTarget); - } - let hash = &self.bitcoin_hash().into_le(); - if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) } - } - - /// Returns the total work of the block - pub fn work(&self) -> Uint256 { - // 2**256 / (target + 1) == ~target / (target+1) + 1 (eqn shamelessly stolen from bitcoind) - let mut ret = !self.target(); - let mut ret1 = self.target(); - ret1.increment(); - ret = ret / ret1; - ret.increment(); - ret - } -} - -impl BitcoinHash for BlockHeader { - fn bitcoin_hash(&self) -> Sha256dHash { - use network::serialize::serialize; - Sha256dHash::from_data(&serialize(self).unwrap()) - } -} - -impl BitcoinHash for Block { - fn bitcoin_hash(&self) -> Sha256dHash { - self.header.bitcoin_hash() - } -} - -impl_consensus_encoding!(BlockHeader, version, prev_blockhash, merkle_root, time, bits, nonce); -impl_consensus_encoding!(Block, header, txdata); -impl_consensus_encoding!(LoneBlockHeader, header, tx_count); - -#[cfg(test)] -mod tests { - use serialize::hex::FromHex; - - use blockdata::block::Block; - use network::serialize::{deserialize, serialize}; - - #[test] - fn block_test() { - let some_block = "010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000".from_hex().unwrap(); - let cutoff_block = "010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac".from_hex().unwrap(); - - let prevhash = "4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000".from_hex().unwrap(); - let merkle = "bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c".from_hex().unwrap(); - - let decode: Result = deserialize(&some_block); - let bad_decode: Result = deserialize(&cutoff_block); - - assert!(decode.is_ok()); - assert!(bad_decode.is_err()); - let real_decode = decode.unwrap(); - assert_eq!(real_decode.header.version, 1); - assert_eq!(serialize(&real_decode.header.prev_blockhash).ok(), Some(prevhash)); - // [test] TODO: actually compute the merkle root - assert_eq!(serialize(&real_decode.header.merkle_root).ok(), Some(merkle)); - assert_eq!(real_decode.header.time, 1231965655); - assert_eq!(real_decode.header.bits, 486604799); - assert_eq!(real_decode.header.nonce, 2067413810); - // [test] TODO: check the transaction data - - assert_eq!(serialize(&real_decode).ok(), Some(some_block)); - } -} - diff --git a/bitcoin/src/blockdata/blockchain.rs b/bitcoin/src/blockdata/blockchain.rs deleted file mode 100644 index 61595df..0000000 --- a/bitcoin/src/blockdata/blockchain.rs +++ /dev/null @@ -1,617 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// 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 . -// - -//! # Bitcoin Blockchain -//! -//! This module provides the structures and functions to maintain the -//! blockchain. -//! - -use num::{FromPrimitive, Zero}; -use std::{marker, ptr}; - -use blockdata::block::{Block, BlockHeader}; -use blockdata::transaction::Transaction; -use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN, - TARGET_BLOCK_SPACING, max_target, genesis_block}; -use network::constants::Network; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{BitcoinHash, SimpleDecoder, SimpleEncoder}; -use util::BitArray; -use util; -use util::Error::{BlockNotFound, DuplicateHash, PrevHashNotFound}; -use util::uint::Uint256; -use util::hash::Sha256dHash; -use util::patricia_tree::PatriciaTree; - -type BlockTree = PatriciaTree>; -type NodePtr = *const BlockchainNode; - -/// A link in the blockchain -pub struct BlockchainNode { - /// The actual block - pub block: Block, - /// Total work from genesis to this point - pub total_work: Uint256, - /// Expected value of `block.header.bits` for this block; only changes every - /// `blockdata::constants::DIFFCHANGE_INTERVAL;` blocks - pub required_difficulty: Uint256, - /// Height above genesis - pub height: u32, - /// Whether the transaction data is stored - pub has_txdata: bool, - /// Pointer to block's parent - prev: NodePtr, - /// Pointer to block's child - next: NodePtr -} - -impl BlockchainNode { - /// Is the node on the main chain? - fn is_on_main_chain(&self, chain: &Blockchain) -> bool { - if self.block.header == unsafe { (*chain.best_tip).block.header } { - true - } else { - unsafe { - let mut scan = self.next; - while !scan.is_null() { - if (*scan).block.header == (*chain.best_tip).block.header { - return true; - } - scan = (*scan).next; - } - } - false - } - } -} - -impl ConsensusEncodable for BlockchainNode { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { - try!(self.block.consensus_encode(s)); - try!(self.total_work.consensus_encode(s)); - try!(self.required_difficulty.consensus_encode(s)); - try!(self.height.consensus_encode(s)); - try!(self.has_txdata.consensus_encode(s)); - // Don't serialize the prev or next pointers - Ok(()) - } -} - -impl ConsensusDecodable for BlockchainNode { - #[inline] - fn consensus_decode(d: &mut D) -> Result { - Ok(BlockchainNode { - block: try!(ConsensusDecodable::consensus_decode(d)), - total_work: try!(ConsensusDecodable::consensus_decode(d)), - required_difficulty: try!(ConsensusDecodable::consensus_decode(d)), - height: try!(ConsensusDecodable::consensus_decode(d)), - has_txdata: try!(ConsensusDecodable::consensus_decode(d)), - prev: ptr::null(), - next: ptr::null() - }) - } -} - -impl BitcoinHash for BlockchainNode { - fn bitcoin_hash(&self) -> Sha256dHash { - self.block.header.bitcoin_hash() - } -} - -/// The blockchain -pub struct Blockchain { - network: Network, - tree: BlockTree, - best_tip: NodePtr, - best_hash: Sha256dHash, - genesis_hash: Sha256dHash -} - -impl ConsensusEncodable for Blockchain { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { - try!(self.network.consensus_encode(s)); - try!(self.tree.consensus_encode(s)); - try!(self.best_hash.consensus_encode(s)); - try!(self.genesis_hash.consensus_encode(s)); - Ok(()) - } -} - -impl ConsensusDecodable for Blockchain { - fn consensus_decode(d: &mut D) -> Result { - let network: Network = try!(ConsensusDecodable::consensus_decode(d)); - let mut tree: BlockTree = try!(ConsensusDecodable::consensus_decode(d)); - let best_hash: Sha256dHash = try!(ConsensusDecodable::consensus_decode(d)); - let genesis_hash: Sha256dHash = try!(ConsensusDecodable::consensus_decode(d)); - - // Lookup best tip - let best = match tree.lookup(&best_hash.into_le(), 256) { - Some(node) => &**node as NodePtr, - None => { - return Err(d.error(format!("best tip {:x} not in tree", best_hash))); - } - }; - // Lookup genesis - if tree.lookup(&genesis_hash.into_le(), 256).is_none() { - return Err(d.error(format!("genesis {:x} not in tree", genesis_hash))); - } - // Reconnect all prev pointers - let raw_tree = &tree as *const BlockTree; - for node in tree.mut_iter() { - let hash = node.block.header.prev_blockhash.into_le(); - let prevptr = - match unsafe { (*raw_tree).lookup(&hash, 256) } { - Some(node) => &**node as NodePtr, - None => ptr::null() - }; - node.prev = prevptr; - } - // Reconnect next pointers on the main chain - unsafe { - let mut scan = best; - while !(*scan).prev.is_null() { - let prev = (*scan).prev as *mut BlockchainNode; - (*prev).next = scan; - scan = prev as NodePtr; - } - - // Check that "genesis" is the genesis - if (*scan).bitcoin_hash() != genesis_hash { - return Err(d.error(format!("no path from tip {:x} to genesis {:x}", - best_hash, genesis_hash))); - } - } - - // Return the chain - Ok(Blockchain { - network: network, - tree: tree, - best_tip: best, - best_hash: best_hash, - genesis_hash: genesis_hash - }) - } -} - -// TODO: this should maybe be public, in which case it needs to be tagged -// with a PhantomData marker tying it to the tree's lifetime. -struct LocatorHashIter { - index: NodePtr, - count: usize, - skip: usize -} - -impl LocatorHashIter { - fn new(init: NodePtr) -> LocatorHashIter { - LocatorHashIter { index: init, count: 0, skip: 1 } - } -} - -impl Iterator for LocatorHashIter { - type Item = Sha256dHash; - - fn next(&mut self) -> Option { - if self.index.is_null() { - return None; - } - let ret = Some(unsafe { (*self.index).bitcoin_hash() }); - - // Rewind once (if we are at the genesis, this will set self.index to None) - self.index = unsafe { (*self.index).prev }; - // If we are not at the genesis, rewind `self.skip` times, or until we are. - if !self.index.is_null() { - for _ in 1..self.skip { - unsafe { - if (*self.index).prev.is_null() { - break; - } - self.index = (*self.index).prev; - } - } - } - - self.count += 1; - if self.count > 10 { - self.skip *= 2; - } - ret - } -} - -/// An iterator over blocks in blockheight order -pub struct BlockIter<'tree> { - index: NodePtr, - // Note: we don't actually touch the blockchain. But we need - // to keep it borrowed to prevent it being mutated, since some - // mutable blockchain methods call .mut_borrow() on the block - // links, which would blow up if the iterator did a regular - // borrow at the same time. - marker: marker::PhantomData<&'tree Blockchain> -} - -/// An iterator over blocks in reverse blockheight order. Note that this -/// is essentially the same as if we'd implemented `DoubleEndedIterator` -/// on `BlockIter` --- but we can't do that since if `BlockIter` is started -/// off the main chain, it will not reach the best tip, so the iterator -/// and its `.rev()` would be iterators over different chains! To avoid -/// this suprising behaviour we simply use separate iterators. -pub struct RevBlockIter<'tree> { - index: NodePtr, - // See comment in BlockIter for why we need this - marker: marker::PhantomData<&'tree Blockchain> -} - -/// An iterator over blocks in reverse blockheight order, which yielding only -/// stale blocks (ending at the point where it would've returned a block on -/// the main chain). It does this by checking if the `next` pointer of the -/// next-to-by-yielded block matches the currently-yielded block. If not, scan -/// forward from next-to-be-yielded block. If we hit the best tip, set the -/// next-to-by-yielded block to None instead. -/// -/// So to handle reorgs, you create a `RevStaleBlockIter` starting from the last -/// known block, and play it until it runs out, rewinding every block except for -/// the last one. Since the UtxoSet `rewind` function sets its `last_hash()` to -/// the prevblockhash of the rewinded block (which will be on the main chain at -/// the end of the iteration), you can then sync it up same as if you were doing -/// a plain old fast-forward. -pub struct RevStaleBlockIter<'tree> { - index: NodePtr, - chain: &'tree Blockchain -} - -impl<'tree> Iterator for BlockIter<'tree> { - type Item = &'tree BlockchainNode; - - fn next(&mut self) -> Option<&'tree BlockchainNode> { - if self.index.is_null() { - return None; - } - unsafe { - let ret = Some(&*self.index); - self.index = (*self.index).next; - ret - } - } -} - -impl<'tree> Iterator for RevBlockIter<'tree> { - type Item = &'tree BlockchainNode; - - fn next(&mut self) -> Option<&'tree BlockchainNode> { - if self.index.is_null() { - return None; - } - unsafe { - let ret = Some(&*self.index); - self.index = (*self.index).prev; - ret - } - } -} - -impl<'tree> Iterator for RevStaleBlockIter<'tree> { - type Item = &'tree Block; - - fn next(&mut self) -> Option<&'tree Block> { - if self.index.is_null() { - return None; - } - - unsafe { - let ret = Some(&(*self.index).block); - let next_index = (*self.index).prev; - // Check if the next block is going to be on the main chain - if !next_index.is_null() && - (*next_index).next != self.index && - (&*next_index).is_on_main_chain(self.chain) { - self.index = ptr::null(); - } else { - self.index = next_index; - } - ret - } - } -} - -/// This function emulates the GetCompact(SetCompact(n)) in the satoshi code, -/// which drops the precision to something that can be encoded precisely in -/// the nBits block header field. Savour the perversity. This is in Bitcoin -/// consensus code. What. Gaah! -fn satoshi_the_precision(n: Uint256) -> Uint256 { - // Shift by B bits right then left to turn the low bits to zero - let bits = 8 * ((n.bits() + 7) / 8 - 3); - let mut ret = n >> bits; - // Oh, did I say B was that fucked up formula? I meant sometimes also + 8. - if ret.bit(23) { - ret = (ret >> 8) << 8; - } - ret << bits -} - -impl Blockchain { - /// Constructs a new blockchain - pub fn new(network: Network) -> Blockchain { - let genesis = genesis_block(network); - let genhash = genesis.header.bitcoin_hash(); - let new_node = Box::new(BlockchainNode { - total_work: Zero::zero(), - required_difficulty: genesis.header.target(), - block: genesis, - height: 0, - has_txdata: true, - prev: ptr::null(), - next: ptr::null() - }); - let raw_ptr = &*new_node as NodePtr; - Blockchain { - network: network, - tree: { - let mut pat = PatriciaTree::new(); - pat.insert(&genhash.into_le(), 256, new_node); - pat - }, - best_hash: genhash, - genesis_hash: genhash, - best_tip: raw_ptr - } - } - - fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec, has_txdata: bool) -> Result<(), util::Error> { - match self.tree.lookup_mut(hash, 256) { - Some(mut existing_block) => { - existing_block.block.txdata.clone_from(&txdata); - existing_block.has_txdata = has_txdata; - Ok(()) - }, - None => Err(BlockNotFound) - } - } - - /// Looks up a block in the chain and returns the BlockchainNode containing it - pub fn get_block(&self, hash: Sha256dHash) -> Option<&BlockchainNode> { - self.tree.lookup(&hash.into_le(), 256).map(|node| &**node) - } - - /// Locates a block in the chain and overwrites its txdata - pub fn add_txdata(&mut self, block: Block) -> Result<(), util::Error> { - self.replace_txdata(&block.header.bitcoin_hash().into_le(), block.txdata, true) - } - - /// Locates a block in the chain and removes its txdata - pub fn remove_txdata(&mut self, hash: Sha256dHash) -> Result<(), util::Error> { - self.replace_txdata(&hash.into_le(), vec![], false) - } - - /// Adds a block header to the chain - pub fn add_header(&mut self, header: BlockHeader) -> Result<(), util::Error> { - self.real_add_block(Block { header: header, txdata: vec![] }, false) - } - - /// Adds a block to the chain - pub fn add_block(&mut self, block: Block) -> Result<(), util::Error> { - self.real_add_block(block, true) - } - - 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 - #[inline] - fn get_prev(chain: &Blockchain, hash: Sha256dHash) -> Option { - if hash == chain.best_hash { - Some(chain.best_tip) - } else { - chain.tree.lookup(&hash.into_le(), 256).map(|boxptr| &**boxptr as NodePtr) - } - } - // Check for multiple inserts (bitcoind from c9a09183 to 3c85d2ec doesn't - // handle locator hashes properly and may return blocks multiple times, - // and this may also happen in case of a reorg. - if self.tree.lookup(&block.header.bitcoin_hash().into_le(), 256).is_some() { - return Err(DuplicateHash); - } - // Construct node, if possible - let new_block = match get_prev(self, block.header.prev_blockhash) { - Some(prev) => { - let difficulty = - // Compute required difficulty if this is a diffchange block - if (unsafe { (*prev).height } + 1) % DIFFCHANGE_INTERVAL == 0 { - let timespan = unsafe { - // Scan back DIFFCHANGE_INTERVAL blocks - let mut scan = prev; - for _ in 0..(DIFFCHANGE_INTERVAL - 1) { - scan = (*scan).prev; - } - // Get clamped timespan between first and last blocks - match (*prev).block.header.time - (*scan).block.header.time { - n if n < DIFFCHANGE_TIMESPAN / 4 => DIFFCHANGE_TIMESPAN / 4, - n if n > DIFFCHANGE_TIMESPAN * 4 => DIFFCHANGE_TIMESPAN * 4, - n => n - } - }; - // Compute new target - let mut target = unsafe { (*prev).block.header.target() }; - target = target.mul_u32(timespan); - target = target / FromPrimitive::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap(); - // Clamp below MAX_TARGET (difficulty 1) - let max = max_target(self.network); - if target > max { target = max }; - // Compactify (make expressible in the 8+24 nBits float format - satoshi_the_precision(target) - // On non-diffchange blocks, Testnet has a rule that any 20-minute-long - // block intervals result the difficulty - } else if self.network == Network::Testnet && - block.header.time > unsafe { (*prev).block.header.time } + 2*TARGET_BLOCK_SPACING { - max_target(self.network) - // On the other hand, if we are in Testnet and the block interval is less - // than 20 minutes, we need to scan backward to find a block for which the - // previous rule did not apply, to find the "real" difficulty. - } else if self.network == Network::Testnet { - // Scan back DIFFCHANGE_INTERVAL blocks - unsafe { - let mut scan = prev; - while (*scan).height % DIFFCHANGE_INTERVAL != 0 && - (*scan).required_difficulty == max_target(self.network) { - scan = (*scan).prev; - } - (*scan).required_difficulty - } - // Otherwise just use the last block's difficulty - } else { - unsafe { (*prev).required_difficulty } - }; - // Create node - let ret = Box::new(BlockchainNode { - total_work: block.header.work() + unsafe { (*prev).total_work }, - block: block, - required_difficulty: difficulty, - height: unsafe { (*prev).height + 1 }, - has_txdata: has_txdata, - prev: prev, - next: ptr::null() - }); - unsafe { - let prev = prev as *mut BlockchainNode; - (*prev).next = &*ret as NodePtr; - } - ret - }, - None => { - return Err(PrevHashNotFound); - } - }; - - // spv validate the block - try!(new_block.block.header.spv_validate(&new_block.required_difficulty)); - - // Insert the new block - let raw_ptr = &*new_block as NodePtr; - self.tree.insert(&new_block.block.header.bitcoin_hash().into_le(), 256, new_block); - // Replace the best tip if necessary - if unsafe { (*raw_ptr).total_work > (*self.best_tip).total_work } { - self.set_best_tip(raw_ptr); - } - Ok(()) - } - - /// Sets the best tip (not public) - fn set_best_tip(&mut self, tip: NodePtr) { - // Fix next links - unsafe { - let mut scan = self.best_tip; - // Scan backward - while !(*scan).prev.is_null() { - // If we hit the old best, there is no need to reorg. - if scan == self.best_tip { break; } - // Otherwise set the next-ptr and carry on - let prev = (*scan).prev as *mut BlockchainNode; - (*prev).next = scan; - scan = (*scan).prev; - } - } - // Set best - self.best_hash = unsafe { (*tip).bitcoin_hash() }; - self.best_tip = tip; - } - - /// Returns the genesis block's blockhash - pub fn genesis_hash(&self) -> Sha256dHash { - self.genesis_hash - } - - /// Returns the best tip - pub fn best_tip(&self) -> &Block { - unsafe { &(*self.best_tip).block } - } - - /// Returns the best tip's blockhash - pub fn best_tip_hash(&self) -> Sha256dHash { - self.best_hash - } - - /// Returns an array of locator hashes used in `getheaders` messages - pub fn locator_hashes(&self) -> Vec { - LocatorHashIter::new(self.best_tip).collect() - } - - /// An iterator over all blocks in the chain starting from `start_hash` - pub fn iter(&self, start_hash: Sha256dHash) -> BlockIter { - let start = match self.tree.lookup(&start_hash.into_le(), 256) { - Some(boxptr) => &**boxptr as NodePtr, - None => ptr::null() - }; - BlockIter { - index: start, - marker: marker::PhantomData - } - } - - /// An iterator over all blocks in reverse order to the genesis, starting with `start_hash` - pub fn rev_iter(&self, start_hash: Sha256dHash) -> RevBlockIter { - let start = match self.tree.lookup(&start_hash.into_le(), 256) { - Some(boxptr) => &**boxptr as NodePtr, - None => ptr::null() - }; - RevBlockIter { - index: start, - marker: marker::PhantomData - } - } - - /// An iterator over all blocks -not- in the best chain, in reverse order, starting from `start_hash` - pub fn rev_stale_iter(&self, start_hash: Sha256dHash) -> RevStaleBlockIter { - let start = match self.tree.lookup(&start_hash.into_le(), 256) { - Some(boxptr) => { - // If we are already on the main chain, we have a dead iterator - if boxptr.is_on_main_chain(self) { - ptr::null() - } else { - &**boxptr as NodePtr - } - } - None => ptr::null() - }; - RevStaleBlockIter { - index: start, - chain: self - } - } -} - -#[cfg(test)] -mod tests { - use blockdata::blockchain::Blockchain; - use blockdata::constants::genesis_block; - use network::constants::Network::Bitcoin; - use network::serialize::{BitcoinHash, deserialize, serialize}; - - #[test] - fn blockchain_serialize_test() { - let empty_chain = Blockchain::new(Bitcoin); - assert_eq!(empty_chain.best_tip().header.bitcoin_hash(), - genesis_block(Bitcoin).header.bitcoin_hash()); - - let serial = serialize(&empty_chain); - let deserial: Result = deserialize(&serial.unwrap()); - - assert!(deserial.is_ok()); - let read_chain = deserial.unwrap(); - assert_eq!(read_chain.best_tip().header.bitcoin_hash(), - genesis_block(Bitcoin).header.bitcoin_hash()); - } -} - - - diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs deleted file mode 100644 index b97a4d4..0000000 --- a/bitcoin/src/blockdata/constants.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// 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 . -// - -//! # Blockdata constants -//! -//! This module provides various constants relating to the blockchain and -//! consensus code. In particular, it defines the genesis block and its -//! single transaction -//! - -use std::default::Default; -use num::FromPrimitive; - -use blockdata::opcodes; -use blockdata::script; -use blockdata::transaction::{Transaction, TxOut, TxIn}; -use blockdata::block::{Block, BlockHeader}; -use network::constants::Network; -use util::misc::hex_bytes; -use util::hash::MerkleRoot; -use util::uint::Uint256; - -/// The maximum allowable sequence number -pub static MAX_SEQUENCE: u32 = 0xFFFFFFFF; -/// How many satoshis are in "one bitcoin" -pub static COIN_VALUE: u64 = 100_000_000; -/// How many seconds between blocks we expect on average -pub static TARGET_BLOCK_SPACING: u32 = 600; -/// How many blocks between diffchanges -pub static DIFFCHANGE_INTERVAL: u32 = 2016; -/// How much time on average should occur between diffchanges -pub static DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600; - -/// In Bitcoind this is insanely described as ~((u256)0 >> 32) -pub fn max_target(_: Network) -> Uint256 { - ::from_u64(0xFFFF).unwrap() << 208 -} - -/// The maximum value allowed in an output (useful for sanity checking, -/// since keeping everything below this value should prevent overflows -/// if you are doing anything remotely sane with monetary values). -pub fn max_money(_: Network) -> u64 { - 21_000_000 * COIN_VALUE -} - -/// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block -fn bitcoin_genesis_tx() -> Transaction { - // Base - let mut ret = Transaction { - version: 1, - lock_time: 0, - input: vec![], - output: vec![] - }; - - // Inputs - let in_script = script::Builder::new().push_scriptint(486604799) - .push_scriptint(4) - .push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks") - .into_script(); - ret.input.push(TxIn { - prev_hash: Default::default(), - prev_index: 0xFFFFFFFF, - script_sig: in_script, - sequence: MAX_SEQUENCE - }); - - // Outputs - let out_script = script::Builder::new() - .push_slice(&hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap()) - .push_opcode(opcodes::All::OP_CHECKSIG) - .into_script(); - ret.output.push(TxOut { - value: 50 * COIN_VALUE, - script_pubkey: out_script - }); - - // end - ret -} - -/// Constructs and returns the genesis block -pub fn genesis_block(network: Network) -> Block { - match network { - Network::Bitcoin => { - let txdata = vec![bitcoin_genesis_tx()]; - Block { - header: BlockHeader { - version: 1, - prev_blockhash: Default::default(), - merkle_root: txdata.merkle_root(), - time: 1231006505, - bits: 0x1d00ffff, - nonce: 2083236893 - }, - txdata: txdata - } - } - Network::Testnet => { - let txdata = vec![bitcoin_genesis_tx()]; - Block { - header: BlockHeader { - version: 1, - prev_blockhash: Default::default(), - merkle_root: txdata.merkle_root(), - time: 1296688602, - bits: 0x1d00ffff, - nonce: 414098458 - }, - txdata: txdata - } - } - } -} - -#[cfg(test)] -mod test { - use std::default::Default; - use serialize::hex::FromHex; - - use network::constants::Network; - use network::serialize::{BitcoinHash, serialize}; - use blockdata::constants::{genesis_block, bitcoin_genesis_tx}; - use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE}; - - #[test] - fn bitcoin_genesis_first_transaction() { - let gen = bitcoin_genesis_tx(); - - assert_eq!(gen.version, 1); - assert_eq!(gen.input.len(), 1); - assert_eq!(gen.input[0].prev_hash, Default::default()); - assert_eq!(gen.input[0].prev_index, 0xFFFFFFFF); - assert_eq!(serialize(&gen.input[0].script_sig).ok(), - Some("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73".from_hex().unwrap())); - - assert_eq!(gen.input[0].sequence, MAX_SEQUENCE); - assert_eq!(gen.output.len(), 1); - assert_eq!(serialize(&gen.output[0].script_pubkey).ok(), - Some("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac".from_hex().unwrap())); - assert_eq!(gen.output[0].value, 50 * COIN_VALUE); - assert_eq!(gen.lock_time, 0); - - assert_eq!(gen.bitcoin_hash().be_hex_string(), - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); - } - - #[test] - fn bitcoin_genesis_full_block() { - let gen = genesis_block(Network::Bitcoin); - - assert_eq!(gen.header.version, 1); - assert_eq!(gen.header.prev_blockhash, Default::default()); - assert_eq!(gen.header.merkle_root.be_hex_string(), - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); - assert_eq!(gen.header.time, 1231006505); - assert_eq!(gen.header.bits, 0x1d00ffff); - assert_eq!(gen.header.nonce, 2083236893); - assert_eq!(gen.header.bitcoin_hash().be_hex_string(), - "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string()); - } - - #[test] - fn testnet_genesis_full_block() { - let gen = genesis_block(Network::Testnet); - assert_eq!(gen.header.version, 1); - assert_eq!(gen.header.prev_blockhash, Default::default()); - assert_eq!(gen.header.merkle_root.be_hex_string(), - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); - assert_eq!(gen.header.time, 1296688602); - assert_eq!(gen.header.bits, 0x1d00ffff); - assert_eq!(gen.header.nonce, 414098458); - assert_eq!(gen.header.bitcoin_hash().be_hex_string(), - "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string()); - } -} - diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs deleted file mode 100644 index 1d2871e..0000000 --- a/bitcoin/src/blockdata/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// 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 . -// - -//! # Blockdata -//! -//! This module defines structions and functions for storing the blocks and -//! transactions which make up the Bitcoin system. -//! - -pub mod constants; -pub mod opcodes; -pub mod script; -pub mod transaction; -pub mod block; -pub mod blockchain; - - diff --git a/bitcoin/src/blockdata/opcodes.rs b/bitcoin/src/blockdata/opcodes.rs deleted file mode 100644 index 73f5f7b..0000000 --- a/bitcoin/src/blockdata/opcodes.rs +++ /dev/null @@ -1,699 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// 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 . -// - -//! # Opcodes -//! -//! Bitcoin's script uses a stack-based assembly language. This module defines -//! all of the opcodes -//! - -#![allow(non_camel_case_types)] - -use serde; - -// Heavy stick to translate between opcode types -use std::mem::transmute; - -use network::serialize::{SimpleDecoder, SimpleEncoder}; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; - -// Note: I am deliberately not implementing PartialOrd or Ord on the -// opcode enum. If you want to check ranges of opcodes, etc., -// write an #[inline] helper function which casts to u8s. - -/// A script Opcode -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[repr(u8)] -pub enum All { - /// Push an empty array onto the stack - OP_PUSHBYTES_0 = 0x0, - /// Push the next byte as an array onto the stack - OP_PUSHBYTES_1 = 0x01, - /// Push the next 2 bytes as an array onto the stack - OP_PUSHBYTES_2 = 0x02, - /// Push the next 2 bytes as an array onto the stack - OP_PUSHBYTES_3 = 0x03, - /// Push the next 4 bytes as an array onto the stack - OP_PUSHBYTES_4 = 0x04, - /// Push the next 5 bytes as an array onto the stack - OP_PUSHBYTES_5 = 0x05, - /// Push the next 6 bytes as an array onto the stack - OP_PUSHBYTES_6 = 0x06, - /// Push the next 7 bytes as an array onto the stack - OP_PUSHBYTES_7 = 0x07, - /// Push the next 8 bytes as an array onto the stack - OP_PUSHBYTES_8 = 0x08, - /// Push the next 9 bytes as an array onto the stack - OP_PUSHBYTES_9 = 0x09, - /// Push the next 10 bytes as an array onto the stack - OP_PUSHBYTES_10 = 0x0a, - /// Push the next 11 bytes as an array onto the stack - OP_PUSHBYTES_11 = 0x0b, - /// Push the next 12 bytes as an array onto the stack - OP_PUSHBYTES_12 = 0x0c, - /// Push the next 13 bytes as an array onto the stack - OP_PUSHBYTES_13 = 0x0d, - /// Push the next 14 bytes as an array onto the stack - OP_PUSHBYTES_14 = 0x0e, - /// Push the next 15 bytes as an array onto the stack - OP_PUSHBYTES_15 = 0x0f, - /// Push the next 16 bytes as an array onto the stack - OP_PUSHBYTES_16 = 0x10, - /// Push the next 17 bytes as an array onto the stack - OP_PUSHBYTES_17 = 0x11, - /// Push the next 18 bytes as an array onto the stack - OP_PUSHBYTES_18 = 0x12, - /// Push the next 19 bytes as an array onto the stack - OP_PUSHBYTES_19 = 0x13, - /// Push the next 20 bytes as an array onto the stack - OP_PUSHBYTES_20 = 0x14, - /// Push the next 21 bytes as an array onto the stack - OP_PUSHBYTES_21 = 0x15, - /// Push the next 22 bytes as an array onto the stack - OP_PUSHBYTES_22 = 0x16, - /// Push the next 23 bytes as an array onto the stack - OP_PUSHBYTES_23 = 0x17, - /// Push the next 24 bytes as an array onto the stack - OP_PUSHBYTES_24 = 0x18, - /// Push the next 25 bytes as an array onto the stack - OP_PUSHBYTES_25 = 0x19, - /// Push the next 26 bytes as an array onto the stack - OP_PUSHBYTES_26 = 0x1a, - /// Push the next 27 bytes as an array onto the stack - OP_PUSHBYTES_27 = 0x1b, - /// Push the next 28 bytes as an array onto the stack - OP_PUSHBYTES_28 = 0x1c, - /// Push the next 29 bytes as an array onto the stack - OP_PUSHBYTES_29 = 0x1d, - /// Push the next 30 bytes as an array onto the stack - OP_PUSHBYTES_30 = 0x1e, - /// Push the next 31 bytes as an array onto the stack - OP_PUSHBYTES_31 = 0x1f, - /// Push the next 32 bytes as an array onto the stack - OP_PUSHBYTES_32 = 0x20, - /// Push the next 33 bytes as an array onto the stack - OP_PUSHBYTES_33 = 0x21, - /// Push the next 34 bytes as an array onto the stack - OP_PUSHBYTES_34 = 0x22, - /// Push the next 35 bytes as an array onto the stack - OP_PUSHBYTES_35 = 0x23, - /// Push the next 36 bytes as an array onto the stack - OP_PUSHBYTES_36 = 0x24, - /// Push the next 37 bytes as an array onto the stack - OP_PUSHBYTES_37 = 0x25, - /// Push the next 38 bytes as an array onto the stack - OP_PUSHBYTES_38 = 0x26, - /// Push the next 39 bytes as an array onto the stack - OP_PUSHBYTES_39 = 0x27, - /// Push the next 40 bytes as an array onto the stack - OP_PUSHBYTES_40 = 0x28, - /// Push the next 41 bytes as an array onto the stack - OP_PUSHBYTES_41 = 0x29, - /// Push the next 42 bytes as an array onto the stack - OP_PUSHBYTES_42 = 0x2a, - /// Push the next 43 bytes as an array onto the stack - OP_PUSHBYTES_43 = 0x2b, - /// Push the next 44 bytes as an array onto the stack - OP_PUSHBYTES_44 = 0x2c, - /// Push the next 45 bytes as an array onto the stack - OP_PUSHBYTES_45 = 0x2d, - /// Push the next 46 bytes as an array onto the stack - OP_PUSHBYTES_46 = 0x2e, - /// Push the next 47 bytes as an array onto the stack - OP_PUSHBYTES_47 = 0x2f, - /// Push the next 48 bytes as an array onto the stack - OP_PUSHBYTES_48 = 0x30, - /// Push the next 49 bytes as an array onto the stack - OP_PUSHBYTES_49 = 0x31, - /// Push the next 50 bytes as an array onto the stack - OP_PUSHBYTES_50 = 0x32, - /// Push the next 51 bytes as an array onto the stack - OP_PUSHBYTES_51 = 0x33, - /// Push the next 52 bytes as an array onto the stack - OP_PUSHBYTES_52 = 0x34, - /// Push the next 53 bytes as an array onto the stack - OP_PUSHBYTES_53 = 0x35, - /// Push the next 54 bytes as an array onto the stack - OP_PUSHBYTES_54 = 0x36, - /// Push the next 55 bytes as an array onto the stack - OP_PUSHBYTES_55 = 0x37, - /// Push the next 56 bytes as an array onto the stack - OP_PUSHBYTES_56 = 0x38, - /// Push the next 57 bytes as an array onto the stack - OP_PUSHBYTES_57 = 0x39, - /// Push the next 58 bytes as an array onto the stack - OP_PUSHBYTES_58 = 0x3a, - /// Push the next 59 bytes as an array onto the stack - OP_PUSHBYTES_59 = 0x3b, - /// Push the next 60 bytes as an array onto the stack - OP_PUSHBYTES_60 = 0x3c, - /// Push the next 61 bytes as an array onto the stack - OP_PUSHBYTES_61 = 0x3d, - /// Push the next 62 bytes as an array onto the stack - OP_PUSHBYTES_62 = 0x3e, - /// Push the next 63 bytes as an array onto the stack - OP_PUSHBYTES_63 = 0x3f, - /// Push the next 64 bytes as an array onto the stack - OP_PUSHBYTES_64 = 0x40, - /// Push the next 65 bytes as an array onto the stack - OP_PUSHBYTES_65 = 0x41, - /// Push the next 66 bytes as an array onto the stack - OP_PUSHBYTES_66 = 0x42, - /// Push the next 67 bytes as an array onto the stack - OP_PUSHBYTES_67 = 0x43, - /// Push the next 68 bytes as an array onto the stack - OP_PUSHBYTES_68 = 0x44, - /// Push the next 69 bytes as an array onto the stack - OP_PUSHBYTES_69 = 0x45, - /// Push the next 70 bytes as an array onto the stack - OP_PUSHBYTES_70 = 0x46, - /// Push the next 71 bytes as an array onto the stack - OP_PUSHBYTES_71 = 0x47, - /// Push the next 72 bytes as an array onto the stack - OP_PUSHBYTES_72 = 0x48, - /// Push the next 73 bytes as an array onto the stack - OP_PUSHBYTES_73 = 0x49, - /// Push the next 74 bytes as an array onto the stack - OP_PUSHBYTES_74 = 0x4a, - /// Push the next 75 bytes as an array onto the stack - OP_PUSHBYTES_75 = 0x4b, - /// Read the next byte as N; push the next N bytes as an array onto the stack - OP_PUSHDATA1 = 0x4c, - /// Read the next 2 bytes as N; push the next N bytes as an array onto the stack - OP_PUSHDATA2 = 0x4d, - /// Read the next 4 bytes as N; push the next N bytes as an array onto the stack - OP_PUSHDATA4 = 0x4e, - /// Push the array [0x80] onto the stack - OP_PUSHNUM_NEG1 = 0x4f, - /// Synonym for OP_RETURN - OP_RESERVED = 0x50, - /// Push the array [0x01] onto the stack - OP_PUSHNUM_1 = 0x51, - /// Push the array [0x02] onto the stack - OP_PUSHNUM_2 = 0x52, - /// Push the array [0x03] onto the stack - OP_PUSHNUM_3 = 0x53, - /// Push the array [0x04] onto the stack - OP_PUSHNUM_4 = 0x54, - /// Push the array [0x05] onto the stack - OP_PUSHNUM_5 = 0x55, - /// Push the array [0x06] onto the stack - OP_PUSHNUM_6 = 0x56, - /// Push the array [0x07] onto the stack - OP_PUSHNUM_7 = 0x57, - /// Push the array [0x08] onto the stack - OP_PUSHNUM_8 = 0x58, - /// Push the array [0x09] onto the stack - OP_PUSHNUM_9 = 0x59, - /// Push the array [0x0a] onto the stack - OP_PUSHNUM_10 = 0x5a, - /// Push the array [0x0b] onto the stack - OP_PUSHNUM_11 = 0x5b, - /// Push the array [0x0c] onto the stack - OP_PUSHNUM_12 = 0x5c, - /// Push the array [0x0d] onto the stack - OP_PUSHNUM_13 = 0x5d, - /// Push the array [0x0e] onto the stack - OP_PUSHNUM_14 = 0x5e, - /// Push the array [0x0f] onto the stack - OP_PUSHNUM_15 = 0x5f, - /// Push the array [0x10] onto the stack - OP_PUSHNUM_16 = 0x60, - /// Does nothing - OP_NOP = 0x61, - /// Synonym for OP_RETURN - OP_VER = 0x62, - /// Pop and execute the next statements if a nonzero element was popped - OP_IF = 0x63, - /// Pop and execute the next statements if a zero element was popped - OP_NOTIF = 0x64, - /// Fail the script unconditionally, does not even need to be executed - OP_VERIF = 0x65, - /// Fail the script unconditionally, does not even need to be executed - OP_VERNOTIF = 0x66, - /// Execute statements if those after the previous OP_IF were not, and vice-versa. - /// If there is no previous OP_IF, this acts as a RETURN. - OP_ELSE = 0x67, - /// Pop and execute the next statements if a zero element was popped - OP_ENDIF = 0x68, - /// If the top value is zero or the stack is empty, fail; otherwise, pop the stack - OP_VERIFY = 0x69, - /// Fail the script immediately. (Must be executed.) - OP_RETURN = 0x6a, - /// Pop one element from the main stack onto the alt stack - OP_TOALTSTACK = 0x6b, - /// Pop one element from the alt stack onto the main stack - OP_FROMALTSTACK = 0x6c, - /// Drops the top two stack items - OP_2DROP = 0x6d, - /// Duplicates the top two stack items as AB -> ABAB - OP_2DUP = 0x6e, - /// Duplicates the two three stack items as ABC -> ABCABC - OP_3DUP = 0x6f, - /// Copies the two stack items of items two spaces back to - /// the front, as xxAB -> ABxxAB - OP_2OVER = 0x70, - /// Moves the two stack items four spaces back to the front, - /// as xxxxAB -> ABxxxx - OP_2ROT = 0x71, - /// Swaps the top two pairs, as ABCD -> CDAB - OP_2SWAP = 0x72, - /// Duplicate the top stack element unless it is zero - OP_IFDUP = 0x73, - /// Push the current number of stack items onto te stack - OP_DEPTH = 0x74, - /// Drops the top stack item - OP_DROP = 0x75, - /// Duplicates the top stack item - OP_DUP = 0x76, - /// Drops the second-to-top stack item - OP_NIP = 0x77, - /// Copies the second-to-top stack item, as xA -> AxA - OP_OVER = 0x78, - /// Pop the top stack element as N. Copy the Nth stack element to the top - OP_PICK = 0x79, - /// Pop the top stack element as N. Move the Nth stack element to the top - OP_ROLL = 0x7a, - /// Rotate the top three stack items, as [top next1 next2] -> [next2 top next1] - OP_ROT = 0x7b, - /// Swap the top two stack items - OP_SWAP = 0x7c, - /// Copy the top stack item to before the second item, as [top next] -> [top next top] - OP_TUCK = 0x7d, - /// Fail the script unconditionally, does not even need to be executed - OP_CAT = 0x7e, - /// Fail the script unconditionally, does not even need to be executed - OP_SUBSTR = 0x7f, - /// Fail the script unconditionally, does not even need to be executed - OP_LEFT = 0x80, - /// Fail the script unconditionally, does not even need to be executed - OP_RIGHT = 0x81, - /// Pushes the length of the top stack item onto the stack - OP_SIZE = 0x82, - /// Fail the script unconditionally, does not even need to be executed - OP_INVERT = 0x83, - /// Fail the script unconditionally, does not even need to be executed - OP_AND = 0x84, - /// Fail the script unconditionally, does not even need to be executed - OP_OR = 0x85, - /// Fail the script unconditionally, does not even need to be executed - OP_XOR = 0x86, - /// Pushes 1 if the inputs are exactly equal, 0 otherwise - OP_EQUAL = 0x87, - /// Returns success if the inputs are exactly equal, failure otherwise - OP_EQUALVERIFY = 0x88, - /// Synonym for OP_RETURN - OP_RESERVED1 = 0x89, - /// Synonym for OP_RETURN - OP_RESERVED2 = 0x8a, - /// Increment the top stack element in place - OP_1ADD = 0x8b, - /// Decrement the top stack element in place - OP_1SUB = 0x8c, - /// Fail the script unconditionally, does not even need to be executed - OP_2MUL = 0x8d, - /// Fail the script unconditionally, does not even need to be executed - OP_2DIV = 0x8e, - /// Multiply the top stack item by -1 in place - OP_NEGATE = 0x8f, - /// Absolute value the top stack item in place - OP_ABS = 0x90, - /// Map 0 to 1 and everything else to 0, in place - OP_NOT = 0x91, - /// Map 0 to 0 and everything else to 1, in place - OP_0NOTEQUAL = 0x92, - /// Pop two stack items and push their sum - OP_ADD = 0x93, - /// Pop two stack items and push the second minus the top - OP_SUB = 0x94, - /// Fail the script unconditionally, does not even need to be executed - OP_MUL = 0x95, - /// Fail the script unconditionally, does not even need to be executed - OP_DIV = 0x96, - /// Fail the script unconditionally, does not even need to be executed - OP_MOD = 0x97, - /// Fail the script unconditionally, does not even need to be executed - OP_LSHIFT = 0x98, - /// Fail the script unconditionally, does not even need to be executed - OP_RSHIFT = 0x99, - /// Pop the top two stack items and push 1 if both are nonzero, else push 0 - OP_BOOLAND = 0x9a, - /// Pop the top two stack items and push 1 if either is nonzero, else push 0 - OP_BOOLOR = 0x9b, - /// Pop the top two stack items and push 1 if both are numerically equal, else push 0 - OP_NUMEQUAL = 0x9c, - /// Pop the top two stack items and return success if both are numerically equal, else return failure - OP_NUMEQUALVERIFY = 0x9d, - /// Pop the top two stack items and push 0 if both are numerically equal, else push 1 - OP_NUMNOTEQUAL = 0x9e, - /// Pop the top two items; push 1 if the second is less than the top, 0 otherwise - OP_LESSTHAN = 0x9f, - /// Pop the top two items; push 1 if the second is greater than the top, 0 otherwise - OP_GREATERTHAN = 0xa0, - /// Pop the top two items; push 1 if the second is <= the top, 0 otherwise - OP_LESSTHANOREQUAL = 0xa1, - /// Pop the top two items; push 1 if the second is >= the top, 0 otherwise - OP_GREATERTHANOREQUAL = 0xa2, - /// Pop the top two items; push the smaller - OP_MIN = 0xa3, - /// Pop the top two items; push the larger - OP_MAX = 0xa4, - /// Pop the top three items; if the top is >= the second and < the third, push 1, otherwise push 0 - OP_WITHIN = 0xa5, - /// Pop the top stack item and push its RIPEMD160 hash - OP_RIPEMD160 = 0xa6, - /// Pop the top stack item and push its SHA1 hash - OP_SHA1 = 0xa7, - /// Pop the top stack item and push its SHA256 hash - OP_SHA256 = 0xa8, - /// Pop the top stack item and push its RIPEMD(SHA256) hash - OP_HASH160 = 0xa9, - /// Pop the top stack item and push its SHA256(SHA256) hash - OP_HASH256 = 0xaa, - /// Ignore this and everything preceding when deciding what to sign when signature-checking - OP_CODESEPARATOR = 0xab, - /// https://en.bitcoin.it/wiki/OP_CHECKSIG pushing 1/0 for success/failure - OP_CHECKSIG = 0xac, - /// https://en.bitcoin.it/wiki/OP_CHECKSIG returning success/failure - OP_CHECKSIGVERIFY = 0xad, - /// Pop N, N pubkeys, M, M signatures, a dummy (due to bug in reference code), and verify that all M signatures are valid. - /// Push 1 for "all valid", 0 otherwise - OP_CHECKMULTISIG = 0xae, - /// Like the above but return success/failure - OP_CHECKMULTISIGVERIFY = 0xaf, - /// Does nothing - OP_NOP1 = 0xb0, - /// Does nothing - OP_NOP2 = 0xb1, - /// Does nothing - OP_NOP3 = 0xb2, - /// Does nothing - OP_NOP4 = 0xb3, - /// Does nothing - OP_NOP5 = 0xb4, - /// Does nothing - OP_NOP6 = 0xb5, - /// Does nothing - OP_NOP7 = 0xb6, - /// Does nothing - OP_NOP8 = 0xb7, - /// Does nothing - OP_NOP9 = 0xb8, - /// Does nothing - OP_NOP10 = 0xb9, - // Every other opcode acts as OP_RETURN - /// Synonym for OP_RETURN - OP_RETURN_186 = 0xba, - /// Synonym for OP_RETURN - OP_RETURN_187 = 0xbb, - /// Synonym for OP_RETURN - OP_RETURN_188 = 0xbc, - /// Synonym for OP_RETURN - OP_RETURN_189 = 0xbd, - /// Synonym for OP_RETURN - OP_RETURN_190 = 0xbe, - /// Synonym for OP_RETURN - OP_RETURN_191 = 0xbf, - /// Synonym for OP_RETURN - OP_RETURN_192 = 0xc0, - /// Synonym for OP_RETURN - OP_RETURN_193 = 0xc1, - /// Synonym for OP_RETURN - OP_RETURN_194 = 0xc2, - /// Synonym for OP_RETURN - OP_RETURN_195 = 0xc3, - /// Synonym for OP_RETURN - OP_RETURN_196 = 0xc4, - /// Synonym for OP_RETURN - OP_RETURN_197 = 0xc5, - /// Synonym for OP_RETURN - OP_RETURN_198 = 0xc6, - /// Synonym for OP_RETURN - OP_RETURN_199 = 0xc7, - /// Synonym for OP_RETURN - OP_RETURN_200 = 0xc8, - /// Synonym for OP_RETURN - OP_RETURN_201 = 0xc9, - /// Synonym for OP_RETURN - OP_RETURN_202 = 0xca, - /// Synonym for OP_RETURN - OP_RETURN_203 = 0xcb, - /// Synonym for OP_RETURN - OP_RETURN_204 = 0xcc, - /// Synonym for OP_RETURN - OP_RETURN_205 = 0xcd, - /// Synonym for OP_RETURN - OP_RETURN_206 = 0xce, - /// Synonym for OP_RETURN - OP_RETURN_207 = 0xcf, - /// Synonym for OP_RETURN - OP_RETURN_208 = 0xd0, - /// Synonym for OP_RETURN - OP_RETURN_209 = 0xd1, - /// Synonym for OP_RETURN - OP_RETURN_210 = 0xd2, - /// Synonym for OP_RETURN - OP_RETURN_211 = 0xd3, - /// Synonym for OP_RETURN - OP_RETURN_212 = 0xd4, - /// Synonym for OP_RETURN - OP_RETURN_213 = 0xd5, - /// Synonym for OP_RETURN - OP_RETURN_214 = 0xd6, - /// Synonym for OP_RETURN - OP_RETURN_215 = 0xd7, - /// Synonym for OP_RETURN - OP_RETURN_216 = 0xd8, - /// Synonym for OP_RETURN - OP_RETURN_217 = 0xd9, - /// Synonym for OP_RETURN - OP_RETURN_218 = 0xda, - /// Synonym for OP_RETURN - OP_RETURN_219 = 0xdb, - /// Synonym for OP_RETURN - OP_RETURN_220 = 0xdc, - /// Synonym for OP_RETURN - OP_RETURN_221 = 0xdd, - /// Synonym for OP_RETURN - OP_RETURN_222 = 0xde, - /// Synonym for OP_RETURN - OP_RETURN_223 = 0xdf, - /// Synonym for OP_RETURN - OP_RETURN_224 = 0xe0, - /// Synonym for OP_RETURN - OP_RETURN_225 = 0xe1, - /// Synonym for OP_RETURN - OP_RETURN_226 = 0xe2, - /// Synonym for OP_RETURN - OP_RETURN_227 = 0xe3, - /// Synonym for OP_RETURN - OP_RETURN_228 = 0xe4, - /// Synonym for OP_RETURN - OP_RETURN_229 = 0xe5, - /// Synonym for OP_RETURN - OP_RETURN_230 = 0xe6, - /// Synonym for OP_RETURN - OP_RETURN_231 = 0xe7, - /// Synonym for OP_RETURN - OP_RETURN_232 = 0xe8, - /// Synonym for OP_RETURN - OP_RETURN_233 = 0xe9, - /// Synonym for OP_RETURN - OP_RETURN_234 = 0xea, - /// Synonym for OP_RETURN - OP_RETURN_235 = 0xeb, - /// Synonym for OP_RETURN - OP_RETURN_236 = 0xec, - /// Synonym for OP_RETURN - OP_RETURN_237 = 0xed, - /// Synonym for OP_RETURN - OP_RETURN_238 = 0xee, - /// Synonym for OP_RETURN - OP_RETURN_239 = 0xef, - /// Synonym for OP_RETURN - OP_RETURN_240 = 0xf0, - /// Synonym for OP_RETURN - OP_RETURN_241 = 0xf1, - /// Synonym for OP_RETURN - OP_RETURN_242 = 0xf2, - /// Synonym for OP_RETURN - OP_RETURN_243 = 0xf3, - /// Synonym for OP_RETURN - OP_RETURN_244 = 0xf4, - /// Synonym for OP_RETURN - OP_RETURN_245 = 0xf5, - /// Synonym for OP_RETURN - OP_RETURN_246 = 0xf6, - /// Synonym for OP_RETURN - OP_RETURN_247 = 0xf7, - /// Synonym for OP_RETURN - OP_RETURN_248 = 0xf8, - /// Synonym for OP_RETURN - OP_RETURN_249 = 0xf9, - /// Synonym for OP_RETURN - OP_RETURN_250 = 0xfa, - /// Synonym for OP_RETURN - OP_RETURN_251 = 0xfb, - /// Synonym for OP_RETURN - OP_RETURN_252 = 0xfc, - /// Synonym for OP_RETURN - OP_RETURN_253 = 0xfd, - /// Synonym for OP_RETURN - OP_RETURN_254 = 0xfe, - /// Synonym for OP_RETURN - OP_RETURN_255 = 0xff, -} - -impl All { - /// Classifies an Opcode into a broad class - #[inline] - pub fn classify(&self) -> Class { - // 17 opcodes - if *self == All::OP_VERIF || *self == All::OP_VERNOTIF || - *self == All::OP_CAT || *self == All::OP_SUBSTR || - *self == All::OP_LEFT || *self == All::OP_RIGHT || - *self == All::OP_INVERT || *self == All::OP_AND || - *self == All::OP_OR || *self == All::OP_XOR || - *self == All::OP_2MUL || *self == All::OP_2DIV || - *self == All::OP_MUL || *self == All::OP_DIV || *self == All::OP_MOD || - *self == All::OP_LSHIFT || *self == All::OP_RSHIFT { - Class::IllegalOp - // 11 opcodes - } else if *self == All::OP_NOP || - (All::OP_NOP1 as u8 <= *self as u8 && - *self as u8 <= All::OP_NOP10 as u8) { - Class::NoOp - // 75 opcodes - } else if *self == All::OP_RESERVED || *self == All::OP_VER || *self == All::OP_RETURN || - *self == All::OP_RESERVED1 || *self == All::OP_RESERVED2 || - *self as u8 >= All::OP_RETURN_186 as u8 { - Class::ReturnOp - // 1 opcode - } else if *self == All::OP_PUSHNUM_NEG1 { - Class::PushNum(-1) - // 16 opcodes - } else if All::OP_PUSHNUM_1 as u8 <= *self as u8 && - *self as u8 <= All::OP_PUSHNUM_16 as u8 { - Class::PushNum(1 + *self as i32 - All::OP_PUSHNUM_1 as i32) - // 76 opcodes - } else if *self as u8 <= All::OP_PUSHBYTES_75 as u8 { - Class::PushBytes(*self as u32) - // 60 opcodes - } else { - Class::Ordinary(unsafe { transmute(*self) }) - } - } -} - -impl From for All { - #[inline] - fn from(b: u8) -> All { - unsafe { transmute(b) } - } -} - - -display_from_debug!(All); - -impl ConsensusDecodable for All { - #[inline] - fn consensus_decode(d: &mut D) -> Result { - Ok(All::from(try!(d.read_u8()))) - } -} - -impl ConsensusEncodable for All { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_u8(*self as u8) - } -} - -impl serde::Serialize for All { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> - where S: serde::Serializer, - { - serializer.visit_str(&self.to_string()) - } -} - -/// Empty stack is also FALSE -pub static OP_FALSE: All = All::OP_PUSHBYTES_0; -/// Number 1 is also TRUE -pub static OP_TRUE: All = All::OP_PUSHNUM_1; - -/// Broad categories of opcodes with similar behavior -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Class { - /// Pushes the given number onto the stack - PushNum(i32), - /// Pushes the given number of bytes onto the stack - PushBytes(u32), - /// Fails the script if executed - ReturnOp, - /// Fails the script even if not executed - IllegalOp, - /// Does nothing - NoOp, - /// Any opcode not covered above - Ordinary(Ordinary) -} - -display_from_debug!(Class); - -impl serde::Serialize for Class { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> - where S: serde::Serializer, - { - serializer.visit_str(&self.to_string()) - } -} - -macro_rules! ordinary_opcode { - ($($op:ident),*) => ( - #[repr(u8)] - #[doc(hidden)] - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub enum Ordinary { - $( $op = All::$op as u8 ),* - } - ); -} - -/// "Ordinary" opcodes -- should be 60 of these -ordinary_opcode! { - // pushdata - OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4, - // control flow - OP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, OP_VERIFY, - // stack - OP_TOALTSTACK, OP_FROMALTSTACK, - OP_2DROP, OP_2DUP, OP_3DUP, OP_2OVER, OP_2ROT, OP_2SWAP, - OP_DROP, OP_DUP, OP_NIP, OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK, - OP_IFDUP, OP_DEPTH, OP_SIZE, - // equality - OP_EQUAL, OP_EQUALVERIFY, - // arithmetic - OP_1ADD, OP_1SUB, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL, - OP_ADD, OP_SUB, OP_BOOLAND, OP_BOOLOR, - OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN, - OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL, - OP_MIN, OP_MAX, OP_WITHIN, - // crypto - OP_RIPEMD160, OP_SHA1, OP_SHA256, OP_HASH160, OP_HASH256, - OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY, - OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY -} - - diff --git a/bitcoin/src/blockdata/script.rs b/bitcoin/src/blockdata/script.rs deleted file mode 100644 index 3456be9..0000000 --- a/bitcoin/src/blockdata/script.rs +++ /dev/null @@ -1,3164 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// 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 . -// - -//! # Script -//! -//! Scripts define Bitcoin's digital signature scheme: a signature is formed -//! from a script (the second half of which is defined by a coin to be spent, -//! and the first half provided by the spending transaction), and is valid -//! iff the script leaves `TRUE` on the stack after being evaluated. -//! Bitcoin's script is a stack-based assembly language similar in spirit to -//! Forth. -//! -//! This module provides the structures and functions needed to support scripts. -//! - -use std::default::Default; -use std::{error, fmt, ops}; -use serialize::hex::ToHex; - -use crypto::digest::Digest; -use crypto::ripemd160::Ripemd160; -use crypto::sha1::Sha1; -use crypto::sha2::Sha256; -use secp256k1::{self, Secp256k1}; -use secp256k1::key::PublicKey; -use serde; - -use blockdata::opcodes; -use blockdata::transaction::{Transaction, TxIn}; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{SimpleDecoder, SimpleEncoder, serialize}; -use util::hash::Sha256dHash; -use util::misc::script_find_and_remove; - -#[derive(Clone, PartialEq, Eq, Hash)] -/// A Bitcoin script -pub struct Script(Box<[u8]>); - -impl fmt::Debug for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut index = 0; - - try!(f.write_str("Script(")); - while index < self.0.len() { - let opcode = opcodes::All::from(self.0[index]); - - let data_len = if let opcodes::Class::PushBytes(n) = opcode.classify() { - n as usize - } else { - match opcode { - opcodes::All::OP_PUSHDATA1 => { - if self.0.len() < index + 1 { - try!(f.write_str("")); - break; - } - match read_uint(&self.0[index..], 1) { - Ok(n) => { index += 1; n as usize } - Err(_) => { try!(f.write_str("")); break; } - } - } - opcodes::All::OP_PUSHDATA2 => { - if self.0.len() < index + 2 { - try!(f.write_str("")); - break; - } - match read_uint(&self.0[index..], 2) { - Ok(n) => { index += 2; n as usize } - Err(_) => { try!(f.write_str("")); break; } - } - } - opcodes::All::OP_PUSHDATA4 => { - if self.0.len() < index + 4 { - try!(f.write_str("")); - break; - } - match read_uint(&self.0[index..], 4) { - Ok(n) => { index += 4; n as usize } - Err(_) => { try!(f.write_str("")); break; } - } - } - _ => 0 - } - }; - - if index > 0 { try!(f.write_str(" ")); } - // Write the opcode - if opcode == opcodes::All::OP_PUSHBYTES_0 { - try!(f.write_str("OP_0")); - } else { - try!(write!(f, "{:?}", opcode)); - } - index += 1; - // Write any pushdata - if data_len > 0 { - try!(f.write_str(" ")); - if index + data_len < self.0.len() { - for ch in &self.0[index..index + data_len] { - try!(write!(f, "{:02x}", ch)); - } - index += data_len; - } else { - try!(f.write_str("")); - break; - } - } - } - f.write_str(")") - } -} - -impl fmt::Display for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self, f) - } -} - -impl fmt::LowerHex for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for &ch in self.0.iter() { - try!(write!(f, "{:02x}", ch)); - } - Ok(()) - } -} - -impl fmt::UpperHex for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for &ch in self.0.iter() { - try!(write!(f, "{:02X}", ch)); - } - Ok(()) - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -/// An object which can be used to construct a script piece by piece -pub struct Builder(Vec); -display_from_debug!(Builder); - -/// Ways that a script might fail. Not everything is split up as -/// much as it could be; patches welcome if more detailed errors -/// would help you. -#[derive(PartialEq, Eq, Debug, Clone)] -pub enum Error { - /// Tried to set a boolean to both values, but neither worked - AnalyzeNeitherBoolWorks, - /// Tried to set a boolean to the given value, but it already - /// had the other value - AnalyzeSetBoolMismatch(bool), - /// Validation of an element failed - AnalyzeValidateFailed, - /// OP_CHECKSIG was called with a bad public key - BadPublicKey, - /// OP_CHECKSIG was called with a bad signature - BadSignature, - /// An ECDSA error - Ecdsa(secp256k1::Error), - /// An OP_ELSE happened while not in an OP_IF tree - ElseWithoutIf, - /// An OP_ENDIF happened while not in an OP_IF tree - EndifWithoutIf, - /// An OP_EQUALVERIFY failed (expected, gotten) - EqualVerifyFailed(String, String), - /// An OP_IF happened with an empty stack - IfEmptyStack, - /// An illegal opcode appeared in the script (does not need to be executed) - IllegalOpcode, - /// The interpreter overflowed its stack. This never happens for - /// script evaluation, only non-consensus analysis passes. - InterpreterStackOverflow, - /// Some opcode expected a parameter, but it was missing or truncated - EarlyEndOfScript, - /// An OP_RETURN or synonym was executed - ExecutedReturn, - /// A multisig tx with negative or too many keys - MultisigBadKeyCount(isize), - /// A multisig tx with negative or too many signatures - MultisigBadSigCount(isize), - /// Used OP_PICK with a negative index - NegativePick, - /// Used OP_ROLL with a negative index - NegativeRoll, - /// Tried to execute a signature operation but no transaction context was provided - NoTransaction, - /// An OP_NUMEQUALVERIFY failed (expected, gotten) - NumEqualVerifyFailed(i64, i64), - /// Tried to read an array off the stack as a number when it was more than 4 bytes - NumericOverflow, - /// Some stack operation was done with an empty stack - PopEmptyStack, - /// Analysis was unable to determine script input - Unanalyzable, - /// Analysis showed script cannot be satisfied - Unsatisfiable, - /// An OP_VERIFY happened with an empty stack - VerifyEmptyStack, - /// An OP_VERIFY happened with zero on the stack - VerifyFailed, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Ecdsa(ref e) => fmt::Display::fmt(e, f), - Error::EqualVerifyFailed(ref exp, ref got) => write!(f, "OP_EQUALVERIFY failed; {} != {}", exp, got), - Error::MultisigBadKeyCount(n) => write!(f, "bad number {} of keys for multisignature", n), - Error::MultisigBadSigCount(n) => write!(f, "bad number {} of signatures for multisignature", n), - Error::NumEqualVerifyFailed(exp, got) => write!(f, "OP_NUMEQUALVERIFY failed; {} != {}", exp, got), - _ => f.write_str(error::Error::description(self)) - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Ecdsa(ref e) => Some(e), - _ => None - } - } - - fn description(&self) -> &'static str { - match *self { - Error::AnalyzeNeitherBoolWorks => "analyzer: switch on boolean but neither side is satisfiable", - Error::AnalyzeSetBoolMismatch(_) => "analyzer: conflicting requirements on boolean", - Error::AnalyzeValidateFailed => "analyzer: conflicting requirements on stack element", - Error::BadPublicKey => "analyzer: CHECKSIG called with bad public key", - Error::BadSignature => "analyzer: CHECKSIG called with bad signature", - Error::Ecdsa(_) => "libsecp error", - Error::ElseWithoutIf => "unexpected OP_ELSE", - Error::EndifWithoutIf => "unexpected OP_ENDIF", - Error::EqualVerifyFailed(_, _) => "OP_EQUALVERIFY failed", - Error::IfEmptyStack => "OP_IF called with nothing on the stack", - Error::IllegalOpcode => "an illegal opcode exists in the script", - Error::InterpreterStackOverflow => "analyzer: stack overflow", - Error::EarlyEndOfScript => "unexpected end of script", - Error::ExecutedReturn => "OP_RETURN or equivalent was executed", - Error::MultisigBadKeyCount(_) => "bad key count for multisignature", - Error::MultisigBadSigCount(_) => "bad signature count for multisignature", - Error::NegativePick => "OP_PICK called with negative index", - Error::NegativeRoll => "OP_ROLL called with negative index", - Error::NoTransaction => "OP_CHECKSIG evaluated outside of transaction environment", - Error::NumEqualVerifyFailed(_, _) => "OP_NUMEQUALVERIFY failed", - Error::NumericOverflow => "numeric overflow (number on stack larger than 4 bytes)", - Error::PopEmptyStack => "stack was empty but script expected otherwise", - Error::Unanalyzable => "analyzer: unable to determine script satisfiability", - Error::Unsatisfiable => "analyzer: script is unsatisfiable", - Error::VerifyEmptyStack => "OP_VERIFY called on an empty stack", - Error::VerifyFailed => "OP_VERIFY called with false on top of stack" - } - } -} - -/// A rule for validating an abstract stack element -pub struct Validator { - /// List of other elements to pass to both `check` and `update` - args: Vec, - /// Function which confirms that the current value is consistent with - /// the stack state, returning `false` if not. - check: fn(&AbstractStackElem, &[usize]) -> bool, - /// Function which updates the current stack based on the element's - /// value, if it has a value, otherwise updates the element's value - /// based on the current stack, if possible. Returns `false` if it - /// is forced to do something inconsistent. - update: fn(&mut AbstractStackElem, &[usize]) -> Result<(), Error> -} - -impl Clone for Validator { - fn clone(&self) -> Validator { - Validator { - args: self.args.clone(), - check: self.check, - update: self.update - } - } -} - -// Validators -mod check { - use super::AbstractStackElem; - - pub fn op_size(elem: &AbstractStackElem, others: &[usize]) -> bool { - let other = unsafe { elem.lookup(others[0]) }; - elem.num_hi() >= other.len_lo() as i64 && - elem.num_lo() <= other.len_hi() as i64 - } - - pub fn op_equal(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - match elem.bool_value() { - None => true, - Some(false) => { - (one.num_value().is_none() || two.num_value().is_none() || - one.num_value().unwrap() != two.num_value().unwrap()) && - (one.bool_value() != Some(false) || two.bool_value() != Some(false)) && - (one.raw_value().is_none() || two.raw_value().is_none() || - one.raw_value().unwrap() != two.raw_value().unwrap()) - } - Some(true) => { - one.len_lo() <= two.len_hi() && - one.len_hi() >= two.len_lo() && - one.num_lo() <= two.num_hi() && - one.num_hi() >= two.num_lo() && - (one.bool_value().is_none() || two.bool_value().is_none() || - one.bool_value().unwrap() == two.bool_value().unwrap()) && - (one.raw_value().is_none() || two.raw_value().is_none() || - one.raw_value().unwrap() == two.raw_value().unwrap()) - } - } - } - - pub fn op_not(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - if !one.may_be_numeric() { - return false; - } - - match elem.bool_value() { - None => true, - Some(false) => one.num_hi() != 0 || one.num_lo() != 0, - Some(true) => one.num_hi() >= 0 && one.num_lo() <= 0 - } - } - - pub fn op_0notequal(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - if !one.may_be_numeric() { return false; } - match elem.bool_value() { - None => true, - Some(false) => one.num_hi() >= 0 && one.num_lo() <= 0, - Some(true) => one.num_hi() != 0 || one.num_lo() != 0 - } - } - - pub fn op_numequal(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - if !one.may_be_numeric() { return false; } - if !two.may_be_numeric() { return false; } - match elem.bool_value() { - None => true, - Some(false) => { - (one.num_value().is_none() || two.num_value().is_none() || - one.num_value().unwrap() != two.num_value().unwrap()) && - (one.bool_value().is_none() || two.bool_value().is_none() || - one.bool_value().unwrap() != two.bool_value().unwrap()) - } - Some(true) => { - one.num_lo() <= two.num_hi() && - one.num_hi() >= two.num_lo() && - (one.num_value().is_none() || two.num_value().is_none() || - one.num_value().unwrap() == two.num_value().unwrap()) && - (one.bool_value().is_none() || two.bool_value().is_none() || - one.bool_value().unwrap() == two.bool_value().unwrap()) - } - } - } - - pub fn op_numnotequal(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - if !one.may_be_numeric() { return false; } - if !two.may_be_numeric() { return false; } - match elem.bool_value() { - None => true, - Some(false) => one.may_be_lt(two) || one.may_be_gt(two), - Some(true) => one.may_be_lteq(two) && one.may_be_gteq(two) - } - } - - pub fn op_numlt(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - if !one.may_be_numeric() { return false; } - if !two.may_be_numeric() { return false; } - match elem.bool_value() { - None => true, - Some(true) => one.may_be_lt(two), - Some(false) => one.may_be_gteq(two), - } - } - - pub fn op_numgt(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - if !one.may_be_numeric() { return false; } - if !two.may_be_numeric() { return false; } - match elem.bool_value() { - None => true, - Some(true) => one.may_be_gt(two), - Some(false) => one.may_be_lteq(two) - } - } - - pub fn op_numlteq(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - if !one.may_be_numeric() { return false; } - if !two.may_be_numeric() { return false; } - match elem.bool_value() { - None => true, - Some(false) => one.may_be_gt(two), - Some(true) => one.may_be_lteq(two) - } - } - - pub fn op_numgteq(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - if !one.may_be_numeric() { return false; } - if !two.may_be_numeric() { return false; } - match elem.bool_value() { - None => true, - Some(true) => one.may_be_gteq(two), - Some(false) => one.may_be_lt(two) - } - } - - pub fn op_ripemd160(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash160() - } - - pub fn op_sha1(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash160() - } - - pub fn op_hash160(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash160() - } - - pub fn op_sha256(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash256() - } - - pub fn op_hash256(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash256() - } - - pub fn op_checksig(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - let two = unsafe { elem.lookup(others[1]) }; - match elem.bool_value() { - None => true, - Some(false) => true, - Some(true) => one.may_be_signature() && two.may_be_pubkey() - } - } - -} - -mod update { - use super::{AbstractStackElem, Error}; - use crypto::digest::Digest; - use crypto::ripemd160::Ripemd160; - use crypto::sha1::Sha1; - use crypto::sha2::Sha256; - - pub fn op_size(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - let (lo, hi) = { - let one = unsafe { elem.lookup(others[0]) }; - (one.len_lo() as i64, one.len_hi() as i64) - }; - try!(elem.set_numeric()); - try!(elem.set_num_lo(lo)); - elem.set_num_hi(hi) - } - - fn boolean(elem: &mut AbstractStackElem) -> Result<(), Error> { - // Test boolean values - elem.bool_val = Some(true); - let true_works = elem.validate(); - elem.bool_val = Some(false); - let false_works = elem.validate(); - elem.bool_val = None; - // Update according to what worked - match (true_works, false_works) { - (true, true) => Ok(()), - (false, false) => Err(Error::AnalyzeNeitherBoolWorks), - (true, false) => elem.set_bool_value(true), - (false, true) => elem.set_bool_value(false) - } - } - - pub fn op_equal(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => boolean(elem), - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - // Booleans are the only thing we can do something useful with re "not equal" - match (one.bool_value(), two.bool_value()) { - (None, None) => Ok(()), - (None, Some(x)) => one.set_bool_value(!x), - (Some(x), None) => two.set_bool_value(!x), - (Some(x), Some(y)) if x == y => Err(Error::Unsatisfiable), - (Some(_), Some(_)) => Ok(()) - } - } - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - // Equalize numeric bounds - try!(one.set_num_lo(two.num_lo())); - try!(one.set_num_hi(two.num_hi())); - try!(two.set_num_lo(one.num_lo())); - try!(two.set_num_hi(one.num_hi())); - // Equalize boolean values - match (one.bool_value(), two.bool_value()) { - (None, None) => {}, - (None, Some(x)) => try!(one.set_bool_value(x)), - (Some(x), None) => try!(two.set_bool_value(x)), - (Some(x), Some(y)) if x == y => {}, - (Some(_), Some(_)) => { return Err(Error::Unsatisfiable); } - } - // Equalize full values - match (one.raw_value().map(|r| r.to_vec()), - two.raw_value().map(|r| r.to_vec())) { - (None, None) => {}, - (None, Some(x)) => try!(one.set_value(&x)), - (Some(x), None) => try!(two.set_value(&x)), - (Some(x), Some(y)) => { if x != y { return Err(Error::Unsatisfiable); } } - } - Ok(()) - } - } - } - - pub fn op_not(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => boolean(elem), - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - try!(one.set_numeric()); - match one.bool_value() { - None => one.set_bool_value(true), - Some(true) => Ok(()), - Some(false) => Err(Error::Unsatisfiable) - } - } - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - try!(one.set_numeric()); - match one.bool_value() { - None => one.set_num_value(0), - Some(true) => Err(Error::Unsatisfiable), - Some(false) => Ok(()) - } - } - } - } - - pub fn op_0notequal(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => boolean(elem), - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - try!(one.set_numeric()); - match one.bool_value() { - None => one.set_num_value(0), - Some(true) => Err(Error::Unsatisfiable), - Some(false) => Ok(()) - } - } - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - try!(one.set_numeric()); - match one.bool_value() { - None => one.set_bool_value(true), - Some(true) => Ok(()), - Some(false) => Err(Error::Unsatisfiable) - } - } - } - } - - pub fn op_numequal(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => boolean(elem), - Some(false) => { - // todo: find a way to force the numbers to be nonequal - Ok(()) - } - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - try!(one.set_num_lo(two.num_lo())); - try!(one.set_num_hi(two.num_hi())); - try!(two.set_num_lo(one.num_lo())); - two.set_num_hi(one.num_hi()) - } - } - } - - pub fn op_numnotequal(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => boolean(elem), - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - try!(one.set_num_lo(two.num_lo())); - try!(one.set_num_hi(two.num_hi())); - try!(two.set_num_lo(one.num_lo())); - two.set_num_hi(one.num_hi()) - } - Some(true) => { - // todo: find a way to force the numbers to be nonequal - Ok(()) - } - } - } - - pub fn op_numlt(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => boolean(elem), - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_hi(two.num_hi() - 1)); - two.set_num_lo(one.num_lo() + 1) - } - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_lo(two.num_lo())); - two.set_num_hi(one.num_hi()) - } - } - } - - pub fn op_numgt(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => try!(boolean(elem)), - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_lo(two.num_lo() + 1)); - try!(two.set_num_hi(one.num_hi() - 1)); - } - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_hi(two.num_hi())); - try!(two.set_num_lo(one.num_lo())); - } - } - Ok(()) - } - - pub fn op_numlteq(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => try!(boolean(elem)), - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_hi(two.num_hi())); - try!(two.set_num_lo(one.num_lo())); - } - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_lo(two.num_lo() + 1)); - try!(two.set_num_hi(one.num_hi() - 1)); - } - } - Ok(()) - } - - pub fn op_numgteq(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => try!(boolean(elem)), - Some(true) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_lo(two.num_lo())); - try!(two.set_num_hi(one.num_hi())); - } - Some(false) => { - let one = unsafe { elem.lookup_mut(others[0]) }; - let two = unsafe { elem.lookup_mut(others[1]) }; - try!(one.set_numeric()); - try!(two.set_numeric()); - - try!(one.set_num_hi(two.num_hi() - 1)); - try!(two.set_num_lo(one.num_lo() + 1)); - } - } - Ok(()) - } - - pub fn op_ripemd160(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(20)); - try!(elem.set_len_hi(20)); - - let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { - None => None, - Some(x) => { - let mut out = [0; 20]; - let mut engine = Ripemd160::new(); - engine.input(x); - engine.result(&mut out); - Some(out) - } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } - } - - pub fn op_sha1(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(20)); - try!(elem.set_len_hi(20)); - - let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { - None => None, - Some(x) => { - let mut out = [0; 20]; - let mut engine = Sha1::new(); - engine.input(x); - engine.result(&mut out); - Some(out) - } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } - } - - pub fn op_hash160(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(20)); - try!(elem.set_len_hi(20)); - - let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { - None => None, - Some(x) => { - let mut out1 = [0; 32]; - let mut out2 = [0; 20]; - let mut engine = Sha256::new(); - engine.input(x); - engine.result(&mut out1); - let mut engine = Ripemd160::new(); - engine.input(&out1); - engine.result(&mut out2); - Some(out2) - } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } - } - - pub fn op_sha256(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(32)); - try!(elem.set_len_hi(32)); - - let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { - None => None, - Some(x) => { - let mut out = [0; 32]; - let mut engine = Sha256::new(); - engine.input(x); - engine.result(&mut out); - Some(out) - } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } - } - - pub fn op_hash256(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(32)); - try!(elem.set_len_hi(32)); - - let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { - None => None, - Some(x) => { - let mut out = [0; 32]; - let mut engine = Sha256::new(); - engine.input(x); - engine.result(&mut out); - let mut engine = Sha256::new(); - engine.input(&out); - engine.result(&mut out); - Some(out) - } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } - } - - pub fn op_checksig(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => boolean(elem), - Some(false) => Ok(()), // nothing we can do to enforce an invalid sig - Some(true) => { - let sig = unsafe { elem.lookup_mut(others[0]) }; - let pk = unsafe { elem.lookup_mut(others[1]) }; - - // todo add DER encoding enforcement - try!(pk.set_len_lo(33)); - try!(pk.set_len_hi(65)); - try!(sig.set_len_lo(75)); - sig.set_len_hi(80) - } - } - } -} - -/// An abstract element on the stack, used to describe a satisfying -/// script input -#[derive(Clone)] -pub struct AbstractStackElem { - /// The raw data, if known - raw: Option>, - /// Boolean value, if forced - bool_val: Option, - /// Lower bound when read as number - num_lo: i64, - /// Upper bound when read as number - num_hi: i64, - /// Length lower bound - len_lo: usize, - /// Length upper bound - len_hi: usize, - /// Relations this must satisfy - validators: Vec, - /// Index of the element in its stack allocator - alloc_index: Option -} - -impl AbstractStackElem { - /// Create a new exact integer - pub fn new_num(n: i64) -> AbstractStackElem { - let raw = build_scriptint(n); - AbstractStackElem { - num_lo: n, - num_hi: n, - len_lo: raw.len(), - len_hi: raw.len(), - raw: Some(raw), - bool_val: Some(n != 0), - validators: vec![], - alloc_index: None - } - } - - /// Create a new exact boolean - pub fn new_bool(b: bool) -> AbstractStackElem { - AbstractStackElem::new_num(if b { 1 } else { 0 }) - } - - /// Create a new exact data - pub fn new_raw(data: &[u8]) -> AbstractStackElem { - let n = read_scriptint(data); - AbstractStackElem { - num_lo: match n { Ok(n) => n, Err(_) => -(1 << 31) }, - num_hi: match n { Ok(n) => n, Err(_) => 1 << 31 }, - len_lo: data.len(), - len_hi: data.len(), - bool_val: Some(read_scriptbool(data)), - raw: Some(data.to_vec()), - validators: vec![], - alloc_index: None - } - } - - /// Create a new unknown element - pub fn new_unknown() -> AbstractStackElem { - AbstractStackElem { - num_lo: -(1 << 31), - num_hi: 1 << 31, - len_lo: 0, - len_hi: 1 << 20, // blocksize limit - bool_val: None, - raw: None, - validators: vec![], - alloc_index: None - } - } - - /// Looks up another stack item by index - unsafe fn lookup(&self, idx: usize) -> &AbstractStackElem { - let mypos = self as *const _; - let myidx = self.alloc_index.unwrap() as isize; - &*mypos.offset(idx as isize - myidx) - } - - /// Looks up another stack item by index - unsafe fn lookup_mut(&self, idx: usize) -> &mut AbstractStackElem { - let mypos = self as *const _ as *mut _; - let myidx = self.alloc_index.unwrap() as isize; - &mut *mypos.offset(idx as isize - myidx) - } - - /// Retrieve the boolean value of the stack element, if it can be determined - pub fn bool_value(&self) -> Option { - self.bool_val - } - - /// Retrieves the raw value of the stack element, if it can be determined - pub fn raw_value(&self) -> Option<&[u8]> { - self.raw.as_ref().map(|x| &x[..]) - } - - /// Retrieve the upper bound for this element's numeric value. - /// This can always be determined since there is a fixed upper - /// bound for all numbers. - pub fn num_hi(&self) -> i64 { - self.num_hi - } - - /// Retrieve the lower bound for this element's numeric value. - /// This can always be determined since there is a fixed lower - /// bound for all numbers. - pub fn num_lo(&self) -> i64 { - self.num_lo - } - - /// Retrieve the upper bound for this element's length. This always - /// exists as a finite value, though the default upper limit is some - /// impractically large number - pub fn len_hi(&self) -> usize { - self.len_hi - } - - /// Retrieve the lower bound for this element's length. This always - /// exists since it is at least zero :) - pub fn len_lo(&self) -> usize { - self.len_lo - } - - /// Retries the element's numeric value, if it can be determined - pub fn num_value(&self) -> Option { - let lo = self.num_lo(); - let hi = self.num_hi(); - if lo == hi { Some(lo) } else { None } - } - - /// Propagate any changes to all nodes which are referenced - fn update(&mut self) -> Result<(), Error> { - // Check that this node is consistent before doing any propagation - if !self.validate() { - return Err(Error::AnalyzeValidateFailed); - } - - let validators = self.validators.clone(); - for v in validators.iter().cloned() { - try!((v.update)(self, &v.args)); - } - Ok(()) - } - - /// Check that all rules are satisfied - fn validate(&mut self) -> bool { - if self.num_hi < self.num_lo { return false; } - if self.len_hi < self.len_lo { return false; } - - self.validators.iter().all(|rule| (rule.check)(self, &rule.args)) - } - - /// Sets the boolean value - pub fn set_bool_value(&mut self, val: bool) - -> Result<(), Error> { - match self.bool_val { - Some(x) => { - if x != val { return Err(Error::AnalyzeSetBoolMismatch(val)); } - } - None => { - self.bool_val = Some(val); - if !val { - try!(self.set_num_value(0)); - } else if self.num_lo() == 0 && self.num_hi == 1 { - // This seems like a special case but actually everything that - // is `set_boolean` satisfies it - try!(self.set_num_value(1)); - } - try!(self.update()); - } - } - Ok(()) - } - - /// Sets the numeric value - pub fn set_num_value(&mut self, val: i64) -> Result<(), Error> { - try!(self.set_num_lo(val)); - self.set_num_hi(val) - } - - /// Sets the entire value of the - pub fn set_value(&mut self, val: &[u8]) -> Result<(), Error> { - match self.raw_value().map(|x| x.to_vec()) { - Some(x) => { if &x[..] == val { Ok(()) } else { Err(Error::Unsatisfiable) } } - None => { - try!(self.set_len_lo(val.len())); - try!(self.set_len_hi(val.len())); - try!(self.set_bool_value(read_scriptbool(val))); - if let Ok(n) = read_scriptint(val) { - try!(self.set_num_lo(n)); - try!(self.set_num_hi(n)); - } - try!(self.set_bool_value(read_scriptbool(val))); - self.raw = Some(val.to_vec()); - Ok(()) - } - } - } - - /// Sets a number to be numerically parseable - pub fn set_numeric(&mut self) -> Result<(), Error> { - self.set_len_hi(4) - } - - /// Whether an element could possibly be a number - pub fn may_be_numeric(&self) -> bool { - self.len_lo() <= 4 - } - - /// Whether an element could possibly be a signature - pub fn may_be_signature(&self) -> bool { - self.len_lo() <= 78 && self.len_hi() >= 77 - // todo check DER encoding - } - - /// Whether an element could possibly be a pubkey - pub fn may_be_pubkey(&self) -> bool { - let s = Secp256k1::with_caps(secp256k1::ContextFlag::None); - ((self.len_lo() <= 33 && self.len_hi() >= 33) || - (self.len_lo() <= 65 && self.len_hi() >= 65)) && - (self.raw_value().is_none() || PublicKey::from_slice(&s, self.raw_value().unwrap()).is_ok()) - } - - /// Whether an element could possibly be less than another - pub fn may_be_lt(&self, other: &AbstractStackElem) -> bool { - self.num_lo() < other.num_hi() && - self.num_value().is_none() || other.num_value().is_none() || - self.num_value().unwrap() < other.num_value().unwrap() - } - - /// Whether an element could possibly be greater than another - pub fn may_be_gt(&self, other: &AbstractStackElem) -> bool { - self.num_hi() > other.num_lo() && - (self.num_value().is_none() || other.num_value().is_none() || - self.num_value().unwrap() > other.num_value().unwrap()) - } - - /// Whether an element could possibly be less than or equal to another - pub fn may_be_lteq(&self, other: &AbstractStackElem) -> bool { - self.num_lo() <= other.num_hi() && - self.num_value().is_none() || other.num_value().is_none() || - self.num_value().unwrap() <= other.num_value().unwrap() - } - - /// Whether an element could possibly be greater than or equal to another - pub fn may_be_gteq(&self, other: &AbstractStackElem) -> bool { - self.num_hi() >= other.num_lo() && - (self.num_value().is_none() || other.num_value().is_none() || - self.num_value().unwrap() >= other.num_value().unwrap()) - } - - /// Whether an element could possibly be a 20-byte hash - pub fn may_be_hash160(&self) -> bool { - self.len_lo() <= 20 && self.len_hi() >= 20 - } - - /// Whether an element could possibly be a 32-byte hash - pub fn may_be_hash256(&self) -> bool { - self.len_lo() <= 32 && self.len_hi() >= 32 - } - - /// Sets a number to be an opcode-pushed boolean - pub fn set_boolean(&mut self) -> Result<(), Error> { - try!(self.set_len_hi(1)); - try!(self.set_num_lo(0)); - self.set_num_hi(1) - } - - /// Sets a numeric lower bound on a value - pub fn set_num_lo(&mut self, value: i64) -> Result<(), Error> { - if self.num_lo < value { - self.num_lo = value; - if value > 0 { try!(self.set_bool_value(true)); } - if value == 0 && self.num_hi == 0 { try!(self.set_bool_value(false)); } - try!(self.update()); - } - Ok(()) - } - - /// Sets a numeric upper bound on a value - pub fn set_num_hi(&mut self, value: i64) -> Result<(), Error> { - if self.num_hi > value { - self.num_hi = value; - if value < 0 { try!(self.set_bool_value(true)); } - if value == 0 && self.num_lo == 0 { try!(self.set_bool_value(false)); } - try!(self.update()); - } - Ok(()) - } - - /// Sets a lower length bound on a value - pub fn set_len_lo(&mut self, value: usize) -> Result<(), Error> { - if self.len_lo < value { - self.len_lo = value; - if value > 0 { try!(self.set_bool_value(true)); } - if value == 0 && self.num_hi == 0 { try!(self.set_bool_value(false)); } - try!(self.update()); - } - Ok(()) - } - - /// Sets a upper length bound on a value - pub fn set_len_hi(&mut self, value: usize) -> Result<(), Error> { - if self.len_hi > value { - self.len_hi = value; - try!(self.update()); - } - Ok(()) - } - - /// Adds some condition on the element - pub fn add_validator(&mut self, cond: Validator) -> Result<(), Error> { - self.validators.push(cond); - self.update() - } -} - - -/// The stack used by the script satisfier -#[derive(Clone)] -pub struct AbstractStack { - /// Actual elements on the stack - stack: Vec, - /// Actual elements on the altstack - alt_stack: Vec, - /// Stack needed to satisfy the script before execution - initial_stack: Vec, - /// Local allocator to allow cloning; refs are indices into here - alloc: Vec -} - -impl AbstractStack { - /// Construct a new empty abstract stack - pub fn new() -> AbstractStack { - AbstractStack { - stack: vec![], - alt_stack: vec![], - initial_stack: vec![], - alloc: vec![] - } - } - - fn allocate(&mut self, mut elem: AbstractStackElem) -> usize { - elem.alloc_index = Some(self.alloc.len()); - self.alloc.push(elem); - self.alloc.len() - 1 - } - - fn push_initial(&mut self, elem: AbstractStackElem) { - let idx = self.allocate(elem); - self.initial_stack.insert(0, idx); - self.stack.insert(0, idx); - } - - /// Construct the initial stack in the end - pub fn build_initial_stack(&self) -> Vec { - self.initial_stack.iter().map(|&i| self.alloc[i].clone()).collect() - } - - /// Increase the stack size to `n`, adding elements to the initial - /// stack as necessary - pub fn require_n_elems(&mut self, n: usize) { - while self.stack.len() < n { - self.push_initial(AbstractStackElem::new_unknown()); - } - } - - /// Push a copy of an existing element by index - pub fn push(&mut self, elem: usize) { - self.stack.push(elem); - } - - /// Push a new element - pub fn push_alloc(&mut self, elem: AbstractStackElem) -> &mut AbstractStackElem { - let idx = self.allocate(elem); - self.stack.push(idx); - &mut self.alloc[idx] - } - - - /// Obtain a mutable element to the top stack element - pub fn peek_mut(&mut self) -> &mut AbstractStackElem { - if self.stack.is_empty() { - self.push_initial(AbstractStackElem::new_unknown()); - } - - &mut self.alloc[*self.stack.last().unwrap()] - } - - /// Obtain a stackref to the current top element - pub fn peek_index(&mut self) -> usize { - if self.stack.is_empty() { - self.push_initial(AbstractStackElem::new_unknown()); - } - *self.stack.last().unwrap() - } - - /// Drop the top stack item - fn pop(&mut self) -> usize { - if self.stack.is_empty() { - self.push_initial(AbstractStackElem::new_unknown()); - } - self.stack.pop().unwrap() - } - - /// Obtain a mutable reference to the top stack item, but remove it from the stack - fn pop_mut(&mut self) -> &mut AbstractStackElem { - if self.stack.is_empty() { - self.push_initial(AbstractStackElem::new_unknown()); - } - - &mut self.alloc[self.stack.pop().unwrap()] - } - - - /// Move the top stack item to the altstack - pub fn top_to_altstack(&mut self) { - if self.stack.is_empty() { - self.push_initial(AbstractStackElem::new_unknown()); - } - - let pop = self.stack.pop().unwrap(); - self.alt_stack.push(pop); - } - - /// Move the top altstack item to the stack, failing if the - /// altstack is empty. (Note that input scripts pass their - /// stack to the output script but /not/ the altstack, so - /// there is no input that can make an empty altstack nonempty.) - pub fn top_from_altstack(&mut self) -> Result<(), Error> { - match self.alt_stack.pop() { - Some(x) => { self.stack.push(x); Ok(()) } - None => Err(Error::PopEmptyStack) - } - } - - /// Length of the current stack - fn len(&self) -> usize { - self.stack.len() - } - - /// Delete an element from the middle of the current stack - fn remove(&mut self, idx: usize) { - self.stack.remove(idx); - } -} - -impl ops::Index for AbstractStack { - type Output = usize; - #[inline] - fn index(&self, index: usize) -> &usize { - &self.stack[index] - } -} - -impl ops::Index> for AbstractStack { - type Output = [usize]; - #[inline] - fn index(&self, index: ops::Range) -> &[usize] { - &self.stack[index] - } -} - -impl ops::Index> for AbstractStack { - type Output = [usize]; - #[inline] - fn index(&self, index: ops::RangeTo) -> &[usize] { - &self.stack[index] - } -} - -impl ops::Index> for AbstractStack { - type Output = [usize]; - #[inline] - fn index(&self, index: ops::RangeFrom) -> &[usize] { - &self.stack[index] - } -} - -impl ops::Index for AbstractStack { - type Output = [usize]; - #[inline] - fn index(&self, _: ops::RangeFull) -> &[usize] { - &self.stack[..] - } -} - -impl ops::IndexMut for AbstractStack { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut usize { - &mut self.stack[index] - } -} - -impl ops::IndexMut> for AbstractStack { - #[inline] - fn index_mut(&mut self, index: ops::Range) -> &mut [usize] { - &mut self.stack[index] - } -} - -impl ops::IndexMut> for AbstractStack { - #[inline] - fn index_mut(&mut self, index: ops::RangeTo) -> &mut [usize] { - &mut self.stack[index] - } -} - -impl ops::IndexMut> for AbstractStack { - #[inline] - fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [usize] { - &mut self.stack[index] - } -} - -impl ops::IndexMut for AbstractStack { - #[inline] - fn index_mut(&mut self, _: ops::RangeFull) -> &mut [usize] { - &mut self.stack[..] - } -} - -impl serde::Serialize for Error { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> - where S: serde::Serializer - { - serializer.visit_str(&self.to_string()) - } -} - -/// A single iteration of a script execution -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct TraceIteration { - index: usize, - op_count: usize, - opcode: opcodes::All, - executed: bool, - errored: bool, - effect: opcodes::Class, - stack: Vec -} - -/// A full trace of a script execution -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct ScriptTrace { - /// A copy of the script - pub script: Script, - /// A copy of the script's initial stack, hex-encoded - pub initial_stack: Vec, - /// A list of iterations - pub iterations: Vec, - /// An error if one was returned, or None - pub error: Option -} - -/// Hashtype of a transaction, encoded in the last byte of a signature, -/// specifically in the last 5 bits `byte & 31` -#[derive(PartialEq, Eq, Debug, Clone)] -pub enum SigHashType { - /// 0x1: Sign all outputs - All, - /// 0x2: Sign no outputs --- anyone can choose the destination - None, - /// 0x3: Sign the output whose index matches this input's index. If none exists, - /// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`. - /// (This rule is probably an unintentional C++ism, but it's consensus so we have - /// to follow it.) - Single, - /// ???: Anything else is a non-canonical synonym for SigHashAll, for example - /// zero appears a few times in the chain - Unknown -} - -impl SigHashType { - /// Returns a SigHashType along with a boolean indicating whether - /// the `ANYONECANPAY` flag is set, read from the last byte of a signature. - fn from_signature(signature: &[u8]) -> (SigHashType, bool) { - let byte = signature[signature.len() - 1]; - let sighash = match byte & 0x1f { - 1 => SigHashType::All, - 2 => SigHashType::None, - 3 => SigHashType::Single, - _ => SigHashType::Unknown - }; - (sighash, (byte & 0x80) != 0) - } -} - -/// A structure that can hold either a slice or vector, as necessary -#[derive(Clone, Debug)] -pub enum MaybeOwned<'a> { - /// Freshly llocated memory - Owned(Vec), - /// Pointer into the original script - Borrowed(&'a [u8]) -} - -impl<'a> PartialEq for MaybeOwned<'a> { - #[inline] - fn eq(&self, other: &MaybeOwned) -> bool { &self[..] == &other[..] } -} - -impl<'a> Eq for MaybeOwned<'a> {} - -impl<'a> ops::Index for MaybeOwned<'a> { - type Output = u8; - - #[inline] - fn index(&self, index: usize) -> &u8 { - match *self { - MaybeOwned::Owned(ref v) => &v[index], - MaybeOwned::Borrowed(ref s) => &s[index] - } - } -} - -impl<'a> ops::Index> for MaybeOwned<'a> { - type Output = [u8]; - - #[inline] - fn index(&self, index: ops::Range) -> &[u8] { - match *self { - MaybeOwned::Owned(ref v) => &v[index], - MaybeOwned::Borrowed(ref s) => &s[index] - } - } -} - -impl<'a> ops::Index> for MaybeOwned<'a> { - type Output = [u8]; - - #[inline] - fn index(&self, index: ops::RangeTo) -> &[u8] { - match *self { - MaybeOwned::Owned(ref v) => &v[index], - MaybeOwned::Borrowed(ref s) => &s[index] - } - } -} - -impl<'a> ops::Index> for MaybeOwned<'a> { - type Output = [u8]; - - #[inline] - fn index(&self, index: ops::RangeFrom) -> &[u8] { - match *self { - MaybeOwned::Owned(ref v) => &v[index], - MaybeOwned::Borrowed(ref s) => &s[index] - } - } -} - -impl<'a> ops::Index for MaybeOwned<'a> { - type Output = [u8]; - - #[inline] - fn index(&self, _: ops::RangeFull) -> &[u8] { - match *self { - MaybeOwned::Owned(ref v) => &v[..], - MaybeOwned::Borrowed(ref s) => &s[..] - } - } -} - -impl<'a> MaybeOwned<'a> { - /// The number of bytes stored in the vector - #[inline] - fn len(&self) -> usize { - match *self { - MaybeOwned::Owned(ref v) => v.len(), - MaybeOwned::Borrowed(ref s) => s.len() - } - } -} - -static SCRIPT_TRUE: &'static [u8] = &[0x01]; -static SCRIPT_FALSE: &'static [u8] = &[0x00]; - -/// Helper to encode an integer in script format -fn build_scriptint(n: i64) -> Vec { - if n == 0 { return vec![] } - - let neg = n < 0; - - let mut abs = if neg { -n } else { n } as usize; - let mut v = vec![]; - while abs > 0xFF { - v.push((abs & 0xFF) as u8); - abs >>= 8; - } - // If the number's value causes the sign bit to be set, we need an extra - // byte to get the correct value and correct sign bit - if abs & 0x80 != 0 { - v.push(abs as u8); - v.push(if neg { 0x80u8 } else { 0u8 }); - } - // Otherwise we just set the sign bit ourselves - else { - abs |= if neg { 0x80 } else { 0 }; - v.push(abs as u8); - } - v -} - -/// Helper to decode an integer in script format -/// Notice that this fails on overflow: the result is the same as in -/// bitcoind, that only 4-byte signed-magnitude values may be read as -/// numbers. They can be added or subtracted (and a long time ago, -/// multiplied and divided), and this may result in numbers which -/// can't be written out in 4 bytes or less. This is ok! The number -/// just can't be read as a number again. -/// This is a bit crazy and subtle, but it makes sense: you can load -/// 32-bit numbers and do anything with them, which back when mult/div -/// was allowed, could result in up to a 64-bit number. We don't want -/// overflow since that's suprising --- and we don't want numbers that -/// don't fit in 64 bits (for efficiency on modern processors) so we -/// simply say, anything in excess of 32 bits is no longer a number. -/// This is basically a ranged type implementation. -pub fn read_scriptint(v: &[u8]) -> Result { - let len = v.len(); - if len == 0 { return Ok(0); } - if len > 4 { return Err(Error::NumericOverflow); } - - let (mut ret, sh) = v.iter() - .fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8)); - if v[len - 1] & 0x80 != 0 { - ret &= (1 << (sh - 1)) - 1; - ret = -ret; - } - Ok(ret) -} - -/// This is like "read_scriptint then map 0 to false and everything -/// else as true", except that the overflow rules don't apply. -#[inline] -pub fn read_scriptbool(v: &[u8]) -> bool { - !(v.is_empty() || - ((v[v.len() - 1] == 0 || v[v.len() - 1] == 0x80) && - v.iter().rev().skip(1).all(|&w| w == 0))) -} - -/// Read a script-encoded unsigned integer -pub fn read_uint(data: &[u8], size: usize) -> Result { - if data.len() < size { - Err(Error::EarlyEndOfScript) - } else { - let mut ret = 0; - for (i, item) in data.iter().take(size).enumerate() { - ret += (*item as usize) << (i * 8); - } - Ok(ret) - } -} - -/// Check a signature -- returns an error that is currently just translated -/// into a 0/1 to push onto the script stack -fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script: Vec, - tx: &Transaction, input_index: usize) -> Result<(), Error> { - - // Check public key - let pubkey = PublicKey::from_slice(secp, pk_slice); - if pubkey.is_err() { - return Err(Error::BadPublicKey); - } - let pubkey = pubkey.unwrap(); - - // Check signature and hashtype - if sig_slice.len() == 0 { - return Err(Error::BadSignature); - } - let (hashtype, anyone_can_pay) = SigHashType::from_signature(sig_slice); - - // Compute the transaction data to be hashed - let mut tx_copy = Transaction { version: tx.version, lock_time: tx.lock_time, - input: Vec::with_capacity(tx.input.len()), - output: tx.output.clone() }; - - // Put the script into an Option so that we can move it (via take_unwrap()) - // in the following branch/loop without the move-checker complaining about - // multiple moves. - let mut script = Some(script); - if anyone_can_pay { - // For anyone-can-pay transactions we replace the whole input array - // with just the current input, to ensure the others have no effect. - let mut old_input = tx.input[input_index].clone(); - old_input.script_sig = Script(script.take().unwrap().into_boxed_slice()); - tx_copy.input = vec![old_input]; - } else { - // Otherwise we keep all the inputs, blanking out the others and even - // resetting their sequence no. if appropriate - for (n, input) in tx.input.iter().enumerate() { - // Zero out the scripts of other inputs - let mut new_input = TxIn { prev_hash: input.prev_hash, - prev_index: input.prev_index, - sequence: input.sequence, - script_sig: Script::new() }; - if n == input_index { - new_input.script_sig = Script(script.take().unwrap().into_boxed_slice()); - } else { - new_input.script_sig = Script::new(); - // If we aren't signing them, also zero out the sequence number - if hashtype == SigHashType::Single || hashtype == SigHashType::None { - new_input.sequence = 0; - } - } - tx_copy.input.push(new_input); - } - } - - // Erase outputs as appropriate - let mut sighash_single_bug = false; - match hashtype { - SigHashType::None => { tx_copy.output = vec![]; } - SigHashType::Single => { - if input_index < tx_copy.output.len() { - let mut new_outs = Vec::with_capacity(input_index + 1); - for _ in 0..input_index { - new_outs.push(Default::default()) - } - new_outs.push(tx_copy.output.swap_remove(input_index)); - tx_copy.output = new_outs; - } else { - sighash_single_bug = true; - } - } - SigHashType::All | SigHashType::Unknown => {} - } - - let signature_hash = if sighash_single_bug { - vec![1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0] - } else { - let mut data_to_sign = serialize(&tx_copy).unwrap(); - data_to_sign.push(*sig_slice.last().unwrap()); - data_to_sign.push(0); - data_to_sign.push(0); - data_to_sign.push(0); - serialize(&Sha256dHash::from_data(&data_to_sign[..])).unwrap() - }; - - // We can unwrap -- only failure mode is on length, which is fixed to 32 - let msg = secp256k1::Message::from_slice(&signature_hash[..]).unwrap(); - // TODO: both from_der_lax and normalize() should not be used once BIP66 is accepted - let mut sig = try!(secp256k1::Signature::from_der_lax(secp, sig_slice).map_err(Error::Ecdsa)); - // Normalize it - sig.normalize_s(secp); - - Secp256k1::verify(secp, &msg, &sig, &pubkey).map_err(Error::Ecdsa) -} - -// Macro to translate English stack instructions into Rust code. -// All number are references to stack positions: 1 is the top, -// 2 is the second-to-top, etc. The numbers do not change within -// an opcode; to delete the top two items do `drop 1 drop 2` -// rather than `drop 1 drop 1`, which will fail. -// This is useful for only about a dozen opcodes, but those ones -// were really hard to read and verify -- see OP_PICK and OP_ROLL -// for an example of what Rust vector-stack manipulation looks -// like. -// Commands can be given in any order, except that `require` should -// always come first and `drop` should always come last, to avoid -// surprises. -macro_rules! stack_opcode { - ($stack:ident: $($cmd:ident $args:tt);*) => ({ - // Record top - let mut top = $stack.len(); - &mut top; // shut up warnings in case top is either unread or unmutated - $(stack_opcode_internal!($cmd: $stack, top, $args);)* - }); -} - -// The actual commands available to the above macro -macro_rules! stack_opcode_internal { - (require: $stack:ident, $top:ident, $r:expr) => ({ - $stack.require_n_elems($r); - $top = $stack.len(); - }); - (copy: $stack:ident, $top:ident, $c:expr) => ({ - if $top < $c { return Err(Error::PopEmptyStack); } - let elem = $stack[$top - $c].clone(); - $stack.push(elem); - }); - (swap: $stack:ident, $top:ident, ($a:expr, $b:expr)) => ({ - if $top < $a || $top < $b { return Err(Error::PopEmptyStack); } - (&mut $stack[..]).swap($top - $a, $top - $b); - }); - (perm: $stack:ident, $top:ident, ($first:expr, $($i:expr),*)) => ({ - if $top < $first { return Err(Error::PopEmptyStack); } - let first = $first; - $( - if $top < $i { return Err(Error::PopEmptyStack); } - (&mut $stack[..]).swap($top - first, $top - $i); - )* - }); - (drop: $stack:ident, $top:ident, $d:expr) => ({ - if $top < $d { return Err(Error::PopEmptyStack); } - $stack.remove($top - $d); - }); -} - -/// Macro to translate numerical operations into stack ones -macro_rules! num_opcode { - ($stack:ident($($var:ident),*): $op:expr) => ({ - $( - let $var = try!(read_scriptint(&match $stack.pop() { - Some(elem) => elem, - None => { return Err(Error::PopEmptyStack); } - }[..])); - )* - $stack.push(MaybeOwned::Owned(build_scriptint($op))); - // Return a tuple of all the variables - ($( $var ),*) - }); -} - -macro_rules! unary_opcode_satisfy { - ($stack:ident, $op:ident) => ({ - let one = $stack.pop(); - let cond = $stack.push_alloc(AbstractStackElem::new_unknown()); - try!(cond.add_validator(Validator { args: vec![one], - check: check::$op, - update: update::$op })); - }) -} - -macro_rules! boolean_opcode_satisfy { - ($stack:ident, unary $op:ident) => ({ - let one = $stack.pop(); - let cond = $stack.push_alloc(AbstractStackElem::new_unknown()); - try!(cond.set_boolean()); - try!(cond.add_validator(Validator { args: vec![one], - check: check::$op, - update: update::$op })); - }); - ($stack:ident, binary $op:ident) => ({ - let one = $stack.pop(); - let two = $stack.pop(); - let cond = $stack.push_alloc(AbstractStackElem::new_unknown()); - try!(cond.set_boolean()); - try!(cond.add_validator(Validator { args: vec![two, one], - check: check::$op, - update: update::$op })); - }); - ($stack:ident, ternary $op:ident) => ({ - let one = $stack.pop(); - let two = $stack.pop(); - let three = $stack.pop(); - let mut cond = $stack.push_alloc(AbstractStackElem::new_unknown()); - try!(cond.set_boolean()); - try!(cond.add_validator(Validator { args: vec![three, two, one], - check: check::$op, - update: update::$op })); - }); -} - -/// Macro to translate hashing operations into stack ones -macro_rules! hash_opcode { - ($stack:ident, $hash:ident) => ({ - match $stack.pop() { - None => { return Err(Error::PopEmptyStack); } - Some(v) => { - let mut engine = $hash::new(); - engine.input(&v[..]); - let mut ret = Vec::with_capacity(engine.output_bits() / 8); - // Force-set the length even though the vector is uninitialized - // This is OK only because u8 has no destructor - unsafe { ret.set_len(engine.output_bits() / 8); } - engine.result(&mut ret); - $stack.push(MaybeOwned::Owned(ret)); - } - } - }); -} - -// OP_VERIFY macro -macro_rules! op_verify { - ($stack:expr, $err:expr) => ( - match $stack.last().map(|v| read_scriptbool(&v[..])) { - None => { return Err(Error::VerifyEmptyStack); } - Some(false) => { return Err($err); } - Some(true) => { $stack.pop(); } - } - ) -} - -macro_rules! op_verify_satisfy { - ($stack:expr) => ({ - try!($stack.peek_mut().set_bool_value(true)); - $stack.pop(); - }) -} - -impl Script { - /// Creates a new empty script - pub fn new() -> Script { Script(vec![].into_boxed_slice()) } - - /// The length in bytes of the script - 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 - pub fn trace<'a>(&'a self, secp: &Secp256k1, stack: &mut Vec>, - input_context: Option<(&Transaction, usize)>) - -> ScriptTrace { - let mut trace = ScriptTrace { - script: self.clone(), - initial_stack: stack.iter().map(|elem| (&elem[..]).to_hex()).collect(), - iterations: vec![], - error: None - }; - - match self.evaluate(secp, stack, input_context, Some(&mut trace.iterations)) { - Ok(_) => {}, - Err(e) => { trace.error = Some(e.clone()); } - } - trace - } - - /// Evaluate the script, modifying the stack in place - pub fn evaluate<'a>(&'a self, secp: &Secp256k1, stack: &mut Vec>, - input_context: Option<(&Transaction, usize)>, - mut trace: Option<&mut Vec>) - -> Result<(), Error> { - let mut codeseparator_index = 0; - let mut exec_stack = vec![]; - let mut alt_stack = vec![]; - - let mut index = 0; - let mut op_count = 0; - while index < self.0.len() { - let executing = exec_stack.iter().all(|e| *e); - let byte = self.0[index]; - // Write out the trace, except the stack which we don't know yet - if let Some(ref mut t) = trace { - let opcode = opcodes::All::from(byte); - t.push(TraceIteration { - index: index, - opcode: opcode, - executed: executing, - errored: true, - op_count: op_count, - effect: opcode.classify(), - stack: vec!["".to_owned()] - }); - } - op_count += 1; - index += 1; - // The definitions of all these categories are in opcodes.rs - match (executing, opcodes::All::from(byte).classify()) { - // Illegal operations mean failure regardless of execution state - (_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode), - // Push number - (true, opcodes::Class::PushNum(n)) => stack.push(MaybeOwned::Owned(build_scriptint(n as i64))), - // Return operations mean failure, but only if executed - (true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn), - // Data-reading statements still need to read, even when not executing - (_, opcodes::Class::PushBytes(n)) => { - let n = n as usize; - if self.0.len() < index + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(&self.0[index..index + n])); } - index += n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { - if self.0.len() < index + 1 { return Err(Error::EarlyEndOfScript); } - let n = try!(read_uint(&self.0[index..], 1)); - if self.0.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 1..index + n + 1])); } - index += 1 + n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { - if self.0.len() < index + 2 { return Err(Error::EarlyEndOfScript); } - let n = try!(read_uint(&self.0[index..], 2)); - if self.0.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 2..index + n + 2])); } - index += 2 + n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { - if self.0.len() < index + 4 { return Err(Error::EarlyEndOfScript); } - let n = try!(read_uint(&self.0[index..], 4)); - if self.0.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 4..index + n + 4])); } - index += 4 + n; - } - // If-statements take effect when not executing - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_IF)) | - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_NOTIF)) => exec_stack.push(false), - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ELSE)) => { - match exec_stack.last_mut() { - Some(ref_e) => { *ref_e = !*ref_e } - None => { return Err(Error::ElseWithoutIf); } - } - } - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ENDIF)) => { - if exec_stack.pop().is_none() { - return Err(Error::EndifWithoutIf); - } - } - // No-ops and non-executed operations do nothing - (true, opcodes::Class::NoOp) | (false, _) => {} - // Actual opcodes - (true, opcodes::Class::Ordinary(op)) => { - match op { - opcodes::Ordinary::OP_PUSHDATA1 | opcodes::Ordinary::OP_PUSHDATA2 | opcodes::Ordinary::OP_PUSHDATA4 => { - // handled above - } - opcodes::Ordinary::OP_IF => { - match stack.pop().map(|v| read_scriptbool(&v[..])) { - None => { return Err(Error::IfEmptyStack); } - Some(b) => exec_stack.push(b) - } - } - opcodes::Ordinary::OP_NOTIF => { - match stack.pop().map(|v| read_scriptbool(&v[..])) { - None => { return Err(Error::IfEmptyStack); } - Some(b) => exec_stack.push(!b), - } - } - opcodes::Ordinary::OP_ELSE => { - match exec_stack.last_mut() { - Some(ref_e) => { *ref_e = !*ref_e } - None => { return Err(Error::ElseWithoutIf); } - } - } - opcodes::Ordinary::OP_ENDIF => { - if exec_stack.pop().is_none() { - return Err(Error::EndifWithoutIf); - } - } - opcodes::Ordinary::OP_VERIFY => op_verify!(stack, Error::VerifyFailed), - opcodes::Ordinary::OP_TOALTSTACK => { - match stack.pop() { - None => { return Err(Error::PopEmptyStack); } - Some(elem) => { alt_stack.push(elem); } - } - } - opcodes::Ordinary::OP_FROMALTSTACK => { - match alt_stack.pop() { - None => { return Err(Error::PopEmptyStack); } - Some(elem) => { stack.push(elem); } - } - } - opcodes::Ordinary::OP_2DROP => stack_opcode!(stack: drop 1; drop 2), - opcodes::Ordinary::OP_2DUP => stack_opcode!(stack: copy 2; copy 1), - opcodes::Ordinary::OP_3DUP => stack_opcode!(stack: copy 3; copy 2; copy 1), - opcodes::Ordinary::OP_2OVER => stack_opcode!(stack: copy 4; copy 3), - opcodes::Ordinary::OP_2ROT => stack_opcode!(stack: perm (1, 3, 5); - perm (2, 4, 6)), - opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack: swap (2, 4); swap (1, 3)), - opcodes::Ordinary::OP_DROP => stack_opcode!(stack: drop 1), - opcodes::Ordinary::OP_DUP => stack_opcode!(stack: copy 1), - opcodes::Ordinary::OP_NIP => stack_opcode!(stack: drop 2), - opcodes::Ordinary::OP_OVER => stack_opcode!(stack: copy 2), - opcodes::Ordinary::OP_PICK => { - let n = match stack.pop() { - Some(data) => try!(read_scriptint(&data[..])), - None => { return Err(Error::PopEmptyStack); } - }; - if n < 0 { return Err(Error::NegativePick); } - let n = n as usize; - stack_opcode!(stack: copy (n + 1)) - } - opcodes::Ordinary::OP_ROLL => { - let n = match stack.pop() { - Some(data) => try!(read_scriptint(&data[..])), - None => { return Err(Error::PopEmptyStack); } - }; - if n < 0 { return Err(Error::NegativeRoll); } - let n = n as usize; - stack_opcode!(stack: copy (n + 1); drop (n + 1)) - } - opcodes::Ordinary::OP_ROT => stack_opcode!(stack: perm (1, 2, 3)), - opcodes::Ordinary::OP_SWAP => stack_opcode!(stack: swap (1, 2)), - opcodes::Ordinary::OP_TUCK => stack_opcode!(stack: copy 2; copy 1; drop 2), - opcodes::Ordinary::OP_IFDUP => { - match stack.last().map(|v| read_scriptbool(&v[..])) { - None => { return Err(Error::IfEmptyStack); } - Some(false) => {} - Some(true) => { stack_opcode!(stack: copy 1); } - } - } - opcodes::Ordinary::OP_DEPTH => { - let len = stack.len() as i64; - stack.push(MaybeOwned::Owned(build_scriptint(len))); - } - opcodes::Ordinary::OP_SIZE => { - match stack.last().map(|v| v.len() as i64) { - None => { return Err(Error::IfEmptyStack); } - Some(n) => { stack.push(MaybeOwned::Owned(build_scriptint(n))); } - } - } - opcodes::Ordinary::OP_EQUAL | opcodes::Ordinary::OP_EQUALVERIFY => { - if stack.len() < 2 { return Err(Error::PopEmptyStack); } - let a = stack.pop().unwrap(); - let b = stack.pop().unwrap(); - stack.push(MaybeOwned::Borrowed(if a == b { SCRIPT_TRUE } else { SCRIPT_FALSE })); - if op == opcodes::Ordinary::OP_EQUALVERIFY { - op_verify!(stack, Error::EqualVerifyFailed((&a[..]).to_hex(), - (&b[..]).to_hex())); - } - } - opcodes::Ordinary::OP_1ADD => { num_opcode!(stack(a): a + 1); } - opcodes::Ordinary::OP_1SUB => { num_opcode!(stack(a): a - 1); } - opcodes::Ordinary::OP_NEGATE => { num_opcode!(stack(a): -a); } - opcodes::Ordinary::OP_ABS => { num_opcode!(stack(a): a.abs()); } - opcodes::Ordinary::OP_NOT => { num_opcode!(stack(a): if a == 0 {1} else {0}); } - opcodes::Ordinary::OP_0NOTEQUAL => { num_opcode!(stack(a): if a != 0 {1} else {0}); } - opcodes::Ordinary::OP_ADD => { num_opcode!(stack(b, a): a + b); } - opcodes::Ordinary::OP_SUB => { num_opcode!(stack(b, a): a - b); } - opcodes::Ordinary::OP_BOOLAND => { num_opcode!(stack(b, a): if a != 0 && b != 0 {1} else {0}); } - opcodes::Ordinary::OP_BOOLOR => { num_opcode!(stack(b, a): if a != 0 || b != 0 {1} else {0}); } - opcodes::Ordinary::OP_NUMEQUAL => { num_opcode!(stack(b, a): if a == b {1} else {0}); } - opcodes::Ordinary::OP_NUMNOTEQUAL => { num_opcode!(stack(b, a): if a != b {1} else {0}); } - opcodes::Ordinary::OP_NUMEQUALVERIFY => { - let (b, a) = num_opcode!(stack(b, a): if a == b {1} else {0}); - op_verify!(stack, Error::NumEqualVerifyFailed(a, b)); - } - opcodes::Ordinary::OP_LESSTHAN => { num_opcode!(stack(b, a): if a < b {1} else {0}); } - opcodes::Ordinary::OP_GREATERTHAN => { num_opcode!(stack(b, a): if a > b {1} else {0}); } - opcodes::Ordinary::OP_LESSTHANOREQUAL => { num_opcode!(stack(b, a): if a <= b {1} else {0}); } - opcodes::Ordinary::OP_GREATERTHANOREQUAL => { num_opcode!(stack(b, a): if a >= b {1} else {0}); } - opcodes::Ordinary::OP_MIN => { num_opcode!(stack(b, a): if a < b {a} else {b}); } - opcodes::Ordinary::OP_MAX => { num_opcode!(stack(b, a): if a > b {a} else {b}); } - opcodes::Ordinary::OP_WITHIN => { num_opcode!(stack(c, b, a): if b <= a && a < c {1} else {0}); } - opcodes::Ordinary::OP_RIPEMD160 => hash_opcode!(stack, Ripemd160), - opcodes::Ordinary::OP_SHA1 => hash_opcode!(stack, Sha1), - opcodes::Ordinary::OP_SHA256 => hash_opcode!(stack, Sha256), - opcodes::Ordinary::OP_HASH160 => { - hash_opcode!(stack, Sha256); - hash_opcode!(stack, Ripemd160); - } - opcodes::Ordinary::OP_HASH256 => { - hash_opcode!(stack, Sha256); - hash_opcode!(stack, Sha256); - } - opcodes::Ordinary::OP_CODESEPARATOR => { codeseparator_index = index; } - opcodes::Ordinary::OP_CHECKSIG | opcodes::Ordinary::OP_CHECKSIGVERIFY => { - if stack.len() < 2 { return Err(Error::PopEmptyStack); } - - let pk = stack.pop().unwrap(); - let pk_slice = &pk[..]; - let sig = stack.pop().unwrap(); - let sig_slice = &sig[..]; - - // Compute the section of script that needs to be hashed: everything - // from the last CODESEPARATOR, except the signature itself. - let mut script = (&self.0[codeseparator_index..]).to_vec(); - let remove = Builder::new().push_slice(sig_slice); - script_find_and_remove(&mut script, &remove[..]); - // Also all of the OP_CODESEPARATORS, even the unevaluated ones - script_find_and_remove(&mut script, &[opcodes::Ordinary::OP_CODESEPARATOR as u8]); - - // This is as far as we can go without a transaction, so fail here - if input_context.is_none() { return Err(Error::NoTransaction); } - // Otherwise unwrap it - let (tx, input_index) = input_context.unwrap(); - - match check_signature(secp, sig_slice, pk_slice, script, tx, input_index) { - Ok(()) => stack.push(MaybeOwned::Borrowed(SCRIPT_TRUE)), - _ => stack.push(MaybeOwned::Borrowed(SCRIPT_FALSE)) - } - if op == opcodes::Ordinary::OP_CHECKSIGVERIFY { op_verify!(stack, Error::VerifyFailed); } - } - opcodes::Ordinary::OP_CHECKMULTISIG | opcodes::Ordinary::OP_CHECKMULTISIGVERIFY => { - // Read all the keys - if stack.len() < 1 { return Err(Error::PopEmptyStack); } - let n_keys = try!(read_scriptint(&stack.pop().unwrap()[..])); - if n_keys < 0 || n_keys > 20 { - return Err(Error::MultisigBadKeyCount(n_keys as isize)); - } - - if (stack.len() as i64) < n_keys { return Err(Error::PopEmptyStack); } - let mut keys = Vec::with_capacity(n_keys as usize); - for _ in 0..n_keys { - keys.push(stack.pop().unwrap()); - } - - // Read all the signatures - if stack.len() < 1 { return Err(Error::PopEmptyStack); } - let n_sigs = try!(read_scriptint(&stack.pop().unwrap()[..])); - if n_sigs < 0 || n_sigs > n_keys { - return Err(Error::MultisigBadSigCount(n_sigs as isize)); - } - - if (stack.len() as i64) < n_sigs { return Err(Error::PopEmptyStack); } - let mut sigs = Vec::with_capacity(n_sigs as usize); - for _ in 0..n_sigs { - sigs.push(stack.pop().unwrap()); - } - - // Pop one more element off the stack to be replicate a consensus bug - if stack.pop().is_none() { return Err(Error::PopEmptyStack); } - - // Compute the section of script that needs to be hashed: everything - // from the last CODESEPARATOR, except the signatures themselves. - let mut script = (&self.0[codeseparator_index..]).to_vec(); - for sig in &sigs { - let remove = Builder::new().push_slice(&sig[..]); - script_find_and_remove(&mut script, &remove[..]); - script_find_and_remove(&mut script, &[opcodes::Ordinary::OP_CODESEPARATOR as u8]); - } - - // This is as far as we can go without a transaction, so fail here - if input_context.is_none() { return Err(Error::NoTransaction); } - // Otherwise unwrap it - let (tx, input_index) = input_context.unwrap(); - - // Check signatures - let mut key_iter = keys.iter(); - let mut sig_iter = sigs.iter(); - let mut key = key_iter.next(); - let mut sig = sig_iter.next(); - loop { - match (key, sig) { - // Try to validate the signature with the given key - (Some(k), Some(s)) => { - // Move to the next signature if it is valid for the current key - if check_signature(secp, &s[..], &k[..], script.clone(), tx, input_index).is_ok() { - sig = sig_iter.next(); - } - // Move to the next key in any case - key = key_iter.next(); - } - // Run out of signatures, success - (_, None) => { - stack.push(MaybeOwned::Borrowed(SCRIPT_TRUE)); - break; - } - // Run out of keys to match to signatures, fail - (None, Some(_)) => { - stack.push(MaybeOwned::Borrowed(SCRIPT_FALSE)); - break; - } - } - } - if op == opcodes::Ordinary::OP_CHECKMULTISIGVERIFY { op_verify!(stack, Error::VerifyFailed); } - } - } // end opcode match - } // end classification match - } // end loop - // Store the stack in the trace - trace.as_mut().map(|t| - t.last_mut().map(|t| { - t.errored = false; - t.stack = stack.iter().map(|elem| (&elem[..]).to_hex()).collect(); - }) - ); - } - Ok(()) - } - - /// Checks whether a script pubkey is a p2sh output - #[inline] - pub fn is_p2sh(&self) -> bool { - self.0.len() == 23 && - self.0[0] == opcodes::All::OP_HASH160 as u8 && - self.0[1] == opcodes::All::OP_PUSHBYTES_20 as u8 && - self.0[22] == opcodes::All::OP_EQUAL as u8 - } - - /// Whether a script can be proven to have no satisfying input - pub fn is_provably_unspendable(&self) -> bool { - match self.satisfy() { - Ok(_) | Err(Error::Unanalyzable) => false, - Err(_) => true - } - } - - /// Evaluate the script to determine whether any possible input will cause it - /// to accept. Returns true if it is guaranteed to fail; false otherwise. - pub fn satisfy(&self) -> Result, Error> { - fn recurse(script: &[u8], - mut stack: AbstractStack, - mut exec_stack: Vec, - depth: usize) -> Result, Error> { - - // Avoid doing more than 64k forks - if depth > 16 { return Err(Error::InterpreterStackOverflow); } - - let mut index = 0; - while index < script.len() { - let executing = exec_stack.iter().all(|e| *e); - let byte = script[index]; - index += 1; - // The definitions of all these categories are in opcodes.rs - match (executing, opcodes::All::from(byte).classify()) { - // Illegal operations mean failure regardless of execution state - (_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode), - // Push number - (true, opcodes::Class::PushNum(n)) => { stack.push_alloc(AbstractStackElem::new_num(n as i64)); }, - // Return operations mean failure, but only if executed - (true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn), - // Data-reading statements still need to read, even when not executing - (_, opcodes::Class::PushBytes(n)) => { - let n = n as usize; - if script.len() < index + n { return Err(Error::EarlyEndOfScript); } - if executing { - stack.push_alloc(AbstractStackElem::new_raw(&script[index..index + n])); - } - index += n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { - if script.len() < index + 1 { return Err(Error::EarlyEndOfScript); } - let n = match read_uint(&script[index..], 1) { - Ok(n) => n, - Err(_) => { return Err(Error::EarlyEndOfScript); } - }; - if script.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } - if executing { - stack.push_alloc(AbstractStackElem::new_raw(&script[index + 1..index + n + 1])); - } - index += 1 + n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { - if script.len() < index + 2 { return Err(Error::EarlyEndOfScript); } - let n = match read_uint(&script[index..], 2) { - Ok(n) => n, - Err(_) => { return Err(Error::EarlyEndOfScript); } - }; - if script.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } - if executing { - stack.push_alloc(AbstractStackElem::new_raw(&script[index + 2..index + n + 2])); - } - index += 2 + n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { - let n = match read_uint(&script[index..], 4) { - Ok(n) => n, - Err(_) => { return Err(Error::EarlyEndOfScript); } - }; - if script.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } - if executing { - stack.push_alloc(AbstractStackElem::new_raw(&script[index + 4..index + n + 4])); - } - index += 4 + n; - } - // If-statements take effect when not executing - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_IF)) | - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_NOTIF)) => exec_stack.push(false), - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ELSE)) => { - match exec_stack.last_mut() { - Some(ref_e) => { *ref_e = !*ref_e } - None => { return Err(Error::ElseWithoutIf); } - } - } - (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ENDIF)) => { - if exec_stack.pop().is_none() { - return Err(Error::EndifWithoutIf); - } - } - // No-ops and non-executed operations do nothing - (true, opcodes::Class::NoOp) | (false, _) => {} - // Actual opcodes - (true, opcodes::Class::Ordinary(op)) => { - match op { - opcodes::Ordinary::OP_PUSHDATA1 | opcodes::Ordinary::OP_PUSHDATA2 | opcodes::Ordinary::OP_PUSHDATA4 => { - // handled above - } - opcodes::Ordinary::OP_IF => { - let top_bool = { - let top = stack.peek_mut(); - top.bool_value() - }; - match top_bool { - None => { - let mut stack_true = stack.clone(); - // Try pushing false and see what happens - if stack.peek_mut().set_bool_value(false).is_ok() { - if let Ok(res) = recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) { - return Ok(res); - } - } - // Failing that, push true - try!(stack_true.peek_mut().set_bool_value(true)); - return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1); - } - Some(val) => { - stack.pop(); - exec_stack.push(val) - } - } - } - opcodes::Ordinary::OP_NOTIF => { - let top_bool = { - let top = stack.peek_mut(); - top.bool_value() - }; - match top_bool { - None => { - let mut stack_true = stack.clone(); - // Try pushing false and see what happens - if stack.peek_mut().set_bool_value(false).is_ok() { - if let Ok(res) = recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) { - return Ok(res); - } - } - // Failing that, push true - try!(stack_true.peek_mut().set_bool_value(true)); - return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1); - } - Some(val) => { - stack.pop(); - exec_stack.push(!val) - } - } - } - opcodes::Ordinary::OP_ELSE => { - match exec_stack.last_mut() { - Some(ref_e) => { *ref_e = !*ref_e } - None => { return Err(Error::ElseWithoutIf); } - } - } - opcodes::Ordinary::OP_ENDIF => { - if exec_stack.pop().is_none() { - return Err(Error::EndifWithoutIf); - } - } - opcodes::Ordinary::OP_VERIFY => op_verify_satisfy!(stack), - opcodes::Ordinary::OP_TOALTSTACK => { stack.top_to_altstack(); } - opcodes::Ordinary::OP_FROMALTSTACK => { try!(stack.top_from_altstack()); } - opcodes::Ordinary::OP_2DROP => stack_opcode!(stack: require 2; drop 1; drop 2), - opcodes::Ordinary::OP_2DUP => stack_opcode!(stack: require 2; copy 2; copy 1), - opcodes::Ordinary::OP_3DUP => stack_opcode!(stack: require 3; copy 3; copy 2; copy 1), - opcodes::Ordinary::OP_2OVER => stack_opcode!(stack: require 4; copy 4; copy 3), - opcodes::Ordinary::OP_2ROT => stack_opcode!(stack: require 6; - perm (1, 3, 5); - perm (2, 4, 6)), - opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack: require 4; - swap (2, 4); - swap (1, 3)), - opcodes::Ordinary::OP_DROP => stack_opcode!(stack: require 1; drop 1), - opcodes::Ordinary::OP_DUP => stack_opcode!(stack: require 1; copy 1), - opcodes::Ordinary::OP_NIP => stack_opcode!(stack: require 2; drop 2), - opcodes::Ordinary::OP_OVER => stack_opcode!(stack: require 2; copy 2), - opcodes::Ordinary::OP_PICK => { - let top_n = { - let top = stack.peek_mut(); - try!(top.set_numeric()); - try!(top.set_num_lo(0)); - top.num_value().map(|n| n as usize) - }; - stack.pop(); - match top_n { - Some(n) => stack_opcode!(stack: require (n + 1); copy (n + 1)), - // The stack will wind up with the 1 and nth inputs being identical - // with n input-dependent. I can imagine scripts which check this - // condition or its negation for various n to get arbitrary finite - // sets of allowable values. It's not clear to me that this is - // feasible to analyze. - None => { return Err(Error::Unanalyzable); } - } - } - opcodes::Ordinary::OP_ROLL => { - let top_n = { - let top = stack.peek_mut(); - try!(top.set_numeric()); - try!(top.set_num_lo(0)); - top.num_value().map(|n| n as usize) - }; - stack.pop(); - match top_n { - Some(n) => stack_opcode!(stack: require (n + 1); copy (n + 1); drop (n + 1)), - // The stack will wind up reordered, so in principle I could just force - // the input to be zero (other n values can be converted to zero by just - // manually rearranging the input). The problem is if numeric bounds are - // later set on n. I can't analyze that. - None => { return Err(Error::Unanalyzable); } - } - } - opcodes::Ordinary::OP_ROT => stack_opcode!(stack: require 3; perm (1, 2, 3)), - opcodes::Ordinary::OP_SWAP => stack_opcode!(stack: require 3; swap (1, 2)), - opcodes::Ordinary::OP_TUCK => stack_opcode!(stack: require 2; copy 2; copy 1; drop 2), - opcodes::Ordinary::OP_IFDUP => { - let top_bool = { - let top = stack.peek_mut(); - top.bool_value() - }; - match top_bool { - Some(false) => { } - Some(true) => { stack_opcode!(stack: require 1; copy 1); } - None => { - let mut stack_true = stack.clone(); - // Try pushing false and see what happens - if stack.peek_mut().set_bool_value(false).is_ok() { - if let Ok(res) = recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) { - return Ok(res); - } - } - // Failing that, push true - try!(stack_true.peek_mut().set_bool_value(true)); - return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1); - } - } - } - opcodes::Ordinary::OP_DEPTH => { - let len = stack.len() as i64; - let new_elem = stack.push_alloc(AbstractStackElem::new_unknown()); - try!(new_elem.set_numeric()); - try!(new_elem.set_num_lo(len)); - } - opcodes::Ordinary::OP_SIZE => { - let top = stack.peek_index(); - let new_elem = stack.push_alloc(AbstractStackElem::new_unknown()); - try!(new_elem.set_numeric()); - try!(new_elem.add_validator(Validator { args: vec![top], - check: check::op_size, - update: update::op_size })); - } - opcodes::Ordinary::OP_EQUAL => boolean_opcode_satisfy!(stack, binary op_equal), - opcodes::Ordinary::OP_EQUALVERIFY => { - boolean_opcode_satisfy!(stack, binary op_equal); - op_verify_satisfy!(stack); - } - opcodes::Ordinary::OP_NOT => boolean_opcode_satisfy!(stack, unary op_not), - opcodes::Ordinary::OP_0NOTEQUAL => boolean_opcode_satisfy!(stack, unary op_0notequal), - opcodes::Ordinary::OP_NUMEQUAL => boolean_opcode_satisfy!(stack, binary op_numequal), - opcodes::Ordinary::OP_NUMEQUALVERIFY => { - boolean_opcode_satisfy!(stack, binary op_numequal); - op_verify_satisfy!(stack); - } - opcodes::Ordinary::OP_NUMNOTEQUAL => boolean_opcode_satisfy!(stack, binary op_numnotequal), - opcodes::Ordinary::OP_LESSTHAN => boolean_opcode_satisfy!(stack, binary op_numlt), - opcodes::Ordinary::OP_GREATERTHAN => boolean_opcode_satisfy!(stack, binary op_numgt), - opcodes::Ordinary::OP_LESSTHANOREQUAL => boolean_opcode_satisfy!(stack, binary op_numlteq), - opcodes::Ordinary::OP_GREATERTHANOREQUAL => boolean_opcode_satisfy!(stack, binary op_numgteq), - opcodes::Ordinary::OP_1ADD | opcodes::Ordinary::OP_1SUB | opcodes::Ordinary::OP_NEGATE | - opcodes::Ordinary::OP_ABS | opcodes::Ordinary::OP_ADD | opcodes::Ordinary::OP_SUB | - opcodes::Ordinary::OP_BOOLAND | opcodes::Ordinary::OP_BOOLOR | - opcodes::Ordinary::OP_MIN | opcodes::Ordinary::OP_MAX | opcodes::Ordinary::OP_WITHIN => { - return Err(Error::Unanalyzable); - } - opcodes::Ordinary::OP_RIPEMD160 => unary_opcode_satisfy!(stack, op_ripemd160), - opcodes::Ordinary::OP_SHA1 => unary_opcode_satisfy!(stack, op_sha1), - opcodes::Ordinary::OP_SHA256 => unary_opcode_satisfy!(stack, op_sha256), - opcodes::Ordinary::OP_HASH160 => unary_opcode_satisfy!(stack, op_hash160), - opcodes::Ordinary::OP_HASH256 => unary_opcode_satisfy!(stack, op_hash256), - // Ignore code separators since we don't check signatures - opcodes::Ordinary::OP_CODESEPARATOR => {} - opcodes::Ordinary::OP_CHECKSIG => boolean_opcode_satisfy!(stack, binary op_checksig), - opcodes::Ordinary::OP_CHECKSIGVERIFY => { - boolean_opcode_satisfy!(stack, binary op_checksig); - op_verify_satisfy!(stack); - } - opcodes::Ordinary::OP_CHECKMULTISIG | opcodes::Ordinary::OP_CHECKMULTISIGVERIFY => { - let (n_keys, n_keys_hi) = { - let elem = stack.pop_mut(); - try!(elem.set_numeric()); - try!(elem.set_num_lo(0)); - try!(elem.set_num_hi(20)); - (elem.num_lo(), elem.num_hi()) - }; - let mut allowable_failures: i64 = 0; - for _ in 0..n_keys { - let key = stack.pop_mut(); - if key.may_be_pubkey() { - allowable_failures += 1; - } - } - if n_keys == n_keys_hi { - let (n_sigs, n_sigs_hi) = { - let elem = stack.pop_mut(); - try!(elem.set_numeric()); - try!(elem.set_num_lo(0)); - try!(elem.set_num_hi(n_keys)); - (elem.num_lo(), elem.num_hi()) - }; - allowable_failures -= n_sigs; - for _ in 0..n_sigs { - let sig = stack.pop_mut(); - if !sig.may_be_signature() { - allowable_failures -= 1; - } - if allowable_failures < 0 { - return Err(Error::Unsatisfiable); - } - if n_sigs != n_sigs_hi { return Err(Error::Unanalyzable); } - } - } else { return Err(Error::Unanalyzable); } - // Successful multisig, push an unknown boolean - { - let result = stack.push_alloc(AbstractStackElem::new_unknown()); - try!(result.set_boolean()) - } - - // If it's a VERIFY op, assume it passed and carry on - if op == opcodes::Ordinary::OP_CHECKMULTISIGVERIFY { - op_verify_satisfy!(stack); - } - } - } - } - } - } - // If we finished, we are only unspendable if we have false on the stack - match stack.peek_mut().bool_value() { - None => stack.peek_mut().set_bool_value(true).map(|_| stack.build_initial_stack()), - Some(true) => Ok(stack.build_initial_stack()), - Some(false) => Err(Error::Unsatisfiable) - } - } - - recurse(&self.0, AbstractStack::new(), vec![], 1) - } -} - -impl Default for Script { - fn default() -> Script { Script(vec![].into_boxed_slice()) } -} - -/// Creates a new script from an existing vector -impl From> for Script { - fn from(v: Vec) -> Script { Script(v.into_boxed_slice()) } -} - -impl_index_newtype!(Script, u8); - -/// A "parsed opcode" which allows iterating over a Script in a more sensible way -pub enum Instruction<'a> { - /// Push a bunch of data - PushBytes(&'a [u8]), - /// Some non-push opcode - Op(opcodes::All), - /// An opcode we were unable to parse - Error(Error) -} - -/// Iterator over a script returning parsed opcodes -pub struct Instructions<'a> { - data: &'a [u8] -} - -impl<'a> IntoIterator for &'a Script { - type Item = Instruction<'a>; - type IntoIter = Instructions<'a>; - fn into_iter(self) -> Instructions<'a> { Instructions { data: &self.0[..] } } -} - -impl<'a> Iterator for Instructions<'a> { - type Item = Instruction<'a>; - - fn next(&mut self) -> Option> { - if self.data.is_empty() { - return None; - } - - match opcodes::All::from(self.data[0]).classify() { - opcodes::Class::PushBytes(n) => { - let n = n as usize; - if self.data.len() < n + 1 { - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - let ret = Some(Instruction::PushBytes(&self.data[1..n+1])); - self.data = &self.data[n + 1..]; - ret - } - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => { - if self.data.len() < 2 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } - let n = match read_uint(&self.data[1..], 1) { - Ok(n) => n, - Err(e) => { return Some(Instruction::Error(e)); } - }; - if self.data.len() < n + 2 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } - let ret = Some(Instruction::PushBytes(&self.data[2..n+2])); - self.data = &self.data[n + 2..]; - ret - } - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => { - if self.data.len() < 3 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } - let n = match read_uint(&self.data[1..], 2) { - Ok(n) => n, - Err(e) => { return Some(Instruction::Error(e)); } - }; - if self.data.len() < n + 3 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } - let ret = Some(Instruction::PushBytes(&self.data[3..n + 3])); - self.data = &self.data[n + 3..]; - ret - } - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => { - if self.data.len() < 5 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } - let n = match read_uint(&self.data[1..], 4) { - Ok(n) => n, - Err(e) => { return Some(Instruction::Error(e)); } - }; - if self.data.len() < n + 5 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } - let ret = Some(Instruction::PushBytes(&self.data[5..n + 5])); - self.data = &self.data[n + 5..]; - ret - } - // Everything else we can push right through - _ => { - let ret = Some(Instruction::Op(opcodes::All::from(self.data[0]))); - self.data = &self.data[1..]; - ret - } - } - } -} - -impl Builder { - /// Creates a new empty script - pub fn new() -> Builder { Builder(vec![]) } - - /// The length in bytes of the script - 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 - /// encoded as little-endian signed-magnitude numbers, but there are - /// dedicated opcodes to push some small integers. - pub fn push_int(mut self, data: i64) -> Builder { - // We can special-case -1, 1-16 - if data == -1 || (data >= 1 && data <= 16) { - self.0.push((data + opcodes::OP_TRUE as i64) as u8); - self - } - // We can also special-case zero - else if data == 0 { - self.0.push(opcodes::OP_FALSE as u8); - self - } - // Otherwise encode it as data - else { self.push_scriptint(data) } - } - - /// Adds instructions to push an integer onto the stack, using the explicit - /// encoding regardless of the availability of dedicated opcodes. - pub fn push_scriptint(self, data: i64) -> Builder { - self.push_slice(&build_scriptint(data)) - } - - /// Adds instructions to push some arbitrary data onto the stack - pub fn push_slice(mut self, data: &[u8]) -> Builder { - // Start with a PUSH opcode - match data.len() { - n if n < opcodes::Ordinary::OP_PUSHDATA1 as usize => { self.0.push(n as u8); }, - n if n < 0x100 => { - self.0.push(opcodes::Ordinary::OP_PUSHDATA1 as u8); - self.0.push(n as u8); - }, - n if n < 0x10000 => { - self.0.push(opcodes::Ordinary::OP_PUSHDATA2 as u8); - self.0.push((n % 0x100) as u8); - self.0.push((n / 0x100) as u8); - }, - n if n < 0x100000000 => { - self.0.push(opcodes::Ordinary::OP_PUSHDATA4 as u8); - self.0.push((n % 0x100) as u8); - self.0.push(((n / 0x100) % 0x100) as u8); - self.0.push(((n / 0x10000) % 0x100) as u8); - self.0.push((n / 0x1000000) as u8); - } - _ => panic!("tried to put a 4bn+ sized object into a script!") - } - // Then push the acraw - self.0.extend(data.iter().cloned()); - self - } - - /// Adds a single opcode to the script - pub fn push_opcode(mut self, data: opcodes::All) -> Builder { - self.0.push(data as u8); - self - } - - /// Converts the `Builder` into an unmodifiable `Script` - pub fn into_script(self) -> Script { - Script(self.0.into_boxed_slice()) - } -} - -/// Adds an individual opcode to the script -impl Default for Builder { - fn default() -> Builder { Builder(vec![]) } -} - -/// Creates a new script from an existing vector -impl From> for Builder { - fn from(v: Vec) -> Builder { Builder(v) } -} - -impl_index_newtype!(Builder, u8); - -// User-facing serialization -impl serde::Serialize for Script { - fn serialize(&self, s: &mut S) -> Result<(), S::Error> - where S: serde::Serializer, - { - s.visit_str(&format!("{:x}", self)) - } -} - -impl serde::Deserialize for Script { - fn deserialize(d: &mut D) -> Result - where D: serde::Deserializer - { - use serialize::hex::FromHex; - - struct ScriptVisitor; - impl serde::de::Visitor for ScriptVisitor { - type Value = Script; - - fn visit_string(&mut self, v: String) -> Result - where E: serde::de::Error - { - self.visit_str(&v) - } - - fn visit_str(&mut self, hex_str: &str) -> Result - where E: serde::de::Error - { - let raw_vec: Vec = try!(hex_str.from_hex() - .map_err(|_| serde::de::Error::syntax("bad script hex"))); - Ok(Script::from(raw_vec)) - } - } - - d.visit(ScriptVisitor) - } -} - -// Network serialization -impl ConsensusEncodable for Script { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { - self.0.consensus_encode(s) - } -} - -impl ConsensusDecodable for Script { - #[inline] - fn consensus_decode(d: &mut D) -> Result { - Ok(Script(try!(ConsensusDecodable::consensus_decode(d)))) - } -} - -#[cfg(test)] -mod test { - use secp256k1::Secp256k1; - use serialize::hex::FromHex; - - use super::*; - use super::build_scriptint; - use super::MaybeOwned::Owned; - - use network::serialize::{deserialize, serialize}; - use blockdata::opcodes; - use blockdata::transaction::Transaction; - - fn test_tx(tx_hex: &'static str, output_hex: Vec<&'static str>) { - let s = Secp256k1::new(); - let tx_hex = tx_hex.from_hex().unwrap(); - - let tx: Transaction = deserialize(&tx_hex).ok().expect("transaction"); - let script_pk: Vec