Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no_std support #528

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 12 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ readme = "README.md"


[features]
default = [ "secp-recovery" ]
default = [ "std", "secp-recovery" ]
base64 = [ "base64-compat" ]
fuzztarget = ["secp256k1/fuzztarget", "bitcoin_hashes/fuzztarget"]
unstable = []
Expand All @@ -21,15 +21,18 @@ use-serde = ["serde", "bitcoin_hashes/serde", "secp256k1/serde"]
secp-endomorphism = ["secp256k1/endomorphism"]
secp-lowmemory = ["secp256k1/lowmemory"]
secp-recovery = ["secp256k1/recovery"]
std = ["secp256k1/std", "bitcoin_hashes/std"]
use-bare-io = ["bare-io", "bitcoin_hashes/bare-io"]

[dependencies]
base64-compat = { version = "1.0.0", optional = true }
bech32 = "0.7.2"
bitcoin_hashes = "0.9.0"
bitcoin_hashes = { git = "https://github.com/justinmoon/bitcoin_hashes.git", branch = "more_no_std", features = [], default-features = false }
Copy link
Author

Choose a reason for hiding this comment

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

secp256k1 = { version = "0.19.0", features = [ "recovery" ] }

bitcoinconsensus = { version = "0.19.0-1", optional = true }
serde = { version = "1", optional = true }
bare-io = { version = "0.2", optional = true }

[dev-dependencies]
serde_derive = "<1.0.99"
Expand All @@ -38,3 +41,10 @@ serde_test = "1"
secp256k1 = { version = "0.19.0", features = [ "recovery", "rand-std" ] }
# We need to pin ryu (transitive dep from serde_json) to stay compatible with Rust 1.22.0
ryu = "<1.0.5"

[[example]]
name = "bip32"

[[example]]
name = "handshake"
required-features = ["std"]
3 changes: 3 additions & 0 deletions contrib/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ do
cargo test --verbose --features="$feature"
done

# Test no_std
cargo test --verbose --features="use-bare-io" --no-default-features

# Fuzz if told to
if [ "$DO_FUZZ" = true ]
then
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/deserialize_address.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extern crate bitcoin;
use std::str::FromStr;
use core::str::FromStr;
fn do_test(data: &[u8]) {
let data_str = String::from_utf8_lossy(data);
let addr = match bitcoin::util::address::Address::from_str(&data_str) {
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/deserialize_amount.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extern crate bitcoin;
use std::str::FromStr;
use core::str::FromStr;
fn do_test(data: &[u8]) {
let data_str = String::from_utf8_lossy(data);

Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/outpoint_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate bitcoin;
use bitcoin::blockdata::transaction::OutPoint;
use bitcoin::consensus::encode;

use std::str::FromStr;
use core::str::FromStr;

fn do_test(data: &[u8]) {
let lowercase: Vec<u8> = data.iter().map(|c| match *c {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/fuzz_targets/uint128_fuzz.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate bitcoin;
use std::str::FromStr;
use std::convert::Into;
use core::str::FromStr;
use core::convert::Into;

fn do_test(data: &[u8]) {
macro_rules! read_ints {
Expand Down
7 changes: 5 additions & 2 deletions src/blockdata/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
//! these blocks and the blockchain.
//!

use std::fmt;
use core::fmt;
use alloc::vec::Vec;

use util;
use util::Error::{BlockBadTarget, BlockBadProofOfWork};
Expand Down Expand Up @@ -308,12 +309,14 @@ impl fmt::Display for Bip34Error {
}
}

impl ::std::error::Error for Bip34Error {}
#[cfg(feature = "std")]
impl std::error::Error for Bip34Error {}
Copy link
Author

Choose a reason for hiding this comment

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

I don't quite understand what a lack of an Error impl in `no_std would mean here ...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not too much. The whole Error concept is std-only usually. The Result type doesn't require the second generic parameter to be Error, so it has very few effects.


#[cfg(test)]
mod tests {
use hashes::hex::FromHex;

use alloc::{vec::Vec, string::ToString};
use blockdata::block::{Block, BlockHeader};
use consensus::encode::{deserialize, serialize};

Expand Down
6 changes: 4 additions & 2 deletions src/blockdata/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
//! single transaction
//!

use std::default::Default;
use core::default::Default;
use alloc::vec::Vec;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe it's possible to avoid bumping MSRV if use like this is conditional. Assuming it's fine to have diferent MSRV for different features (I think it's reasonable).


use hashes::hex::FromHex;
use hashes::sha256d;
Expand Down Expand Up @@ -159,7 +160,8 @@ pub fn genesis_block(network: Network) -> Block {

#[cfg(test)]
mod test {
use std::default::Default;
use core::default::Default;
use alloc::{vec::Vec, string::ToString};
use hashes::hex::FromHex;

use network::constants::Network;
Expand Down
6 changes: 3 additions & 3 deletions src/blockdata/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

#[cfg(feature = "serde")] use serde;

use std::fmt;
use core::{fmt, convert::From};

// Note: I am deliberately not implementing PartialOrd or Ord on the
// opcode enum. If you want to check ranges of opcodes, etc.,
Expand Down Expand Up @@ -816,7 +816,7 @@ impl Ordinary {

#[cfg(test)]
mod tests {
use std::collections::HashSet;
use alloc::collections::BTreeSet;

use super::*;

Expand All @@ -834,7 +834,7 @@ mod tests {

#[test]
fn str_roundtrip() {
let mut unique = HashSet::new();
let mut unique = BTreeSet::new();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should not be needed in tests, there's no point in making tests no_std

roundtrip!(unique, OP_PUSHBYTES_0);
roundtrip!(unique, OP_PUSHBYTES_1);
roundtrip!(unique, OP_PUSHBYTES_2);
Expand Down
17 changes: 10 additions & 7 deletions src/blockdata/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
//! This module provides the structures and functions needed to support scripts.
//!

use std::default::Default;
use std::{error, fmt, io};
use io;

use core::{fmt, default::Default};
use alloc::{boxed::Box, vec::Vec, string::String};

#[cfg(feature = "serde")] use serde;

Expand All @@ -34,7 +36,7 @@ use blockdata::opcodes;
use consensus::{encode, Decodable, Encodable};
use hashes::Hash;
#[cfg(feature="bitcoinconsensus")] use bitcoinconsensus;
#[cfg(feature="bitcoinconsensus")] use std::convert;
#[cfg(feature="bitcoinconsensus")] use core::convert::From;
#[cfg(feature="bitcoinconsensus")] use OutPoint;

use util::key::PublicKey;
Expand Down Expand Up @@ -120,11 +122,12 @@ impl fmt::Display for Error {
}
}

impl error::Error for Error {}
#[cfg(feature = "std")]
impl std::error::Error for Error {}

#[cfg(feature="bitcoinconsensus")]
#[doc(hidden)]
impl convert::From<bitcoinconsensus::Error> for Error {
impl From<bitcoinconsensus::Error> for Error {
fn from(err: bitcoinconsensus::Error) -> Error {
match err {
_ => Error::BitcoinConsensus(err)
Expand Down Expand Up @@ -760,7 +763,7 @@ impl<'de> serde::Deserialize<'de> for Script {
where
D: serde::Deserializer<'de>,
{
use std::fmt::Formatter;
use core::fmt::Formatter;
use hashes::hex::FromHex;

struct Visitor;
Expand Down Expand Up @@ -829,7 +832,7 @@ impl Decodable for Script {

#[cfg(test)]
mod test {
use std::str::FromStr;
use core::str::FromStr;

use super::*;
use super::build_scriptint;
Expand Down
21 changes: 12 additions & 9 deletions src/blockdata/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
//! This module provides the structures and functions needed to support transactions.
//!

use std::default::Default;
use std::{error, fmt, io, str};
use io;
use core::{fmt, str, default::Default};
use alloc::{string::{ToString, String}, vec::Vec};

use hashes::{self, Hash, sha256d};
use hashes::hex::FromHex;
Expand Down Expand Up @@ -107,7 +108,7 @@ pub enum ParseOutPointError {
/// Error in TXID part.
Txid(hashes::hex::Error),
/// Error in vout part.
Vout(::std::num::ParseIntError),
Vout(::core::num::ParseIntError),
/// Error in general format.
Format,
/// Size exceeds max.
Expand All @@ -128,8 +129,9 @@ impl fmt::Display for ParseOutPointError {
}
}

impl error::Error for ParseOutPointError {
fn cause(&self) -> Option<&dyn error::Error> {
#[cfg(feature = "std")]
impl std::error::Error for ParseOutPointError {
fn cause(&self) -> Option<&dyn std::error::Error> {
match *self {
ParseOutPointError::Txid(ref e) => Some(e),
ParseOutPointError::Vout(ref e) => Some(e),
Expand All @@ -150,7 +152,7 @@ fn parse_vout(s: &str) -> Result<u32, ParseOutPointError> {
Ok(s.parse().map_err(ParseOutPointError::Vout)?)
}

impl ::std::str::FromStr for OutPoint {
impl ::core::str::FromStr for OutPoint {
type Err = ParseOutPointError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Expand Down Expand Up @@ -684,9 +686,10 @@ impl SigHashType {

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

use std::str::FromStr;
use core::str::FromStr;
use alloc::string::ToString;
use blockdata::constants::WITNESS_SCALE_FACTOR;
use blockdata::script::Script;
use consensus::encode::serialize;
Expand Down Expand Up @@ -1277,7 +1280,7 @@ mod tests {
#[cfg(feature="bitcoinconsensus")]
fn test_transaction_verify () {
use hashes::hex::FromHex;
use std::collections::HashMap;
use alloc::collections::HashMap;
use blockdata::script;
// a random recent segwit transaction from blockchain using both old and segwit inputs
let mut spending: Transaction = deserialize(Vec::from_hex("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700")
Expand Down
48 changes: 29 additions & 19 deletions src/consensus/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,22 @@
//! big-endian decimals, etc.)
//!

use std::{fmt, error, io, mem, u32};
use std::borrow::Cow;
use std::io::{Cursor, Read, Write};
use hashes::hex::ToHex;

use core::{fmt, mem, u32, convert::From};
use alloc::{string::String, vec::Vec, borrow::Cow, boxed::Box};

use hashes::hex::ToHex;
use hashes::{sha256d, Hash};
use hash_types::{BlockHash, FilterHash, TxMerkleNode, FilterHeader};

use io::{self, Cursor, Read, Write};

use util::endian;
use util::psbt;

use blockdata::transaction::{TxOut, Transaction, TxIn};
use network::message_blockdata::Inventory;
use network::address::{Address, AddrV2Message};
#[cfg(feature = "std")]
use network::{message_blockdata::Inventory, address::{Address, AddrV2Message}};

/// Encoding error
#[derive(Debug)]
Expand Down Expand Up @@ -109,8 +111,9 @@ impl fmt::Display for Error {
}
}

impl error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> {
#[cfg(feature = "std")]
impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn std::error::Error> {
match *self {
Error::Io(ref e) => Some(e),
Error::Psbt(ref e) => Some(e),
Expand Down Expand Up @@ -249,7 +252,7 @@ macro_rules! decoder_fn {
($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => {
#[inline]
fn $name(&mut self) -> Result<$val_type, Error> {
debug_assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22
debug_assert_eq!(::core::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22
let mut val = [0; $byte_len];
self.read_exact(&mut val[..]).map_err(Error::Io)?;
Ok(endian::$readfn(&val))
Expand Down Expand Up @@ -598,10 +601,14 @@ impl_vec!(TxMerkleNode);
impl_vec!(Transaction);
impl_vec!(TxOut);
impl_vec!(TxIn);
impl_vec!(Inventory);
impl_vec!(Vec<u8>);
impl_vec!((u32, Address));
impl_vec!(u64);

#[cfg(feature = "std")]
impl_vec!(Inventory);
#[cfg(feature = "std")]
impl_vec!((u32, Address));
#[cfg(feature = "std")]
impl_vec!(AddrV2Message);

fn consensus_encode_with_size<S: io::Write>(data: &[u8], mut s: S) -> Result<usize, Error> {
Expand Down Expand Up @@ -735,15 +742,16 @@ impl Decodable for sha256d::Hash {
// Tests
#[cfg(test)]
mod tests {
use std::{io, mem, fmt};
use std::mem::discriminant;
use super::*;
use core::{mem::{self, discriminant}, fmt};
use alloc::string::ToString;
use super::{deserialize, serialize, Error, CheckedData, VarInt};
use super::{Transaction, BlockHash, FilterHash, TxMerkleNode, TxOut, TxIn};
use consensus::{Encodable, deserialize_partial, Decodable};
use util::endian::{u64_to_array_le, u32_to_array_le, u16_to_array_le};
use secp256k1::rand::{thread_rng, Rng};
use network::message_blockdata::Inventory;
use network::Address;
#[cfg(feature = "std")]
use network::{Address, message_blockdata::Inventory};

#[test]
fn serialize_int_test() {
Expand Down Expand Up @@ -818,7 +826,7 @@ mod tests {
}

fn test_varint_len(varint: VarInt, expected: usize) {
let mut encoder = io::Cursor::new(vec![]);
let mut encoder = vec![];
assert_eq!(varint.consensus_encode(&mut encoder).unwrap(), expected);
assert_eq!(varint.len(), expected);
}
Expand Down Expand Up @@ -949,10 +957,12 @@ mod tests {
test_len_is_max_vec::<Transaction>();
test_len_is_max_vec::<TxOut>();
test_len_is_max_vec::<TxIn>();
test_len_is_max_vec::<Inventory>();
test_len_is_max_vec::<Vec<u8>>();
test_len_is_max_vec::<(u32, Address)>();
test_len_is_max_vec::<u64>();
#[cfg(feature = "std")]
test_len_is_max_vec::<(u32, Address)>();
#[cfg(feature = "std")]
test_len_is_max_vec::<Inventory>();
}

fn test_len_is_max_vec<T>() where Vec<T>: Decodable, T: fmt::Debug {
Expand All @@ -967,7 +977,7 @@ mod tests {
assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string()));
assert_eq!(
deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
Some(::std::borrow::Cow::Borrowed("Andrew"))
Some(::alloc::borrow::Cow::Borrowed("Andrew"))
);
}

Expand Down