essential_node_db/query_range/
address.rs

1//! Addressed queries query for the most recent version of a key less than or equal to a
2//! given block address or solution set index. This is useful for querying un-finalized blocks
3//! where forks may exist. These queries fall back to finalized queries if the value is not found.
4
5use essential_node_db_sql as sql;
6use essential_types::{ContentAddress, Key, Value, Word};
7use rusqlite::{named_params, Connection, OptionalExtension, Transaction};
8
9use crate::{blob_from_words, words_from_blob, QueryError};
10
11/// Query the most recent value for a key in a contract's state
12/// that was set at or before the given block address.
13///
14/// This is inclusive of the block's state (..=block_address).
15pub fn query_state_inclusive_block(
16    conn: &Connection,
17    contract_ca: &ContentAddress,
18    key: &Key,
19    block_address: &ContentAddress,
20) -> Result<Option<Value>, QueryError> {
21    let mut stmt = conn.prepare(sql::query::QUERY_STATE_BLOCK_ADDRESS)?;
22    let value_blob: Option<(Option<Vec<u8>>, Word)> = stmt
23        .query_row(
24            named_params! {
25                ":contract_ca": contract_ca.0,
26                ":key": blob_from_words(key),
27                ":block_address": block_address.0,
28                ":solution_set_index": None::<u64>,
29            },
30            |row| {
31                let value = row.get("found_value")?;
32                let number = row.get("number")?;
33                Ok((value, number))
34            },
35        )
36        .optional()?;
37    match value_blob {
38        None => Ok(None),
39        Some((Some(value_blob), _)) => Ok(Some(words_from_blob(&value_blob))),
40        Some((None, block_number)) => {
41            super::finalized::query_state_inclusive_block(conn, contract_ca, key, block_number)
42        }
43    }
44}
45
46/// Query for the most recent version value of a key in a contracts state
47/// that was set before the given block number.
48///
49/// This is exclusive of the block's state (..block_address).
50pub fn query_state_exclusive_block(
51    tx: &Transaction,
52    contract_ca: &ContentAddress,
53    key: &Key,
54    block_address: &ContentAddress,
55) -> Result<Option<Value>, QueryError> {
56    let Some(parent_addr) = crate::get_parent_block_address(tx, block_address)? else {
57        return Ok(None);
58    };
59    query_state_inclusive_block(tx, contract_ca, key, &parent_addr)
60}
61
62/// Query for the most recent version value of a key in a contracts state
63/// that was set at or before the given block address and
64/// solution set index (within that block).
65///
66/// This is inclusive of the solution's state mutations
67/// `..=block_address[..=solution_set_index]`
68pub fn query_state_inclusive_solution_set(
69    conn: &Connection,
70    contract_ca: &ContentAddress,
71    key: &Key,
72    block_address: &ContentAddress,
73    solution_set_index: u64,
74) -> Result<Option<Value>, QueryError> {
75    let mut stmt = conn.prepare(sql::query::QUERY_STATE_BLOCK_ADDRESS)?;
76    let value_blob: Option<(Option<Vec<u8>>, Word)> = stmt
77        .query_row(
78            named_params! {
79                ":contract_ca": contract_ca.0,
80                ":key": blob_from_words(key),
81                ":block_address": block_address.0,
82                ":solution_set_index": Some(solution_set_index),
83            },
84            |row| {
85                let value = row.get("found_value")?;
86                let number = row.get("number")?;
87                Ok((value, number))
88            },
89        )
90        .optional()?;
91    match value_blob {
92        None => Ok(None),
93        Some((Some(value_blob), _)) => Ok(Some(words_from_blob(&value_blob))),
94        Some((None, block_number)) => {
95            super::finalized::query_state_inclusive_block(conn, contract_ca, key, block_number)
96        }
97    }
98}
99
100/// Query for the most recent version value of a key in a contracts state
101/// that was set at or before the given block address and before the
102/// solution set index (within that block).
103///
104/// This is exclusive of the solution set's state `..=block_address[..solution_set_index]`.
105pub fn query_state_exclusive_solution_set(
106    tx: &Transaction,
107    contract_ca: &ContentAddress,
108    key: &Key,
109    block_address: &ContentAddress,
110    solution_set_index: u64,
111) -> Result<Option<Value>, QueryError> {
112    match solution_set_index.checked_sub(1) {
113        Some(solution_set_index) => query_state_inclusive_solution_set(
114            tx,
115            contract_ca,
116            key,
117            block_address,
118            solution_set_index,
119        ),
120        None => query_state_exclusive_block(tx, contract_ca, key, block_address),
121    }
122}