Skip to content

Commit

Permalink
Scarb fmt and tool-versions
Browse files Browse the repository at this point in the history
  • Loading branch information
b-j-roberts committed Jul 24, 2024
1 parent 8c88c53 commit 09b451c
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 442 deletions.
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
scarb 2.6.3
1 change: 1 addition & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ edition = "2023_11"
# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html

[dependencies]
starknet = "2.6.3"
117 changes: 59 additions & 58 deletions src/compiler.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,72 @@ use shinigami::opcodes::Opcode;
// Compiler that takes a Bitcoin Script program and compiles it into a bytecode
#[derive(Destruct)]
pub struct Compiler {
// Dict containing opcode names to their bytecode representation
opcodes: Felt252Dict<u8>
// Dict containing opcode names to their bytecode representation
opcodes: Felt252Dict<u8>
}

pub trait CompilerTrait {
// Create a compiler, initializing the opcode dict
fn new() -> Compiler;
// Compiles a program like "OP_1 OP_2 OP_ADD" into a bytecode run by the Engine.
fn compile(self: Compiler, script: ByteArray) -> ByteArray;
// Create a compiler, initializing the opcode dict
fn new() -> Compiler;
// Compiles a program like "OP_1 OP_2 OP_ADD" into a bytecode run by the Engine.
fn compile(self: Compiler, script: ByteArray) -> ByteArray;
}

pub impl CompilerTraitImpl of CompilerTrait {
fn new() -> Compiler {
let mut opcodes = Default::default();
// Add the opcodes to the dict
opcodes.insert('OP_0', Opcode::OP_0);
opcodes.insert('OP_1', Opcode::OP_1);
opcodes.insert('OP_ADD', Opcode::OP_ADD);
Compiler { opcodes }
}
fn new() -> Compiler {
let mut opcodes = Default::default();
// Add the opcodes to the dict
opcodes.insert('OP_0', Opcode::OP_0);
opcodes.insert('OP_1', Opcode::OP_1);
opcodes.insert('OP_ADD', Opcode::OP_ADD);
Compiler { opcodes }
}

// TODO: Why self is mutable?
fn compile(mut self: Compiler, script: ByteArray) -> ByteArray {
let mut bytecode = "";
let seperator = ' ';
let byte_shift = 256;
let max_word_size = 31;
let mut current: felt252 = '';
let mut i = 0;
let mut word_len = 0;
let mut current_word: felt252 = '';
while i < script.len() {
let char = script[i].into();
if char == seperator {
let opcode = self.opcodes.get(current);
current_word = current_word * byte_shift + opcode.into();
word_len += 1;
if word_len >= max_word_size {
// Add the current word to the bytecode representation
bytecode.append_word(current_word, max_word_size);
word_len = 0;
// TODO: Why self is mutable?
fn compile(mut self: Compiler, script: ByteArray) -> ByteArray {
let mut bytecode = "";
let seperator = ' ';
let byte_shift = 256;
let max_word_size = 31;
let mut current: felt252 = '';
let mut i = 0;
let mut word_len = 0;
let mut current_word: felt252 = '';
while i < script
.len() {
let char = script[i].into();
if char == seperator {
let opcode = self.opcodes.get(current);
current_word = current_word * byte_shift + opcode.into();
word_len += 1;
if word_len >= max_word_size {
// Add the current word to the bytecode representation
bytecode.append_word(current_word, max_word_size);
word_len = 0;
}
current = '';
} else {
// Add the char to the bytecode representation
current = current * byte_shift + char;
}
i += 1;
};
// Handle the last opcode
if current != '' {
let opcode = self.opcodes.get(current);
current_word = current_word * byte_shift + opcode.into();
word_len += 1;
if word_len >= max_word_size {
// Add the current word to the bytecode representation
bytecode.append_word(current_word, max_word_size);
word_len = 0;
}
}
if word_len > 0 {
// Add the current word to the bytecode representation
bytecode.append_word(current_word, word_len);
}
current = '';
} else {
// Add the char to the bytecode representation
current = current * byte_shift + char;
}
i += 1;
};
// Handle the last opcode
if current != '' {
let opcode = self.opcodes.get(current);
current_word = current_word * byte_shift + opcode.into();
word_len += 1;
if word_len >= max_word_size {
// Add the current word to the bytecode representation
bytecode.append_word(current_word, max_word_size);
word_len = 0;
}
}
if word_len > 0 {
// Add the current word to the bytecode representation
bytecode.append_word(current_word, word_len);
}

bytecode
}
bytecode
}
}
147 changes: 75 additions & 72 deletions src/engine.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,91 +4,94 @@ use shinigami::opcodes::opcodes::Opcode::execute;
// Represents the VM that executes Bitcoin scripts
#[derive(Destruct)]
pub struct Engine {
// The script to execute
script: @ByteArray,
// Program counter within the current script
opcode_idx: usize,
// Primary data stack
pub dstack: ScriptStack,
// Alternate data stack
pub astack: ScriptStack,
// TODO
// ...
// The script to execute
script: @ByteArray,
// Program counter within the current script
opcode_idx: usize,
// Primary data stack
pub dstack: ScriptStack,
// Alternate data stack
pub astack: ScriptStack,
// TODO
// ...
}

pub trait EngineTrait {
// Create a new Engine with the given script
fn new(script: ByteArray) -> Engine;
fn get_dstack(ref self: Engine) -> Span<ByteArray>;
fn get_astack(ref self: Engine) -> Span<ByteArray>;
// Executes the next instruction in the script
fn step(ref self: Engine) -> bool; // TODO return type w/ error handling
// Executes the entire script and returns top of stack or error if script fails
fn execute(ref self: Engine) -> Result<ByteArray, felt252>;
// Create a new Engine with the given script
fn new(script: ByteArray) -> Engine;
fn get_dstack(ref self: Engine) -> Span<ByteArray>;
fn get_astack(ref self: Engine) -> Span<ByteArray>;
// Executes the next instruction in the script
fn step(ref self: Engine) -> bool; // TODO return type w/ error handling
// Executes the entire script and returns top of stack or error if script fails
fn execute(ref self: Engine) -> Result<ByteArray, felt252>;
}

pub impl EngineTraitImpl of EngineTrait {
fn new(script: ByteArray) -> Engine {
Engine {
script: @script,
opcode_idx: 0,
dstack: ScriptStackImpl::new(),
astack: ScriptStackImpl::new(),
fn new(script: ByteArray) -> Engine {
Engine {
script: @script,
opcode_idx: 0,
dstack: ScriptStackImpl::new(),
astack: ScriptStackImpl::new(),
}
}
}

fn get_dstack(ref self: Engine) -> Span<ByteArray> {
return self.dstack.stack_to_span();
}

fn get_astack(ref self: Engine) -> Span<ByteArray> {
return self.astack.stack_to_span();
}
fn get_dstack(ref self: Engine) -> Span<ByteArray> {
return self.dstack.stack_to_span();
}

fn step(ref self: Engine) -> bool {
if self.opcode_idx >= self.script.len() {
return false;
fn get_astack(ref self: Engine) -> Span<ByteArray> {
return self.astack.stack_to_span();
}

let opcode = self.script[self.opcode_idx];
execute(opcode, ref self);
self.opcode_idx += 1;
return true;
}
fn step(ref self: Engine) -> bool {
if self.opcode_idx >= self.script.len() {
return false;
}

let opcode = self.script[self.opcode_idx];
execute(opcode, ref self);
self.opcode_idx += 1;
return true;
}

fn execute(ref self: Engine) -> Result<ByteArray, felt252> {
while self.opcode_idx < self.script.len() {
let opcode = self.script[self.opcode_idx];
execute(opcode, ref self);
self.opcode_idx += 1;
// TODO: remove debug
// self.dstack.print();
// println!("==================");
};
fn execute(ref self: Engine) -> Result<ByteArray, felt252> {
while self
.opcode_idx < self
.script
.len() {
let opcode = self.script[self.opcode_idx];
execute(opcode, ref self);
self.opcode_idx += 1;
// TODO: remove debug
// self.dstack.print();
// println!("==================");
};

// TODO: CheckErrorCondition
if self.dstack.len() < 1 {
return Result::Err('Stack empty at end of script');
} else if self.dstack.len() > 1 {
return Result::Err('Stack must contain item');
} else {
// TODO: pop bool
let top_stack = self.dstack.pop_byte_array();
let ret_val = top_stack.clone();
let mut is_ok = false;
let mut i = 0;
while i < top_stack.len() {
if top_stack[i] != 0 {
is_ok = true;
break;
// TODO: CheckErrorCondition
if self.dstack.len() < 1 {
return Result::Err('Stack empty at end of script');
} else if self.dstack.len() > 1 {
return Result::Err('Stack must contain item');
} else {
// TODO: pop bool
let top_stack = self.dstack.pop_byte_array();
let ret_val = top_stack.clone();
let mut is_ok = false;
let mut i = 0;
while i < top_stack.len() {
if top_stack[i] != 0 {
is_ok = true;
break;
}
i += 1;
};
if is_ok {
return Result::Ok(ret_val);
} else {
return Result::Err('Script failed');
}
}
i += 1;
};
if is_ok {
return Result::Ok(ret_val);
} else {
return Result::Err('Script failed');
}
}
}
}
12 changes: 6 additions & 6 deletions src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
pub mod compiler;
pub mod opcodes {
pub mod opcodes;
mod tests {
#[cfg(test)]
mod test_opcodes;
}
pub(crate) use opcodes::Opcode;
pub mod opcodes;
mod tests {
#[cfg(test)]
mod test_opcodes;
}
pub(crate) use opcodes::Opcode;
}
pub mod engine;
pub mod stack;
Expand Down
22 changes: 11 additions & 11 deletions src/main.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use shinigami::compiler::CompilerTraitImpl;
use shinigami::engine::EngineTraitImpl;

fn main() {
let program = "OP_0 OP_1 OP_ADD";
println!("Running Bitcoin Script: {}", program);
let mut compiler = CompilerTraitImpl::new();
let bytecode = compiler.compile(program);
let mut engine = EngineTraitImpl::new(bytecode);
let res = engine.execute();
if res.is_ok() {
println!("Execution successful");
} else {
println!("Execution failed");
}
let program = "OP_0 OP_1 OP_ADD";
println!("Running Bitcoin Script: {}", program);
let mut compiler = CompilerTraitImpl::new();
let bytecode = compiler.compile(program);
let mut engine = EngineTraitImpl::new(bytecode);
let res = engine.execute();
if res.is_ok() {
println!("Execution successful");
} else {
println!("Execution failed");
}
}
Loading

0 comments on commit 09b451c

Please sign in to comment.