Line data Source code
1 : #include "fd_sysvar_slot_hashes.h"
2 : #include "fd_sysvar.h"
3 : #include "../fd_acc_mgr.h"
4 : #include "../fd_borrowed_account.h"
5 : #include "../fd_system_ids.h"
6 : #include "../context/fd_exec_slot_ctx.h"
7 : /* FIXME These constants should be header defines */
8 :
9 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_hashes.rs#L11 */
10 : FD_FN_UNUSED static const ulong slot_hashes_max_entries = 512;
11 :
12 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/sysvar/slot_hashes.rs#L12 */
13 : static const ulong slot_hashes_account_size = 20488;
14 :
15 : void
16 : fd_sysvar_slot_hashes_write( fd_exec_slot_ctx_t * slot_ctx,
17 0 : fd_slot_hashes_global_t * slot_hashes_global ) {
18 0 : uchar enc[slot_hashes_account_size];
19 0 : fd_memset( enc, 0, slot_hashes_account_size );
20 0 : fd_bincode_encode_ctx_t ctx = {
21 0 : .data = enc,
22 0 : .dataend = enc + slot_hashes_account_size,
23 0 : };
24 0 : if( fd_slot_hashes_encode_global( slot_hashes_global, &ctx ) ) {
25 0 : FD_LOG_ERR(("fd_slot_hashes_encode failed"));
26 0 : }
27 0 : fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_slot_hashes_id, enc, slot_hashes_account_size, slot_ctx->slot );
28 0 : }
29 :
30 : ulong
31 0 : fd_sysvar_slot_hashes_footprint( ulong slot_hashes_cap ) {
32 0 : return sizeof(fd_slot_hashes_global_t) +
33 0 : deq_fd_slot_hash_t_footprint( slot_hashes_cap ) + deq_fd_slot_hash_t_align();
34 0 : }
35 :
36 : void *
37 : fd_sysvar_slot_hashes_new( void * mem,
38 0 : ulong slot_hashes_cap ) {
39 0 : if( FD_UNLIKELY( !mem ) ) {
40 0 : FD_LOG_ERR(( "Unable to allocate memory for slot hashes" ));
41 0 : }
42 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_SYSVAR_SLOT_HASHES_ALIGN ) ) ) {
43 0 : FD_LOG_ERR(( "Memory for slot hashes is not aligned" ));
44 0 : }
45 :
46 0 : fd_slot_hashes_global_t * slot_hashes_global = (fd_slot_hashes_global_t *)mem;
47 :
48 0 : uchar * slot_hash_mem = (uchar*)fd_ulong_align_up( (ulong)((uchar *)mem + sizeof(fd_slot_hashes_global_t)), deq_fd_slot_hash_t_align() );
49 0 : deq_fd_slot_hash_t_new( (void*)slot_hash_mem, slot_hashes_cap );
50 0 : slot_hashes_global->hashes_offset = (ulong)slot_hash_mem - (ulong)slot_hashes_global;
51 :
52 0 : return slot_hashes_global;
53 0 : }
54 :
55 : fd_slot_hashes_global_t *
56 : fd_sysvar_slot_hashes_join( void * shmem,
57 0 : fd_slot_hash_t ** slot_hash ) {
58 0 : fd_slot_hashes_global_t * slot_hashes_global = (fd_slot_hashes_global_t *)shmem;
59 0 : *slot_hash = deq_fd_slot_hash_t_join( (uchar*)shmem + slot_hashes_global->hashes_offset );
60 :
61 0 : return slot_hashes_global;
62 0 : }
63 :
64 : void *
65 : fd_sysvar_slot_hashes_leave( fd_slot_hashes_global_t * slot_hashes_global,
66 0 : fd_slot_hash_t * slot_hash ) {
67 0 : deq_fd_slot_hash_t_leave( slot_hash );
68 :
69 0 : return slot_hashes_global;
70 0 : }
71 :
72 : void *
73 0 : fd_sysvar_slot_hashes_delete( void * mem ) {
74 0 : void * slot_hash_mem = (void *)fd_ulong_align_up( (ulong)((uchar *)mem + sizeof(fd_slot_hashes_global_t)), deq_fd_slot_hash_t_align() );
75 0 : deq_fd_slot_hash_t_delete( slot_hash_mem );
76 :
77 0 : return mem;
78 0 : }
79 :
80 : void
81 : fd_sysvar_slot_hashes_init( fd_exec_slot_ctx_t * slot_ctx,
82 0 : fd_spad_t * runtime_spad ) {
83 0 : FD_SPAD_FRAME_BEGIN( runtime_spad ) {
84 0 : void * mem = fd_spad_alloc( runtime_spad, FD_SYSVAR_SLOT_HASHES_ALIGN, fd_sysvar_slot_hashes_footprint( FD_SYSVAR_SLOT_HASHES_CAP ) );
85 0 : fd_slot_hash_t * shnull = NULL;
86 0 : fd_slot_hashes_global_t * slot_hashes_global = fd_sysvar_slot_hashes_join( fd_sysvar_slot_hashes_new( mem, FD_SYSVAR_SLOT_HASHES_CAP ), &shnull );
87 :
88 0 : fd_sysvar_slot_hashes_write( slot_ctx, slot_hashes_global);
89 0 : fd_sysvar_slot_hashes_delete( fd_sysvar_slot_hashes_leave( slot_hashes_global, shnull ) );
90 0 : } FD_SPAD_FRAME_END;
91 0 : }
92 :
93 : /* https://github.com/anza-xyz/agave/blob/b11ca828cfc658b93cb86a6c5c70561875abe237/runtime/src/bank.rs#L2283-L2294 */
94 : void
95 0 : fd_sysvar_slot_hashes_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
96 0 : FD_SPAD_FRAME_BEGIN( runtime_spad ) {
97 0 : fd_slot_hashes_global_t * slot_hashes_global = fd_sysvar_slot_hashes_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad );
98 0 : fd_slot_hash_t * hashes = NULL;
99 0 : if( FD_UNLIKELY( !slot_hashes_global ) ) {
100 : /* Note: Agave's implementation initializes a new slot_hashes if it doesn't already exist (refer to above URL). */
101 0 : void * mem = fd_spad_alloc( runtime_spad, FD_SYSVAR_SLOT_HASHES_ALIGN, fd_sysvar_slot_hashes_footprint( FD_SYSVAR_SLOT_HASHES_CAP ) );
102 0 : slot_hashes_global = fd_sysvar_slot_hashes_new( mem, FD_SYSVAR_SLOT_HASHES_CAP );
103 0 : }
104 0 : slot_hashes_global = fd_sysvar_slot_hashes_join( slot_hashes_global, &hashes );
105 :
106 0 : uchar found = 0;
107 0 : for( deq_fd_slot_hash_t_iter_t iter = deq_fd_slot_hash_t_iter_init( hashes );
108 0 : !deq_fd_slot_hash_t_iter_done( hashes, iter );
109 0 : iter = deq_fd_slot_hash_t_iter_next( hashes, iter ) ) {
110 0 : fd_slot_hash_t * ele = deq_fd_slot_hash_t_iter_ele( hashes, iter );
111 0 : if( ele->slot == slot_ctx->slot ) {
112 0 : fd_hash_t const * bank_hash = fd_bank_bank_hash_query( slot_ctx->bank );
113 0 : memcpy( &ele->hash, bank_hash, sizeof(fd_hash_t) );
114 0 : found = 1;
115 0 : }
116 0 : }
117 :
118 0 : if( !found ) {
119 : // https://github.com/firedancer-io/solana/blob/08a1ef5d785fe58af442b791df6c4e83fe2e7c74/runtime/src/bank.rs#L2371
120 0 : fd_slot_hash_t slot_hash = {
121 0 : .hash = fd_bank_bank_hash_get( slot_ctx->bank ), // parent hash?
122 0 : .slot = fd_bank_prev_slot_get( slot_ctx->bank ), // parent_slot
123 0 : };
124 0 : FD_LOG_DEBUG(( "fd_sysvar_slot_hash_update: slot %lu, hash %s", slot_hash.slot, FD_BASE58_ENC_32_ALLOCA( slot_hash.hash.key ) ));
125 :
126 0 : if( deq_fd_slot_hash_t_full( hashes ) )
127 0 : memset( deq_fd_slot_hash_t_pop_tail_nocopy( hashes ), 0, sizeof(fd_slot_hash_t) );
128 :
129 0 : deq_fd_slot_hash_t_push_head( hashes, slot_hash );
130 0 : }
131 :
132 0 : fd_sysvar_slot_hashes_write( slot_ctx, slot_hashes_global );
133 0 : fd_sysvar_slot_hashes_leave( slot_hashes_global, hashes );
134 0 : } FD_SPAD_FRAME_END;
135 0 : }
136 :
137 : fd_slot_hashes_global_t *
138 : fd_sysvar_slot_hashes_read( fd_funk_t * funk,
139 : fd_funk_txn_t * funk_txn,
140 0 : fd_spad_t * spad ) {
141 0 : FD_TXN_ACCOUNT_DECL( rec );
142 0 : int err = fd_txn_account_init_from_funk_readonly( rec, (fd_pubkey_t const *)&fd_sysvar_slot_hashes_id, funk, funk_txn );
143 0 : if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
144 0 : return NULL;
145 0 : }
146 :
147 : /* This check is needed as a quirk of the fuzzer. If a sysvar account
148 : exists in the accounts database, but doesn't have any lamports,
149 : this means that the account does not exist. This wouldn't happen
150 : in a real execution environment. */
151 0 : if( FD_UNLIKELY( rec->vt->get_lamports( rec )==0 ) ) {
152 0 : return NULL;
153 0 : }
154 :
155 0 : fd_bincode_decode_ctx_t decode = {
156 0 : .data = rec->vt->get_data( rec ),
157 0 : .dataend = rec->vt->get_data( rec ) + rec->vt->get_data_len( rec )
158 0 : };
159 :
160 0 : ulong total_sz = 0UL;
161 0 : err = fd_slot_hashes_decode_footprint( &decode, &total_sz );
162 0 : if( FD_UNLIKELY( err ) ) {
163 0 : return NULL;
164 0 : }
165 :
166 0 : uchar * mem = fd_spad_alloc( spad, fd_slot_hashes_align(), total_sz );
167 :
168 0 : if( FD_UNLIKELY( !mem ) ) {
169 0 : FD_LOG_ERR(( "Unable to allocate memory for slot hashes" ));
170 0 : }
171 :
172 0 : return fd_slot_hashes_decode_global( mem, &decode );
173 0 : }
|