Skip to content

Commit

Permalink
Add no_std support
Browse files Browse the repository at this point in the history
  • Loading branch information
mcroad committed Jun 5, 2022
1 parent afdb725 commit ac16e05
Show file tree
Hide file tree
Showing 43 changed files with 488 additions and 120 deletions.
36 changes: 33 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Checkout Crate
uses: actions/checkout@v2
- name: Install hongfuzz dependancies
run: sudo apt install build-essential binutils-dev libunwind-dev libblocksruntime-dev liblzma-dev
run: sudo apt update && sudo apt install build-essential binutils-dev libunwind-dev libblocksruntime-dev liblzma-dev
- name: Checkout Toolchain
uses: actions-rs/toolchain@v1
with:
Expand All @@ -24,6 +24,7 @@ jobs:
- name: Running fuzzer
env:
DO_FUZZ: true
DO_NO_STD: true
run: ./contrib/test.sh

Nightly:
Expand All @@ -41,6 +42,7 @@ jobs:
- name: Running benchmarks
env:
DO_BENCH: true
DO_NO_STD: true
run: ./contrib/test.sh
- name: Building docs
env:
Expand All @@ -56,7 +58,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
rust: [stable, beta, nightly, 1.41.1]
include:
- rust: stable
- rust: beta
- rust: nightly
- rust: 1.41.1
- rust: 1.47
DO_NO_STD: true
steps:
- name: Checkout Crate
uses: actions/checkout@v2
Expand All @@ -69,4 +77,26 @@ jobs:
- name: Running cargo
env:
DO_FEATURE_MATRIX: true
run: ./contrib/test.sh
DO_NO_STD: ${{ matrix.DO_NO_STD }}
run: ./contrib/test.sh

Embedded:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up QEMU
run: sudo apt update && sudo apt install -y qemu-system-arm gcc-arm-none-eabi
- name: Checkout Toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rust-src
target: thumbv7m-none-eabi
- name: Run
env:
RUSTFLAGS: "-C link-arg=-Tlink.x"
CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER: "qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -nographic -semihosting-config enable=on,target=native -kernel"
run: cd embedded && cargo run --target thumbv7m-none-eabi --release
16 changes: 12 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,44 @@ readme = "README.md"
edition = "2018"

[features]
default = ["std"]
std = ["bitcoin/std", "bitcoin/secp-recovery"]
no-std = ["hashbrown", "bitcoin/no-std"]
compiler = []
trace = []
unstable = []
default = []
use-serde = ["serde", "bitcoin/use-serde"]
rand = ["bitcoin/rand"]

[dependencies]
bitcoin = "0.28.0"
serde = { version = "1.0", optional = true}
bitcoin = { version = "0.28.1", default-features = false }
serde = { version = "1.0", optional = true }
hashbrown = { version = "0.11", optional = true }

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

[[example]]
name = "htlc"
required-features = ["compiler"]
required-features = ["std", "compiler"]

[[example]]
name = "parse"
required-features = ["std"]

[[example]]
name = "sign_multisig"
required-features = ["std"]

[[example]]
name = "verify_tx"
required-features = ["std"]

[[example]]
name = "psbt"
required-features = ["std"]

[[example]]
name = "xpub_descriptors"
required-features = ["std"]
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ are convertible to `bitcoin::PublicKey`
completing an unsigned `bitcoin::TxIn` with appropriate data
* Determining the specific keys, hash preimages and timelocks used to spend
coins in a given Bitcoin transaction
* `no_std` support enabled by disabling the `default-features` and enabling
`"no-std"`. See `embedded/` for an example.

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


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

## Contributing
Contributions are generally welcome. If you intend to make larger changes please
Expand Down
18 changes: 18 additions & 0 deletions contrib/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ then
cargo run --example xpub_descriptors
fi

if [ "$DO_NO_STD" = true ]
then
# Build no_std, to make sure that cfg(test) doesn't hide any issues
cargo build --verbose --no-default-features --features="no-std"

# Test no_std
cargo test --verbose --no-default-features --features="no-std"

# Build all features
cargo build --verbose --no-default-features --features="no-std $FEATURES"

# Build specific features
for feature in ${FEATURES}
do
cargo build --verbose --no-default-features --features="no-std $feature"
done
fi

# Bench if told to (this only works with the nightly toolchain)
if [ "$DO_BENCH" = true ]
then
Expand Down
28 changes: 28 additions & 0 deletions embedded/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
authors = [
"Riccardo Casatta <riccardo@casatta.it>",
"Dev Random <c1.devrandom@niftybox.net>",
]
edition = "2018"
readme = "README.md"
name = "embedded"
version = "0.1.0"

[dependencies]
cortex-m = "0.6.0"
cortex-m-rt = "0.6.10"
cortex-m-semihosting = "0.3.3"
panic-halt = "0.2.0"
alloc-cortex-m = "0.4.1"
miniscript = { path = "../", default-features = false, features = ["no-std"] }

[[bin]]
name = "embedded"
test = false
bench = false

[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
opt-level = "z"
22 changes: 22 additions & 0 deletions embedded/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Running

To run the embedded test, first prepare your environment:

```shell
sudo ./scripts/install-deps
rustup target add thumbv7m-none-eabi
```

Then:

```shell
source ./scripts/env.sh && cargo run +nightly --target thumbv7m-none-eabi
```

Output should be something like:

```text
heap size 1048576
descriptor sh(wsh(or_d(c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352))))
p2sh address 3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns
```
5 changes: 5 additions & 0 deletions embedded/memory.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
MEMORY
{
FLASH : ORIGIN = 0x00000000, LENGTH = 2048K
RAM : ORIGIN = 0x20000000, LENGTH = 512K
}
2 changes: 2 additions & 0 deletions embedded/scripts/env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export RUSTFLAGS="-C link-arg=-Tlink.x"
export CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER="qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -nographic -semihosting-config enable=on,target=native -kernel"
3 changes: 3 additions & 0 deletions embedded/scripts/install-deps
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

apt install gcc-arm-none-eabi qemu-system-arm gdb-multiarch
82 changes: 82 additions & 0 deletions embedded/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#![no_std]
#![no_main]
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]

extern crate alloc;

use alloc::string::ToString;
use core::alloc::Layout;
use core::panic::PanicInfo;

use alloc_cortex_m::CortexMHeap;

use core::str::FromStr;

use cortex_m::asm;
use cortex_m_rt::entry;
use cortex_m_semihosting::{debug, hprintln};

// this is the allocator the application will use
#[global_allocator]
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();

const HEAP_SIZE: usize = 1024 * 256; // 256 KB

#[entry]
fn main() -> ! {
hprintln!("heap size {}", HEAP_SIZE).unwrap();

unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) }

// begin miniscript test
let descriptor = "sh(wsh(or_d(\
c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),\
c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352)\
)))";
hprintln!("descriptor {}", descriptor).unwrap();
let desc =
miniscript::Descriptor::<miniscript::bitcoin::PublicKey>::from_str(descriptor).unwrap();

// Derive the P2SH address
let p2sh_addr = desc
.address(miniscript::bitcoin::Network::Bitcoin)
.unwrap()
.to_string();
hprintln!("p2sh address {}", p2sh_addr).unwrap();
assert_eq!(p2sh_addr, "3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns");

// Check whether the descriptor is safe
// This checks whether all spend paths are accessible in bitcoin network.
// It maybe possible that some of the spend require more than 100 elements in Wsh scripts
// Or they contain a combination of timelock and heightlock.
assert!(desc.sanity_check().is_ok());

// Estimate the satisfaction cost
assert_eq!(desc.max_satisfaction_weight().unwrap(), 293);
// end miniscript test

// exit QEMU
// NOTE do not run this on hardware; it can corrupt OpenOCD state
debug::exit(debug::EXIT_SUCCESS);

loop {}
}

// define what happens in an Out Of Memory (OOM) condition
#[alloc_error_handler]
fn alloc_error(_layout: Layout) -> ! {
hprintln!("alloc error").unwrap();
debug::exit(debug::EXIT_FAILURE);
asm::bkpt();

loop {}
}

#[inline(never)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
hprintln!("panic {:?}", info.message()).unwrap();
debug::exit(debug::EXIT_FAILURE);
loop {}
}
5 changes: 3 additions & 2 deletions src/descriptor/bare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
//! Also includes pk, and pkh descriptors
//!
use std::fmt;
use std::str::FromStr;
use core::fmt;
use core::str::FromStr;

use bitcoin::blockdata::script;
use bitcoin::{Address, Network, Script};
Expand All @@ -28,6 +28,7 @@ use super::checksum::{desc_checksum, verify_checksum};
use crate::expression::{self, FromTree};
use crate::miniscript::context::ScriptContext;
use crate::policy::{semantic, Liftable};
use crate::prelude::*;
use crate::util::{varint_len, witness_to_scriptsig};
use crate::{
BareCtx, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey,
Expand Down
5 changes: 3 additions & 2 deletions src/descriptor/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
//! This module contains a re-implementation of the function used by Bitcoin Core to calculate the
//! checksum of a descriptor
use std::iter::FromIterator;
use core::iter::FromIterator;

use crate::prelude::*;
use crate::Error;

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

use super::*;

Expand Down
Loading

0 comments on commit ac16e05

Please sign in to comment.