Skip to content

Commit

Permalink
OP_ROLL
Browse files Browse the repository at this point in the history
  • Loading branch information
oxlime committed Sep 19, 2024
1 parent ea0f61a commit 32daac8
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/script/engine.zig
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub const Engine = struct {
Opcode.OP_CHECKSIG => try self.opCheckSig(),
Opcode.OP_NIP => try self.opNip(),
Opcode.OP_OVER => try self.opOver(),
Opcode.OP_ROLL => try self.opRoll(),
Opcode.OP_SWAP => try self.opSwap(),
Opcode.OP_TUCK => try self.opTuck(),
Opcode.OP_SIZE => try self.opSize(),
Expand Down Expand Up @@ -379,6 +380,16 @@ pub const Engine = struct {
try self.stack.pushByteArray(value);
}

/// OP_ROLL: Pop the top stack element as N. Move the Nth stack element to the top.
///
/// # Returns
/// - `EngineError`: If an error occurs during execution
fn opRoll(self: *Engine) !void {
const n = try self.stack.popInt();
const value = try self.stack.removeAt(@intCast(n));
try self.stack.pushElement(value);
}

/// OP_SWAP: The top two items on the stack are swapped.
///
/// /// # Returns
Expand Down Expand Up @@ -719,6 +730,28 @@ test "Script execution OP_1 OP_2 OP_3 OP_OVER" {
try std.testing.expectEqual(3, element1);
}

test "Script execution OP_1 OP_2 OP_3 OP_ROLL" {
const allocator = std.testing.allocator;

// Simple script: OP_1 OP_2 OP_3 OP_2 OP_PICK
const script_bytes = [_]u8{ 0x51, 0x52, 0x53, 0x52, 0x7a };
const script = Script.init(&script_bytes);

var engine = Engine.init(allocator, script, .{});
defer engine.deinit();

try engine.execute();
try std.testing.expectEqual(3, engine.stack.len());

const element0 = try engine.stack.peekInt(0);
const element1 = try engine.stack.peekInt(1);
const element2 = try engine.stack.peekInt(2);

try std.testing.expectEqual(1, element0);
try std.testing.expectEqual(3, element1);
try std.testing.expectEqual(2, element2);
}

test "Script execution OP_1 OP_2 OP_3 OP_SWAP" {
const allocator = std.testing.allocator;

Expand Down
24 changes: 24 additions & 0 deletions src/script/stack.zig
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,30 @@ pub const Stack = struct {
return std.mem.readVarInt(i64, elem, native_endian);
}

/// Removes an item from the stack at the specified index
///
/// # Arguments
/// - `index`: The index of the item to remove (0 is the top of the stack)
///
/// # Returns
/// - `StackError` if the index is out of bounds
/// - `[]u8`: The removed item
pub fn removeAt(self: *Stack, index: usize) StackError![]u8 {
const value = try self.allocator.dupe(u8, try self.peek(index));

var i: usize = 0;
while (i < index) : (i += 1) {
const next_value = try self.peek(index - i - 1);
const entry = self.items.items[self.len() - index + i - 1];
self.allocator.free(entry);
self.items.items[self.len() - index + i - 1] = try self.allocator.dupe(u8, next_value);
}
const last_entry = self.items.popOrNull() orelse return StackError.StackUnderflow;
self.allocator.free(last_entry);

return value;
}

/// Get the number of items in the stack
///
/// # Returns
Expand Down

0 comments on commit 32daac8

Please sign in to comment.