Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 32 additions & 15 deletions src/account.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,30 @@ const PublicKey = @import("public_key.zig").PublicKey;
pub const ACCOUNT_DATA_PADDING = 10 * 1024;

pub const Account = struct {
pub const DATA_HEADER = 88;
/// A Solana account sliced from what is provided as inputs to the BPF virtual machine.
pub const Data = extern struct {
pub const Data = packed struct {
duplicate_index: u8,
is_signer: bool,
is_writable: bool,
is_executable: bool,
_: [4]u8,
is_signer: u8,
is_writable: u8,
is_executable: u8,
original_data_len: u32,
id: PublicKey,
owner_id: PublicKey,
lamports: u64,
data_len: usize,
data_len: u64,

comptime {
std.debug.assert(@offsetOf(Account.Data, "duplicate_index") == 0);
std.debug.assert(@offsetOf(Account.Data, "is_signer") == 0 + 1);
std.debug.assert(@offsetOf(Account.Data, "is_writable") == 0 + 1 + 1);
std.debug.assert(@offsetOf(Account.Data, "is_executable") == 0 + 1 + 1 + 1);
std.debug.assert(@offsetOf(Account.Data, "_") == 0 + 1 + 1 + 1 + 1);
std.debug.assert(@offsetOf(Account.Data, "original_data_len") == 0 + 1 + 1 + 1 + 1);
std.debug.assert(@offsetOf(Account.Data, "id") == 0 + 1 + 1 + 1 + 1 + 4);
std.debug.assert(@offsetOf(Account.Data, "owner_id") == 0 + 1 + 1 + 1 + 1 + 4 + 32);
std.debug.assert(@offsetOf(Account.Data, "lamports") == 0 + 1 + 1 + 1 + 1 + 4 + 32 + 32);
std.debug.assert(@offsetOf(Account.Data, "data_len") == 0 + 1 + 1 + 1 + 1 + 4 + 32 + 32 + 8);
std.debug.assert(@sizeOf(Account.Data) == 1 + 1 + 1 + 1 + 4 + 32 + 32 + 8 + 8);
std.debug.assert(@bitSizeOf(Account.Data) == DATA_HEADER * 8);
}
};

Expand Down Expand Up @@ -63,30 +64,46 @@ pub const Account = struct {
return self.ptr.owner_id;
}

pub fn assign(self: Account, new_owner_id: PublicKey) void {
self.ptr.owner_id = new_owner_id;
}

pub fn data(self: Account) []u8 {
const data_ptr = @as([*]u8, @ptrFromInt(@intFromPtr(self.ptr))) + @sizeOf(Account.Data);
const data_ptr = @as([*]u8, @ptrFromInt(@intFromPtr(self.ptr))) + DATA_HEADER;
return data_ptr[0..self.ptr.data_len];
}

pub fn isWritable(self: Account) bool {
return self.ptr.is_writable;
return self.ptr.is_writable == 1;
}

pub fn isExecutable(self: Account) bool {
return self.ptr.is_executable;
return self.ptr.is_executable == 1;
}

pub fn isSigner(self: Account) bool {
return self.ptr.is_signer;
return self.ptr.is_signer == 1;
}

pub fn dataLen(self: Account) usize {
pub fn dataLen(self: Account) u64 {
return self.ptr.data_len;
}

pub fn realloc(self: Account, new_data_len: u64) error.InvalidRealloc!void {
const diff = @subWithOverflow(new_data_len, self.original_data_len);
if (diff[1] == 0 and diff[0] > ACCOUNT_DATA_PADDING) {
return error.InvalidRealloc;
}
self.reallocUnchecked(new_data_len);
}

pub fn reallocUnchecked(self: Account, new_data_len: u64) void {
self.ptr.data_len = new_data_len;
}

pub fn info(self: Account) Account.Info {
const data_ptr = @as([*]u8, @ptrFromInt(@intFromPtr(self.ptr))) + @sizeOf(Account.Data);
const rent_epoch = @as(*u64, @ptrFromInt(std.mem.alignForward(usize, @intFromPtr(self.ptr) + self.ptr.data_len + ACCOUNT_DATA_PADDING, @alignOf(usize))));
const data_ptr = @as([*]u8, @ptrFromInt(@intFromPtr(self.ptr))) + DATA_HEADER;
const rent_epoch = @as(*u64, @ptrFromInt(std.mem.alignForward(u64, @intFromPtr(self.ptr) + self.ptr.data_len + ACCOUNT_DATA_PADDING, @alignOf(u64))));

return .{
.id = &self.ptr.id,
Expand Down
6 changes: 3 additions & 3 deletions src/context.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub const Context = struct {
num_accounts: usize,
accounts: [64]Account,
data: []const u8,
program_id: *PublicKey,
program_id: *align(1) PublicKey,

pub fn load(input: [*]u8) !Context {
var ptr: [*]u8 = input;
Expand All @@ -25,7 +25,7 @@ pub const Context = struct {
ptr += @sizeOf(usize);
accounts[i] = accounts[data.duplicate_index];
} else {
ptr += @sizeOf(Account.Data);
ptr += Account.DATA_HEADER;
ptr = @as([*]u8, @ptrFromInt(std.mem.alignForward(usize, @intFromPtr(ptr) + data.data_len + ACCOUNT_DATA_PADDING, @alignOf(usize))));
ptr += @sizeOf(u64);
accounts[i] = .{ .ptr = @as(*Account.Data, @ptrCast(@alignCast(data))) };
Expand All @@ -39,7 +39,7 @@ pub const Context = struct {
const data = ptr[0..data_len];
ptr += data_len;

const program_id = @as(*PublicKey, @ptrCast(ptr));
const program_id = @as(*align(1) PublicKey, @ptrCast(ptr));
ptr += @sizeOf(PublicKey);

return Context{
Expand Down
16 changes: 8 additions & 8 deletions src/public_key.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ pub const ProgramDerivedAddress = struct {
bump_seed: [1]u8,
};

pub const PublicKey = extern struct {
pub const PublicKey = packed struct {
pub const length: usize = 32;
pub const base58_length: usize = 44;

pub const max_num_seeds: usize = 16;
pub const max_seed_length: usize = 32;

bytes: [PublicKey.length]u8,
bytes: u256,

pub fn from(bytes: [PublicKey.length]u8) PublicKey {
return .{ .bytes = bytes };
return .{ .bytes = mem.bytesToValue(u256, &bytes) };
}

pub fn comptimeFromBase58(comptime encoded: []const u8) PublicKey {
Expand All @@ -47,11 +47,11 @@ pub const PublicKey = extern struct {
}

pub fn equals(self: PublicKey, other: PublicKey) bool {
return mem.eql(u8, &self.bytes, &other.bytes);
return self.bytes == other.bytes;
}

pub fn isPointOnCurve(self: PublicKey) bool {
const Y = std.crypto.ecc.Curve25519.Fe.fromBytes(self.bytes);
const Y = std.crypto.ecc.Curve25519.Fe.fromBytes(mem.toBytes(self.bytes));
const Z = std.crypto.ecc.Curve25519.Fe.one;
const YY = Y.sq();
const u = YY.sub(Z);
Expand Down Expand Up @@ -125,9 +125,9 @@ pub const PublicKey = extern struct {
inline while (i < seeds.len) : (i += 1) {
hasher.update(seeds[i]);
}
hasher.update(&program_id.bytes);
hasher.update(mem.asBytes(&program_id.bytes));
hasher.update("ProgramDerivedAddress");
hasher.final(&address.bytes);
hasher.final(mem.asBytes(&address.bytes));

if (address.isPointOnCurve()) {
return error.InvalidSeeds;
Expand Down Expand Up @@ -222,7 +222,7 @@ pub const PublicKey = extern struct {
_ = fmt;
_ = options;
var buffer: [base58.bitcoin.getEncodedLengthUpperBound(PublicKey.length)]u8 = undefined;
try writer.print("{s}", .{base58.bitcoin.encode(&buffer, &self.bytes)});
try writer.print("{s}", .{base58.bitcoin.encode(&buffer, mem.asBytes(&self.bytes))});
}
};

Expand Down
4 changes: 2 additions & 2 deletions src/rent.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub const Rent = struct {
/// Account storage overhead for calculation of base rent.
pub const account_storage_overhead: u64 = 128;

pub const Data = extern struct {
pub const Data = packed struct {
lamports_per_byte_year: u64 = Rent.default_lamports_per_byte_year,
exemption_threshold: f64 = Rent.default_exemption_threshold,
burn_percent: u8 = Rent.default_burn_percent,
Expand All @@ -43,7 +43,7 @@ pub const Rent = struct {

pub fn getMinimumBalance(self: Rent.Data, data_len: usize) u64 {
const total_data_len: u64 = Rent.account_storage_overhead + data_len;
return @intFromFloat(@as(f64, @floatFromInt(total_data_len * self.lamports_per_byte_year)) * self.exemption_threshold);
return total_data_len * self.lamports_per_byte_year * @as(u64, @intFromFloat(self.exemption_threshold));
}
};

Expand Down