Skip to content

Commit 902f7a5

Browse files
committed
Merge branch 'script_macro'
2 parents bb80b54 + b21c2fc commit 902f7a5

File tree

6 files changed

+191
-48
lines changed

6 files changed

+191
-48
lines changed

Cargo.toml

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[package]
22
name = "bitcoin-script"
3-
version = "0.1.3"
4-
authors = ["Matt Bell <[email protected]>"]
5-
edition = "2018"
3+
version = "0.2.0"
4+
authors = ["Matt Bell <[email protected]>", "Lukas George [email protected]"]
5+
edition = "2021"
66
description = "Inline Bitcoin scripts"
77
license = "MIT"
8-
repository = "https://github.com/mappum/rust-bitcoin-script"
8+
repository = "https://github.com/BitVM/rust-bitcoin-script"
99

1010
[lib]
1111
proc-macro = true
@@ -20,3 +20,27 @@ proc-macro-error = "1.0.4"
2020
lazy_static = "1.4.0"
2121
hex = "0.4.3"
2222
proc-macro2 = "1.0.51"
23+
24+
[patch.crates-io.base58check]
25+
git = "https://github.com/rust-bitcoin/rust-bitcoin"
26+
branch = "bitvm"
27+
28+
[patch.crates-io.bitcoin]
29+
git = "https://github.com/rust-bitcoin/rust-bitcoin"
30+
branch = "bitvm"
31+
32+
[patch.crates-io.bitcoin_hashes]
33+
git = "https://github.com/rust-bitcoin/rust-bitcoin"
34+
branch = "bitvm"
35+
36+
[patch.crates-io.bitcoin-internals]
37+
git = "https://github.com/rust-bitcoin/rust-bitcoin"
38+
branch = "bitvm"
39+
40+
[patch.crates-io.bitcoin-io]
41+
git = "https://github.com/rust-bitcoin/rust-bitcoin"
42+
branch = "bitvm"
43+
44+
[patch.crates-io.bitcoin-units]
45+
git = "https://github.com/rust-bitcoin/rust-bitcoin"
46+
branch = "bitvm"

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
## Usage
1212

13-
This crate exports a `bitcoin_script!` macro which can be used to build Bitcoin scripts. The macro returns the [`Script`](https://docs.rs/bitcoin/0.23.0/bitcoin/blockdata/script/struct.Script.html) type from the [`bitcoin`](https://github.com/rust-bitcoin/rust-bitcoin) crate.
13+
This crate exports a `script!` macro which can be used to build Bitcoin scripts. The macro returns the [`Script`](https://docs.rs/bitcoin/0.23.0/bitcoin/blockdata/script/struct.Script.html) type from the [`bitcoin`](https://github.com/rust-bitcoin/rust-bitcoin) crate.
1414

1515
**Example:**
1616

@@ -19,7 +19,7 @@ This crate exports a `bitcoin_script!` macro which can be used to build Bitcoin
1919

2020
use bitcoin_script::bitcoin_script;
2121

22-
let htlc_script = bitcoin_script! {
22+
let htlc_script = script! {
2323
OP_IF
2424
OP_SHA256 <digest> OP_EQUALVERIFY OP_DUP OP_SHA256 <seller_pubkey_hash>
2525
OP_ELSE
@@ -43,7 +43,7 @@ Whitespace is ignored - scripts can be formatted in the author's preferred style
4343
All normal opcodes are available, in the form `OP_X`.
4444

4545
```rust
46-
let script = bitcoin_script!(OP_CHECKSIG OP_VERIFY);
46+
let script = script!(OP_CHECKSIG OP_VERIFY);
4747
```
4848

4949
#### Integer Literals
@@ -55,15 +55,15 @@ For example:
5555
- `255` will resolve to a length-delimited varint: `0x02ff00` (note the extra zero byte, due to the way Bitcoin scripts use the most-significant bit to represent the sign)`
5656

5757
```rust
58-
let script = bitcoin_script!(123 -456 999999);
58+
let script = script!(123 -456 999999);
5959
```
6060

6161
#### Hex Literals
6262

6363
Hex strings can be specified, prefixed with `0x`.
6464

6565
```rust
66-
let script = bitcoin_script!(
66+
let script = script!(
6767
0x0102030405060708090a0b0c0d0e0f OP_HASH160
6868
);
6969
```
@@ -81,7 +81,7 @@ Rust expressions of the following types are supported:
8181
```rust
8282
let bytes = vec![1, 2, 3];
8383

84-
let script = bitcoin_script! {
84+
let script = script! {
8585
<bytes> OP_CHECKSIGVERIFY
8686

8787
<2016 * 5> OP_CSV

src/generate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn generate_escape(builder: TokenStream, expression: TokenStream, span: Span) ->
5151
#[allow(clippy::all)]
5252

5353
use ::bitcoin::blockdata::script::Builder;
54-
fn push(builder: Builder, value: impl pushable::Pushable) -> Builder {
54+
fn push<T: pushable::Pushable>(builder: Builder, value: T) -> Builder {
5555
value.bitcoin_script_push(builder)
5656
}
5757
push(builder, value)

src/lib.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//!
99
//! ## Usage
1010
//!
11-
//! This crate exports a `bitcoin_script!` macro which can be used to build
11+
//! This crate exports a `script!` macro which can be used to build
1212
//! Bitcoin scripts. The macro returns the
1313
//! [`Script`](https://docs.rs/bitcoin/0.23.0/bitcoin/blockdata/script/struct.Script.html)
1414
//! type from the [`bitcoin`](https://github.com/rust-bitcoin/rust-bitcoin)
@@ -19,14 +19,14 @@
1919
//! ```rust
2020
//! #![feature(proc_macro_hygiene)]
2121
//!
22-
//! use bitcoin_script::{bitcoin_script, define_pushable};
22+
//! use bitcoin_script::{script, define_pushable};
2323
//!
2424
//! define_pushable!();
2525
//! # let digest = 0;
2626
//! # let seller_pubkey_hash = 0;
2727
//! # let buyer_pubkey_hash = 0;
2828
//!
29-
//! let htlc_script = bitcoin_script! {
29+
//! let htlc_script = script! {
3030
//! OP_IF
3131
//! OP_SHA256 <digest> OP_EQUALVERIFY OP_DUP OP_SHA256 <seller_pubkey_hash>
3232
//! OP_ELSE
@@ -59,8 +59,8 @@
5959
//!
6060
//! ```rust
6161
//! # #![feature(proc_macro_hygiene)]
62-
//! # use bitcoin_script::bitcoin_script;
63-
//! let script = bitcoin_script!(OP_CHECKSIG OP_VERIFY);
62+
//! # use bitcoin_script::script;
63+
//! let script = script!(OP_CHECKSIG OP_VERIFY);
6464
//! ```
6565
//!
6666
//! #### Integer Literals
@@ -73,8 +73,8 @@
7373
//!
7474
//! ```rust
7575
//! # #![feature(proc_macro_hygiene)]
76-
//! # use bitcoin_script::bitcoin_script;
77-
//! let script = bitcoin_script!(123 -456 999999);
76+
//! # use bitcoin_script::script;
77+
//! let script = script!(123 -456 999999);
7878
//! ```
7979
//!
8080
//! #### Hex Literals
@@ -83,8 +83,8 @@
8383
//!
8484
//! ```rust
8585
//! # #![feature(proc_macro_hygiene)]
86-
//! # use bitcoin_script::bitcoin_script;
87-
//! let script = bitcoin_script!(
86+
//! # use bitcoin_script::script;
87+
//! let script = script!(
8888
//! 0x0102030405060708090a0b0c0d0e0f OP_HASH160
8989
//! );
9090
//! ```
@@ -104,11 +104,11 @@
104104
//!
105105
//! ```rust
106106
//! # #![feature(proc_macro_hygiene)]
107-
//! # use bitcoin_script::{bitcoin_script, define_pushable};
107+
//! # use bitcoin_script::{script, define_pushable};
108108
//! define_pushable!();
109109
//! let bytes = vec![1, 2, 3];
110110
//!
111-
//! let script = bitcoin_script! {
111+
//! let script = script! {
112112
//! <bytes> OP_CHECKSIGVERIFY
113113
//!
114114
//! <2016 * 5> OP_CSV
@@ -128,7 +128,7 @@ use quote::quote;
128128

129129
#[proc_macro]
130130
#[proc_macro_error]
131-
pub fn bitcoin_script(tokens: TokenStream) -> TokenStream {
131+
pub fn script(tokens: TokenStream) -> TokenStream {
132132
set_dummy(quote!((::bitcoin::Script::new())));
133133
generate(parse(tokens.into())).into()
134134
}
@@ -188,7 +188,10 @@ pub fn define_pushable(_: TokenStream) -> TokenStream {
188188
}
189189
impl NotU8Pushable for ::bitcoin::ScriptBuf {
190190
fn bitcoin_script_push(self, builder: Builder) -> Builder {
191-
Builder::from([builder.into_bytes(), self.into_bytes()].concat())
191+
let mut script_vec = vec![];
192+
script_vec.extend_from_slice(builder.as_bytes());
193+
script_vec.extend_from_slice(self.as_bytes());
194+
Builder::from(script_vec)
192195
}
193196
}
194197
impl<T: NotU8Pushable> NotU8Pushable for Vec<T> {

src/parse.rs

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use bitcoin::blockdata::opcodes::Opcode;
1+
use bitcoin::{blockdata::opcodes::Opcode, opcodes::all::OP_RESERVED};
22
use proc_macro2::{
3-
Delimiter,
4-
Span, TokenStream,
3+
Delimiter, Span, TokenStream,
54
TokenTree::{self, *},
65
};
76
use quote::quote;
7+
use std::iter::Peekable;
88
use std::str::FromStr;
99

1010
#[derive(Debug)]
@@ -41,14 +41,20 @@ macro_rules! abort {
4141
}
4242

4343
pub fn parse(tokens: TokenStream) -> Vec<(Syntax, Span)> {
44-
let mut tokens = tokens.into_iter();
44+
let mut tokens = tokens.into_iter().peekable();
4545
let mut syntax = Vec::with_capacity(64);
4646

4747
while let Some(token) = tokens.next() {
4848
let token_str = token.to_string();
4949
syntax.push(match (&token, token_str.as_ref()) {
5050
// Wrap for loops such that they return a Vec<ScriptBuf>
5151
(Ident(_), ident_str) if ident_str == "for" => parse_for_loop(token, &mut tokens),
52+
// Wrap if-else statements such that they return a Vec<ScriptBuf>
53+
(Ident(_), ident_str) if ident_str == "if" => parse_if(token, &mut tokens),
54+
// Replace DEBUG with OP_RESERVED
55+
(Ident(_), ident_str) if ident_str == "DEBUG" => {
56+
(Syntax::Opcode(OP_RESERVED), token.span())
57+
}
5258

5359
// identifier, look up opcode
5460
(Ident(_), _) => {
@@ -85,10 +91,52 @@ pub fn parse(tokens: TokenStream) -> Vec<(Syntax, Span)> {
8591
_ => abort!(token.span(), "unexpected token"),
8692
});
8793
}
88-
8994
syntax
9095
}
9196

97+
fn parse_if<T>(token: TokenTree, tokens: &mut Peekable<T>) -> (Syntax, Span)
98+
where
99+
T: Iterator<Item = TokenTree>,
100+
{
101+
// Use a Vec here to get rid of warnings when the variable is overwritten
102+
let mut escape = quote! {
103+
let mut script_var = vec![];
104+
};
105+
escape.extend(std::iter::once(token.clone()));
106+
107+
while let Some(if_token) = tokens.next() {
108+
match if_token {
109+
Group(block) if block.delimiter() == Delimiter::Brace => {
110+
let inner_block = block.stream();
111+
escape.extend(quote! {
112+
{
113+
script_var.extend_from_slice(script! {
114+
#inner_block
115+
}.as_bytes());
116+
}
117+
});
118+
119+
match tokens.peek() {
120+
Some(else_token) if else_token.to_string().as_str() == "else" => continue,
121+
_ => break,
122+
}
123+
}
124+
_ => {
125+
escape.extend(std::iter::once(if_token));
126+
continue;
127+
}
128+
};
129+
}
130+
escape = quote! {
131+
{
132+
#escape;
133+
bitcoin::script::ScriptBuf::from(script_var)
134+
}
135+
}
136+
.into();
137+
(Syntax::Escape(escape), token.span())
138+
}
139+
92140
fn parse_for_loop<T>(token: TokenTree, tokens: &mut T) -> (Syntax, Span)
93141
where
94142
T: Iterator<Item = TokenTree>,
@@ -104,11 +152,11 @@ where
104152
let inner_block = block.stream();
105153
escape.extend(quote! {
106154
{
107-
script_var.push(bitcoin_script !{
108-
#inner_block
109-
});
155+
script_var.extend_from_slice(script !{
156+
#inner_block
157+
}.as_bytes());
110158
}
111-
script_var
159+
bitcoin::script::ScriptBuf::from(script_var)
112160
});
113161
break;
114162
}
@@ -119,7 +167,7 @@ where
119167
};
120168
}
121169

122-
(Syntax::Escape(quote!{ { #escape }}.into()), token.span())
170+
(Syntax::Escape(quote! { { #escape } }.into()), token.span())
123171
}
124172

125173
fn parse_escape<T>(token: TokenTree, tokens: &mut T) -> (Syntax, Span)

0 commit comments

Comments
 (0)