Skip to content

Commit

Permalink
Merge #71: Add ffi module
Browse files Browse the repository at this point in the history
01a48d1 Add public ffi module (Tobin C. Harding)
6782fd1 Remove travis config file (Tobin C. Harding)
a446115 Remove written by comment (Tobin C. Harding)
e8ff1a9 Shoosh C++ compiler (Tobin C. Harding)
8d21e3d Fix rustdoc link (Tobin C. Harding)
596e2ce Move extern C stuff to bottom of file (Tobin C. Harding)
7c1cb29 Remove wildcard import (Tobin C. Harding)
1d36f2c Move error code to bottom of file (Tobin C. Harding)
bed7cde Improve docs on verify function (Tobin C. Harding)

Pull request description:

  This is #67 without the final version bump patch.

  Do a bunch of cleanups then add an `ffi` module to encapsulate the FFI function declarations.

ACKs for top commit:
  apoelstra:
    ACK 01a48d1

Tree-SHA512: 5e951156498319c0559c5ba48da10810d3112f2372801d778b579e0ecf12bfe2c69d570c9837563d0de06272f4a8e76ae2d9a8afdc1f3a10733cbed96cc5e201
  • Loading branch information
apoelstra committed Dec 6, 2023
2 parents a692bb3 + 01a48d1 commit 76ada74
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 109 deletions.
13 changes: 0 additions & 13 deletions .travis.yml

This file was deleted.

3 changes: 2 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ fn main() {
.cpp(true)
.include("depend/bitcoin/src")
.include("depend/bitcoin/src/secp256k1/include")
.define("__STDC_FORMAT_MACROS", None);
.define("__STDC_FORMAT_MACROS", None)
.flag_if_supported("-Wno-implicit-fallthrough");

// **Secp256k1**
if !cfg!(feature = "external-secp") {
Expand Down
188 changes: 94 additions & 94 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,64 +11,13 @@
//!
//! And that is exactly what this library is, the Rust bindings to `bitcoinconsensus`.
//!
//! [`bitcoin/doc/shared-libraries`]: <https://github.com/bitcoin/bitcoin/blob/master/doc/shared-libraries.md>
//! [`bitcoin/doc/shared-libraries.md`]: <https://github.com/bitcoin/bitcoin/blob/master/doc/shared-libraries.md>
mod types;

use core::fmt;

use crate::types::*;

/// Errors returned by [`libbitcoinconsensus`].
///
/// The error variant identifiers mimic those from `libbitcoinconsensus`.
///
/// [`libbitcoinconsensus`]: <https://github.com/bitcoin/bitcoin/blob/master/doc/shared-libraries.md#errors>
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Error {
/// Default value, passed to `libbitcoinconsensus` as a return parameter.
ERR_SCRIPT = 0,
/// An invalid index for `txTo`.
ERR_TX_INDEX,
/// `txToLen` did not match with the size of `txTo`.
ERR_TX_SIZE_MISMATCH,
/// An error deserializing `txTo`.
ERR_TX_DESERIALIZE,
/// Input amount is required if WITNESS is used.
ERR_AMOUNT_REQUIRED,
/// Script verification `flags` are invalid (i.e. not part of the libconsensus interface).
ERR_INVALID_FLAGS,
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;

let s = match *self {
ERR_SCRIPT => "error value was not set (value still 0)",
ERR_TX_INDEX => "an invalid index for txTo",
ERR_TX_SIZE_MISMATCH => "txToLen did not match with the size of txTo",
ERR_TX_DESERIALIZE => "an error deserializing txTo",
ERR_AMOUNT_REQUIRED => "input amount is required if WITNESS is used",
ERR_INVALID_FLAGS => "script verification flags are invalid",
};
f.write_str(s)
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*;

match *self {
ERR_SCRIPT | ERR_TX_INDEX | ERR_TX_SIZE_MISMATCH | ERR_TX_DESERIALIZE
| ERR_AMOUNT_REQUIRED | ERR_INVALID_FLAGS => None,
}
}
}
use crate::types::c_uint;

/// Do not enable any verification.
pub const VERIFY_NONE: c_uint = 0;
Expand All @@ -92,24 +41,6 @@ pub const VERIFY_ALL: c_uint = VERIFY_P2SH
| VERIFY_CHECKSEQUENCEVERIFY
| VERIFY_WITNESS;

extern "C" {
/// Returns `libbitcoinconsensus` version.
pub fn bitcoinconsensus_version() -> c_int;

/// Verifies that the transaction input correctly spends the previous
/// output, considering any additional constraints specified by flags.
pub fn bitcoinconsensus_verify_script_with_amount(
script_pubkey: *const c_uchar,
script_pubkeylen: c_uint,
amount: u64,
tx_to: *const c_uchar,
tx_tolen: c_uint,
n_in: c_uint,
flags: c_uint,
err: *mut Error,
) -> c_int;
}

/// Computes flags for soft fork activation heights on the Bitcoin network.
pub fn height_to_flags(height: u32) -> u32 {
let mut flag = VERIFY_NONE;
Expand All @@ -134,46 +65,41 @@ pub fn height_to_flags(height: u32) -> u32 {
}

/// Returns `libbitcoinconsensus` version.
pub fn version() -> u32 { unsafe { bitcoinconsensus_version() as u32 } }
pub fn version() -> u32 { unsafe { ffi::bitcoinconsensus_version() as u32 } }

/// Verifies a single spend (input) of a Bitcoin transaction.
///
/// Note that amount will only be checked for Segwit transactions.
///
/// # Arguments
///
/// * spend_output_script: A Bitcoin transaction output script to be spent, serialized in Bitcoin's on wire format.
/// * amount: The spent output amount in satoshis.
/// * spending_transaction: The spending Bitcoin transaction, serialized in Bitcoin's on wire format.
/// * input_index: The index of the input within spending_transaction.
/// * `spend_output`: A Bitcoin transaction output script to be spent, serialized in Bitcoin's on wire format.
/// * `amount`: The spent output amount in satoshis.
/// * `spending_transaction`: The spending Bitcoin transaction, serialized in Bitcoin's on wire format.
/// * `input_index`: The index of the input within spending_transaction.
///
/// # Examples
///
/// The (randomly choosen) Bitcoin transaction [aca326a724eda9a461c10a876534ecd5ae7b27f10f26c3862fb996f80ea2d45d](https://blockchain.info/tx/aca326a724eda9a461c10a876534ecd5ae7b27f10f26c3862fb996f80ea2d45d)
/// The (randomly choosen) Bitcoin transaction
///
/// `aca326a724eda9a461c10a876534ecd5ae7b27f10f26c3862fb996f80ea2d45d`
///
/// spends one input, that is the first output of
/// [95da344585fcf2e5f7d6cbf2c3df2dcce84f9196f7a7bb901a43275cd6eb7c3f](https://blockchain.info/tx/95da344585fcf2e5f7d6cbf2c3df2dcce84f9196f7a7bb901a43275cd6eb7c3f)
/// with a value of 630482530 satoshis.
///
/// The spending transaction in wire format is:
/// `95da344585fcf2e5f7d6cbf2c3df2dcce84f9196f7a7bb901a43275cd6eb7c3f`
///
/// `
/// spending = 02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700
/// `
/// The spending transaction serialized is:
///
/// The script of the first output of the spent transaction is:
/// `spending = 02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700`
///
/// `
/// spent = 76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac
/// `
/// The script of the first output of the spent transaction is:
///
/// The (pseudo code) call:
/// `spent = 76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac`
///
/// `
/// verify(spent, 630482530, spending, 0)
/// `
/// should return `Ok(())`.
/// The (pseudo code) call: `verify(spent, 630482530, spending, 0)` should return `Ok(())`.
///
/// **Note** since the spent amount will only be checked for Segwit transactions and the above example is not segwit, `verify` will succeed with any amount.
/// **Note** since the spent amount will only be checked for Segwit transactions and the above
/// example is not segwit, `verify` will succeed with any amount.
pub fn verify(
spent_output: &[u8],
amount: u64,
Expand All @@ -194,7 +120,7 @@ pub fn verify_with_flags(
unsafe {
let mut error = Error::ERR_SCRIPT;

let ret = bitcoinconsensus_verify_script_with_amount(
let ret = ffi::bitcoinconsensus_verify_script_with_amount(
spent_output_script.as_ptr(),
spent_output_script.len() as c_uint,
amount,
Expand All @@ -212,6 +138,80 @@ pub fn verify_with_flags(
}
}

pub mod ffi {
use crate::types::{c_int, c_uchar, c_uint};
use crate::Error;

extern "C" {
/// Returns `libbitcoinconsensus` version.
pub fn bitcoinconsensus_version() -> c_int;

/// Verifies that the transaction input correctly spends the previous
/// output, considering any additional constraints specified by flags.
pub fn bitcoinconsensus_verify_script_with_amount(
script_pubkey: *const c_uchar,
script_pubkeylen: c_uint,
amount: u64,
tx_to: *const c_uchar,
tx_tolen: c_uint,
n_in: c_uint,
flags: c_uint,
err: *mut Error,
) -> c_int;
}
}

/// Errors returned by [`libbitcoinconsensus`].
///
/// The error variant identifiers mimic those from `libbitcoinconsensus`.
///
/// [`libbitcoinconsensus`]: <https://github.com/bitcoin/bitcoin/blob/master/doc/shared-libraries.md#errors>
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Error {
/// Default value, passed to `libbitcoinconsensus` as a return parameter.
ERR_SCRIPT = 0,
/// An invalid index for `txTo`.
ERR_TX_INDEX,
/// `txToLen` did not match with the size of `txTo`.
ERR_TX_SIZE_MISMATCH,
/// An error deserializing `txTo`.
ERR_TX_DESERIALIZE,
/// Input amount is required if WITNESS is used.
ERR_AMOUNT_REQUIRED,
/// Script verification `flags` are invalid (i.e. not part of the libconsensus interface).
ERR_INVALID_FLAGS,
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;

let s = match *self {
ERR_SCRIPT => "error value was not set (value still 0)",
ERR_TX_INDEX => "an invalid index for txTo",
ERR_TX_SIZE_MISMATCH => "txToLen did not match with the size of txTo",
ERR_TX_DESERIALIZE => "an error deserializing txTo",
ERR_AMOUNT_REQUIRED => "input amount is required if WITNESS is used",
ERR_INVALID_FLAGS => "script verification flags are invalid",
};
f.write_str(s)
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*;

match *self {
ERR_SCRIPT | ERR_TX_INDEX | ERR_TX_SIZE_MISMATCH | ERR_TX_DESERIALIZE
| ERR_AMOUNT_REQUIRED | ERR_INVALID_FLAGS => None,
}
}
}

#[cfg(test)]
mod tests {
extern crate rustc_serialize as serialize;
Expand Down
1 change: 0 additions & 1 deletion src/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Written by the Rust Bitcoin developers.
// SPDX-License-Identifier: CC0-1.0

#![allow(non_camel_case_types)]
Expand Down

0 comments on commit 76ada74

Please sign in to comment.