1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#[allow(unused_imports)]
use crate::spv_state::*;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::pubkey::Pubkey;

// HeaderStore is a data structure that allows linked list style cheap appends and
// sequential reads, but also has a "lookup index" to speed up random access
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum HeaderStoreError {
    InvalidHeader,
    GroupExists,
    GroupDNE,
    InvalidBlockHeight,
}

// AccountList is a linked list of groups of blockheaders. It stores sequential blockheaders
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct HeaderStore {
    pub index: Vec<Pubkey>,
    // number of header entries to include per group account
    pub group_size: u16,
    // base_height is the height of the first header in the first headerAccount
    pub base_height: u32,
    // top_height is the running last header loaded
    pub top_height: u32,
    // account that administrates the headerstore and benefits from fees accrued
    pub owner: Pubkey,
}

impl HeaderStore {
    pub fn get_group(self, block_height: u32) -> Result<Pubkey, HeaderStoreError> {
        if block_height < self.base_height || block_height > self.top_height {
            Err(HeaderStoreError::InvalidBlockHeight)
        } else {
            let gheight = (block_height - self.base_height) / u32::from(self.group_size);
            let grouppk: Pubkey = self.index[gheight as usize];
            Ok(grouppk)
        }
    }

    pub fn top_group(self) -> Result<Pubkey, HeaderStoreError> {
        if self.index.is_empty() {
            Err(HeaderStoreError::GroupDNE)
        } else {
            let grouppk: Pubkey = *self.index.last().unwrap();
            Ok(grouppk)
        }
    }

    pub fn append_header(mut self, blockheader: &BlockHeader) -> Result<(), HeaderStoreError> {
        match self.top_group() {
            Ok(n) => {
                let group = n;
                Ok(())
            }
            Err(e) => {
                // HeaderStore is empty need to create first group
                if HeaderStoreError::GroupDNE == e {
                    Ok(())
                } else {
                    Err(e)
                }
                //reinsert
            }
        }
    }

    pub fn replace_header(
        mut self,
        blockheader: &BlockHeader,
        block_height: u32,
    ) -> Result<(), HeaderStoreError> {
        match self.get_group(block_height) {
            Err(e) => Err(HeaderStoreError::InvalidHeader),
            Ok(n) => {
                let group = n;
                Ok(())
            }
        }
        //reinsert
    }

    pub fn append_group(mut self, pubkey: Pubkey) -> Result<(), HeaderStoreError> {
        if self.index.contains(&pubkey) {
            // group to be appended is already in the index
            Err(HeaderStoreError::GroupExists)
        } else {
            Ok(())
            //reinsert
        }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct HeaderAccountInfo {
    // parent stores the pubkey of the parent AccountList
    pub parent: Pubkey,
    // stores a vec of BlockHeader structs
    pub headers: Vec<BlockHeader>,
    // next DataAccount in the chain or none if last
    pub next: Option<Pubkey>,
}