Skip to content

Commit ea76eb1

Browse files
committed
Merge #277: Add no_std support
ac16e05 Add no_std support (mcroad) Pull request description: Closes #201. Related to bitcoindevkit/bdk#205 Not ready. - [x] `no_std` example - [x] updated readme with instructions - [x] tests pass - [x] rust-bitcoin/rust-bitcoin#637 includes `secp256k1/alloc` feature in `bitcoin/no-std`. Released on `0.28.0` - [x] rust-bitcoin/rust-bitcoin#690 Rust `1.47` set as `no_std` MSRV. Released in `0.28.1`. Maintains backward compatibility. To use it in a `no_std` context set `default-features = false` and enable the `no-std` feature. ~~To the maintainers: I added the `no-std-compat` crate. It wraps `core` and `hashbrown` and makes them look like `std`. This is a different than what `rust-bitcoin` did. They use `core` and `hashbrown` directly. I believe using `no-std-compat` makes the code more readable. I'd like to hear your thoughts on this.~~ Now using `hashbrown` and `core` directly. ACKs for top commit: sanket1729: ACK ac16e05 Tree-SHA512: 5c26cb50374b7844acbcc5a7607f5710ce19ec0aff4caed1346ed4a2fb708a909205a7d87cc27a773624f43b2a99a71c3ba4bb1cdf2dfec0584833df00b9f032
2 parents afdb725 + ac16e05 commit ea76eb1

Some content is hidden

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

43 files changed

+488
-120
lines changed

.github/workflows/rust.yml

+33-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Checkout Crate
1515
uses: actions/checkout@v2
1616
- name: Install hongfuzz dependancies
17-
run: sudo apt install build-essential binutils-dev libunwind-dev libblocksruntime-dev liblzma-dev
17+
run: sudo apt update && sudo apt install build-essential binutils-dev libunwind-dev libblocksruntime-dev liblzma-dev
1818
- name: Checkout Toolchain
1919
uses: actions-rs/toolchain@v1
2020
with:
@@ -24,6 +24,7 @@ jobs:
2424
- name: Running fuzzer
2525
env:
2626
DO_FUZZ: true
27+
DO_NO_STD: true
2728
run: ./contrib/test.sh
2829

2930
Nightly:
@@ -41,6 +42,7 @@ jobs:
4142
- name: Running benchmarks
4243
env:
4344
DO_BENCH: true
45+
DO_NO_STD: true
4446
run: ./contrib/test.sh
4547
- name: Building docs
4648
env:
@@ -56,7 +58,13 @@ jobs:
5658
runs-on: ubuntu-latest
5759
strategy:
5860
matrix:
59-
rust: [stable, beta, nightly, 1.41.1]
61+
include:
62+
- rust: stable
63+
- rust: beta
64+
- rust: nightly
65+
- rust: 1.41.1
66+
- rust: 1.47
67+
DO_NO_STD: true
6068
steps:
6169
- name: Checkout Crate
6270
uses: actions/checkout@v2
@@ -69,4 +77,26 @@ jobs:
6977
- name: Running cargo
7078
env:
7179
DO_FEATURE_MATRIX: true
72-
run: ./contrib/test.sh
80+
DO_NO_STD: ${{ matrix.DO_NO_STD }}
81+
run: ./contrib/test.sh
82+
83+
Embedded:
84+
runs-on: ubuntu-latest
85+
steps:
86+
- name: Checkout
87+
uses: actions/checkout@v2
88+
- name: Set up QEMU
89+
run: sudo apt update && sudo apt install -y qemu-system-arm gcc-arm-none-eabi
90+
- name: Checkout Toolchain
91+
uses: actions-rs/toolchain@v1
92+
with:
93+
profile: minimal
94+
toolchain: nightly
95+
override: true
96+
components: rust-src
97+
target: thumbv7m-none-eabi
98+
- name: Run
99+
env:
100+
RUSTFLAGS: "-C link-arg=-Tlink.x"
101+
CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER: "qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -nographic -semihosting-config enable=on,target=native -kernel"
102+
run: cd embedded && cargo run --target thumbv7m-none-eabi --release

Cargo.toml

+12-4
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,44 @@ readme = "README.md"
1111
edition = "2018"
1212

1313
[features]
14+
default = ["std"]
15+
std = ["bitcoin/std", "bitcoin/secp-recovery"]
16+
no-std = ["hashbrown", "bitcoin/no-std"]
1417
compiler = []
1518
trace = []
1619
unstable = []
17-
default = []
1820
use-serde = ["serde", "bitcoin/use-serde"]
1921
rand = ["bitcoin/rand"]
2022

2123
[dependencies]
22-
bitcoin = "0.28.0"
23-
serde = { version = "1.0", optional = true}
24+
bitcoin = { version = "0.28.1", default-features = false }
25+
serde = { version = "1.0", optional = true }
26+
hashbrown = { version = "0.11", optional = true }
2427

2528
[dev-dependencies]
2629
bitcoind = {version = "0.26.1", features=["22_0"]}
2730
actual-rand = { package = "rand", version = "0.8.4"}
2831

2932
[[example]]
3033
name = "htlc"
31-
required-features = ["compiler"]
34+
required-features = ["std", "compiler"]
3235

3336
[[example]]
3437
name = "parse"
38+
required-features = ["std"]
3539

3640
[[example]]
3741
name = "sign_multisig"
42+
required-features = ["std"]
3843

3944
[[example]]
4045
name = "verify_tx"
46+
required-features = ["std"]
4147

4248
[[example]]
4349
name = "psbt"
50+
required-features = ["std"]
4451

4552
[[example]]
4653
name = "xpub_descriptors"
54+
required-features = ["std"]

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@ are convertible to `bitcoin::PublicKey`
2727
completing an unsigned `bitcoin::TxIn` with appropriate data
2828
* Determining the specific keys, hash preimages and timelocks used to spend
2929
coins in a given Bitcoin transaction
30+
* `no_std` support enabled by disabling the `default-features` and enabling
31+
`"no-std"`. See `embedded/` for an example.
3032

3133
More information can be found in [the documentation](https://docs.rs/miniscript)
3234
or in [the `examples/` directory](https://github.com/apoelstra/rust-miniscript/tree/master/examples)
3335

3436

3537
## Minimum Supported Rust Version (MSRV)
36-
This library should always compile with any combination of features on **Rust 1.41.1**.
38+
This library should always compile with any combination of features (minus
39+
`no-std`) on **Rust 1.41.1** or **Rust 1.47** with `no-std`.
3740

3841
## Contributing
3942
Contributions are generally welcome. If you intend to make larger changes please

contrib/test.sh

+18
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,24 @@ then
5555
cargo run --example xpub_descriptors
5656
fi
5757

58+
if [ "$DO_NO_STD" = true ]
59+
then
60+
# Build no_std, to make sure that cfg(test) doesn't hide any issues
61+
cargo build --verbose --no-default-features --features="no-std"
62+
63+
# Test no_std
64+
cargo test --verbose --no-default-features --features="no-std"
65+
66+
# Build all features
67+
cargo build --verbose --no-default-features --features="no-std $FEATURES"
68+
69+
# Build specific features
70+
for feature in ${FEATURES}
71+
do
72+
cargo build --verbose --no-default-features --features="no-std $feature"
73+
done
74+
fi
75+
5876
# Bench if told to (this only works with the nightly toolchain)
5977
if [ "$DO_BENCH" = true ]
6078
then

embedded/Cargo.toml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
authors = [
3+
"Riccardo Casatta <[email protected]>",
4+
"Dev Random <[email protected]>",
5+
]
6+
edition = "2018"
7+
readme = "README.md"
8+
name = "embedded"
9+
version = "0.1.0"
10+
11+
[dependencies]
12+
cortex-m = "0.6.0"
13+
cortex-m-rt = "0.6.10"
14+
cortex-m-semihosting = "0.3.3"
15+
panic-halt = "0.2.0"
16+
alloc-cortex-m = "0.4.1"
17+
miniscript = { path = "../", default-features = false, features = ["no-std"] }
18+
19+
[[bin]]
20+
name = "embedded"
21+
test = false
22+
bench = false
23+
24+
[profile.release]
25+
codegen-units = 1 # better optimizations
26+
debug = true # symbols are nice and they don't increase the size on Flash
27+
lto = true # better optimizations
28+
opt-level = "z"

embedded/README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Running
2+
3+
To run the embedded test, first prepare your environment:
4+
5+
```shell
6+
sudo ./scripts/install-deps
7+
rustup target add thumbv7m-none-eabi
8+
```
9+
10+
Then:
11+
12+
```shell
13+
source ./scripts/env.sh && cargo run +nightly --target thumbv7m-none-eabi
14+
```
15+
16+
Output should be something like:
17+
18+
```text
19+
heap size 1048576
20+
descriptor sh(wsh(or_d(c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352))))
21+
p2sh address 3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns
22+
```

embedded/memory.x

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
MEMORY
2+
{
3+
FLASH : ORIGIN = 0x00000000, LENGTH = 2048K
4+
RAM : ORIGIN = 0x20000000, LENGTH = 512K
5+
}

embedded/scripts/env.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export RUSTFLAGS="-C link-arg=-Tlink.x"
2+
export CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER="qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -nographic -semihosting-config enable=on,target=native -kernel"

embedded/scripts/install-deps

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
apt install gcc-arm-none-eabi qemu-system-arm gdb-multiarch

embedded/src/main.rs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#![no_std]
2+
#![no_main]
3+
#![feature(alloc_error_handler)]
4+
#![feature(panic_info_message)]
5+
6+
extern crate alloc;
7+
8+
use alloc::string::ToString;
9+
use core::alloc::Layout;
10+
use core::panic::PanicInfo;
11+
12+
use alloc_cortex_m::CortexMHeap;
13+
14+
use core::str::FromStr;
15+
16+
use cortex_m::asm;
17+
use cortex_m_rt::entry;
18+
use cortex_m_semihosting::{debug, hprintln};
19+
20+
// this is the allocator the application will use
21+
#[global_allocator]
22+
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
23+
24+
const HEAP_SIZE: usize = 1024 * 256; // 256 KB
25+
26+
#[entry]
27+
fn main() -> ! {
28+
hprintln!("heap size {}", HEAP_SIZE).unwrap();
29+
30+
unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) }
31+
32+
// begin miniscript test
33+
let descriptor = "sh(wsh(or_d(\
34+
c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),\
35+
c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352)\
36+
)))";
37+
hprintln!("descriptor {}", descriptor).unwrap();
38+
let desc =
39+
miniscript::Descriptor::<miniscript::bitcoin::PublicKey>::from_str(descriptor).unwrap();
40+
41+
// Derive the P2SH address
42+
let p2sh_addr = desc
43+
.address(miniscript::bitcoin::Network::Bitcoin)
44+
.unwrap()
45+
.to_string();
46+
hprintln!("p2sh address {}", p2sh_addr).unwrap();
47+
assert_eq!(p2sh_addr, "3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns");
48+
49+
// Check whether the descriptor is safe
50+
// This checks whether all spend paths are accessible in bitcoin network.
51+
// It maybe possible that some of the spend require more than 100 elements in Wsh scripts
52+
// Or they contain a combination of timelock and heightlock.
53+
assert!(desc.sanity_check().is_ok());
54+
55+
// Estimate the satisfaction cost
56+
assert_eq!(desc.max_satisfaction_weight().unwrap(), 293);
57+
// end miniscript test
58+
59+
// exit QEMU
60+
// NOTE do not run this on hardware; it can corrupt OpenOCD state
61+
debug::exit(debug::EXIT_SUCCESS);
62+
63+
loop {}
64+
}
65+
66+
// define what happens in an Out Of Memory (OOM) condition
67+
#[alloc_error_handler]
68+
fn alloc_error(_layout: Layout) -> ! {
69+
hprintln!("alloc error").unwrap();
70+
debug::exit(debug::EXIT_FAILURE);
71+
asm::bkpt();
72+
73+
loop {}
74+
}
75+
76+
#[inline(never)]
77+
#[panic_handler]
78+
fn panic(info: &PanicInfo) -> ! {
79+
hprintln!("panic {:?}", info.message()).unwrap();
80+
debug::exit(debug::EXIT_FAILURE);
81+
loop {}
82+
}

src/descriptor/bare.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
//! Also includes pk, and pkh descriptors
1919
//!
2020
21-
use std::fmt;
22-
use std::str::FromStr;
21+
use core::fmt;
22+
use core::str::FromStr;
2323

2424
use bitcoin::blockdata::script;
2525
use bitcoin::{Address, Network, Script};
@@ -28,6 +28,7 @@ use super::checksum::{desc_checksum, verify_checksum};
2828
use crate::expression::{self, FromTree};
2929
use crate::miniscript::context::ScriptContext;
3030
use crate::policy::{semantic, Liftable};
31+
use crate::prelude::*;
3132
use crate::util::{varint_len, witness_to_scriptsig};
3233
use crate::{
3334
BareCtx, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey,

src/descriptor/checksum.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
//! This module contains a re-implementation of the function used by Bitcoin Core to calculate the
44
//! checksum of a descriptor
55
6-
use std::iter::FromIterator;
6+
use core::iter::FromIterator;
77

8+
use crate::prelude::*;
89
use crate::Error;
910

1011
const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
@@ -100,7 +101,7 @@ pub(super) fn verify_checksum(s: &str) -> Result<&str, Error> {
100101
}
101102
#[cfg(test)]
102103
mod test {
103-
use std::str;
104+
use core::str;
104105

105106
use super::*;
106107

0 commit comments

Comments
 (0)