Skip to content

Commit 969841f

Browse files
committed
Use a static script_map per thread
1 parent 9c6074d commit 969841f

File tree

5 files changed

+66
-60
lines changed

5 files changed

+66
-60
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ repository = "https://github.com/BitVM/rust-bitcoin-script"
3939

4040
[dependencies]
4141
bitcoin = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm", features = ["rand-std"]}
42+
lazy_static = "1.5.0"
4243
script-macro = { path = "./macro" }
4344
stdext = "0.3.3"
4445

src/analyzer.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
use crate::builder::{Block, StructuredScript};
2-
use crate::chunker::Chunk;
1+
use crate::builder::{thread_get_script, Block, StructuredScript};
32
use bitcoin::blockdata::opcodes::Opcode;
43
use bitcoin::blockdata::script::{read_scriptint, Instruction};
54
use bitcoin::opcodes::all::*;
65
use bitcoin::script::PushBytes;
7-
use bitcoin::ScriptBuf;
8-
use script_macro::script;
96
use std::borrow::BorrowMut;
10-
use std::cmp::{max, min};
7+
use std::cmp::min;
118
use std::panic;
129

1310
#[derive(Debug, Clone, Default, PartialEq)]
@@ -149,16 +146,13 @@ impl StackAnalyzer {
149146
for block in builder.blocks.iter() {
150147
match block {
151148
Block::Call(id) => {
152-
let called_script = builder
153-
.script_map
154-
.get(id)
155-
.expect("Missing entry for a called script");
149+
let called_script = thread_get_script(id);
156150
match called_script.stack_hint() {
157151
Some(stack_hint) => {
158152
self.debug_position += called_script.len();
159153
self.stack_change(stack_hint)
160154
}
161-
None => self.merge_script(called_script),
155+
None => self.merge_script(&called_script),
162156
};
163157
}
164158
Block::Script(block_script) => {

src/builder.rs

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,36 @@ use std::cmp::min;
77
use std::collections::HashMap;
88
use std::convert::TryFrom;
99
use std::hash::{DefaultHasher, Hash, Hasher};
10+
use std::sync::RwLock;
1011
use std::{fs::File, io::Write};
1112

1213
use crate::analyzer::{StackAnalyzer, StackStatus};
1314
use crate::chunker::Chunker;
1415

16+
// One global script map per thread.
17+
thread_local! {
18+
static SCRIPT_MAP: RwLock<HashMap<u64, Box<StructuredScript>>> =
19+
RwLock::new(HashMap::new());
20+
}
21+
22+
pub(crate) fn thread_add_script(id: u64, script: StructuredScript) {
23+
SCRIPT_MAP.with(|script_map| {
24+
let mut map = script_map.write().unwrap();
25+
if !map.contains_key(&id) {
26+
map.insert(id, Box::new(script));
27+
}
28+
});
29+
}
30+
31+
pub(crate) fn thread_get_script(id: &u64) -> Box<StructuredScript> {
32+
SCRIPT_MAP.with(|script_map| {
33+
let map = script_map.read().unwrap();
34+
map.get(id)
35+
.expect("script id not found in SCRIPT_MAP")
36+
.clone()
37+
})
38+
}
39+
1540
#[derive(Clone, Debug, Hash)]
1641
pub enum Block {
1742
Call(u64),
@@ -36,8 +61,6 @@ pub struct StructuredScript {
3661
extra_endif_positions: Vec<usize>,
3762
max_if_interval: (usize, usize),
3863
pub blocks: Vec<Block>,
39-
// TODO: It may be worth to lazy initialize the script_map
40-
pub script_map: HashMap<u64, StructuredScript>,
4164
}
4265

4366
impl Hash for StructuredScript {
@@ -65,7 +88,6 @@ impl StructuredScript {
6588
extra_endif_positions: vec![],
6689
max_if_interval: (0, 0),
6790
blocks,
68-
script_map: HashMap::new(),
6991
}
7092
}
7193

@@ -87,7 +109,9 @@ impl StructuredScript {
87109
if self.is_script_buf() {
88110
match &self.blocks[0] {
89111
Block::Call(_) => unreachable!(),
90-
Block::Script(block_script) => block_script.instructions().collect::<Vec<_>>().len() == 1,
112+
Block::Script(block_script) => {
113+
block_script.instructions().collect::<Vec<_>>().len() == 1
114+
}
91115
}
92116
} else {
93117
false
@@ -109,10 +133,7 @@ impl StructuredScript {
109133
assert!(current_pos <= position, "Target position not found");
110134
match block {
111135
Block::Call(id) => {
112-
let called_script = self
113-
.script_map
114-
.get(id)
115-
.expect("Missing entry for a called script");
136+
let called_script = thread_get_script(id);
116137
if position >= current_pos && position < current_pos + called_script.len() {
117138
return called_script.debug_info(position - current_pos);
118139
}
@@ -259,8 +280,8 @@ impl StructuredScript {
259280
self.num_unclosed_ifs += data.num_unclosed_ifs;
260281
let id = calculate_hash(&data);
261282
self.blocks.push(Block::Call(id));
262-
// Register script
263-
self.script_map.entry(id).or_insert(data);
283+
// Register script in the global script map
284+
thread_add_script(id, data);
264285
self
265286
}
266287

@@ -270,10 +291,7 @@ impl StructuredScript {
270291
for block in self.blocks.as_slice() {
271292
match block {
272293
Block::Call(id) => {
273-
let called_script = self
274-
.script_map
275-
.get(id)
276-
.expect("Missing entry for a called script");
294+
let called_script = thread_get_script(id);
277295
// Check if the script with the hash id is in cache
278296
match cache.get(id) {
279297
Some(called_start) => {
@@ -329,6 +347,7 @@ impl StructuredScript {
329347
}
330348

331349
pub fn compile(self) -> ScriptBuf {
350+
println!("starting compile step");
332351
let mut script = Vec::with_capacity(self.size);
333352
let mut cache = HashMap::new();
334353
self.compile_to_bytes(&mut script, &mut cache);
@@ -348,12 +367,8 @@ impl StructuredScript {
348367
File::create("analyzed_chunk_stats.txt").expect("Unable to create stats file");
349368
let chunk_stats = chunker.chunks.iter().map(|chunk| chunk.stats.clone());
350369
for entry in chunk_stats {
351-
writeln!(
352-
stats_file,
353-
"{:?}",
354-
entry.stack_input_size
355-
)
356-
.expect("Unable to write to stats file");
370+
writeln!(stats_file, "{:?}", entry.stack_input_size)
371+
.expect("Unable to write to stats file");
357372
}
358373
let mut chunk_sizes_iter = chunk_sizes.iter();
359374
let mut scripts = vec![];
@@ -397,19 +412,19 @@ impl StructuredScript {
397412
Some(hint) => {
398413
hint.stack_changed = changed;
399414
hint.deepest_stack_accessed = access;
400-
},
401-
None => self.stack_hint = Some(StackAnalyzer::plain_stack_status(access, changed))
415+
}
416+
None => self.stack_hint = Some(StackAnalyzer::plain_stack_status(access, changed)),
402417
}
403418
self
404419
}
405-
420+
406421
pub fn add_altstack_hint(mut self, access: i32, changed: i32) -> Self {
407422
match &mut self.stack_hint {
408423
Some(hint) => {
409424
hint.altstack_changed = changed;
410425
hint.deepest_altstack_accessed = access;
411-
},
412-
None => self.stack_hint = Some(StackAnalyzer::plain_stack_status(access, changed))
426+
}
427+
None => self.stack_hint = Some(StackAnalyzer::plain_stack_status(access, changed)),
413428
}
414429
self
415430
}

src/chunker.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
use core::panic;
22

3-
use bitcoin::{
4-
opcodes::all::{OP_ENDIF, OP_IF, OP_NOTIF},
5-
script::Instruction,
6-
ScriptBuf,
7-
};
3+
use bitcoin::ScriptBuf;
84

95
use crate::{
10-
analyzer::{self, StackStatus},
11-
builder::{Block, StructuredScript},
6+
analyzer::StackStatus,
7+
builder::{thread_get_script, Block, StructuredScript},
128
StackAnalyzer,
139
};
1410

@@ -203,11 +199,11 @@ impl Chunker {
203199
);
204200
}
205201
} else {
206-
for block in builder.blocks {
202+
for block in &builder.blocks {
207203
match block {
208204
Block::Call(id) => {
209-
let sub_builder = builder.script_map.get(&id).unwrap();
210-
undo_info.call_stack.push(Box::new(sub_builder.clone()));
205+
let sub_builder = thread_get_script(id);
206+
undo_info.call_stack.push(sub_builder);
211207
}
212208
Block::Script(script_buf) => {
213209
// Split the script_buf
@@ -287,8 +283,8 @@ impl Chunker {
287283
for block in builder.blocks.iter().rev() {
288284
match block {
289285
Block::Call(id) => {
290-
let sub_builder = builder.script_map.get(id).unwrap();
291-
self.call_stack.push(Box::new(sub_builder.clone()));
286+
let sub_builder = thread_get_script(id);
287+
self.call_stack.push(sub_builder);
292288
contains_call = true;
293289
}
294290
Block::Script(script_buf) => {
@@ -322,10 +318,10 @@ impl Chunker {
322318
.try_into()
323319
.expect("Consuming more stack elements than there are on the stack 3"),
324320
altstack_input_size: input_altstack_size,
325-
altstack_output_size: status
326-
.altstack_changed
327-
.try_into()
328-
.expect(&format!("Consuming more stack elements than there are on the altstack: {:?}", status)),
321+
altstack_output_size: status.altstack_changed.try_into().expect(&format!(
322+
"Consuming more stack elements than there are on the altstack: {:?}",
323+
status
324+
)),
329325
};
330326

331327
Chunk::new(chunk_scripts, chunk_len, chunk_stats, last_constant)

tests/test.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -234,15 +234,15 @@ fn test_non_optimal_opcodes() {
234234
OP_DROP
235235
OP_DROP
236236

237-
for i in 0..4 {
238-
OP_ROLL
239-
{ i }
240-
}
241-
242-
for i in 0..4 {
243-
{ i }
244-
OP_ROLL
245-
}
237+
//for i in 0..4 {
238+
// OP_ROLL
239+
// { i }
240+
//}
241+
242+
//for i in 0..4 {
243+
// { i }
244+
// OP_ROLL
245+
//}
246246

247247
};
248248

0 commit comments

Comments
 (0)