Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub use bitcoin::consensus::encode::MAX_VEC_SIZE;
/// Encoding error
#[derive(Debug)]
pub enum Error {
/// And I/O error
Io(io::Error),
/// A Bitcoin encoding error.
Bitcoin(btcenc::Error),
/// Tried to allocate an oversized vector
Expand All @@ -46,6 +48,7 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Io(ref e) => write!(f, "I/O error: {}", e),
Error::Bitcoin(ref e) => write!(f, "a Bitcoin type encoding error: {}", e),
Error::OversizedVectorAllocation {
requested: ref r,
Expand Down Expand Up @@ -73,6 +76,13 @@ impl From<btcenc::Error> for Error {
}
}

#[doc(hidden)]
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Error::Io(error)
}
}

/// Data which can be encoded in a consensus-consistent way
pub trait Encodable {
/// Encode an object with a well-defined format, should only ever error if
Expand Down Expand Up @@ -153,6 +163,7 @@ macro_rules! impl_upstream {
impl_upstream!(u8);
impl_upstream!(u32);
impl_upstream!(u64);
impl_upstream!([u8;4]);
impl_upstream!([u8; 32]);
impl_upstream!(Box<[u8]>);
impl_upstream!(Vec<u8>);
Expand Down
25 changes: 25 additions & 0 deletions src/endian.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
macro_rules! define_le_to_array {
($name: ident, $type: ty, $byte_len: expr) => {
#[inline]
pub fn $name(val: $type) -> [u8; $byte_len] {
debug_assert_eq!(::std::mem::size_of::<$type>(), $byte_len); // size_of isn't a constfn in 1.22
let mut res = [0; $byte_len];
for i in 0..$byte_len {
res[i] = ((val >> i*8) & 0xff) as u8;
}
res
}
}
}

define_le_to_array!(u32_to_array_le, u32, 4);

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn endianness_test() {
assert_eq!(u32_to_array_le(0xdeadbeef), [0xef, 0xbe, 0xad, 0xde]);
}
}
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ pub mod opcodes;
pub mod script;
mod transaction;
pub mod slip77;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would prefer you retain this whitespace

pub mod sighash;
// consider making upstream public
mod endian;
// re-export bitcoin deps which we re-use
pub use bitcoin::{bech32, hashes, secp256k1};
// export everything at the top level so it can be used as `elements::Transaction` etc.
pub use address::{Address, AddressParams, AddressError};
pub use transaction::{OutPoint, PeginData, PegoutData, TxIn, TxOut, TxInWitness, TxOutWitness, Transaction, AssetIssuance};
pub use transaction::{OutPoint, PeginData, PegoutData, SigHashType, TxIn, TxOut, TxInWitness, TxOutWitness, Transaction, AssetIssuance};
pub use block::{BlockHeader, Block};
pub use block::ExtData as BlockExtData;
pub use ::bitcoin::consensus::encode::VarInt;
Expand Down
74 changes: 71 additions & 3 deletions src/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ use std::{fmt, io, ops};
#[cfg(feature = "serde")] use serde;

use encode::{self, Decodable, Encodable};
use {opcodes, ScriptHash, WScriptHash};
use bitcoin::hashes::Hash;
use {opcodes, ScriptHash, WScriptHash, PubkeyHash, WPubkeyHash};

use bitcoin::PublicKey;

Expand Down Expand Up @@ -208,6 +209,75 @@ impl Script {
/// Creates a new empty script
pub fn new() -> Script { Script(vec![].into_boxed_slice()) }

/// Generates P2PK-type of scriptPubkey
pub fn new_p2pk(pubkey: &PublicKey) -> Script {
Builder::new()
.push_key(pubkey)
.push_opcode(opcodes::all::OP_CHECKSIG)
.into_script()
}

/// Generates P2PKH-type of scriptPubkey
pub fn new_p2pkh(pubkey_hash: &PubkeyHash) -> Script {
Builder::new()
.push_opcode(opcodes::all::OP_DUP)
.push_opcode(opcodes::all::OP_HASH160)
.push_slice(&pubkey_hash[..])
.push_opcode(opcodes::all::OP_EQUALVERIFY)
.push_opcode(opcodes::all::OP_CHECKSIG)
.into_script()
}

/// Generates P2SH-type of scriptPubkey with a given hash of the redeem script
pub fn new_p2sh(script_hash: &ScriptHash) -> Script {
Builder::new()
.push_opcode(opcodes::all::OP_HASH160)
.push_slice(&script_hash[..])
.push_opcode(opcodes::all::OP_EQUAL)
.into_script()
}

/// Generates P2WPKH-type of scriptPubkey
pub fn new_v0_wpkh(pubkey_hash: &WPubkeyHash) -> Script {
Script::new_witness_program(::bech32::u5::try_from_u8(0).unwrap(), &pubkey_hash.to_vec())
}

/// Generates P2WSH-type of scriptPubkey with a given hash of the redeem script
pub fn new_v0_wsh(script_hash: &WScriptHash) -> Script {
Script::new_witness_program(::bech32::u5::try_from_u8(0).unwrap(), &script_hash.to_vec())
}

/// Generates P2WSH-type of scriptPubkey with a given hash of the redeem script
pub fn new_witness_program(ver: ::bech32::u5, program: &[u8]) -> Script {
let mut verop = ver.to_u8();
assert!(verop <= 16, "incorrect witness version provided: {}", verop);
if verop > 0 {
verop = 0x50 + verop;
}
Builder::new()
.push_opcode(verop.into())
.push_slice(&program)
.into_script()
}

/// Generates OP_RETURN-type of scriptPubkey for a given data
pub fn new_op_return(data: &[u8]) -> Script {
Builder::new()
.push_opcode(opcodes::all::OP_RETURN)
.push_slice(data)
.into_script()
}

/// Returns 160-bit hash of the script
pub fn script_hash(&self) -> ScriptHash {
ScriptHash::hash(&self.as_bytes())
}

/// Returns 256-bit hash of the script for P2WSH outputs
pub fn wscript_hash(&self) -> WScriptHash {
WScriptHash::hash(&self.as_bytes())
}

/// The length in bytes of the script
pub fn len(&self) -> usize { self.0.len() }

Expand All @@ -225,7 +295,6 @@ impl Script {

/// Compute the P2SH output corresponding to this redeem script
pub fn to_p2sh(&self) -> Script {
use bitcoin::hashes::Hash;
Builder::new().push_opcode(opcodes::all::OP_HASH160)
.push_slice(&ScriptHash::hash(&self.0)[..])
.push_opcode(opcodes::all::OP_EQUAL)
Expand All @@ -235,7 +304,6 @@ impl Script {
/// Compute the P2WSH output corresponding to this witnessScript (aka the "witness redeem
/// script")
pub fn to_v0_p2wsh(&self) -> Script {
use bitcoin::hashes::Hash;
Builder::new().push_int(0)
.push_slice(&WScriptHash::hash(&self.0)[..])
.into_script()
Expand Down
Loading