From 16ee3c343524709863f2e6a09925207bfc643992 Mon Sep 17 00:00:00 2001 From: Sonic Date: Fri, 23 Aug 2024 23:38:24 +0300 Subject: [PATCH 1/3] add compute budget instructions --- src/associated_token_account.zig | 2 +- src/compute_budget.zig | 118 +++++++++++++++++++++++++++++++ src/root.zig | 1 + 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/compute_budget.zig diff --git a/src/associated_token_account.zig b/src/associated_token_account.zig index 40eb7d4..6ed9814 100644 --- a/src/associated_token_account.zig +++ b/src/associated_token_account.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const sol = @import("sol"); const bincode = @import("bincode"); +const sol = @import("solana-program-sdk"); pub const program_id = sol.PublicKey.comptimeFromBase58("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); diff --git a/src/compute_budget.zig b/src/compute_budget.zig new file mode 100644 index 0000000..2dcc10e --- /dev/null +++ b/src/compute_budget.zig @@ -0,0 +1,118 @@ +const std = @import("std"); +const sol = @import("solana-program-sdk"); +const bincode = @import("bincode"); + +const Account = sol.Account; + +const ComputeBudget = @This(); + +pub const id = sol.PublicKey.comptimeFromBase58("ComputeBudget111111111111111111111111111111"); + +pub fn requestHeapFrame(allocator: std.mem.Allocator, params: struct { bytes: u32 }) !sol.Instruction { + const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ + .request_heap_frame = .{ .bytes = params.bytes }, + }, .{}); + defer allocator.free(data); + + return sol.Instruction.from(.{ + .program_id = &id, + .accounts = &[_]Account.Param{}, + .data = data, + }); +} + +pub fn setComputeUnitLimit(allocator: std.mem.Allocator, params: struct { units: u32 }) !sol.Instruction { + const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ + .set_compute_unit_limit = .{ .units = params.units }, + }, .{}); + defer allocator.free(data); + + return sol.Instruction.from(.{ + .program_id = &id, + .accounts = &[_]Account.Param{}, + .data = data, + }); +} + +pub fn setComputeUnitPrice(allocator: std.mem.Allocator, params: struct { micro_lamports: u64 }) !sol.Instruction { + const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ + .set_compute_unit_price = .{ .micro_lamports = params.micro_lamports }, + }, .{}); + defer allocator.free(data); + + return sol.Instruction.from(.{ + .program_id = &id, + .accounts = &[_]Account.Param{}, + .data = data, + }); +} + +pub fn setLoadedAccountsDataSizeLimit(allocator: std.mem.Allocator, params: struct { bytes: u32 }) !sol.Instruction { + const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ + .set_loaded_accounts_data_size_limit = .{ .bytes = params.bytes }, + }, .{}); + defer allocator.free(data); + + return sol.Instruction.from(.{ + .program_id = &id, + .accounts = &[_]Account.Param{}, + .data = data, + }); +} + +pub const Instruction = union(enum(u8)) { + // deprecated variant, reserved value. + unused, + /// Request a specific transaction-wide program heap region size in bytes. + /// The value requested must be a multiple of 1024. This new heap region + /// size applies to each program executed in the transaction, including all + /// calls to CPIs. + request_heap_frame: struct { + bytes: u32, + }, + /// Set a specific compute unit limit that the transaction is allowed to consume. + set_compute_unit_limit: struct { + units: u32, + }, + /// Set a compute unit price in "micro-lamports" to pay a higher transaction + /// fee for higher transaction prioritization. + set_compute_unit_price: struct { + micro_lamports: u64, + }, + /// Set a specific transaction-wide account data size limit, in bytes, is allowed to load. + set_loaded_accounts_data_size_limit: struct { + bytes: u32, + }, +}; + +test "build request heap frame ix" { + const ix = try requestHeapFrame(std.testing.allocator, .{ .bytes = 4_000 }); + + try std.testing.expect(ix.program_id.equals(id)); + try std.testing.expectEqual(0, ix.accounts_len); + try std.testing.expectEqual(5, ix.data_len); +} + +test "build set compute limit ix" { + const ix = try setComputeUnitLimit(std.testing.allocator, .{ .units = 1_400_000 }); + + try std.testing.expect(ix.program_id.equals(id)); + try std.testing.expectEqual(0, ix.accounts_len); + try std.testing.expectEqual(5, ix.data_len); +} + +test "build set compute unit price ix" { + const ix = try setComputeUnitPrice(std.testing.allocator, .{ .micro_lamports = 200_000 }); + + try std.testing.expect(ix.program_id.equals(id)); + try std.testing.expectEqual(0, ix.accounts_len); + try std.testing.expectEqual(9, ix.data_len); +} + +test "build set loaded accounts data-size limit ix" { + const ix = try setLoadedAccountsDataSizeLimit(std.testing.allocator, .{ .bytes = 1200 }); + + try std.testing.expect(ix.program_id.equals(id)); + try std.testing.expectEqual(0, ix.accounts_len); + try std.testing.expectEqual(5, ix.data_len); +} diff --git a/src/root.zig b/src/root.zig index 9e8067c..1f8eda4 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,6 +1,7 @@ const std = @import("std"); pub const associated_token_account = @import("associated_token_account.zig"); +pub const compute_budget = @import("compute_budget.zig"); pub const system = @import("system.zig"); pub const token = @import("token.zig"); From ffc697e2a4e9ab212b7c91e68bf2b3f722ad5837 Mon Sep 17 00:00:00 2001 From: Sonic Date: Sun, 25 Aug 2024 20:42:58 +0300 Subject: [PATCH 2/3] extend tests --- src/compute_budget.zig | 44 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/compute_budget.zig b/src/compute_budget.zig index 2dcc10e..bce052b 100644 --- a/src/compute_budget.zig +++ b/src/compute_budget.zig @@ -8,11 +8,10 @@ const ComputeBudget = @This(); pub const id = sol.PublicKey.comptimeFromBase58("ComputeBudget111111111111111111111111111111"); -pub fn requestHeapFrame(allocator: std.mem.Allocator, params: struct { bytes: u32 }) !sol.Instruction { +pub fn requestHeapFrame(allocator: std.mem.Allocator, bytes: u32) !sol.Instruction { const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ - .request_heap_frame = .{ .bytes = params.bytes }, + .request_heap_frame = .{ .bytes = bytes }, }, .{}); - defer allocator.free(data); return sol.Instruction.from(.{ .program_id = &id, @@ -21,11 +20,10 @@ pub fn requestHeapFrame(allocator: std.mem.Allocator, params: struct { bytes: u3 }); } -pub fn setComputeUnitLimit(allocator: std.mem.Allocator, params: struct { units: u32 }) !sol.Instruction { +pub fn setComputeUnitLimit(allocator: std.mem.Allocator, units: u32) !sol.Instruction { const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ - .set_compute_unit_limit = .{ .units = params.units }, + .set_compute_unit_limit = .{ .units = units }, }, .{}); - defer allocator.free(data); return sol.Instruction.from(.{ .program_id = &id, @@ -34,11 +32,10 @@ pub fn setComputeUnitLimit(allocator: std.mem.Allocator, params: struct { units: }); } -pub fn setComputeUnitPrice(allocator: std.mem.Allocator, params: struct { micro_lamports: u64 }) !sol.Instruction { +pub fn setComputeUnitPrice(allocator: std.mem.Allocator, micro_lamports: u64) !sol.Instruction { const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ - .set_compute_unit_price = .{ .micro_lamports = params.micro_lamports }, + .set_compute_unit_price = .{ .micro_lamports = micro_lamports }, }, .{}); - defer allocator.free(data); return sol.Instruction.from(.{ .program_id = &id, @@ -47,11 +44,10 @@ pub fn setComputeUnitPrice(allocator: std.mem.Allocator, params: struct { micro_ }); } -pub fn setLoadedAccountsDataSizeLimit(allocator: std.mem.Allocator, params: struct { bytes: u32 }) !sol.Instruction { +pub fn setLoadedAccountsDataSizeLimit(allocator: std.mem.Allocator, bytes: u32) !sol.Instruction { const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ - .set_loaded_accounts_data_size_limit = .{ .bytes = params.bytes }, + .set_loaded_accounts_data_size_limit = .{ .bytes = bytes }, }, .{}); - defer allocator.free(data); return sol.Instruction.from(.{ .program_id = &id, @@ -86,33 +82,49 @@ pub const Instruction = union(enum(u8)) { }; test "build request heap frame ix" { - const ix = try requestHeapFrame(std.testing.allocator, .{ .bytes = 4_000 }); + const ix = try requestHeapFrame(std.testing.allocator, 4000); + + defer std.testing.allocator.free(ix.data[0..ix.data_len]); try std.testing.expect(ix.program_id.equals(id)); try std.testing.expectEqual(0, ix.accounts_len); try std.testing.expectEqual(5, ix.data_len); + + try std.testing.expect(std.mem.eql(u8, &.{ 0x1, 0xa0, 0xf, 0x0, 0x0 }, ix.data[0..ix.data_len])); } test "build set compute limit ix" { - const ix = try setComputeUnitLimit(std.testing.allocator, .{ .units = 1_400_000 }); + const ix = try setComputeUnitLimit(std.testing.allocator, 1_400_000); + + defer std.testing.allocator.free(ix.data[0..ix.data_len]); try std.testing.expect(ix.program_id.equals(id)); try std.testing.expectEqual(0, ix.accounts_len); try std.testing.expectEqual(5, ix.data_len); + + try std.testing.expect(std.mem.eql(u8, &.{ 0x2, 0xc0, 0x5c, 0x15, 0x0 }, ix.data[0..ix.data_len])); } test "build set compute unit price ix" { - const ix = try setComputeUnitPrice(std.testing.allocator, .{ .micro_lamports = 200_000 }); + const ix = try setComputeUnitPrice(std.testing.allocator, 1000); + + defer std.testing.allocator.free(ix.data[0..ix.data_len]); try std.testing.expect(ix.program_id.equals(id)); try std.testing.expectEqual(0, ix.accounts_len); try std.testing.expectEqual(9, ix.data_len); + + try std.testing.expect(std.mem.eql(u8, &.{ 0x3, 0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, ix.data[0..ix.data_len])); } test "build set loaded accounts data-size limit ix" { - const ix = try setLoadedAccountsDataSizeLimit(std.testing.allocator, .{ .bytes = 1200 }); + const ix = try setLoadedAccountsDataSizeLimit(std.testing.allocator, 1200); + + defer std.testing.allocator.free(ix.data[0..ix.data_len]); try std.testing.expect(ix.program_id.equals(id)); try std.testing.expectEqual(0, ix.accounts_len); try std.testing.expectEqual(5, ix.data_len); + + try std.testing.expect(std.mem.eql(u8, &.{ 0x4, 0xb0, 0x4, 0x0, 0x0 }, ix.data[0..ix.data_len])); } From 11a1f07d656786fea0b5fd4a5ca7cab8d5129443 Mon Sep 17 00:00:00 2001 From: Sonic Date: Sat, 31 Aug 2024 13:25:39 +0300 Subject: [PATCH 3/3] rename units -> compute_units in set_compute_unit_limit ix --- src/compute_budget.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compute_budget.zig b/src/compute_budget.zig index bce052b..fbe8710 100644 --- a/src/compute_budget.zig +++ b/src/compute_budget.zig @@ -20,9 +20,9 @@ pub fn requestHeapFrame(allocator: std.mem.Allocator, bytes: u32) !sol.Instructi }); } -pub fn setComputeUnitLimit(allocator: std.mem.Allocator, units: u32) !sol.Instruction { +pub fn setComputeUnitLimit(allocator: std.mem.Allocator, compute_units: u32) !sol.Instruction { const data = try bincode.writeAlloc(allocator, ComputeBudget.Instruction{ - .set_compute_unit_limit = .{ .units = units }, + .set_compute_unit_limit = .{ .compute_units = compute_units }, }, .{}); return sol.Instruction.from(.{ @@ -68,7 +68,7 @@ pub const Instruction = union(enum(u8)) { }, /// Set a specific compute unit limit that the transaction is allowed to consume. set_compute_unit_limit: struct { - units: u32, + compute_units: u32, }, /// Set a compute unit price in "micro-lamports" to pay a higher transaction /// fee for higher transaction prioritization.