LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_blockstore.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 108 0.0 %
Date: 2025-01-08 12:08:44 Functions: 0 2232 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_blockstore_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_blockstore_h
       3             : 
       4             : /* Blockstore is a high-performance database for storing, building, and
       5             :    tracking blocks.
       6             : 
       7             :    `fd_blockstore` defines a number of useful types e.g. `fd_block_t`,
       8             :    `fd_block_shred`, etc.
       9             : 
      10             :    The blockstore alloc is used for allocating wksp resources for shred
      11             :    headers, microblock headers, and blocks.  This is an fd_alloc.
      12             :    Allocations from this allocator will be tagged with wksp_tag and
      13             :    operations on this allocator will use concurrency group 0. */
      14             : 
      15             : #include "../../ballet/block/fd_microblock.h"
      16             : #include "../../ballet/shred/fd_deshredder.h"
      17             : #include "../../ballet/shred/fd_shred.h"
      18             : #include "../fd_flamenco_base.h"
      19             : #include "../types/fd_types.h"
      20             : #include "fd_rwseq_lock.h"
      21             : #include "stdbool.h"
      22             : #include <fcntl.h>
      23             : 
      24             : /* FD_BLOCKSTORE_{ALIGN,FOOTPRINT} describe the alignment and footprint needed
      25             :    for a blockstore.  ALIGN should be a positive integer power of 2.
      26             :    FOOTPRINT is multiple of ALIGN.  These are provided to facilitate
      27             :    compile time declarations.  */
      28             : 
      29             : /* clang-format off */
      30             : #define FD_BLOCKSTORE_ALIGN     (128UL)
      31             : #define FD_BLOCKSTORE_FOOTPRINT (256UL)
      32           0 : #define FD_BLOCKSTORE_MAGIC     (0xf17eda2ce7b10c00UL) /* firedancer bloc version 0 */
      33             : 
      34             : /* DO NOT MODIFY. */
      35             : // #define FD_BUF_SHRED_MAP_MAX (1UL << 24UL) /* 16 million shreds can be buffered */
      36             : // #define FD_TXN_MAP_LG_MAX    (24)          /* 16 million txns can be stored in the txn map */
      37             : 
      38             : /* TODO this can be removed if we explicitly manage a memory pool for
      39             :    the fd_block_map_t entries */
      40           0 : #define FD_BLOCKSTORE_CHILD_SLOT_MAX    (32UL)        /* the maximum # of children a slot can have */
      41           0 : #define FD_BLOCKSTORE_ARCHIVE_MIN_SIZE  (1UL << 26UL) /* 64MB := ceil(MAX_DATA_SHREDS_PER_SLOT*1228) */
      42             : 
      43             : // TODO centralize these
      44             : // https://github.com/firedancer-io/solana/blob/v1.17.5/sdk/program/src/clock.rs#L34
      45             : #define FD_MS_PER_TICK 6
      46             : 
      47             : // https://github.com/firedancer-io/solana/blob/v1.17.5/core/src/repair/repair_service.rs#L55
      48             : #define FD_REPAIR_TIMEOUT (200 / FD_MS_PER_TICK)
      49             : 
      50           0 : #define FD_BLOCKSTORE_OK                  0
      51           0 : #define FD_BLOCKSTORE_OK_SLOT_COMPLETE    1
      52             : #define FD_BLOCKSTORE_ERR_SHRED_FULL      -1 /* no space left for shreds */
      53           0 : #define FD_BLOCKSTORE_ERR_SLOT_FULL       -2 /* no space left for slots */
      54             : #define FD_BLOCKSTORE_ERR_TXN_FULL        -3 /* no space left for txns */
      55             : #define FD_BLOCKSTORE_ERR_SHRED_MISSING   -4
      56           0 : #define FD_BLOCKSTORE_ERR_SLOT_MISSING    -5
      57           0 : #define FD_BLOCKSTORE_ERR_TXN_MISSING     -6
      58           0 : #define FD_BLOCKSTORE_ERR_SHRED_INVALID   -7 /* shred was invalid */
      59           0 : #define FD_BLOCKSTORE_ERR_DESHRED_INVALID -8 /* deshredded block was invalid */
      60           0 : #define FD_BLOCKSTORE_ERR_NO_MEM          -9 /* no mem */
      61           0 : #define FD_BLOCKSTORE_ERR_UNKNOWN         -99
      62             : /* clang-format on */
      63             : 
      64             : struct fd_shred_key {
      65             :   ulong slot;
      66             :   uint  idx;
      67             : };
      68             : typedef struct fd_shred_key fd_shred_key_t;
      69             : 
      70             : /* clang-format off */
      71             : static const fd_shred_key_t     fd_shred_key_null = { 0 };
      72             : #define FD_SHRED_KEY_NULL       fd_shred_key_null
      73             : #define FD_SHRED_KEY_INVAL(key) (!((key).slot) & !((key).idx))
      74           0 : #define FD_SHRED_KEY_EQ(k0,k1)  (!(((k0).slot) ^ ((k1).slot))) & !(((k0).idx) ^ (((k1).idx)))
      75           0 : #define FD_SHRED_KEY_HASH(key)  ((uint)(((key).slot)<<15UL) | (((key).idx))) /* current max shred idx is 32KB = 2 << 15*/
      76             : /* clang-format on */
      77             : 
      78             : /* fd_buf_shred is a thin wrapper around fd_shred_t that facilitates
      79             :    buffering data shreds before all the shreds for a slot have been
      80             :    received. After all shreds are received, these buffered shreds are
      81             :    released back into memory pool and future queries for the shreds are
      82             :    offset into the block data directly.
      83             : 
      84             :    The blockstore is only aware of data shreds and all APIs involving
      85             :    shreds refers to data shreds.
      86             : 
      87             :    Shreds are buffered into a map as they are received:
      88             : 
      89             :    | 0 | 1 | 2 | x | x | 5 | x |
      90             :              ^           ^
      91             :              c           r
      92             : 
      93             :    c = "consumed" = contiguous window starting from index 0
      94             :    r = "received" = highest index received so far
      95             : 
      96             :    Shred memory layout while stored in the map:
      97             : 
      98             :    | shred hdr | shred payload |
      99             : */
     100             : struct fd_buf_shred {
     101             :   fd_shred_key_t key;
     102             :   ulong          next;
     103             :   union {
     104             :     fd_shred_t hdr;                  /* data shred header */
     105             :     uchar      raw[FD_SHRED_MAX_SZ]; /* the data shred as raw bytes, both header and payload. */
     106             :   };
     107             : };
     108             : typedef struct fd_buf_shred fd_buf_shred_t;
     109             : 
     110             : #define POOL_NAME fd_buf_shred_pool
     111           0 : #define POOL_T    fd_buf_shred_t
     112             : #include "../../util/tmpl/fd_pool.c"
     113             : 
     114             : /* clang-format off */
     115             : #define MAP_NAME               fd_buf_shred_map
     116             : #define MAP_ELE_T              fd_buf_shred_t
     117             : #define MAP_KEY_T              fd_shred_key_t
     118           0 : #define MAP_KEY_EQ(k0,k1)      (FD_SHRED_KEY_EQ(*k0,*k1))
     119           0 : #define MAP_KEY_HASH(key,seed) (FD_SHRED_KEY_HASH(*key)^seed)
     120             : #include "../../util/tmpl/fd_map_chain.c"
     121             : /* clang-format on */
     122             : 
     123             : #define DEQUE_NAME fd_slot_deque
     124           0 : #define DEQUE_T    ulong
     125             : #include "../../util/tmpl/fd_deque_dynamic.c"
     126             : 
     127             : /* fd_block_shred_t is a shred that has been assembled into a block. The
     128             :    shred begins at `off` relative to the start of the block's data
     129             :    region. */
     130             : struct fd_block_shred {
     131             :   fd_shred_t hdr; /* ptr to the data shred header */
     132             :   uchar      merkle[FD_SHRED_MERKLE_ROOT_SZ + FD_SHRED_MERKLE_NODE_SZ*9U /* FD_FEC_SET_MAX_BMTREE_DEPTH */];
     133             :   ulong      merkle_sz;
     134             :   ulong      off; /* offset to the payload relative to the start of the block's data region */
     135             : };
     136             : typedef struct fd_block_shred fd_block_shred_t;
     137             : 
     138             : /*
     139             :  * fd_block_entry_batch_t is a microblock/entry batch within a block.
     140             :  * The offset is relative to the start of the block's data region,
     141             :  * and indicates where the batch ends.  The (exclusive) end offset of
     142             :  * batch i is the (inclusive) start offset of batch i+1.  The 0th batch
     143             :  * always starts at offset 0.
     144             :  * On the wire, the presence of one of the COMPLETE flags in a data
     145             :  * shred marks the end of a batch.
     146             :  * In other words, batch ends are aligned with shred ends, and batch
     147             :  * starts are aligned with shred starts.  Usually a batch comprises
     148             :  * multiple shreds, and a block comprises multiple batches.
     149             :  * This information is useful because bincode deserialization needs to
     150             :  * be performed on a per-batch basis.  Precisely a single array of
     151             :  * microblocks/entries is expected to be deserialized from a batch.
     152             :  * Trailing bytes in each batch are ignored by default.
     153             :  */
     154             : struct fd_block_entry_batch {
     155             :   ulong end_off; /* exclusive */
     156             : };
     157             : typedef struct fd_block_entry_batch fd_block_entry_batch_t;
     158             : 
     159             : /* fd_block_micro_t is a microblock ("entry" in Solana parlance) within
     160             :    a block. The microblock begins at `off` relative to the start of the
     161             :    block's data region. */
     162             : struct fd_block_micro {
     163             :   ulong off; /* offset into block data */
     164             : };
     165             : typedef struct fd_block_micro fd_block_micro_t;
     166             : 
     167             : /* fd_block_txn_t is a transaction that has been parsed and is part of a
     168             :    block. The transaction begins at `off` relative to the start of the
     169             :    block's data region. */
     170             : struct fd_block_txn {
     171             :   ulong txn_off; /* offset into block data of transaction */
     172             :   ulong id_off;  /* offset into block data of transaction identifiers */
     173             :   ulong sz;
     174             : };
     175             : typedef struct fd_block_txn fd_block_txn_t;
     176             : 
     177             : /* If the 0th bit is set, this indicates the block is preparing, which
     178             :    means it might be partially executed e.g. a subset of the microblocks
     179             :    have been executed.  It is not safe to remove, relocate, or modify
     180             :    the block in any way at this time.
     181             : 
     182             :    Callers holding a pointer to a block should always make sure to
     183             :    inspect this flag.
     184             : 
     185             :    Other flags mainly provide useful metadata for read-only callers, eg.
     186             :    RPC. */
     187             : 
     188           0 : #define FD_BLOCK_FLAG_RECEIVING 0 /* xxxxxxx1 still receiving shreds */
     189           0 : #define FD_BLOCK_FLAG_COMPLETED 1 /* xxxxxx1x received the block ie. all shreds (SLOT_COMPLETE) */
     190           0 : #define FD_BLOCK_FLAG_REPLAYING 2 /* xxxxx1xx replay in progress (DO NOT REMOVE) */
     191           0 : #define FD_BLOCK_FLAG_PROCESSED 3 /* xxxx1xxx successfully replayed the block */
     192           0 : #define FD_BLOCK_FLAG_EQVOCSAFE 4 /* xxxx1xxx 52% of cluster has voted on this (slot, bank hash) */
     193           0 : #define FD_BLOCK_FLAG_CONFIRMED 5 /* xxx1xxxx 2/3 of cluster has voted on this (slot, bank hash) */
     194           0 : #define FD_BLOCK_FLAG_FINALIZED 6 /* xx1xxxxx 2/3 of cluster has rooted this slot */
     195             : #define FD_BLOCK_FLAG_DEADBLOCK 7 /* x1xxxxxx failed to replay the block */
     196             : 
     197             : /* Rewards assigned after block is executed */
     198             : 
     199             : struct fd_block_rewards {
     200             :   ulong collected_fees;
     201             :   fd_hash_t leader;
     202             :   ulong post_balance;
     203             : };
     204             : typedef struct fd_block_rewards fd_block_rewards_t;
     205             : 
     206             : /* Remaining bits [4, 8) are reserved.
     207             : 
     208             :    To avoid confusion, please use `fd_bits.h` API
     209             :    ie. `fd_uchar_set_bit`, `fd_uchar_extract_bit`. */
     210             : 
     211             : struct fd_block {
     212             : 
     213             :   /* Computed rewards */
     214             : 
     215             :   fd_block_rewards_t rewards;
     216             : 
     217             :   /* data region
     218             : 
     219             :   A block's data region is indexed to support iterating by shred,
     220             :   microblock/entry batch, microblock/entry, or transaction.
     221             :   This is done by iterating the headers for each, stored in allocated
     222             :   memory.
     223             :   To iterate shred payloads, for example, a caller should iterate the headers in tandem with the data region
     224             :   (offsetting by the bytes indicated in the shred header).
     225             : 
     226             :   Note random access of individual shred indices is not performant, due to the variable-length
     227             :   nature of shreds. */
     228             : 
     229             :   ulong data_gaddr;   /* ptr to the beginning of the block's allocated data region */
     230             :   ulong data_sz;      /* block size */
     231             :   ulong shreds_gaddr; /* ptr to the first fd_block_shred_t */
     232             :   ulong shreds_cnt;
     233             :   ulong batch_gaddr;  /* list of fd_block_entry_batch_t */
     234             :   ulong batch_cnt;
     235             :   ulong micros_gaddr; /* ptr to the list of fd_blockstore_micro_t */
     236             :   ulong micros_cnt;
     237             :   ulong txns_gaddr;   /* ptr to the list of fd_block_txn_t */
     238             :   ulong txns_cnt;
     239             :   ulong txns_meta_gaddr; /* ptr to the allocation for txn meta data */
     240             :   ulong txns_meta_sz;
     241             : };
     242             : typedef struct fd_block fd_block_t;
     243             : 
     244             : struct fd_block_map {
     245             :   ulong slot; /* map key */
     246             :   ulong next; /* reserved for use by fd_map_giant.c */
     247             : 
     248             :   /* Ancestry */
     249             : 
     250             :   ulong parent_slot;
     251             :   ulong child_slots[FD_BLOCKSTORE_CHILD_SLOT_MAX];
     252             :   ulong child_slot_cnt;
     253             : 
     254             :   /* Metadata */
     255             : 
     256             :   ulong     height;
     257             :   fd_hash_t block_hash;
     258             :   fd_hash_t bank_hash;
     259             :   fd_hash_t merkle_hash;    /* the last FEC set's merkle hash */
     260             :   ulong     fec_cnt;        /* the number of FEC sets in the slot */
     261             :   uchar     flags;
     262             :   uchar     reference_tick; /* the tick when the leader prepared the block. */
     263             :   long      ts;             /* the wallclock time when we finished receiving the block. */
     264             : 
     265             :   /* Windowing */
     266             : 
     267             :   uint consumed_idx; /* the highest shred idx of the contiguous window from idx 0 (inclusive). */
     268             :   uint received_idx; /* the highest shred idx we've received (exclusive). */
     269             :   uint complete_idx; /* the shred idx with the FD_SHRED_DATA_FLAG_SLOT_COMPLETE flag set. */
     270             : 
     271             :   /* Block */
     272             : 
     273             :   ulong block_gaddr; /* global address to the start of the allocated fd_block_t */
     274             : };
     275             : typedef struct fd_block_map fd_block_map_t;
     276             : 
     277             : /* clang-format off */
     278             : #define MAP_NAME         fd_block_map
     279           0 : #define MAP_T            fd_block_map_t
     280           0 : #define MAP_KEY          slot
     281             : #include "../../util/tmpl/fd_map_giant.c"
     282             : /* clang-format on */
     283             : 
     284             : /* fd_block_idx is an in-memory index of finalized blocks that have been
     285             :    archived to disk.  It records the slot together with the byte offset
     286             :    relative to the start of the file. */
     287             : 
     288             : struct fd_block_idx {
     289             :   ulong     slot;
     290             :   ulong     next;
     291             :   uint      hash;
     292             :   ulong     off;
     293             :   fd_hash_t block_hash;
     294             :   fd_hash_t bank_hash;
     295             : };
     296             : typedef struct fd_block_idx fd_block_idx_t;
     297             : 
     298             : #define MAP_NAME          fd_block_idx
     299           0 : #define MAP_T             fd_block_idx_t
     300           0 : #define MAP_KEY           slot
     301           0 : #define MAP_KEY_HASH(key) ((uint)(key)) /* finalized slots are guaranteed to be unique so perfect hashing */
     302             : #include "../../util/tmpl/fd_map_dynamic.c"
     303             : 
     304             : struct fd_txn_key {
     305             :   ulong v[FD_ED25519_SIG_SZ / sizeof( ulong )];
     306             : };
     307             : typedef struct fd_txn_key fd_txn_key_t;
     308             : 
     309             : struct fd_txn_map {
     310             :   fd_txn_key_t sig;
     311             :   ulong        next;
     312             :   ulong        slot;
     313             :   ulong        offset;
     314             :   ulong        sz;
     315             :   ulong        meta_gaddr; /* ptr to the transaction metadata */
     316             :   ulong        meta_sz;    /* metadata size */
     317             : };
     318             : typedef struct fd_txn_map fd_txn_map_t;
     319             : 
     320             : /* clang-format off */
     321             : int fd_txn_key_equal(fd_txn_key_t const * k0, fd_txn_key_t const * k1);
     322             : ulong fd_txn_key_hash(fd_txn_key_t const * k, ulong seed);
     323             : 
     324             : #define MAP_NAME             fd_txn_map
     325           0 : #define MAP_T                fd_txn_map_t
     326           0 : #define MAP_KEY              sig
     327             : #define MAP_KEY_T            fd_txn_key_t
     328           0 : #define MAP_KEY_EQ(k0,k1)    fd_txn_key_equal(k0,k1)
     329           0 : #define MAP_KEY_HASH(k,seed) fd_txn_key_hash(k, seed)
     330             : #include "../../util/tmpl/fd_map_giant.c"
     331             : 
     332             : /* fd_blockstore_archiver outlines the format of metadata
     333             :    at the start of an archive file - needed so that archive
     334             :    files can be read back on initialization. */
     335             : 
     336             : struct fd_blockstore_archiver {
     337             :   ulong magic;
     338             :   ulong fd_size_max;      /* maximum size of the archival file */
     339             :   ulong num_blocks;       /* number of blocks in the archival file. needed for reading back */
     340             :   ulong head;             /* location of least recently written block */
     341             :   ulong tail;             /* location after most recently written block */
     342             : };
     343             : typedef struct fd_blockstore_archiver fd_blockstore_archiver_t;
     344           0 : #define FD_BLOCKSTORE_ARCHIVE_START sizeof(fd_blockstore_archiver_t)
     345             : 
     346             : struct __attribute__((aligned(FD_BLOCKSTORE_ALIGN))) fd_blockstore {
     347             : /* clang-format on */
     348             : 
     349             :   /* Metadata */
     350             : 
     351             :   ulong magic;
     352             :   ulong blockstore_gaddr;
     353             :   ulong wksp_tag;
     354             :   ulong seed;
     355             : 
     356             :   /* Concurrency */
     357             : 
     358             :   fd_rwseq_lock_t lock;
     359             : 
     360             :   /* Persistence */
     361             : 
     362             :   fd_blockstore_archiver_t archiver;
     363             :   ulong mrw_slot; /* most recently written slot */
     364             : 
     365             :   /* Slot metadata */
     366             : 
     367             :   ulong lps; /* latest processed slot */
     368             :   ulong hcs; /* highest confirmed slot */
     369             :   ulong smr; /* supermajority root. DO NOT MODIFY DIRECTLY. */
     370             :   ulong wmk; /* watermark. DO NOT MODIFY DIRECTLY. */
     371             : 
     372             :   /* Config limits */
     373             : 
     374             :   ulong shred_max; /* maximum # of shreds that can be held in memory */
     375             :   ulong block_max; /* maximum # of blocks that can be held in memory */
     376             :   ulong idx_max;   /* maximum # of blocks that can be indexed from the archival file */
     377             :   ulong txn_max;   /* maximum # of transactions that can be indexed from blocks */
     378             :   ulong alloc_max; /* maximum bytes that can be allocated */
     379             : 
     380             :   /* Owned */
     381             : 
     382             :   ulong shred_pool_gaddr; /* memory pool for buffering shreds before block assembly */
     383             :   ulong shred_map_gaddr;  /* map of (slot, shred_idx)->shred */
     384             :   ulong block_map_gaddr;  /* map of slot->(slot_meta, block) */
     385             :   ulong block_idx_gaddr;  /* map of slot->byte offset in archival file */
     386             :   ulong slot_deque_gaddr; /* deque of slot numbers */
     387             :   ulong txn_map_gaddr;
     388             :   ulong alloc_gaddr;
     389             : };
     390             : typedef struct fd_blockstore fd_blockstore_t;
     391             : 
     392             : FD_PROTOTYPES_BEGIN
     393             : 
     394             : /* Construction API */
     395             : 
     396             : /* TODO document lifecycle methods */
     397             : 
     398             : FD_FN_CONST static inline ulong
     399           0 : fd_blockstore_align( void ) {
     400           0 :   return alignof(fd_blockstore_t);
     401           0 : }
     402             : 
     403             : FD_FN_CONST static inline ulong
     404           0 : fd_blockstore_footprint( ulong shred_max, ulong block_max, ulong idx_max, ulong txn_max ) {
     405           0 :   int lg_idx_max = fd_ulong_find_msb( fd_ulong_pow2_up( idx_max ) );
     406           0 :   return FD_LAYOUT_FINI(
     407           0 :     FD_LAYOUT_APPEND(
     408           0 :     FD_LAYOUT_APPEND(
     409           0 :     FD_LAYOUT_APPEND(
     410           0 :     FD_LAYOUT_APPEND(
     411           0 :     FD_LAYOUT_APPEND(
     412           0 :     FD_LAYOUT_APPEND(
     413           0 :     FD_LAYOUT_APPEND(
     414           0 :     FD_LAYOUT_APPEND(
     415           0 :     FD_LAYOUT_INIT,
     416           0 :       alignof(fd_blockstore_t),  sizeof(fd_blockstore_t) ),
     417           0 :       fd_buf_shred_pool_align(), fd_buf_shred_pool_footprint( shred_max ) ),
     418           0 :       fd_buf_shred_map_align(),  fd_buf_shred_map_footprint( shred_max ) ),
     419           0 :       fd_block_map_align(),      fd_block_map_footprint( block_max ) ),
     420           0 :       fd_block_idx_align(),      fd_block_idx_footprint( lg_idx_max ) ),
     421           0 :       fd_slot_deque_align(),     fd_slot_deque_footprint( block_max ) ),
     422           0 :       fd_txn_map_align(),        fd_txn_map_footprint( txn_max ) ),
     423           0 :       fd_alloc_align(),          fd_alloc_footprint() ),
     424           0 :     fd_blockstore_align() );
     425           0 : }
     426             : 
     427             : void *
     428             : fd_blockstore_new( void * shmem,
     429             :                    ulong  wksp_tag,
     430             :                    ulong  seed,
     431             :                    ulong  shred_max,
     432             :                    ulong  block_max,
     433             :                    ulong  idx_max,
     434             :                    ulong  txn_max );
     435             : 
     436             : fd_blockstore_t *
     437             : fd_blockstore_join( void * shblockstore );
     438             : 
     439             : void *
     440             : fd_blockstore_leave( fd_blockstore_t * blockstore );
     441             : 
     442             : void *
     443             : fd_blockstore_delete( void * shblockstore );
     444             : 
     445             : /* fd_blockstore_init initializes a blockstore with the given
     446             :    `slot_bank`.  This bank is used for initializing fields (SMR, etc.),
     447             :    and should be the bank upon finishing a snapshot load if booting from
     448             :    a snapshot, genesis bank otherwise.  It is also used to "fake" the
     449             :    snapshot block as if that block's data were available.  The metadata
     450             :    for this block's slot will be populated (fd_block_map_t) but the
     451             :    actual block data (fd_block_t) won't exist. This is done to bootstrap
     452             :    the various components for live replay (turbine, repair, etc.)
     453             : 
     454             :    `fd` is a file descriptor for the blockstore archival file.  As part
     455             :    of `init`, blockstore rebuilds an in-memory index of the archival
     456             :    file.  */
     457             : 
     458             : fd_blockstore_t *
     459             : fd_blockstore_init( fd_blockstore_t * blockstore, int fd, ulong fd_size_max, fd_slot_bank_t const * slot_bank );
     460             : 
     461             : /* fd_blockstore_fini finalizes a blockstore.
     462             : 
     463             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     464             :    function. */
     465             : 
     466             : void
     467             : fd_blockstore_fini( fd_blockstore_t * blockstore );
     468             : 
     469             : /* Accessors */
     470             : 
     471             : /* fd_blockstore_wksp returns the local join to the wksp backing the
     472             :    blockstore. The lifetime of the returned pointer is at least as long
     473             :    as the lifetime of the local join.  Assumes blockstore is a current
     474             :    local join. */
     475             : 
     476             : FD_FN_PURE static inline fd_wksp_t *
     477           0 : fd_blockstore_wksp( fd_blockstore_t * blockstore ) {
     478           0 :   return (fd_wksp_t *)( ( (ulong)blockstore ) - blockstore->blockstore_gaddr );
     479           0 : }
     480             : 
     481             : /* fd_blockstore_wksp_tag returns the workspace allocation tag used by
     482             :    the blockstore for its wksp allocations.  Will be positive.  Assumes
     483             :    blockstore is a current local join. */
     484             : 
     485             : FD_FN_PURE static inline ulong
     486           0 : fd_blockstore_wksp_tag( fd_blockstore_t const * blockstore ) {
     487           0 :   return blockstore->wksp_tag;
     488           0 : }
     489             : 
     490             : /* fd_blockstore_seed returns the hash seed used by the blockstore for various hash
     491             :    functions.  Arbitrary value.  Assumes blockstore is a current local join.
     492             :    TODO: consider renaming hash_seed? */
     493             : FD_FN_PURE static inline ulong
     494           0 : fd_blockstore_seed( fd_blockstore_t const * blockstore ) {
     495           0 :   return blockstore->seed;
     496           0 : }
     497             : 
     498             : /* fd_blockstore_buf_shred_pool returns a pointer in the caller's
     499             :    address space to the pool pointer fd_buf_shred_t * in the blockstore
     500             :    wksp.  Assumes blockstore is local join.  Lifetime of the returned
     501             :    pointer is that of the local join. */
     502             : 
     503             : FD_FN_PURE static inline fd_buf_shred_t *
     504           0 : fd_blockstore_shred_pool( fd_blockstore_t * blockstore ) {
     505           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore ), blockstore->shred_pool_gaddr );
     506           0 : }
     507             : 
     508             : /* fd_blockstore_buf_shred_map returns a pointer in the caller's address
     509             :    space to the fd_buf_shred_map_t * in the blockstore wksp.  Assumes
     510             :    blockstore is local join.  Lifetime of the returned pointer is that
     511             :    of the local join. */
     512             : 
     513             : FD_FN_PURE static inline fd_buf_shred_map_t *
     514           0 : fd_blockstore_shred_map( fd_blockstore_t * blockstore ) {
     515           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore ), blockstore->shred_map_gaddr );
     516           0 : }
     517             : 
     518             : /* fd_block_map returns a pointer in the caller's address space to the
     519             :    fd_block_map_t in the blockstore wksp.  Assumes blockstore is local
     520             :    join.  Lifetime of the returned pointer is that of the local join. */
     521             : 
     522             : FD_FN_PURE static inline fd_block_map_t *
     523           0 : fd_blockstore_block_map( fd_blockstore_t * blockstore ) {
     524           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore ), blockstore->block_map_gaddr );
     525           0 : }
     526             : 
     527             : /* fd_block_idx returns a pointer in the caller's address space to the
     528             :    fd_block_idx_t in the blockstore wksp.  Assumes blockstore is local
     529             :    join.  Lifetime of the returned pointer is that of the local join. */
     530             : 
     531             : FD_FN_PURE static inline fd_block_idx_t *
     532           0 : fd_blockstore_block_idx( fd_blockstore_t * blockstore ) {
     533           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore ), blockstore->block_idx_gaddr );
     534           0 : }
     535             : 
     536             : /* fd_slot_deque returns a pointer in the caller's address space to the
     537             :    fd_slot_deque_t in the blockstore wksp.  Assumes blockstore is local
     538             :    join.  Lifetime of the returned pointer is that of the local join. */
     539             : 
     540             : FD_FN_PURE static inline ulong *
     541           0 : fd_blockstore_slot_deque( fd_blockstore_t * blockstore ) {
     542           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore), blockstore->slot_deque_gaddr );
     543           0 : }
     544             : 
     545             : /* fd_txn_map returns a pointer in the caller's address space to the blockstore's
     546             :    block map. Assumes blockstore is local join. Lifetime of the returned pointer is that of the
     547             :    local join. */
     548             : 
     549             : FD_FN_PURE static inline fd_txn_map_t *
     550           0 : fd_blockstore_txn_map( fd_blockstore_t * blockstore ) {
     551           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore), blockstore->txn_map_gaddr );
     552           0 : }
     553             : 
     554             : /* fd_blockstore_alloc returns a pointer in the caller's address space to
     555             :    the blockstore's allocator. */
     556             : 
     557             : FD_FN_PURE static inline fd_alloc_t * /* Lifetime is that of the local join */
     558           0 : fd_blockstore_alloc( fd_blockstore_t * blockstore ) {
     559           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore), blockstore->alloc_gaddr );
     560           0 : }
     561             : 
     562             : /* fd_blockstore_block_data_laddr returns a local pointer to the block's
     563             :    data.  The returned pointer lifetime is until the block is removed. */
     564             : 
     565             : FD_FN_PURE static inline uchar *
     566           0 : fd_blockstore_block_data_laddr( fd_blockstore_t * blockstore, fd_block_t * block ) {
     567           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore ), block->data_gaddr );
     568           0 : }
     569             : 
     570             : FD_FN_PURE static inline fd_block_entry_batch_t *
     571           0 : fd_blockstore_block_batch_laddr( fd_blockstore_t * blockstore, fd_block_t * block ) {
     572           0 :   return fd_wksp_laddr_fast( fd_blockstore_wksp( blockstore ), block->batch_gaddr );
     573           0 : }
     574             : 
     575             : /* fd_buf_shred_query queries the blockstore for shred at slot,
     576             :    shred_idx.  Returns a pointer to the shred or NULL if not in
     577             :    blockstore.  The returned pointer lifetime is until the shred is
     578             :    removed.  Check return value for error info.  This API only works for
     579             :    shreds from incomplete blocks.
     580             : 
     581             :    Callers should hold the read lock during the entirety of its read to
     582             :    ensure the pointer remains valid. */
     583             : fd_shred_t *
     584             : fd_buf_shred_query( fd_blockstore_t * blockstore, ulong slot, uint shred_idx );
     585             : 
     586             : /* fd_buf_shred_query_copy_data queries the blockstore for shred at
     587             :    slot, shred_idx. Copies the shred data to the given buffer and
     588             :    returns the data size. Returns -1 on failure.
     589             : 
     590             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     591             :    function. */
     592             : long
     593             : fd_buf_shred_query_copy_data( fd_blockstore_t * blockstore,
     594             :                               ulong             slot,
     595             :                               uint              shred_idx,
     596             :                               void *            buf,
     597             :                               ulong             buf_max );
     598             : 
     599             : /* fd_blockstore_block_query queries blockstore for block at slot.
     600             :    Returns a pointer to the block or NULL if not in blockstore.  The
     601             :    returned pointer lifetime is until the block is removed.  Check
     602             :    return value for error info.
     603             : 
     604             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     605             :    function. */
     606             : fd_block_t *
     607             : fd_blockstore_block_query( fd_blockstore_t * blockstore, ulong slot );
     608             : 
     609             : /* fd_blockstore_block_hash_query queries blockstore for the block hash
     610             :    at slot. This is the final poh hash for a slot.
     611             : 
     612             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     613             :    function. */
     614             : fd_hash_t const *
     615             : fd_blockstore_block_hash_query( fd_blockstore_t * blockstore, ulong slot );
     616             : 
     617             : /* fd_blockstore_bank_hash_query query blockstore for the bank hash for
     618             :    a given slot.
     619             : 
     620             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     621             :    function. */
     622             : fd_hash_t const *
     623             : fd_blockstore_bank_hash_query( fd_blockstore_t * blockstore, ulong slot );
     624             : 
     625             : /* fd_blockstore_block_map_query queries the blockstore for the block
     626             :    map entry at slot.  Returns a pointer to the slot meta or NULL if not
     627             :    in blockstore.  The returned pointer lifetime is until the slot meta
     628             :    is removed.
     629             : 
     630             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     631             :    function. */
     632             : fd_block_map_t *
     633             : fd_blockstore_block_map_query( fd_blockstore_t * blockstore, ulong slot );
     634             : 
     635             : /* fd_blockstore_parent_slot_query queries the parent slot of slot.
     636             : 
     637             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     638             :    function. */
     639             : ulong
     640             : fd_blockstore_parent_slot_query( fd_blockstore_t * blockstore, ulong slot );
     641             : 
     642             : /* fd_blockstore_child_slots_query queries slot's child slots.  Return
     643             :    values are saved in slots_out and slot_cnt.  Returns FD_BLOCKSTORE_OK
     644             :    on success, FD_BLOCKSTORE_ERR_SLOT_MISSING if slot is not in the
     645             :    blockstore.  The returned slot array is always <= the max size
     646             :    FD_BLOCKSTORE_CHILD_SLOT_MAX and contiguous.  Empty slots in the
     647             :    array are set to FD_SLOT_NULL.
     648             : 
     649             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     650             :    function. */
     651             : 
     652             : int
     653             : fd_blockstore_child_slots_query( fd_blockstore_t * blockstore, ulong slot, ulong ** slots_out, ulong * slot_cnt );
     654             : 
     655             : /* fd_blockstore_block_frontier_query query the frontier i.e. all the
     656             :    blocks that need to be replayed that haven't been.  These are the
     657             :    slot children of the current frontier that are shred complete.
     658             : 
     659             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     660             :    function. */
     661             : fd_block_t *
     662             : fd_blockstore_block_frontier_query( fd_blockstore_t * blockstore,
     663             :                                     ulong *           parents,
     664             :                                     ulong             parents_sz );
     665             : 
     666             : /* fd_blockstore_block_data_query_volatile queries the block map entry
     667             :    (metadata and block data) in a lock-free thread-safe manner that does
     668             :    not block writes.  Copies the metadata (fd_block_map_t) into
     669             :    block_map_entry_out.  Allocates a new block data (uchar *) using
     670             :    alloc, copies the block data into it, and sets the block_data_out
     671             :    pointer.  Caller provides the allocator via alloc for the copied
     672             :    block data (an allocator is needed because the block data sz is not
     673             :    known apriori).  Returns FD_BLOCKSTORE_SLOT_MISSING if slot is
     674             :    missing: caller MUST ignore out pointers in this case. Otherwise this
     675             :    call cannot fail and returns FD_BLOCKSTORE_OK. */
     676             : 
     677             : int
     678             : fd_blockstore_block_data_query_volatile( fd_blockstore_t *    blockstore,
     679             :                                          int                  fd,
     680             :                                          ulong                slot,
     681             :                                          fd_valloc_t          alloc,
     682             :                                          fd_hash_t *          parent_block_hash_out,
     683             :                                          fd_block_map_t *     block_map_entry_out,
     684             :                                          fd_block_rewards_t * block_rewards_out,
     685             :                                          uchar **             block_data_out,
     686             :                                          ulong *              block_data_sz_out );
     687             : 
     688             : /* fd_blockstore_block_map_query_volatile is the same as above except it
     689             :    only copies out the metadata (fd_block_map_t).  Returns
     690             :    FD_BLOCKSTORE_SLOT_MISSING if slot is missing, otherwise
     691             :    FD_BLOCKSTORE_OK. */
     692             : 
     693             : int
     694             : fd_blockstore_block_map_query_volatile( fd_blockstore_t * blockstore,
     695             :                                         int               fd,
     696             :                                         ulong             slot,
     697             :                                         fd_block_map_t *  block_map_entry_out );
     698             : 
     699             : /* fd_blockstore_txn_query queries the transaction data for the given
     700             :    signature.
     701             : 
     702             :    IMPORTANT!  Caller MUST hold the read lock when calling this
     703             :    function. */
     704             : fd_txn_map_t *
     705             : fd_blockstore_txn_query( fd_blockstore_t * blockstore, uchar const sig[static FD_ED25519_SIG_SZ] );
     706             : 
     707             : /* Query the transaction data for the given signature in a thread
     708             :    safe manner. The transaction data is copied out. txn_data_out can
     709             :    be NULL if you are only interested in the transaction metadata. */
     710             : int
     711             : fd_blockstore_txn_query_volatile( fd_blockstore_t * blockstore,
     712             :                                   int               fd,
     713             :                                   uchar const       sig[static FD_ED25519_SIG_SZ],
     714             :                                   fd_txn_map_t *    txn_out,
     715             :                                   long *            blk_ts,
     716             :                                   uchar *           blk_flags,
     717             :                                   uchar             txn_data_out[FD_TXN_MTU] );
     718             : 
     719             : /* fd_blockstore_slot_remove removes slot from blockstore, including all
     720             :    relevant internal structures.
     721             : 
     722             :    IMPORTANT!  Caller MUST hold the write lock when calling this
     723             :    function. */
     724             : void
     725             : fd_blockstore_slot_remove( fd_blockstore_t * blockstore, ulong slot );
     726             : 
     727             : /* Operations */
     728             : 
     729             : /* fd_buf_shred_insert inserts shred into the blockstore, fast O(1).
     730             :    Fail if this shred is already in the blockstore or the blockstore is
     731             :    full.  Returns an error code indicating success or failure.
     732             :    TODO eventually this will need to support "upsert" duplicate shred handling.
     733             : 
     734             :    IMPORTANT!  Caller MUST hold the write lock when calling this
     735             :    function. */
     736             : int
     737             : fd_buf_shred_insert( fd_blockstore_t * blockstore, fd_shred_t const * shred );
     738             : 
     739             : /* fd_blockstore_buffered_shreds_remove removes all the unassembled shreds
     740             :    for a slot
     741             : 
     742             :    IMPORTANT!  Caller MUST hold the write lock when calling this
     743             :    function. */
     744             : int
     745             : fd_blockstore_buffered_shreds_remove( fd_blockstore_t * blockstore, ulong slot );
     746             : 
     747             : /* fd_blockstore_block_height_update sets the block height.
     748             : 
     749             :    IMPORTANT!  Caller MUST hold the write lock when calling this
     750             :    function. */
     751             : void
     752             : fd_blockstore_block_height_update( fd_blockstore_t * blockstore, ulong slot, ulong block_height );
     753             : 
     754             : /* fd_blockstore_publish publishes all blocks until the current
     755             :    blockstore smr (`blockstore->smr`).  Publishing entails 1. pruning
     756             :    and 2. archiving.  Pruning removes any blocks that are not part of
     757             :    the same fork as the smr (hence the name pruning, like pruning the
     758             :    branches of a tree).  Archiving removes from memory any slots < smr
     759             :    that are on the same fork, but writes those blocks out to disk using
     760             :    the provided file descriptor to the archival file `fd`.
     761             : 
     762             :    Note that slots < smr are ancestors of the smr, and are therefore
     763             :    finalized slots which is why they are archived.  Blocks removed as a
     764             :    result of pruning are not finalized, and therefore not archived.
     765             : 
     766             :    IMPORTANT!  Caller MUST hold the write lock when calling this
     767             :    function. */
     768             : 
     769             : void
     770             : fd_blockstore_publish( fd_blockstore_t * blockstore, int fd );
     771             : 
     772             : /* fd_blockstore_start_read acquires the read lock */
     773             : static inline void
     774           0 : fd_blockstore_start_read( fd_blockstore_t * blockstore ) {
     775           0 :   fd_rwseq_start_read( &blockstore->lock );
     776           0 : }
     777             : 
     778             : /* fd_blockstore_end_read releases the read lock */
     779             : static inline void
     780           0 : fd_blockstore_end_read( fd_blockstore_t * blockstore ) {
     781           0 :   fd_rwseq_end_read( &blockstore->lock );
     782           0 : }
     783             : 
     784             : /* fd_blockstore_start_write acquire the write lock */
     785             : static inline void
     786           0 : fd_blockstore_start_write( fd_blockstore_t * blockstore ) {
     787           0 :   fd_rwseq_start_write( &blockstore->lock );
     788           0 : }
     789             : 
     790             : /* fd_blockstore_end_write releases the write lock */
     791             : static inline void
     792           0 : fd_blockstore_end_write( fd_blockstore_t * blockstore ) {
     793           0 :   fd_rwseq_end_write( &blockstore->lock );
     794           0 : }
     795             : 
     796             : void
     797             : fd_blockstore_log_block_status( fd_blockstore_t * blockstore, ulong around_slot );
     798             : 
     799             : /* fd_blockstore_log_mem_usage logs the memory usage of blockstore in a
     800             :    human-readable format.  Caller MUST hold the read lock. */
     801             : 
     802             : void
     803             : fd_blockstore_log_mem_usage( fd_blockstore_t * blockstore );
     804             : 
     805             : FD_PROTOTYPES_END
     806             : 
     807             : /* fd_blockstore_ser is a serialization context for archiving a block to
     808             :    disk. */
     809             : 
     810             : struct fd_blockstore_ser {
     811             :   fd_block_map_t * block_map;
     812             :   fd_block_t     * block;
     813             :   uchar          * data;
     814             : };
     815             : typedef struct fd_blockstore_ser fd_blockstore_ser_t;
     816             : 
     817             : /* Archives a block and block map entry to fd at blockstore->off, and does
     818             :    any necessary bookkeeping.
     819             :    If fd is -1, no write is attempted. Returns written size */
     820             : ulong
     821             : fd_blockstore_block_checkpt( fd_blockstore_t * blockstore, 
     822             :                              fd_blockstore_ser_t * ser, 
     823             :                              int fd, 
     824             :                              ulong slot );
     825             : 
     826             : /* Restores a block and block map entry from fd at given offset. As this used by
     827             :    rpcserver, it must return an error code instead of throwing an error on failure. */
     828             : int
     829             : fd_blockstore_block_meta_restore( fd_blockstore_archiver_t * archvr,
     830             :                                   int fd,
     831             :                                   fd_block_idx_t * block_idx_entry,
     832             :                                   fd_block_map_t * block_map_entry_out,
     833             :                                   fd_block_t * block_out );
     834             : 
     835             : /* Reads block data from fd into a given buf. Modifies data_off similarly to
     836             :    meta_restore */
     837             : int 
     838             : fd_blockstore_block_data_restore( fd_blockstore_archiver_t * archvr,
     839             :                                   int fd,
     840             :                                   fd_block_idx_t * block_idx_entry,
     841             :                                   uchar * buf_out,
     842             :                                   ulong buf_max,
     843             :                                   ulong data_sz );
     844             : 
     845             : /* Returns 0 if the archive metadata is valid */
     846             : bool
     847             : fd_blockstore_archiver_verify( fd_blockstore_t * blockstore, fd_blockstore_archiver_t * archiver );
     848             : 
     849             : ulong
     850             : fd_blockstore_archiver_lrw_slot( fd_blockstore_t * blockstore, int fd, fd_block_map_t * lrw_block_map, fd_block_t * lrw_block );
     851             : 
     852             : #endif /* HEADER_fd_src_flamenco_runtime_fd_blockstore_h */

Generated by: LCOV version 1.14