diff --git a/conformance/src/bank_methods.zig b/conformance/src/bank_methods.zig index 22f12ef601..87590d68d8 100644 --- a/conformance/src/bank_methods.zig +++ b/conformance/src/bank_methods.zig @@ -168,6 +168,7 @@ fn applyBuiltinProgramFeatureTransitions( if (!feature_set.active(feature_id, 0)) continue; const maybe_account = accounts_db.getAccountLatest( + allocator, &precompile.program_id, ) catch |err| switch (err) { error.PubkeyNotInIndex => null, @@ -247,7 +248,7 @@ fn tryGetAccount( accounts_db: *AccountsDb, pubkey: Pubkey, ) !?Account { - return accounts_db.getAccountLatest(&pubkey) catch |err| switch (err) { + return accounts_db.getAccountLatest(accounts_db.allocator, &pubkey) catch |err| switch (err) { error.PubkeyNotInIndex => null, else => error.AccountsDbInternal, }; diff --git a/conformance/src/txn_execute.zig b/conformance/src/txn_execute.zig index 9be83cfd1d..b529d720ea 100644 --- a/conformance/src/txn_execute.zig +++ b/conformance/src/txn_execute.zig @@ -316,6 +316,7 @@ fn executeTxnContext( // For fuzzing purposes, accounts db is currently empty so we do not need to check if // the builtin program is migrated or not. const builtin_is_bpf_program = if (try accounts_db.getAccountWithAncestors( + allocator, &builtin_program.program_id, &ancestors, )) |account| blk: { @@ -699,6 +700,7 @@ fn executeTxnContext( // Get lamports per signature from first entry in recent blockhashes const lamports_per_signature = blk: { const account = try accounts_db.getAccountWithAncestors( + allocator, &RecentBlockhashes.ID, &ancestors, ) orelse break :blk null; diff --git a/src/accountsdb/account_store.zig b/src/accountsdb/account_store.zig index 6a20600dc3..db118aa01a 100644 --- a/src/accountsdb/account_store.zig +++ b/src/accountsdb/account_store.zig @@ -71,14 +71,6 @@ pub const AccountReader = union(enum) { thread_safe_map: *ThreadSafeAccountMap, noop, - /// use this to deinit accounts returned by get methods - pub fn allocator(self: AccountReader) Allocator { - return switch (self) { - .noop => sig.utils.allocators.failing.allocator(.{}), - inline else => |item| item.allocator, - }; - } - pub fn forSlot(self: AccountReader, ancestors: *const Ancestors) SlotAccountReader { return switch (self) { .accounts_db => |db| .{ .accounts_db = .{ db, ancestors } }, @@ -88,13 +80,13 @@ pub const AccountReader = union(enum) { } /// Deinit all returned accounts using `account_reader.allocator()` - pub fn getLatest(self: AccountReader, address: Pubkey) !?Account { + pub fn getLatest(self: AccountReader, allocator: std.mem.Allocator, address: Pubkey) !?Account { return switch (self) { .accounts_db => |db| { - const account = try db.getAccountLatest(&address) orelse return null; + const account = try db.getAccountLatest(allocator, &address) orelse return null; if (account.lamports == 0) { // TODO: implement this check in accountsdb to avoid the unnecessary allocation - account.deinit(db.allocator); + account.deinit(allocator); return null; } return account; @@ -149,20 +141,15 @@ pub const SlotModifiedIterator = union(enum) { }; } - pub fn next(self: *SlotModifiedIterator) !?struct { Pubkey, Account } { + pub fn next( + self: *SlotModifiedIterator, + allocator: std.mem.Allocator, + ) !?struct { Pubkey, Account } { return switch (self.*) { - inline else => |*item| try item.next(), + inline else => |*item| try item.next(allocator), .noop => null, }; } - - pub fn allocator(self: SlotModifiedIterator) std.mem.Allocator { - return switch (self) { - .accounts_db => |state| state.db.allocator, - .thread_safe_map => |state| state.allocator, - .noop => sig.utils.allocators.failing.allocator(.{}), - }; - } }; /// Interface for reading any account as it should appear during a particular slot. @@ -196,36 +183,23 @@ pub const SlotAccountReader = union(enum) { single_version_map: *const std.AutoArrayHashMapUnmanaged(Pubkey, Account), noop, - /// use this to deinit accounts returned by get methods - pub fn allocator(self: SlotAccountReader) Allocator { - return switch (self) { - .noop => sig.utils.allocators.failing.allocator(.{}), - .single_version_map => sig.utils.allocators.failing.allocator(.{ - .alloc = .panics, - .resize = .panics, - .free = .panics, - }), - inline else => |item| item[0].allocator, - }; - } - /// Deinit all returned accounts using `account_reader.allocator()` - pub fn get(self: SlotAccountReader, address: Pubkey) !?Account { - const zone = tracy.Zone.init(@src(), .{ .name = "SlotAccountReader.get" }); - defer zone.deinit(); - + pub fn get(self: SlotAccountReader, alloc: std.mem.Allocator, address: Pubkey) !?Account { return switch (self) { .accounts_db => |pair| { const db, const ancestors = pair; - const account = try db.getAccountWithAncestors(&address, ancestors) orelse - return null; + const account = try db.getAccountWithAncestors( + alloc, + &address, + ancestors, + ) orelse return null; if (account.lamports == 0) { - account.deinit(db.allocator); + account.deinit(alloc); return null; } return account; }, - .thread_safe_map => |pair| try pair[0].get(address, pair[1]), + .thread_safe_map => |pair| pair[0].get(address, pair[1]), .single_version_map => |pair| pair.get(address), .noop => null, }; @@ -295,7 +269,7 @@ pub const ThreadSafeAccountMap = struct { self: *ThreadSafeAccountMap, address: Pubkey, ancestors: *const Ancestors, - ) !?Account { + ) ?Account { self.rwlock.lockShared(); defer self.rwlock.unlockShared(); @@ -304,10 +278,13 @@ pub const ThreadSafeAccountMap = struct { for (slot_account_pairs.items) |slot_account| { const slot, const account = slot_account; if (ancestors.containsSlot(slot)) { - return if (account.lamports == 0) null else try toAccount(self.allocator, account); + return if (account.lamports == 0) + null + else + asAccount(account); } if (self.largest_rooted_slot) |largest_rooted_slot| if (slot <= largest_rooted_slot) { - return if (account.lamports == 0) null else try toAccount(self.allocator, account); + return if (account.lamports == 0) null else asAccount(account); }; } @@ -317,19 +294,16 @@ pub const ThreadSafeAccountMap = struct { pub fn getLatest(self: *ThreadSafeAccountMap, address: Pubkey) !?Account { self.rwlock.lockShared(); defer self.rwlock.unlockShared(); + const list = self.pubkey_map.get(address) orelse return null; if (list.items.len == 0) return null; - _, const account = list.items[0]; - return try toAccount(self.allocator, account); + return asAccount(list.items[0][1]); } - fn toAccount(allocator: Allocator, account: AccountSharedData) !Account { - const data = try allocator.dupe(u8, account.data); - errdefer allocator.free(account.data); - + fn asAccount(account: AccountSharedData) Account { return .{ .lamports = account.lamports, - .data = .{ .owned_allocation = data }, + .data = .{ .unowned_allocation = account.data }, .owner = account.owner, .executable = account.executable, .rent_epoch = account.rent_epoch, @@ -343,7 +317,7 @@ pub const ThreadSafeAccountMap = struct { self: *ThreadSafeAccountMap, slot: Slot, address: Pubkey, - account: AccountSharedData, + put_account: AccountSharedData, ) PutError!void { self.rwlock.lock(); defer self.rwlock.unlock(); @@ -354,16 +328,7 @@ pub const ThreadSafeAccountMap = struct { } } - const data = try self.allocator.dupe(u8, account.data); - errdefer self.allocator.free(account.data); - - const account_shared_data: AccountSharedData = .{ - .lamports = account.lamports, - .data = data, - .owner = account.owner, - .executable = account.executable, - .rent_epoch = account.rent_epoch, - }; + const account = try put_account.clone(self.allocator); slot_map: { const slot_map = &self.slot_map; @@ -372,11 +337,12 @@ pub const ThreadSafeAccountMap = struct { for (slot_gop.value_ptr.items) |*pubkey_account| { if (pubkey_account[0].equals(&address)) { self.allocator.free(pubkey_account[1].data); - pubkey_account[1] = account_shared_data; + pubkey_account[1] = account; break :slot_map; } } - try slot_gop.value_ptr.append(self.allocator, .{ address, account_shared_data }); + + try slot_gop.value_ptr.append(self.allocator, .{ address, account }); } { @@ -398,9 +364,9 @@ pub const ThreadSafeAccountMap = struct { ); if (index != versions_list.items.len and versions_list.items[index][0] == slot) { - versions_list.items[index] = .{ slot, account_shared_data }; + versions_list.items[index] = .{ slot, account }; } else { - try versions_list.insert(self.allocator, index, .{ slot, account_shared_data }); + try versions_list.insert(self.allocator, index, .{ slot, account }); } } } @@ -508,12 +474,19 @@ pub const ThreadSafeAccountMap = struct { return self.slot_list.len; } - pub fn next(self: *ThreadSafeAccountMap.SlotModifiedIterator) !?struct { Pubkey, Account } { + pub fn next( + self: *ThreadSafeAccountMap.SlotModifiedIterator, + allocator: std.mem.Allocator, + ) !?struct { Pubkey, Account } { std.debug.assert(self.cursor != std.math.maxInt(usize)); defer self.cursor += 1; if (self.cursor >= self.slot_list.len) return null; - const pubkey, const account = self.slot_list[self.cursor]; - return .{ pubkey, try toAccount(self.allocator, account) }; + const pubkey, const acc = self.slot_list[self.cursor]; + + var account = asAccount(acc); + account.data = .{ .owned_allocation = try allocator.dupe(u8, acc.data) }; + + return .{ pubkey, account }; } }; @@ -525,7 +498,9 @@ pub const ThreadSafeAccountMap = struct { }; test "AccountStore does not return 0-lamport accounts from accountsdb" { - var db, var dir = try AccountsDB.initForTest(std.testing.allocator); + const allocator = std.testing.allocator; + + var db, var dir = try AccountsDB.initForTest(allocator); defer { db.deinit(); dir.cleanup(); @@ -552,16 +527,22 @@ test "AccountStore does not return 0-lamport accounts from accountsdb" { const reader = db.accountReader(); - try std.testing.expectEqual(null, try reader.getLatest(zero_lamport_address)); - try std.testing.expectEqual(1, (try reader.getLatest(one_lamport_address)).?.lamports); + try std.testing.expectEqual(null, try reader.getLatest(allocator, zero_lamport_address)); + try std.testing.expectEqual(1, (try reader.getLatest( + allocator, + one_lamport_address, + )).?.lamports); var ancestors = Ancestors{}; defer ancestors.deinit(std.testing.allocator); - try ancestors.ancestors.put(std.testing.allocator, 0, {}); + try ancestors.ancestors.put(allocator, 0, {}); const slot_reader = db.accountReader().forSlot(&ancestors); - try std.testing.expectEqual(null, try slot_reader.get(zero_lamport_address)); - try std.testing.expectEqual(1, (try slot_reader.get(one_lamport_address)).?.lamports); + try std.testing.expectEqual(null, try slot_reader.get(allocator, zero_lamport_address)); + try std.testing.expectEqual(1, (try slot_reader.get( + allocator, + one_lamport_address, + )).?.lamports); } test ThreadSafeAccountMap { @@ -593,11 +574,24 @@ test ThreadSafeAccountMap { }; try account_store.put(slot1, addr1, expected_account); - try expectAccount(account_reader, addr1, null, sharedToCoreAccount(expected_account)); - try expectAccount(account_reader, addr1, ancestors1, sharedToCoreAccount(expected_account)); + try expectAccount( + allocator, + account_reader, + addr1, + null, + sharedToCoreAccount(expected_account), + ); + try expectAccount( + allocator, + account_reader, + addr1, + ancestors1, + sharedToCoreAccount(expected_account), + ); } fn expectAccount( + allocator: std.mem.Allocator, account_reader: AccountReader, address: Pubkey, maybe_ancestors: ?Ancestors, @@ -605,10 +599,9 @@ fn expectAccount( ) !void { if (!@import("builtin").is_test) @compileError("Not allowed outside of tests."); const actual = if (maybe_ancestors) |*ancestors| - try account_reader.forSlot(ancestors).get(address) + try account_reader.forSlot(ancestors).get(allocator, address) else - try account_reader.getLatest(address); - defer if (actual) |actual_account| actual_account.deinit(account_reader.allocator()); + try account_reader.getLatest(allocator, address); if ((expected == null) != (actual == null)) { try std.testing.expectEqual(expected, actual); @@ -663,6 +656,7 @@ test "insertion basic" { const stores = [_]sig.accounts_db.AccountStore{ simple_store, real_store }; try expectEqualDatabaseWithAncestors( + allocator, &.EMPTY, simple_state.pubkey_map.keys(), simple_store.reader(), @@ -683,6 +677,7 @@ test "insertion basic" { try ancestor_set.addSlot(allocator, slot); try putAccountIntoStores({}, &stores, slot, pubkey, account); try expectEqualDatabaseWithAncestors( + allocator, &ancestor_set, simple_state.pubkey_map.keys(), simple_store.reader(), @@ -697,6 +692,7 @@ test "insertion basic" { const slot: Slot = i; try ancestor_set.subsetInto(slot, allocator, &ancestors_subset); try expectEqualDatabaseWithAncestors( + allocator, &ancestors_subset, simple_state.pubkey_map.keys(), simple_store.reader(), @@ -736,6 +732,7 @@ test "insertion out of order" { const stores = [_]sig.accounts_db.AccountStore{ simple_store, real_store }; try expectEqualDatabaseWithAncestors( + allocator, &.EMPTY, simple_state.pubkey_map.keys(), simple_store.reader(), @@ -761,6 +758,7 @@ test "insertion out of order" { try putAccountIntoStores({}, &stores, slot, pubkey, account); try expectEqualDatabaseWithAncestors( + allocator, &ancestor_set, simple_state.pubkey_map.keys(), simple_store.reader(), @@ -774,6 +772,7 @@ test "insertion out of order" { for (ancestor_set.ancestors.keys()) |slot| { try ancestor_set.subsetInto(slot, allocator, &ancestors_subset); try expectEqualDatabaseWithAncestors( + allocator, &ancestors_subset, simple_state.pubkey_map.keys(), simple_store.reader(), @@ -1118,11 +1117,11 @@ fn expectAccountFromStores( for (stores) |store| { errdefer std.log.err("Occurred with store impl '{s}'", .{@tagName(store)}); const reader = store.reader(); - const actual_account = try reader.forSlot(ancestors).get(address) orelse { + const actual_account = try reader.forSlot(ancestors).get(allocator, address) orelse { try std.testing.expectEqual(maybe_expected_account, null); continue; }; - defer actual_account.deinit(reader.allocator()); + defer actual_account.deinit(allocator); const expected_account = maybe_expected_account orelse { try std.testing.expectEqual(null, actual_account); @@ -1133,6 +1132,7 @@ fn expectAccountFromStores( } fn expectEqualDatabaseWithAncestors( + allocator: std.mem.Allocator, ancestors: *const Ancestors, pubkeys: []const Pubkey, expected: sig.accounts_db.AccountReader, @@ -1144,11 +1144,11 @@ fn expectEqualDatabaseWithAncestors( const expected_for_slot = expected.forSlot(ancestors); const actual_for_slot = actual.forSlot(ancestors); for (pubkeys) |pubkey| { - const expected_account_opt = try expected_for_slot.get(pubkey); - defer if (expected_account_opt) |acc| acc.deinit(expected_for_slot.allocator()); + const expected_account_opt = try expected_for_slot.get(allocator, pubkey); + defer if (expected_account_opt) |acc| acc.deinit(allocator); - const actual_account_opt = try actual_for_slot.get(pubkey); - defer if (actual_account_opt) |acc| acc.deinit(actual_for_slot.allocator()); + const actual_account_opt = try actual_for_slot.get(allocator, pubkey); + defer if (actual_account_opt) |acc| acc.deinit(allocator); if (expected_account_opt == null and actual_account_opt == null) @@ -1167,8 +1167,6 @@ fn expectEqualDatabaseWithAncestors( try actual_account.expectEquals(expected_account); } - const allocator = std.testing.allocator; - var expected_map: std.AutoArrayHashMapUnmanaged(Pubkey, AccountSharedData) = .empty; defer expected_map.deinit(allocator); @@ -1211,8 +1209,8 @@ fn collectModifiedSlotsIntoMap( defer iter.unlock(); try map.ensureTotalCapacity(allocator, iter.len()); while (true) { - const address, const account = try iter.next() orelse break; - defer account.deinit(iter.allocator()); + const address, const account = try iter.next(allocator) orelse break; + defer account.deinit(allocator); map.putAssumeCapacity(address, .{ .lamports = account.lamports, .data = try account.data.readAllAllocate(allocator), diff --git a/src/accountsdb/db.zig b/src/accountsdb/db.zig index 481cbe7491..7059743536 100644 --- a/src/accountsdb/db.zig +++ b/src/accountsdb/db.zig @@ -183,8 +183,8 @@ pub const AccountsDB = struct { index_allocation: Index, number_of_index_shards: usize, on_root_config: sig.accounts_db.manager.Config = .{}, - /// Amount of BufferPool frames, used for cached reads. Default = 1GiB. - buffer_pool_frames: u32 = 2 * 1024 * 1024, + /// Amount of BufferPool frames, used for cached reads. Default = 1GiB (32MiB for tests) + buffer_pool_frames: u32 = if (builtin.is_test) 64 * 1024 else 2 * 1024 * 1024, pub const Index = union(AccountIndex.AllocatorConfig.Tag) { ram, @@ -624,7 +624,7 @@ pub const AccountsDB = struct { } /// multithread entrypoint into loadAndVerifyAccountsFiles. - pub fn loadAndVerifyAccountsFilesMultiThread( + fn loadAndVerifyAccountsFilesMultiThread( loading_threads: []AccountsDB, accounts_dir: std.fs.Dir, file_info_map: AccountsDbFields.FileMap, @@ -649,7 +649,7 @@ pub const AccountsDB = struct { /// loads and verifies the account files into the threads file map /// and stores the accounts into the threads index - pub fn loadAndVerifyAccountsFiles( + fn loadAndVerifyAccountsFiles( self: *AccountsDB, accounts_dir: std.fs.Dir, accounts_per_file_est: usize, @@ -928,7 +928,7 @@ pub const AccountsDB = struct { /// merges multiple thread accounts-dbs into self. /// index merging happens in parallel using `n_threads`. - pub fn mergeMultipleDBs( + fn mergeMultipleDBs( self: *AccountsDB, thread_dbs: []AccountsDB, n_threads: usize, @@ -1013,7 +1013,7 @@ pub const AccountsDB = struct { /// combines multiple thread indexes into the given index. /// each bin is also sorted by pubkey. - pub fn mergeThreadIndexesMultiThread( + fn mergeThreadIndexesMultiThread( logger: Logger, index: *AccountIndex, thread_dbs: []const AccountsDB, @@ -1108,7 +1108,7 @@ pub const AccountsDB = struct { /// NOTE: acquires a shared/read lock on `file_map_fd_rw` and `file_map` - those fields /// must not be under exclusive/write locks before calling this function on the same /// thread, or else this will dead lock. - pub fn computeAccountHashesAndLamports( + fn computeAccountHashesAndLamports( self: *AccountsDB, config: AccountHashesConfig, ) !struct { Hash, u64 } { @@ -1215,12 +1215,15 @@ pub const AccountsDB = struct { return self.slot_index.refs.items.len; } - pub fn next(self: *SlotModifiedIterator) !?struct { Pubkey, Account } { + pub fn next( + self: *SlotModifiedIterator, + allocator: std.mem.Allocator, + ) !?struct { Pubkey, Account } { assert(self.cursor != std.math.maxInt(usize)); defer self.cursor += 1; if (self.cursor >= self.slot_index.refs.items.len) return null; const account_ref = self.slot_index.refs.items[self.cursor]; - const account = try self.db.getAccountFromRef(&account_ref); + const account = try self.db.getAccountFromRef(allocator, &account_ref); return .{ account_ref.pubkey, account }; } }; @@ -1249,7 +1252,7 @@ pub const AccountsDB = struct { /// Validates accountsdb against some snapshot info - if used, it must /// be after loading the snapshot(s) whose information is supplied, /// and before mutating accountsdb. - pub fn validateLoadFromSnapshot( + fn validateLoadFromSnapshot( self: *AccountsDB, params: ValidateLoadFromSnapshotParams, ) !void { @@ -1390,7 +1393,7 @@ pub const AccountsDB = struct { } /// populates the account hashes and total lamports across a given shard slice - pub fn getHashesFromIndex( + fn getHashesFromIndex( self: *AccountsDB, config: AccountsDB.AccountHashesConfig, shards: []ShardedPubkeyRefMap.RwPubkeyRefMap, @@ -1563,18 +1566,19 @@ pub const AccountsDB = struct { error{SlotNotFound}; // NOTE: we need to acquire locks which requires `self: *Self` but we never modify any data - pub fn getAccountFromRef( + fn getAccountFromRef( self: *AccountsDB, + allocator: std.mem.Allocator, account_ref: *const AccountRef, ) GetFileFromRefError!Account { switch (account_ref.location) { .file => |ref_info| { const account = try self.getAccountInFile( - self.allocator, + allocator, ref_info.file_id, ref_info.offset, ); - errdefer account.deinit(self.allocator); + errdefer account.deinit(allocator); return account; }, @@ -1588,7 +1592,7 @@ pub const AccountsDB = struct { const accounts: []Account = slots_and_accounts.items(.account); const account = accounts[ref_info.index]; - return try account.cloneOwned(self.allocator); + return try account.cloneOwned(allocator); }, } } @@ -1614,7 +1618,7 @@ pub const AccountsDB = struct { }; pub const GetAccountFromRefError = GetAccountInFileError || error{SlotNotFound}; - pub fn getAccountFromRefWithReadLock( + fn getAccountFromRefWithReadLock( self: *AccountsDB, account_ref: *const AccountRef, ) GetAccountFromRefError!struct { AccountInCacheOrFile, AccountInCacheOrFileLock } { @@ -1651,28 +1655,28 @@ pub const AccountsDB = struct { /// Gets an account given an file_id and offset value. /// Locks the account file entries, and then unlocks /// them, after returning the clone of the account. - pub fn getAccountInFile( + fn getAccountInFile( self: *AccountsDB, - account_allocator: std.mem.Allocator, + allocator: std.mem.Allocator, file_id: FileId, offset: usize, ) (GetAccountInFileError || std.mem.Allocator.Error)!Account { const account_in_file = try self.getAccountInFileAndLock( - self.allocator, + allocator, &self.buffer_pool, file_id, offset, ); - defer account_in_file.deinit(account_allocator); + defer account_in_file.deinit(allocator); defer self.file_map_fd_rw.unlockShared(); - return try account_in_file.dupeCachedAccount(account_allocator); + return try account_in_file.dupeCachedAccount(allocator); } /// Gets an account given an file_id and offset value. /// Locks the account file entries, and returns the account. /// Must call `self.file_map_fd_rw.unlockShared()` /// when done with the account. - pub fn getAccountInFileAndLock( + fn getAccountInFileAndLock( self: *AccountsDB, metadata_allocator: std.mem.Allocator, buffer_pool: *BufferPool, @@ -1692,7 +1696,7 @@ pub const AccountsDB = struct { /// Gets an account given a file_id and an offset value. /// Assumes `self.file_map_fd_rw` is at least /// locked for reading (shared). - pub fn getAccountInFileAssumeLock( + fn getAccountInFileAssumeLock( self: *AccountsDB, metadata_allocator: std.mem.Allocator, buffer_pool: *BufferPool, @@ -1754,6 +1758,7 @@ pub const AccountsDB = struct { /// mut ref is required for locks. pub fn getAccountLatest( self: *AccountsDB, + allocator: std.mem.Allocator, pubkey: *const Pubkey, ) GetAccountError!?Account { const head_ref, var lock = self.account_index.pubkey_ref_map.getRead(pubkey) orelse @@ -1762,7 +1767,7 @@ pub const AccountsDB = struct { // NOTE: this will always be a safe unwrap since both bounds are null const max_ref = slotListMaxWithinBounds(head_ref.ref_ptr, null, null).?; - const account = try self.getAccountFromRef(max_ref); + const account = try self.getAccountFromRef(allocator, max_ref); return account; } @@ -1771,6 +1776,7 @@ pub const AccountsDB = struct { pub fn getSlotAndAccount( self: *AccountsDB, + allocator: std.mem.Allocator, pubkey: *const Pubkey, ) GetAccountError!struct { Slot, Account } { const head_ref, var lock = self.account_index.pubkey_ref_map.getRead(pubkey) orelse @@ -1779,7 +1785,7 @@ pub const AccountsDB = struct { // NOTE: this will always be a safe unwrap since both bounds are null const max_ref = slotListMaxWithinBounds(head_ref.ref_ptr, null, null).?; - const account = try self.getAccountFromRef(max_ref); + const account = try self.getAccountFromRef(allocator, max_ref); return .{ max_ref.slot, account }; } @@ -1788,6 +1794,7 @@ pub const AccountsDB = struct { /// Will only find rooted accounts, or unrooted accounts from a slot in ancestors. pub fn getAccountWithAncestors( self: *AccountsDB, + allocator: std.mem.Allocator, pubkey: *const Pubkey, ancestors: *const sig.core.Ancestors, ) GetFileFromRefError!?Account { @@ -1805,27 +1812,12 @@ pub const AccountsDB = struct { self.getLargestRootedSlot(), ) orelse return null; - return try self.getAccountFromRef(max_ref); - } - - pub fn getAccountAndReference( - self: *AccountsDB, - pubkey: *const Pubkey, - ) !struct { Account, AccountRef } { - const head_ref, var head_ref_lg = - self.account_index.pubkey_ref_map.getRead(pubkey) orelse return error.PubkeyNotInIndex; - defer head_ref_lg.unlock(); - - // NOTE: this will always be a safe unwrap since both bounds are null - const max_ref = slotListMaxWithinBounds(head_ref.ref_ptr, null, null).?; - const account = try self.getAccountFromRef(max_ref); - - return .{ account, max_ref.* }; + return try self.getAccountFromRef(allocator, max_ref); } pub const GetAccountWithReadLockError = GetAccountFromRefError || error{PubkeyNotInIndex}; - pub fn getAccountWithReadLock( + fn getAccountWithReadLock( self: *AccountsDB, pubkey: *const Pubkey, ) GetAccountWithReadLockError!struct { AccountInCacheOrFile, AccountInCacheOrFileLock } { @@ -1856,7 +1848,7 @@ pub const AccountsDB = struct { pub const GetTypeFromAccountError = GetAccountWithReadLockError || error{DeserializationError}; - pub fn getTypeFromAccount( + fn getTypeFromAccount( self: *AccountsDB, allocator: std.mem.Allocator, comptime T: type, @@ -3528,14 +3520,14 @@ test "write and read an account - basic" { var pubkeys = [_]Pubkey{pubkey}; try accounts_db.putAccountSlice(&accounts, &pubkeys, 19); - var account = try accounts_db.getAccountLatest(&pubkey) orelse unreachable; + var account = try accounts_db.getAccountLatest(allocator, &pubkey) orelse unreachable; defer account.deinit(allocator); try std.testing.expect(test_account.equals(&account)); // new account accounts[0].lamports = 20; try accounts_db.putAccountSlice(&accounts, &pubkeys, 28); - var account_2 = try accounts_db.getAccountLatest(&pubkey) orelse unreachable; + var account_2 = try accounts_db.getAccountLatest(allocator, &pubkey) orelse unreachable; defer account_2.deinit(allocator); try std.testing.expect(accounts[0].equals(&account_2)); } @@ -3571,7 +3563,7 @@ test "write and read an account (write single + read with ancestors)" { // normal get { - var account = (try accounts_db.getAccountLatest(&pubkey)).?; + var account = (try accounts_db.getAccountLatest(allocator, &pubkey)).?; defer account.deinit(allocator); try std.testing.expect(test_account.equals(&account)); } @@ -3579,7 +3571,7 @@ test "write and read an account (write single + read with ancestors)" { // assume we've progessed past the need for ancestors { accounts_db.max_slots.set(.{ .rooted = 10_000, .flushed = 10_000 }); - var account = (try accounts_db.getAccountWithAncestors(&pubkey, &.{})).?; + var account = (try accounts_db.getAccountWithAncestors(allocator, &pubkey, &.{})).?; defer account.deinit(allocator); accounts_db.max_slots.set(.{ .rooted = null, .flushed = null }); try account.expectEquals(test_account); @@ -3591,13 +3583,13 @@ test "write and read an account (write single + read with ancestors)" { defer ancestors.deinit(allocator); try ancestors.ancestors.put(allocator, 5083, {}); - var account = (try accounts_db.getAccountWithAncestors(&pubkey, &ancestors)).?; + var account = (try accounts_db.getAccountWithAncestors(allocator, &pubkey, &ancestors)).?; defer account.deinit(allocator); try account.expectEquals(test_account); } // slot is not in ancestors - try std.testing.expectEqual(null, accounts_db.getAccountWithAncestors(&pubkey, &.{})); + try std.testing.expectEqual(null, accounts_db.getAccountWithAncestors(allocator, &pubkey, &.{})); // write account to the same pubkey in the next slot (!) { @@ -3627,7 +3619,11 @@ test "write and read an account (write single + read with ancestors)" { defer ancestors.deinit(allocator); try ancestors.ancestors.put(allocator, 5083, {}); - var account = (try accounts_db.getAccountWithAncestors(&pubkey, &ancestors)).?; + var account = (try accounts_db.getAccountWithAncestors( + allocator, + &pubkey, + &ancestors, + )).?; defer account.deinit(allocator); try std.testing.expect(test_account.equals(&account)); } @@ -3638,7 +3634,11 @@ test "write and read an account (write single + read with ancestors)" { defer ancestors.deinit(allocator); try ancestors.ancestors.put(allocator, 5084, {}); - var account = (try accounts_db.getAccountWithAncestors(&pubkey, &ancestors)).?; + var account = (try accounts_db.getAccountWithAncestors( + allocator, + &pubkey, + &ancestors, + )).?; defer account.deinit(allocator); try std.testing.expect(test_account_2.equals(&account)); } @@ -4448,8 +4448,10 @@ pub const BenchmarkAccountsDB = struct { var i: usize = 0; while (i < n_accounts) : (i += 1) { const pubkey_idx = indexer.sample(); - const account = try accounts_db.getAccountLatest(&pubkeys[pubkey_idx]) orelse - unreachable; + const account = try accounts_db.getAccountLatest( + allocator, + &pubkeys[pubkey_idx], + ) orelse unreachable; account.deinit(allocator); } } @@ -4460,7 +4462,7 @@ pub const BenchmarkAccountsDB = struct { var i: usize = 0; while (i < do_read_count) : (i += 1) { const pubkey_idx = indexer.sample(); - const account = try accounts_db.getAccountLatest(&pubkeys[pubkey_idx]) orelse + const account = try accounts_db.getAccountLatest(allocator, &pubkeys[pubkey_idx]) orelse unreachable; defer account.deinit(allocator); if (account.data.len() != (pubkey_idx % 1_000)) std.debug.panic( @@ -4522,7 +4524,11 @@ test "insert multiple accounts on same slot" { try accounts_db.putAccount(slot, pubkey, expected); - const maybe_actual = try accounts_db.getAccountWithAncestors(&pubkey, &ancestors); + const maybe_actual = try accounts_db.getAccountWithAncestors( + allocator, + &pubkey, + &ancestors, + ); defer if (maybe_actual) |actual| actual.deinit(allocator); if (maybe_actual) |actual| { @@ -4605,7 +4611,11 @@ test "insert multiple accounts on multiple slots" { try accounts_db.putAccount(slot, pubkey, expected); - const maybe_actual = try accounts_db.getAccountWithAncestors(&pubkey, &ancestors); + const maybe_actual = try accounts_db.getAccountWithAncestors( + allocator, + &pubkey, + &ancestors, + ); defer if (maybe_actual) |actual| actual.deinit(allocator); if (maybe_actual) |actual| @@ -4653,7 +4663,11 @@ test "insert account on multiple slots" { try accounts_db.putAccount(slot, pubkey, expected); - const maybe_actual = try accounts_db.getAccountWithAncestors(&pubkey, &ancestors); + const maybe_actual = try accounts_db.getAccountWithAncestors( + allocator, + &pubkey, + &ancestors, + ); defer if (maybe_actual) |actual| actual.deinit(allocator); if (maybe_actual) |actual| @@ -4683,7 +4697,10 @@ test "missing ancestor returns null" { var ancestors = Ancestors{}; defer ancestors.deinit(allocator); - try std.testing.expectEqual(null, try accounts_db.getAccountWithAncestors(&pubkey, &ancestors)); + try std.testing.expectEqual( + null, + try accounts_db.getAccountWithAncestors(allocator, &pubkey, &ancestors), + ); } test "overwrite account in same slot" { @@ -4710,7 +4727,7 @@ test "overwrite account in same slot" { defer allocator.free(second.data); try accounts_db.putAccount(slot, pubkey, second); - const maybe_actual = try accounts_db.getAccountWithAncestors(&pubkey, &ancestors); + const maybe_actual = try accounts_db.getAccountWithAncestors(allocator, &pubkey, &ancestors); defer if (maybe_actual) |actual| actual.deinit(allocator); if (maybe_actual) |actual| @@ -4772,7 +4789,11 @@ test "insert many duplicate individual accounts, get latest with ancestors" { defer ancestors.deinit(allocator); try ancestors.ancestors.put(allocator, expected.slot, {}); - const maybe_actual = try accounts_db.getAccountWithAncestors(&pubkey, &ancestors); + const maybe_actual = try accounts_db.getAccountWithAncestors( + allocator, + &pubkey, + &ancestors, + ); defer if (maybe_actual) |actual| actual.deinit(allocator); if (maybe_actual) |actual| { diff --git a/src/accountsdb/fuzz.zig b/src/accountsdb/fuzz.zig index 9a941f196f..481233e09f 100644 --- a/src/accountsdb/fuzz.zig +++ b/src/accountsdb/fuzz.zig @@ -323,7 +323,11 @@ pub fn run(seed: u64, args: *std.process.ArgIterator) !void { }{ .ancestors_sub = ancestors_sub.ancestors.keys() }); const account = - try accounts_db.getAccountWithAncestors(&pubkey, &ancestors_sub) orelse { + try accounts_db.getAccountWithAncestors( + allocator, + &pubkey, + &ancestors_sub, + ) orelse { logger.err().logf( "accounts_db missing tracked account '{}': {}", .{ pubkey, tracked_account }, @@ -542,7 +546,7 @@ fn readRandomAccounts( } for (pubkeys) |pubkey| { - const account = db.getAccountLatest(&pubkey) catch |e| + const account = db.getAccountLatest(db.allocator, &pubkey) catch |e| std.debug.panic("getAccount failed with error: {}", .{e}) orelse continue; defer account.deinit(db.allocator); diff --git a/src/accountsdb/manager.zig b/src/accountsdb/manager.zig index 10af278ed5..8e433aec0c 100644 --- a/src/accountsdb/manager.zig +++ b/src/accountsdb/manager.zig @@ -1128,7 +1128,7 @@ test "clean to shrink account file works with zero-lamports" { // slot 500 will be fully dead because its all zero lamports try std.testing.expectEqual(1, delete_account_files.count()); - var account = try accounts_db.getAccountLatest(&pubkey_remain) orelse unreachable; + var account = try accounts_db.getAccountLatest(allocator, &pubkey_remain) orelse unreachable; defer account.deinit(allocator); } @@ -1474,7 +1474,7 @@ test "shrink account file works" { } // last account ref should still be accessible - const account = try accounts_db.getAccountLatest(&pubkey_remain) orelse unreachable; + const account = try accounts_db.getAccountLatest(allocator, &pubkey_remain) orelse unreachable; account.deinit(allocator); } diff --git a/src/consensus/replay_tower.zig b/src/consensus/replay_tower.zig index cd6bbf17ac..ed5e56a26b 100644 --- a/src/consensus/replay_tower.zig +++ b/src/consensus/replay_tower.zig @@ -144,9 +144,10 @@ pub const SlotHistoryAccessor = struct { ancestors: *const Ancestors, ) !SlotHistory { const maybe_account = - try self.account_reader.forSlot(ancestors).get(SlotHistory.ID); + try self.account_reader.forSlot(ancestors).get(allocator, SlotHistory.ID); const account: sig.core.Account = maybe_account orelse return error.MissingSlotHistoryAccount; + defer account.deinit(allocator); var data_iter = account.data.iterator(); const slot_history = try sig.bincode.read( @@ -158,11 +159,8 @@ pub const SlotHistoryAccessor = struct { errdefer slot_history.deinit(allocator); if (data_iter.bytesRemaining() != 0) { - account.deinit(self.account_reader.allocator()); return error.TrailingBytesInSlotHistory; } - account.deinit(self.account_reader.allocator()); - return slot_history; } }; @@ -1830,7 +1828,10 @@ pub fn lastVotedSlotInBank( accounts_db: *sig.accounts_db.AccountsDB, vote_account_pubkey: *const Pubkey, ) !?Slot { - const vote_account = try accounts_db.getAccountLatest(vote_account_pubkey) orelse return null; + const vote_account = try accounts_db.getAccountLatest(allocator, vote_account_pubkey) orelse + return null; + defer vote_account.deinit(allocator); + const vote_state = stateFromAccount( allocator, &vote_account, diff --git a/src/consensus/tower.zig b/src/consensus/tower.zig index 5a943dbdf8..449c0f31a7 100644 --- a/src/consensus/tower.zig +++ b/src/consensus/tower.zig @@ -90,20 +90,22 @@ pub const Tower = struct { slot_account_reader: sig.accounts_db.SlotAccountReader, ) !void { const vote_account = blk: { - const maybe_vote_account = slot_account_reader.get(vote_account_pubkey.*) catch |err| - switch (err) { - error.OutOfMemory, - => |e| return e, - error.InvalidOffset, - error.FileIdNotFound, - error.SlotNotFound, - => null, - }; + const maybe_vote_account = slot_account_reader.get( + allocator, + vote_account_pubkey.*, + ) catch |err| switch (err) { + error.OutOfMemory => |e| return e, + error.InvalidOffset, + error.FileIdNotFound, + error.SlotNotFound, + => null, + }; break :blk maybe_vote_account orelse { self.initializeRoot(fork_root); return; }; }; + defer vote_account.deinit(allocator); const vote_state = try stateFromAccount( allocator, @@ -294,8 +296,10 @@ pub fn lastVotedSlotInBank( accounts_db: *AccountsDB, vote_account_pubkey: *const Pubkey, ) !?Slot { - const vote_account = try accounts_db.getAccountLatest(vote_account_pubkey) orelse + const vote_account = try accounts_db.getAccountLatest(allocator, vote_account_pubkey) orelse return null; + defer vote_account.deinit(allocator); + const vote_state = stateFromAccount( allocator, &vote_account, diff --git a/src/replay/freeze.zig b/src/replay/freeze.zig index 49e43a5f10..4f90b337d0 100644 --- a/src/replay/freeze.zig +++ b/src/replay/freeze.zig @@ -167,7 +167,12 @@ fn finalizeState(allocator: Allocator, params: FinalizeStateParams) !void { ); // Run incinerator - if (try params.account_reader.get(sig.runtime.ids.INCINERATOR)) |incinerator_account| { + if (try params.account_reader.get( + allocator, + sig.runtime.ids.INCINERATOR, + )) |incinerator_account| { + defer incinerator_account.deinit(allocator); + _ = params.capitalization.fetchSub(incinerator_account.lamports, .monotonic); try params.account_store.put( params.update_sysvar.slot, @@ -232,16 +237,17 @@ fn tryPayoutFees( payout: u64, ) !u64 { var fee_collector_account = - if (try account_reader.get(collector_id)) |old_account| - AccountSharedData{ + if (try account_reader.get(allocator, collector_id)) |old_account| blk: { + defer old_account.deinit(allocator); + + break :blk AccountSharedData{ .data = try old_account.data.readAllAllocate(allocator), .lamports = old_account.lamports, .owner = old_account.owner, .executable = old_account.executable, .rent_epoch = old_account.rent_epoch, - } - else - AccountSharedData.EMPTY; + }; + } else AccountSharedData.EMPTY; if (!fee_collector_account.owner.equals(&sig.runtime.program.system.ID)) { return error.InvalidAccountOwner; @@ -294,7 +300,12 @@ pub fn hashSlot(allocator: Allocator, params: HashSlotParams) !struct { ?LtHash, assert(parent_ancestors.ancestors.swapRemove(params.slot)); var lt_hash = params.parent_lt_hash.* orelse return error.UnknownParentLtHash; - lt_hash.mixIn(try deltaLtHash(params.account_reader, params.slot, &parent_ancestors)); + lt_hash.mixIn(try deltaLtHash( + allocator, + params.account_reader, + params.slot, + &parent_ancestors, + )); return .{ lt_hash, Hash.generateSha256(.{ initial_hash, lt_hash.bytes() }) }; } else { @@ -312,10 +323,10 @@ pub fn deltaMerkleHash(account_reader: AccountReader, allocator: Allocator, slot errdefer allocator.free(pubkey_hashes); var i: usize = 0; - while (try iterator.next()) |pubkey_account| : (i += 1) { + while (try iterator.next(allocator)) |pubkey_account| : (i += 1) { const pubkey, const account = pubkey_account; + defer account.deinit(allocator); pubkey_hashes[i] = .{ pubkey, account.hash(pubkey) }; - account.deinit(allocator); } break :pkh pubkey_hashes; @@ -345,6 +356,7 @@ pub fn deltaMerkleHash(account_reader: AccountReader, allocator: Allocator, slot /// Returns the lattice hash of every account that was modified in the slot. pub fn deltaLtHash( + tmp_alloc: std.mem.Allocator, account_reader: AccountReader, slot: Slot, parent_ancestors: *const Ancestors, @@ -354,6 +366,10 @@ pub fn deltaLtHash( assert(!parent_ancestors.containsSlot(slot)); + var arena = std.heap.ArenaAllocator.init(tmp_alloc); + defer arena.deinit(); + const allocator = arena.allocator(); + // TODO: perf - consider using a thread pool // TODO: perf - consider caching old hashes @@ -362,11 +378,13 @@ pub fn deltaLtHash( var hash = LtHash.IDENTITY; var i: usize = 0; - while (try iterator.next()) |pubkey_account| : (i += 1) { + while (try iterator.next(allocator)) |pubkey_account| : (i += 1) { const pubkey, const account = pubkey_account; - defer account.deinit(account_reader.allocator()); - if (try account_reader.forSlot(parent_ancestors).get(pubkey)) |old_acct| { - defer old_acct.deinit(account_reader.allocator()); + defer account.deinit(allocator); + + if (try account_reader.forSlot(parent_ancestors).get(allocator, pubkey)) |old_acct| { + defer old_acct.deinit(allocator); + if (!old_acct.equals(&account)) { hash.mixOut(old_acct.ltHash(pubkey)); hash.mixIn(account.ltHash(pubkey)); @@ -380,7 +398,10 @@ pub fn deltaLtHash( } test "deltaLtHash is identity for 0 accounts" { - try std.testing.expectEqual(LtHash.IDENTITY, try deltaLtHash(.noop, 0, &Ancestors{})); + try std.testing.expectEqual( + LtHash.IDENTITY, + try deltaLtHash(std.testing.allocator, .noop, 0, &Ancestors{}), + ); } test "deltaMerkleHash for 0 accounts" { @@ -600,7 +621,12 @@ test "delta hashes with many accounts" { try parent_ancestors.ancestors.put(allocator, 0, {}); try parent_ancestors.ancestors.put(allocator, 1, {}); - const actual_lt_hash = try deltaLtHash(accounts.accountReader(), hash_slot, &parent_ancestors); + const actual_lt_hash = try deltaLtHash( + allocator, + accounts.accountReader(), + hash_slot, + &parent_ancestors, + ); const actual_merkle_hash = try deltaMerkleHash(accounts.accountReader(), allocator, hash_slot); try std.testing.expectEqualSlices(u16, &expected_lt_hash, &actual_lt_hash.data); diff --git a/src/replay/resolve_lookup.zig b/src/replay/resolve_lookup.zig index ab4ed51c9c..3ad3b37b99 100644 --- a/src/replay/resolve_lookup.zig +++ b/src/replay/resolve_lookup.zig @@ -240,7 +240,8 @@ fn resolveLookupTableAccounts( // handle lookup table accounts for (address_lookups) |lookup| { - const table = try getLookupTable(account_reader, lookup.table_address); + const table = try getLookupTable(allocator, account_reader, lookup.table_address); + defer allocator.free(table.addresses); if (table.meta.status(slot, slot_hashes) == .Deactivated) { return error.AddressLookupTableNotFound; @@ -275,6 +276,7 @@ fn resolveLookupTableAccounts( } fn getLookupTable( + allocator: std.mem.Allocator, account_reader: SlotAccountReader, table_address: Pubkey, ) !AddressLookupTable { @@ -282,9 +284,9 @@ fn getLookupTable( // it against the current slot's ancestors. This won't be usable // until consensus is implemented in replay, so it's not // implemented yet. - const account = try account_reader.get(table_address) orelse + const account = try account_reader.get(allocator, table_address) orelse return error.AddressLookupTableNotFound; - defer account.deinit(account_reader.allocator()); + defer account.deinit(allocator); if (!account.owner.equals(&sig.runtime.program.address_lookup_table.ID)) { return error.InvalidAddressLookupTableOwner; @@ -298,7 +300,8 @@ fn getLookupTable( const account_bytes = buf[0..account.data.len()]; account.data.readAll(account_bytes); - return AddressLookupTable.deserialize(account_bytes) catch { + const table = AddressLookupTable.deserializeOwned(allocator, account_bytes) catch |err| { + if (err == error.OutOfMemory) return err; return error.InvalidAddressLookupTableData; }; @@ -306,6 +309,7 @@ fn getLookupTable( // according to agave's implementation. see here, where agave // discards the value: // https://github.com/anza-xyz/agave/blob/161fc1965bdb4190aa2d7e36c7c745b4661b10ed/runtime/src/bank/address_lookup_table.rs#L36 + return table; } test resolveBatch { @@ -551,7 +555,7 @@ test getLookupTable { try std.testing.expectError( error.InvalidAddressLookupTableOwner, - getLookupTable(account_reader, pubkey), + getLookupTable(allocator, account_reader, pubkey), ); } @@ -570,7 +574,7 @@ test getLookupTable { try std.testing.expectError( error.InvalidAddressLookupTableData, - getLookupTable(account_reader, pubkey), + getLookupTable(allocator, account_reader, pubkey), ); } @@ -589,7 +593,7 @@ test getLookupTable { try std.testing.expectError( error.InvalidAddressLookupTableData, - getLookupTable(account_reader, pubkey), + getLookupTable(allocator, account_reader, pubkey), ); } @@ -602,7 +606,8 @@ test getLookupTable { try put(&map, pubkey, lookup_table); - const loaded_lookup_table = try getLookupTable(account_reader, pubkey); + const loaded_lookup_table = try getLookupTable(allocator, account_reader, pubkey); + defer allocator.free(loaded_lookup_table.addresses); try std.testing.expectEqual(lookup_table.meta, loaded_lookup_table.meta); try std.testing.expect(lookup_table.addresses[0].equals(&loaded_lookup_table.addresses[0])); diff --git a/src/replay/service.zig b/src/replay/service.zig index 38fb64cddb..baadde567f 100644 --- a/src/replay/service.zig +++ b/src/replay/service.zig @@ -507,8 +507,11 @@ pub fn getActiveFeatures( for (0..sig.core.features.NUM_FEATURES) |i| { const possible_feature: sig.core.features.Feature = @enumFromInt(i); const possible_feature_pubkey = sig.core.features.map.get(possible_feature).key; - const feature_account = try account_reader.get(possible_feature_pubkey) orelse continue; - defer feature_account.deinit(account_reader.allocator()); + + const feature_account = try account_reader.get(allocator, possible_feature_pubkey) orelse + continue; + defer feature_account.deinit(allocator); + if (!feature_account.owner.equals(&sig.runtime.ids.FEATURE_PROGRAM_ID)) { continue; } diff --git a/src/replay/update_sysvar.zig b/src/replay/update_sysvar.zig index 85b75772ed..7bce9fc7a6 100644 --- a/src/replay/update_sysvar.zig +++ b/src/replay/update_sysvar.zig @@ -324,7 +324,7 @@ pub fn updateSysvarAccount( deps: UpdateSysvarAccountDeps, ) !void { const maybe_old_account = - try deps.account_store.reader().forSlot(deps.ancestors).get(Sysvar.ID); + try deps.account_store.reader().forSlot(deps.ancestors).get(allocator, Sysvar.ID); defer if (maybe_old_account) |old_account| old_account.deinit(allocator); const new_account = try createSysvarAccount( @@ -393,7 +393,7 @@ fn getSysvarAndDataFromAccount( allocator: Allocator, account_reader: SlotAccountReader, ) !?struct { sysvar: Sysvar, data: []const u8 } { - const maybe_account = try account_reader.get(Sysvar.ID); + const maybe_account = try account_reader.get(allocator, Sysvar.ID); const account = maybe_account orelse return null; defer account.deinit(allocator); @@ -412,7 +412,7 @@ pub fn getSysvarFromAccount( allocator: Allocator, account_reader: SlotAccountReader, ) !?Sysvar { - const maybe_account = try account_reader.get(Sysvar.ID); + const maybe_account = try account_reader.get(allocator, Sysvar.ID); const account = maybe_account orelse return null; defer account.deinit(allocator); @@ -755,7 +755,7 @@ fn insertSysvarCacheAccounts( RecentBlockhashes, }) |Sysvar| { const old_account = if (inherit_from_old_account) - accounts_db.getAccountLatest(&Sysvar.ID) catch null + accounts_db.getAccountLatest(allocator, &Sysvar.ID) catch null else null; defer if (old_account) |acc| acc.deinit(allocator) else {}; @@ -799,7 +799,7 @@ fn getSysvarAndAccount( account_reader: SlotAccountReader, ) !?struct { Sysvar, AccountSharedData } { if (!builtin.is_test) @compileError("only for testing"); - const maybe_account = account_reader.get(Sysvar.ID) catch return null; + const maybe_account = account_reader.get(allocator, Sysvar.ID) catch return null; const account = maybe_account orelse return null; defer account.deinit(allocator); diff --git a/src/runtime/account_loader.zig b/src/runtime/account_loader.zig index 95255965b2..4c6ce37ad2 100644 --- a/src/runtime/account_loader.zig +++ b/src/runtime/account_loader.zig @@ -200,7 +200,7 @@ pub const BatchAccountCache = struct { if (!entry.found_existing) { entry.value_ptr.* = program_data_account; } else { - account_reader.allocator().free(program_data_account.data); + allocator.free(program_data_account.data); } } } @@ -656,14 +656,14 @@ fn getAccountSharedData( reader: SlotAccountReader, pubkey: Pubkey, ) error{ OutOfMemory, GetAccountFailedUnexpectedly }!?AccountSharedData { - const account: sig.core.Account = reader.get(pubkey) catch |err| switch (err) { + const account: sig.core.Account = reader.get(allocator, pubkey) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.FileIdNotFound, error.InvalidOffset, error.SlotNotFound, => return error.GetAccountFailedUnexpectedly, } orelse return null; - defer account.deinit(reader.allocator()); + defer account.deinit(allocator); // NOTE: Tmp fix since accounts DB should not return accounts with 0 lamports. if (account.lamports == 0) return null; diff --git a/src/runtime/program/address_lookup_table/state.zig b/src/runtime/program/address_lookup_table/state.zig index 5482f91f99..2df2280f68 100644 --- a/src/runtime/program/address_lookup_table/state.zig +++ b/src/runtime/program/address_lookup_table/state.zig @@ -102,9 +102,11 @@ pub const AddressLookupTable = struct { } // [agave] https://github.com/anza-xyz/agave/blob/d300f3733f45d64a3b6b9fdb5a1157f378e181c2/sdk/program/src/address_lookup_table/state.rs#L224 + /// NOTE: This AddressLookupTable's 'addresses' slice will point to inside 'data' - consider + /// if you need to clone the buffer (see deserializeOwned). pub fn deserialize( data: []const u8, - ) (error{OutOfMemory} || InstructionError)!AddressLookupTable { + ) error{ UninitializedAccount, InvalidAccountData }!AddressLookupTable { const noalloc = sig.utils.allocators.failing.allocator(.{}); const state = sig.bincode.readFromSlice(noalloc, ProgramState, data, .{}) catch return error.InvalidAccountData; @@ -122,4 +124,14 @@ pub const AddressLookupTable = struct { .addresses = addresses, }; } + + /// Deserializes an AddressLookupTable, coping .addresses into a new buffer. + pub fn deserializeOwned( + allocator: std.mem.Allocator, + data: []const u8, + ) error{ OutOfMemory, UninitializedAccount, InvalidAccountData }!AddressLookupTable { + var table = try AddressLookupTable.deserialize(data); + table.addresses = try allocator.dupe(Pubkey, table.addresses); + return table; + } };