use diesel::prelude::*;
use miden_node_db::DatabaseError;
use miden_protocol::Word;
use miden_protocol::block::{BlockHeader, BlockNumber};
use miden_protocol::crypto::merkle::mmr::PartialMmr;
use miden_protocol::utils::serde::{Deserializable, Serializable};
use crate::db::models::conv as conversions;
use crate::db::schema;
#[derive(Debug, Clone, Insertable)]
#[diesel(table_name = schema::chain_state)]
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
pub struct ChainStateInsert {
pub id: i32,
pub block_num: i64,
pub block_header: Vec<u8>,
pub chain_mmr: Vec<u8>,
pub genesis_commitment: Vec<u8>,
}
#[derive(Debug, Clone, Queryable, Selectable)]
#[diesel(table_name = schema::chain_state)]
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
struct ChainStateRow {
block_num: i64,
block_header: Vec<u8>,
chain_mmr: Vec<u8>,
}
pub fn update_chain_state_tip(
conn: &mut SqliteConnection,
block_num: BlockNumber,
block_header: &BlockHeader,
chain_mmr: &PartialMmr,
) -> Result<(), DatabaseError> {
diesel::update(schema::chain_state::table.find(0i32))
.set((
schema::chain_state::block_num.eq(conversions::block_num_to_i64(block_num)),
schema::chain_state::block_header.eq(conversions::block_header_to_bytes(block_header)),
schema::chain_state::chain_mmr.eq(chain_mmr.to_bytes()),
))
.execute(conn)?;
Ok(())
}
pub fn insert_genesis_chain_state(
conn: &mut SqliteConnection,
genesis_block_header: &BlockHeader,
genesis_commitment: &Word,
) -> Result<(), DatabaseError> {
assert_eq!(
genesis_block_header.block_num(),
BlockNumber::GENESIS,
"bootstrap block number is not 0"
);
let row = ChainStateInsert {
id: 0,
block_num: conversions::block_num_to_i64(genesis_block_header.block_num()),
block_header: conversions::block_header_to_bytes(genesis_block_header),
chain_mmr: PartialMmr::default().to_bytes(),
genesis_commitment: conversions::word_to_bytes(genesis_commitment),
};
diesel::insert_into(schema::chain_state::table).values(&row).execute(conn)?;
Ok(())
}
pub fn select_genesis_commitment(conn: &mut SqliteConnection) -> Result<Word, DatabaseError> {
let commitment: Vec<u8> = schema::chain_state::table
.find(0i32)
.select(schema::chain_state::genesis_commitment)
.first(conn)?;
Word::read_from_bytes(&commitment)
.map_err(|e| DatabaseError::deserialization("genesis commitment", e))
}
pub fn select_chain_state(
conn: &mut SqliteConnection,
) -> Result<Option<(BlockNumber, BlockHeader, PartialMmr)>, DatabaseError> {
let row: Option<ChainStateRow> = schema::chain_state::table
.find(0i32)
.select(ChainStateRow::as_select())
.first(conn)
.optional()?;
row.map(|ChainStateRow { block_num, block_header, chain_mmr }| {
let block_num = conversions::block_num_from_i64(block_num);
let header = BlockHeader::read_from_bytes(&block_header)
.map_err(|e| DatabaseError::deserialization("block header", e))?;
let mmr = PartialMmr::read_from_bytes(&chain_mmr)
.map_err(|e| DatabaseError::deserialization("chain mmr", e))?;
Ok((block_num, header, mmr))
})
.transpose()
}