Line data Source code
1 : #include "fd_sysvar_slot_history.h"
2 : #include "fd_sysvar.h"
3 : #include "fd_sysvar_rent.h"
4 : #include "../fd_executor_err.h"
5 : #include "../fd_system_ids.h"
6 :
7 : /* FIXME These constants should be header defines */
8 :
9 : static const ulong slot_history_min_account_size = 131097;
10 :
11 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L37 */
12 : static const ulong slot_history_max_entries = 1024 * 1024;
13 :
14 : /* TODO: move into seperate bitvec library */
15 : static const ulong bits_per_block = 8 * sizeof(ulong);
16 :
17 : void
18 : fd_sysvar_slot_history_set( fd_slot_history_t * history,
19 0 : ulong i ) {
20 0 : if( FD_UNLIKELY( i > history->next_slot && i - history->next_slot >= slot_history_max_entries ) ) {
21 0 : FD_LOG_WARNING(( "Ignoring out of bounds (i=%lu next_slot=%lu)", i, history->next_slot ));
22 0 : return;
23 0 : }
24 :
25 : // Skipped slots, delete them from history
26 0 : for( ulong j = history->next_slot; j < i; j++ ) {
27 0 : ulong block_idx = (j / bits_per_block) % (history->bits.bits->blocks_len);
28 0 : history->bits.bits->blocks[ block_idx ] &= ~( 1UL << ( j % bits_per_block ) );
29 0 : }
30 0 : ulong block_idx = (i / bits_per_block) % (history->bits.bits->blocks_len);
31 0 : history->bits.bits->blocks[ block_idx ] |= ( 1UL << ( i % bits_per_block ) );
32 0 : }
33 :
34 : static const ulong blocks_len = slot_history_max_entries / bits_per_block;
35 :
36 : int fd_sysvar_slot_history_write_history( fd_exec_slot_ctx_t * slot_ctx,
37 0 : fd_slot_history_t * history ) {
38 0 : ulong sz = fd_slot_history_size( history );
39 0 : if (sz < slot_history_min_account_size)
40 0 : sz = slot_history_min_account_size;
41 0 : uchar enc[ sz ];
42 0 : fd_memset( enc, 0, sz );
43 0 : fd_bincode_encode_ctx_t ctx;
44 0 : ctx.data = enc;
45 0 : ctx.dataend = enc + sz;
46 0 : int err = fd_slot_history_encode( history, &ctx );
47 0 : if (0 != err)
48 0 : return err;
49 0 : return fd_sysvar_set( slot_ctx, fd_sysvar_owner_id.key, &fd_sysvar_slot_history_id, enc, sz, slot_ctx->slot_bank.slot );
50 0 : }
51 :
52 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L16 */
53 : void
54 0 : fd_sysvar_slot_history_init( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
55 : /* Create a new slot history instance */
56 0 : fd_slot_history_t history = {0};
57 0 : fd_slot_history_inner_t * inner = fd_spad_alloc( runtime_spad, alignof(fd_slot_history_inner_t), sizeof(fd_slot_history_inner_t) );
58 0 : inner->blocks = fd_spad_alloc( runtime_spad, alignof(ulong), sizeof(ulong) * blocks_len );
59 0 : memset( inner->blocks, 0, sizeof(ulong) * blocks_len );
60 0 : inner->blocks_len = blocks_len;
61 0 : history.bits.bits = inner;
62 0 : history.bits.len = slot_history_max_entries;
63 :
64 : /* TODO: handle slot != 0 init case */
65 0 : fd_sysvar_slot_history_set( &history, slot_ctx->slot_bank.slot );
66 0 : history.next_slot = slot_ctx->slot_bank.slot + 1;
67 :
68 0 : fd_sysvar_slot_history_write_history( slot_ctx, &history );
69 0 : fd_slot_history_destroy( &history );
70 0 : }
71 :
72 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/bank.rs#L2345 */
73 : int
74 0 : fd_sysvar_slot_history_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
75 : /* Set current_slot, and update next_slot */
76 :
77 0 : fd_pubkey_t const * key = &fd_sysvar_slot_history_id;
78 :
79 0 : FD_TXN_ACCOUNT_DECL( rec );
80 0 : int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, key, rec);
81 0 : if (err)
82 0 : FD_LOG_CRIT(( "fd_acc_mgr_view(slot_history) failed: %d", err ));
83 :
84 0 : fd_bincode_decode_ctx_t ctx = {
85 0 : .data = rec->const_data,
86 0 : .dataend = rec->const_data + rec->const_meta->dlen
87 0 : };
88 :
89 0 : ulong total_sz = 0UL;
90 0 : err = fd_slot_history_decode_footprint( &ctx, &total_sz );
91 0 : if( FD_UNLIKELY( err ) ) {
92 0 : FD_LOG_ERR(( "fd_slot_history_decode_footprint failed" ));
93 0 : }
94 :
95 0 : uchar * mem = fd_spad_alloc( runtime_spad, fd_slot_history_align(), total_sz );
96 0 : if( FD_UNLIKELY( !mem ) ) {
97 0 : FD_LOG_ERR(( "Unable to allocate memory for slot history" ));
98 0 : }
99 :
100 :
101 0 : fd_slot_history_t * history = fd_slot_history_decode( mem, &ctx );
102 :
103 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L48 */
104 0 : fd_sysvar_slot_history_set( history, slot_ctx->slot_bank.slot );
105 0 : history->next_slot = slot_ctx->slot_bank.slot + 1;
106 :
107 0 : ulong sz = fd_slot_history_size( history );
108 0 : if( sz < slot_history_min_account_size )
109 0 : sz = slot_history_min_account_size;
110 :
111 0 : err = fd_acc_mgr_modify( slot_ctx->acc_mgr, slot_ctx->funk_txn, key, 1, sz, rec );
112 0 : if (err)
113 0 : FD_LOG_CRIT(( "fd_acc_mgr_modify(slot_history) failed: %d", err ));
114 :
115 0 : fd_bincode_encode_ctx_t e_ctx = {
116 0 : .data = rec->data,
117 0 : .dataend = rec->data+sz
118 0 : };
119 0 : if( fd_slot_history_encode( history, &e_ctx ) )
120 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
121 :
122 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
123 0 : rec->meta->info.lamports = fd_rent_exempt_minimum_balance( &epoch_bank->rent, sz );
124 :
125 0 : rec->meta->dlen = sz;
126 0 : fd_memcpy( rec->meta->info.owner, fd_sysvar_owner_id.key, sizeof(fd_pubkey_t) );
127 :
128 0 : fd_slot_history_destroy( history );
129 :
130 0 : return 0;
131 0 : }
132 :
133 : fd_slot_history_t *
134 : fd_sysvar_slot_history_read( fd_acc_mgr_t * acc_mgr,
135 : fd_funk_txn_t * funk_txn,
136 0 : fd_spad_t * spad ) {
137 : /* Set current_slot, and update next_slot */
138 :
139 0 : fd_pubkey_t const * key = &fd_sysvar_slot_history_id;
140 :
141 0 : FD_TXN_ACCOUNT_DECL( rec );
142 0 : int err = fd_acc_mgr_view( acc_mgr, funk_txn, key, rec );
143 0 : if( err ) {
144 0 : FD_LOG_CRIT(( "fd_acc_mgr_view(slot_history) failed: %d", err ));
145 0 : }
146 :
147 0 : fd_bincode_decode_ctx_t ctx = {
148 0 : .data = rec->const_data,
149 0 : .dataend = rec->const_data + rec->const_meta->dlen
150 0 : };
151 :
152 0 : ulong total_sz = 0UL;
153 0 : err = fd_slot_history_decode_footprint( &ctx, &total_sz );
154 0 : if( err ) {
155 0 : FD_LOG_ERR(( "fd_slot_history_decode_footprint failed" ));
156 0 : }
157 :
158 0 : uchar * mem = fd_spad_alloc( spad, fd_slot_history_align(), total_sz );
159 0 : if( !mem ) {
160 0 : FD_LOG_ERR(( "Unable to allocate memory for slot history" ));
161 0 : }
162 :
163 0 : return fd_slot_history_decode( mem, &ctx );
164 0 : }
165 :
166 : int
167 : fd_sysvar_slot_history_find_slot( fd_slot_history_t const * history,
168 0 : ulong slot ) {
169 0 : if( slot > history->next_slot - 1UL ) {
170 0 : return FD_SLOT_HISTORY_SLOT_FUTURE;
171 0 : } else if ( slot < fd_ulong_sat_sub( history->next_slot, slot_history_max_entries ) ) {
172 0 : return FD_SLOT_HISTORY_SLOT_TOO_OLD;
173 0 : } else {
174 0 : ulong block_idx = (slot / bits_per_block) % (history->bits.bits->blocks_len);
175 0 : if( history->bits.bits->blocks[ block_idx ] & ( 1UL << ( slot % bits_per_block ) ) ) {
176 0 : return FD_SLOT_HISTORY_SLOT_FOUND;
177 0 : } else {
178 0 : return FD_SLOT_HISTORY_SLOT_NOT_FOUND;
179 0 : }
180 0 : }
181 0 : }
|