kaspa_consensus/model/stores/
virtual_state.rs1use std::ops::Deref;
2use std::sync::Arc;
3
4use arc_swap::ArcSwap;
5use kaspa_consensus_core::api::stats::VirtualStateStats;
6use kaspa_consensus_core::{
7 block::VirtualStateApproxId, coinbase::BlockRewardData, config::genesis::GenesisBlock, tx::TransactionId,
8 utxo::utxo_diff::UtxoDiff, BlockHashMap, BlockHashSet, HashMapCustomHasher,
9};
10use kaspa_database::prelude::{BatchDbWriter, CachedDbItem, DirectDbWriter, StoreResultExtensions};
11use kaspa_database::prelude::{CachePolicy, StoreResult};
12use kaspa_database::prelude::{StoreError, DB};
13use kaspa_database::registry::DatabaseStorePrefixes;
14use kaspa_hashes::Hash;
15use kaspa_muhash::MuHash;
16use rocksdb::WriteBatch;
17use serde::{Deserialize, Serialize};
18
19use super::ghostdag::GhostdagData;
20use super::utxo_set::DbUtxoSetStore;
21
22#[derive(Clone, Serialize, Deserialize, Default)]
23pub struct VirtualState {
24 pub parents: Vec<Hash>,
25 pub ghostdag_data: GhostdagData,
26 pub daa_score: u64,
27 pub bits: u32,
28 pub past_median_time: u64,
29 pub multiset: MuHash,
30 pub utxo_diff: UtxoDiff, pub accepted_tx_ids: Vec<TransactionId>, pub mergeset_rewards: BlockHashMap<BlockRewardData>,
33 pub mergeset_non_daa: BlockHashSet,
34}
35
36impl VirtualState {
37 pub fn new(
38 parents: Vec<Hash>,
39 daa_score: u64,
40 bits: u32,
41 past_median_time: u64,
42 multiset: MuHash,
43 utxo_diff: UtxoDiff,
44 accepted_tx_ids: Vec<TransactionId>,
45 mergeset_rewards: BlockHashMap<BlockRewardData>,
46 mergeset_non_daa: BlockHashSet,
47 ghostdag_data: GhostdagData,
48 ) -> Self {
49 Self {
50 parents,
51 ghostdag_data,
52 daa_score,
53 bits,
54 past_median_time,
55 multiset,
56 utxo_diff,
57 accepted_tx_ids,
58 mergeset_rewards,
59 mergeset_non_daa,
60 }
61 }
62
63 pub fn from_genesis(genesis: &GenesisBlock, ghostdag_data: GhostdagData) -> Self {
64 Self {
65 parents: vec![genesis.hash],
66 ghostdag_data,
67 daa_score: genesis.daa_score,
68 bits: genesis.bits,
69 past_median_time: genesis.timestamp,
70 multiset: MuHash::new(),
71 utxo_diff: UtxoDiff::default(), accepted_tx_ids: genesis.build_genesis_transactions().into_iter().map(|tx| tx.id()).collect(),
73 mergeset_rewards: BlockHashMap::new(),
74 mergeset_non_daa: BlockHashSet::from_iter(std::iter::once(genesis.hash)),
75 }
76 }
77
78 pub fn to_virtual_state_approx_id(&self) -> VirtualStateApproxId {
79 VirtualStateApproxId::new(self.daa_score, self.ghostdag_data.blue_work, self.ghostdag_data.selected_parent)
80 }
81}
82
83impl From<&VirtualState> for VirtualStateStats {
84 fn from(state: &VirtualState) -> Self {
85 Self {
86 num_parents: state.parents.len() as u32,
87 daa_score: state.daa_score,
88 bits: state.bits,
89 past_median_time: state.past_median_time,
90 }
91 }
92}
93
94#[derive(Clone, Default)]
97pub struct LkgVirtualState {
98 inner: Arc<ArcSwap<VirtualState>>,
99}
100
101pub struct LkgVirtualStateGuard(arc_swap::Guard<Arc<VirtualState>>);
104
105impl Deref for LkgVirtualStateGuard {
106 type Target = Arc<VirtualState>;
107
108 fn deref(&self) -> &Self::Target {
109 &self.0
110 }
111}
112
113impl LkgVirtualState {
114 pub fn load(&self) -> LkgVirtualStateGuard {
116 LkgVirtualStateGuard(self.inner.load())
117 }
118
119 pub fn load_full(&self) -> Arc<VirtualState> {
121 self.inner.load_full()
122 }
123
124 fn store(&self, virtual_state: Arc<VirtualState>) {
126 self.inner.store(virtual_state)
127 }
128}
129
130pub struct VirtualStores {
132 pub state: DbVirtualStateStore,
133 pub utxo_set: DbUtxoSetStore,
134}
135
136impl VirtualStores {
137 pub fn new(db: Arc<DB>, lkg_virtual_state: LkgVirtualState, utxoset_cache_policy: CachePolicy) -> Self {
138 Self {
139 state: DbVirtualStateStore::new(db.clone(), lkg_virtual_state),
140 utxo_set: DbUtxoSetStore::new(db, utxoset_cache_policy, DatabaseStorePrefixes::VirtualUtxoset.into()),
141 }
142 }
143}
144
145pub trait VirtualStateStoreReader {
147 fn get(&self) -> StoreResult<Arc<VirtualState>>;
148}
149
150pub trait VirtualStateStore: VirtualStateStoreReader {
151 fn set(&mut self, state: Arc<VirtualState>) -> StoreResult<()>;
152}
153
154#[derive(Clone)]
156pub struct DbVirtualStateStore {
157 db: Arc<DB>,
158 access: CachedDbItem<Arc<VirtualState>>,
159 lkg_virtual_state: LkgVirtualState,
161}
162
163impl DbVirtualStateStore {
164 pub fn new(db: Arc<DB>, lkg_virtual_state: LkgVirtualState) -> Self {
165 let access = CachedDbItem::new(db.clone(), DatabaseStorePrefixes::VirtualState.into());
166 lkg_virtual_state.store(access.read().unwrap_option().unwrap_or_default());
168 Self { db, access, lkg_virtual_state }
169 }
170
171 pub fn clone_with_new_cache(&self) -> Self {
172 Self::new(self.db.clone(), self.lkg_virtual_state.clone())
173 }
174
175 pub fn is_initialized(&self) -> StoreResult<bool> {
176 match self.access.read() {
177 Ok(_) => Ok(true),
178 Err(StoreError::KeyNotFound(_)) => Ok(false),
179 Err(e) => Err(e),
180 }
181 }
182
183 pub fn set_batch(&mut self, batch: &mut WriteBatch, state: Arc<VirtualState>) -> StoreResult<()> {
184 self.lkg_virtual_state.store(state.clone()); self.access.write(BatchDbWriter::new(batch), &state)
186 }
187}
188
189impl VirtualStateStoreReader for DbVirtualStateStore {
190 fn get(&self) -> StoreResult<Arc<VirtualState>> {
191 self.access.read()
192 }
193}
194
195impl VirtualStateStore for DbVirtualStateStore {
196 fn set(&mut self, state: Arc<VirtualState>) -> StoreResult<()> {
197 self.lkg_virtual_state.store(state.clone()); self.access.write(DirectDbWriter::new(&self.db), &state)
199 }
200}