Skip to content

Commit 4826d0c

Browse files
committed
no_std support
Based on the original work by Justin Moon. *MSRV unchanged from 1.29.0.* When `std` is off, `no-std` must be on, and we use the [`alloc`](https://doc.rust-lang.org/alloc/) and core2 crates. The `alloc` crate requires the user define a global allocator. * Import from `core` and `alloc` instead of `std` * `alloc` only used if `no-std` is on * Create `std` feature * Create `no-std` feature which adds a core2 dependency to polyfill `std::io` features. This is an experimental feature and should be used with caution. * CI runs tests `no-std` * MSRV for `no-std` is 1.51 or so
1 parent abff973 commit 4826d0c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+432
-185
lines changed

.github/workflows/rust.yml

+3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@ jobs:
1313
env:
1414
DO_COV: true
1515
AS_DEPENDENCY: true
16+
DO_NO_STD: true
1617
- rust: beta
1718
env:
1819
AS_DEPENDENCY: true
20+
DO_NO_STD: true
1921
- rust: nightly
2022
env:
2123
DO_FUZZ: true
2224
DO_BENCH: true
2325
AS_DEPENDENCY: true
26+
DO_NO_STD: true
2427
- rust: 1.29.0
2528
env:
2629
AS_DEPENDENCY: true

Cargo.toml

+21-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ readme = "README.md"
1212

1313

1414
[features]
15-
default = [ "secp-recovery" ]
15+
default = [ "std", "secp-recovery" ]
1616
base64 = [ "base64-compat" ]
1717
fuzztarget = []
1818
unstable = []
@@ -21,14 +21,24 @@ use-serde = ["serde", "bitcoin_hashes/serde", "secp256k1/serde"]
2121
secp-lowmemory = ["secp256k1/lowmemory"]
2222
secp-recovery = ["secp256k1/recovery"]
2323

24+
# At least one of std, no-std must be enabled.
25+
#
26+
# The no-std feature doesn't disable std - you need to turn off the std feature for that by disabling default.
27+
# Instead no-std enables additional features required for this crate to be usable without std.
28+
# As a result, both can be enabled without conflict.
29+
std = ["secp256k1/std", "bitcoin_hashes/std", "bech32/std"]
30+
no-std = ["hashbrown", "core2/alloc", "bitcoin_hashes/alloc"]
31+
2432
[dependencies]
25-
bech32 = "0.8.0"
26-
bitcoin_hashes = "0.9.6"
27-
secp256k1 = "0.20.2"
33+
bech32 = { version = "0.8.1", default-features = false }
34+
bitcoin_hashes = { version = "0.10.0", default-features = false }
35+
secp256k1 = { version = "0.20.2", default-features = false }
36+
core2 = { version = "0.3.0", optional = true, default-features = false }
2837

2938
base64-compat = { version = "1.0.0", optional = true }
3039
bitcoinconsensus = { version = "0.19.0-3", optional = true }
3140
serde = { version = "1", features = [ "derive" ], optional = true }
41+
hashbrown = { version = "0.8", optional = true }
3242

3343
[dev-dependencies]
3444
serde_json = "<1.0.45"
@@ -37,3 +47,10 @@ secp256k1 = { version = "0.20.0", features = [ "recovery", "rand-std" ] }
3747
bincode = "1.3.1"
3848
# We need to pin ryu (transitive dep from serde_json) to stay compatible with Rust 1.22.0
3949
ryu = "<1.0.5"
50+
51+
[[example]]
52+
name = "bip32"
53+
54+
[[example]]
55+
name = "handshake"
56+
required-features = ["std"]

contrib/test.sh

+39-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#!/bin/sh -ex
22

3-
FEATURES="base64 bitcoinconsensus use-serde rand"
3+
FEATURES="base64 bitcoinconsensus use-serde rand secp-recovery"
4+
5+
# Use toolchain if explicitly specified
6+
if [ -n "$TOOLCHAIN" ]
7+
then
8+
alias cargo="cargo +$TOOLCHAIN"
9+
fi
410

511
pin_common_verions() {
612
cargo generate-lockfile --verbose
@@ -10,7 +16,7 @@ pin_common_verions() {
1016
}
1117

1218
# Pin `cc` for Rust 1.29
13-
if [ -n "$PIN_VERSIONS" ]; then
19+
if [ "$PIN_VERSIONS" = true ]; then
1420
pin_common_verions
1521
cargo update -p byteorder --precise "1.3.4"
1622
fi
@@ -21,20 +27,43 @@ then
2127
fi
2228

2329

24-
# Use toolchain if explicitly specified
25-
if [ -n "$TOOLCHAIN" ]
26-
then
27-
alias cargo="cargo +$TOOLCHAIN"
28-
fi
30+
echo "********* Testing std *************"
31+
# Test without any features other than std first
32+
cargo test --verbose --no-default-features --features="std"
2933

30-
# Test without any features first
31-
cargo test --verbose --no-default-features
34+
echo "********* Testing default *************"
3235
# Then test with the default features
3336
cargo test --verbose
3437

38+
if [ "$DO_NO_STD" = true ]
39+
then
40+
echo "********* Testing no-std build *************"
41+
# Build no_std, to make sure that cfg(test) doesn't hide any issues
42+
cargo build --verbose --features="no-std" --no-default-features
43+
44+
# Build std + no_std, to make sure they are not incompatible
45+
cargo build --verbose --features="no-std"
46+
47+
# Test no_std
48+
cargo test --verbose --features="no-std" --no-default-features
49+
50+
# Build all features
51+
cargo build --verbose --features="no-std $FEATURES" --no-default-features
52+
53+
# Build specific features
54+
for feature in ${FEATURES}
55+
do
56+
cargo build --verbose --features="no-std $feature"
57+
done
58+
59+
cargo run --example bip32 L1HKVVLHXiUhecWnwFYF6L3shkf1E12HUmuZTESvBXUdx3yqVP1D
60+
cargo run --no-default-features --features no-std --example bip32 L1HKVVLHXiUhecWnwFYF6L3shkf1E12HUmuZTESvBXUdx3yqVP1D
61+
fi
62+
3563
# Test each feature
3664
for feature in ${FEATURES}
3765
do
66+
echo "********* Testing "$feature" *************"
3867
cargo test --verbose --features="$feature"
3968
done
4069

@@ -55,7 +84,7 @@ then
5584
fi
5685

5786
# Use as dependency if told to
58-
if [ -n "$AS_DEPENDENCY" ]
87+
if [ "$AS_DEPENDENCY" = true ]
5988
then
6089
cargo new dep_test
6190
cd dep_test

examples/bip32.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use bitcoin::util::bip32::ExtendedPubKey;
1010
use bitcoin::util::bip32::DerivationPath;
1111
use bitcoin::util::bip32::ChildNumber;
1212
use bitcoin::util::address::Address;
13+
use bitcoin::secp256k1::ffi::types::AlignedType;
1314

1415
fn main() {
1516
// This example derives root xprv
@@ -36,7 +37,9 @@ fn main() {
3637
let seed = wif.to_bytes();
3738

3839
// we need secp256k1 context for key derivation
39-
let secp = Secp256k1::new();
40+
let mut buf: Vec<AlignedType> = Vec::new();
41+
buf.resize(Secp256k1::preallocate_size(), AlignedType::zeroed());
42+
let secp = Secp256k1::preallocated_new(buf.as_mut_slice()).unwrap();
4043

4144
// calculate root key from seed
4245
let root = ExtendedPrivKey::new_master(network, &seed).unwrap();

src/blockdata/block.rs

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
//! these blocks and the blockchain.
2121
//!
2222
23+
use prelude::*;
24+
2325
use core::fmt;
2426

2527
use util;
@@ -308,6 +310,7 @@ impl fmt::Display for Bip34Error {
308310
}
309311
}
310312

313+
#[cfg(feature = "std")]
311314
impl ::std::error::Error for Bip34Error {}
312315

313316
#[cfg(test)]

src/blockdata/constants.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
//! single transaction
2020
//!
2121
22+
use prelude::*;
23+
2224
use core::default::Default;
2325

24-
use hashes::hex::FromHex;
26+
use hashes::hex::{HexIterator, Error as HexError};
2527
use hashes::sha256d;
2628
use blockdata::opcodes;
2729
use blockdata::script;
@@ -84,8 +86,11 @@ fn bitcoin_genesis_tx() -> Transaction {
8486
});
8587

8688
// Outputs
89+
let script_bytes: Result<Vec<u8>, HexError> =
90+
HexIterator::new("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap()
91+
.collect();
8792
let out_script = script::Builder::new()
88-
.push_slice(&Vec::from_hex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap())
93+
.push_slice(script_bytes.unwrap().as_slice())
8994
.push_opcode(opcodes::all::OP_CHECKSIG)
9095
.into_script();
9196
ret.output.push(TxOut {

src/blockdata/opcodes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

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

25+
#[cfg(feature = "serde")] use prelude::*;
26+
2527
use core::{fmt, convert::From};
2628

2729
// Note: I am deliberately not implementing PartialOrd or Ord on the

src/blockdata/script.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
//! This module provides the structures and functions needed to support scripts.
2525
//!
2626
27-
use io;
27+
use prelude::*;
2828

29+
use io;
2930
use core::{fmt, default::Default};
3031

3132
#[cfg(feature = "serde")] use serde;
@@ -36,7 +37,7 @@ use consensus::{encode, Decodable, Encodable};
3637
use hashes::{Hash, hex};
3738
use policy::DUST_RELAY_TX_FEE;
3839
#[cfg(feature="bitcoinconsensus")] use bitcoinconsensus;
39-
#[cfg(feature="bitcoinconsensus")] use std::convert;
40+
#[cfg(feature="bitcoinconsensus")] use core::convert::From;
4041
#[cfg(feature="bitcoinconsensus")] use OutPoint;
4142

4243
use util::ecdsa::PublicKey;
@@ -145,11 +146,12 @@ impl fmt::Display for Error {
145146
}
146147
}
147148

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

150152
#[cfg(feature="bitcoinconsensus")]
151153
#[doc(hidden)]
152-
impl convert::From<bitcoinconsensus::Error> for Error {
154+
impl From<bitcoinconsensus::Error> for Error {
153155
fn from(err: bitcoinconsensus::Error) -> Error {
154156
match err {
155157
_ => Error::BitcoinConsensus(err)
@@ -421,11 +423,11 @@ impl Script {
421423
} else if self.is_witness_program() {
422424
32 + 4 + 1 + (107 / 4) + 4 + // The spend cost copied from Core
423425
8 + // The serialized size of the TxOut's amount field
424-
self.consensus_encode(&mut ::std::io::sink()).unwrap() as u64 // The serialized size of this script_pubkey
426+
self.consensus_encode(&mut sink()).unwrap() as u64 // The serialized size of this script_pubkey
425427
} else {
426428
32 + 4 + 1 + 107 + 4 + // The spend cost copied from Core
427429
8 + // The serialized size of the TxOut's amount field
428-
self.consensus_encode(&mut ::std::io::sink()).unwrap() as u64 // The serialized size of this script_pubkey
430+
self.consensus_encode(&mut sink()).unwrap() as u64 // The serialized size of this script_pubkey
429431
};
430432

431433
::Amount::from_sat(sats)

src/blockdata/transaction.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
//! This module provides the structures and functions needed to support transactions.
2424
//!
2525
26+
use prelude::*;
27+
2628
use io;
2729
use core::{fmt, str, default::Default};
28-
use std::error;
30+
#[cfg(feature = "std")] use std::error;
2931

3032
use hashes::{self, Hash, sha256d};
3133
use hashes::hex::FromHex;
@@ -130,8 +132,9 @@ impl fmt::Display for ParseOutPointError {
130132
}
131133
}
132134

133-
impl error::Error for ParseOutPointError {
134-
fn cause(&self) -> Option<&dyn error::Error> {
135+
#[cfg(feature = "std")]
136+
impl error::Error for ParseOutPointError {
137+
fn cause(&self) -> Option<&dyn error::Error> {
135138
match *self {
136139
ParseOutPointError::Txid(ref e) => Some(e),
137140
ParseOutPointError::Vout(ref e) => Some(e),
@@ -630,6 +633,7 @@ impl fmt::Display for NonStandardSigHashType {
630633
}
631634
}
632635

636+
#[cfg(feature = "std")]
633637
impl error::Error for NonStandardSigHashType {}
634638

635639
/// Hashtype of an input's signature, encoded in the last byte of the signature
@@ -1360,6 +1364,7 @@ mod tests {
13601364
use hashes::hex::FromHex;
13611365
use std::collections::HashMap;
13621366
use blockdata::script;
1367+
13631368
// a random recent segwit transaction from blockchain using both old and segwit inputs
13641369
let mut spending: Transaction = deserialize(Vec::from_hex("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700")
13651370
.unwrap().as_slice()).unwrap();

0 commit comments

Comments
 (0)