mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-23 03:59:31 +00:00
add last service request
This commit is contained in:
parent
029f439f0b
commit
6927b05f81
14 changed files with 306 additions and 66 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -531,6 +531,7 @@ dependencies = [
|
||||||
"monero-serai",
|
"monero-serai",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"proptest",
|
"proptest",
|
||||||
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
"serde",
|
"serde",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|
|
@ -25,11 +25,12 @@ cuprate-database = { path = "../database" }
|
||||||
cuprate-database-service = { path = "../service" }
|
cuprate-database-service = { path = "../service" }
|
||||||
cuprate-helper = { path = "../../helper", features = ["fs", "thread", "map"] }
|
cuprate-helper = { path = "../../helper", features = ["fs", "thread", "map"] }
|
||||||
cuprate-types = { path = "../../types", features = ["blockchain"] }
|
cuprate-types = { path = "../../types", features = ["blockchain"] }
|
||||||
|
cuprate-pruning = { path = "../../pruning" }
|
||||||
|
|
||||||
bitflags = { workspace = true, features = ["std", "serde", "bytemuck"] }
|
bitflags = { workspace = true, features = ["std", "serde", "bytemuck"] }
|
||||||
bytemuck = { workspace = true, features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] }
|
bytemuck = { workspace = true, features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] }
|
||||||
curve25519-dalek = { workspace = true }
|
curve25519-dalek = { workspace = true }
|
||||||
cuprate-pruning = { path = "../../pruning" }
|
rand = { workspace = true }
|
||||||
monero-serai = { workspace = true, features = ["std"] }
|
monero-serai = { workspace = true, features = ["std"] }
|
||||||
serde = { workspace = true, optional = true }
|
serde = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! General free functions (related to the database).
|
//! General free functions (related to the database).
|
||||||
|
|
||||||
|
use monero_serai::transaction::{Input, Transaction};
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use cuprate_database::{ConcreteEnv, Env, EnvInner, InitError, RuntimeError, TxRw};
|
use cuprate_database::{ConcreteEnv, Env, EnvInner, InitError, RuntimeError, TxRw};
|
||||||
|
|
||||||
|
@ -61,6 +62,37 @@ pub fn open(config: Config) -> Result<ConcreteEnv, InitError> {
|
||||||
Ok(env)
|
Ok(env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Tx Fee
|
||||||
|
/// Calculates the fee of the [`Transaction`].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// This will panic if the inputs overflow or the transaction outputs too much.
|
||||||
|
pub(crate) fn tx_fee(tx: &Transaction) -> u64 {
|
||||||
|
let mut fee = 0_u64;
|
||||||
|
|
||||||
|
match &tx {
|
||||||
|
Transaction::V1 { prefix, .. } => {
|
||||||
|
for input in &prefix.inputs {
|
||||||
|
match input {
|
||||||
|
Input::Gen(_) => return 0,
|
||||||
|
Input::ToKey { amount, .. } => {
|
||||||
|
fee = fee.checked_add(amount.unwrap_or(0)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for output in &prefix.outputs {
|
||||||
|
fee.checked_sub(output.amount.unwrap_or(0)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Transaction::V2 { proofs, .. } => {
|
||||||
|
fee = proofs.as_ref().unwrap().base.fee;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fee
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
use crate::ops::alt_block::{
|
use crate::ops::alt_block::{
|
||||||
add_alt_transaction_blob, check_add_alt_chain_info, get_alt_chain_history_ranges,
|
add_alt_transaction_blob, check_add_alt_chain_info, get_alt_chain_history_ranges,
|
||||||
get_alt_transaction_blob,
|
get_alt_transaction,
|
||||||
};
|
};
|
||||||
use crate::ops::block::{get_block_extended_header_from_height, get_block_info};
|
use crate::ops::block::{get_block_extended_header_from_height, get_block_info};
|
||||||
use crate::tables::{Tables, TablesMut};
|
use crate::tables::{Tables, TablesMut};
|
||||||
use crate::types::{
|
use crate::types::{AltBlockHeight, BlockHash, BlockHeight, CompactAltBlockInfo};
|
||||||
AltBlockHeight, AltTransactionInfo, BlockHash, BlockHeight, CompactAltBlockInfo,
|
|
||||||
};
|
|
||||||
use bytemuck::TransparentWrapper;
|
use bytemuck::TransparentWrapper;
|
||||||
use cuprate_database::{RuntimeError, StorableVec};
|
use cuprate_database::{DatabaseRo, DatabaseRw, RuntimeError, StorableVec};
|
||||||
use cuprate_helper::map::{combine_low_high_bits_to_u128, split_u128_into_low_high_bits};
|
use cuprate_helper::map::{combine_low_high_bits_to_u128, split_u128_into_low_high_bits};
|
||||||
use cuprate_types::{
|
use cuprate_types::{AltBlockInformation, Chain, ChainId, ExtendedBlockHeader, HardFork};
|
||||||
AltBlockInformation, Chain, ChainId, ExtendedBlockHeader, HardFork,
|
|
||||||
VerifiedTransactionInformation,
|
|
||||||
};
|
|
||||||
use monero_serai::block::{Block, BlockHeader};
|
use monero_serai::block::{Block, BlockHeader};
|
||||||
|
|
||||||
pub fn add_alt_block(
|
pub fn add_alt_block(
|
||||||
|
@ -54,8 +49,8 @@ pub fn add_alt_block(
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
assert_eq!(alt_block.txs.len(), alt_block.block.transactions.len());
|
assert_eq!(alt_block.txs.len(), alt_block.block.transactions.len());
|
||||||
for (tx, tx_hash) in alt_block.txs.iter().zip(&alt_block.block.transactions) {
|
for tx in alt_block.txs.iter() {
|
||||||
add_alt_transaction_blob(tx_hash, StorableVec::wrap_ref(tx), tables)?;
|
add_alt_transaction_blob(tx, tables)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -74,8 +69,8 @@ pub fn get_alt_block(
|
||||||
let txs = block
|
let txs = block
|
||||||
.transactions
|
.transactions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|tx_hash| get_alt_transaction_blob(tx_hash, tables))
|
.map(|tx_hash| get_alt_transaction(tx_hash, tables))
|
||||||
.collect()?;
|
.collect::<Result<_, RuntimeError>>()?;
|
||||||
|
|
||||||
Ok(AltBlockInformation {
|
Ok(AltBlockInformation {
|
||||||
block,
|
block,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::tables::{AltChainInfos, TablesMut};
|
use crate::tables::{AltChainInfos, TablesMut};
|
||||||
use crate::types::{AltBlockHeight, AltChainInfo, BlockHash, BlockHeight};
|
use crate::types::{AltBlockHeight, AltChainInfo, BlockHash, BlockHeight};
|
||||||
use cuprate_database::{DatabaseRo, RuntimeError};
|
use cuprate_database::{DatabaseRo, DatabaseRw, RuntimeError};
|
||||||
use cuprate_types::{Chain, ChainId};
|
use cuprate_types::{Chain, ChainId};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ pub fn check_add_alt_chain_info(
|
||||||
&AltChainInfo {
|
&AltChainInfo {
|
||||||
parent_chain: parent_chain.into(),
|
parent_chain: parent_chain.into(),
|
||||||
common_ancestor_height: alt_block_height.height - 1,
|
common_ancestor_height: alt_block_height.height - 1,
|
||||||
|
chain_height: alt_block_height.height,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,3 +5,20 @@ mod tx;
|
||||||
pub use block::*;
|
pub use block::*;
|
||||||
pub use chain::*;
|
pub use chain::*;
|
||||||
pub use tx::*;
|
pub use tx::*;
|
||||||
|
|
||||||
|
pub fn flush_alt_blocks<'a, E: cuprate_database::EnvInner<'a>>(
|
||||||
|
env_inner: &E,
|
||||||
|
tx_rw: &mut E::Rw<'_>,
|
||||||
|
) -> Result<(), cuprate_database::RuntimeError> {
|
||||||
|
use crate::tables::{
|
||||||
|
AltBlockBlobs, AltBlockHeights, AltBlocksInfo, AltChainInfos, AltTransactionBlobs,
|
||||||
|
AltTransactionInfos,
|
||||||
|
};
|
||||||
|
|
||||||
|
env_inner.clear_db::<AltChainInfos>(tx_rw)?;
|
||||||
|
env_inner.clear_db::<AltBlockHeights>(tx_rw)?;
|
||||||
|
env_inner.clear_db::<AltBlocksInfo>(tx_rw)?;
|
||||||
|
env_inner.clear_db::<AltBlockBlobs>(tx_rw)?;
|
||||||
|
env_inner.clear_db::<AltTransactionBlobs>(tx_rw)?;
|
||||||
|
env_inner.clear_db::<AltTransactionInfos>(tx_rw)
|
||||||
|
}
|
||||||
|
|
|
@ -1,35 +1,57 @@
|
||||||
use crate::tables::{Tables, TablesMut};
|
use crate::tables::{Tables, TablesMut};
|
||||||
use crate::types::{AltTransactionInfo, TxHash};
|
use crate::types::{AltTransactionInfo, TxHash};
|
||||||
use bytemuck::TransparentWrapper;
|
use bytemuck::TransparentWrapper;
|
||||||
use cuprate_database::{RuntimeError, StorableVec};
|
use cuprate_database::{DatabaseRo, DatabaseRw, RuntimeError, StorableVec};
|
||||||
use cuprate_types::VerifiedTransactionInformation;
|
use cuprate_types::VerifiedTransactionInformation;
|
||||||
|
use monero_serai::transaction::Transaction;
|
||||||
|
|
||||||
pub fn add_alt_transaction_blob(
|
pub fn add_alt_transaction_blob(
|
||||||
tx_hash: &TxHash,
|
tx: &VerifiedTransactionInformation,
|
||||||
tx_block: &StorableVec<u8>,
|
|
||||||
tables: &mut impl TablesMut,
|
tables: &mut impl TablesMut,
|
||||||
) -> Result<(), RuntimeError> {
|
) -> Result<(), RuntimeError> {
|
||||||
if tables.tx_ids().get(&tx_hash).is_ok() || tables.alt_transaction_blobs().get(&tx_hash).is_ok()
|
tables.alt_transaction_infos_mut().put(
|
||||||
|
&tx.tx_hash,
|
||||||
|
&AltTransactionInfo {
|
||||||
|
tx_weight: tx.tx_weight,
|
||||||
|
fee: tx.fee,
|
||||||
|
tx_hash: tx.tx_hash,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if tables.tx_ids().get(&tx.tx_hash).is_ok()
|
||||||
|
|| tables.alt_transaction_blobs().get(&tx.tx_hash).is_ok()
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
tables.alt_transaction_blobs_mut().put(&tx_hash, tx_block)
|
tables
|
||||||
|
.alt_transaction_blobs_mut()
|
||||||
|
.put(&tx.tx_hash, StorableVec::wrap_ref(&tx.tx_blob))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_alt_transaction_blob(
|
pub fn get_alt_transaction(
|
||||||
tx_hash: &TxHash,
|
tx_hash: &TxHash,
|
||||||
tables: &impl Tables,
|
tables: &impl Tables,
|
||||||
) -> Result<Vec<u8>, RuntimeError> {
|
) -> Result<VerifiedTransactionInformation, RuntimeError> {
|
||||||
match tables.alt_transaction_blobs().get(tx_hash) {
|
let tx_info = tables.alt_transaction_infos().get(tx_hash)?;
|
||||||
Ok(blob) => Ok(blob.0),
|
|
||||||
|
let tx_blob = match tables.alt_transaction_blobs().get(tx_hash) {
|
||||||
|
Ok(blob) => blob.0,
|
||||||
Err(RuntimeError::KeyNotFound) => {
|
Err(RuntimeError::KeyNotFound) => {
|
||||||
let tx_id = tables.tx_ids().get(tx_hash)?;
|
let tx_id = tables.tx_ids().get(tx_hash)?;
|
||||||
|
|
||||||
let blob = tables.tx_blobs().get(&tx_id)?;
|
let blob = tables.tx_blobs().get(&tx_id)?;
|
||||||
|
|
||||||
Ok(blob.0)
|
blob.0
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Ok(VerifiedTransactionInformation {
|
||||||
|
tx: Transaction::read(&mut tx_blob.as_slice()).unwrap(),
|
||||||
|
tx_blob,
|
||||||
|
tx_weight: tx_info.tx_weight,
|
||||||
|
fee: tx_info.fee,
|
||||||
|
tx_hash: tx_info.tx_hash,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,13 @@ use cuprate_database::{
|
||||||
RuntimeError, StorableVec, {DatabaseRo, DatabaseRw},
|
RuntimeError, StorableVec, {DatabaseRo, DatabaseRw},
|
||||||
};
|
};
|
||||||
use cuprate_helper::map::{combine_low_high_bits_to_u128, split_u128_into_low_high_bits};
|
use cuprate_helper::map::{combine_low_high_bits_to_u128, split_u128_into_low_high_bits};
|
||||||
use cuprate_types::{ExtendedBlockHeader, HardFork, VerifiedBlockInformation};
|
use cuprate_types::{
|
||||||
|
AltBlockInformation, ChainId, ExtendedBlockHeader, HardFork, VerifiedBlockInformation,
|
||||||
|
VerifiedTransactionInformation,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::free::tx_fee;
|
||||||
|
use crate::ops::alt_block;
|
||||||
use crate::{
|
use crate::{
|
||||||
ops::{
|
ops::{
|
||||||
blockchain::{chain_height, cumulative_generated_coins},
|
blockchain::{chain_height, cumulative_generated_coins},
|
||||||
|
@ -106,9 +111,8 @@ pub fn add_block(
|
||||||
cumulative_rct_outs,
|
cumulative_rct_outs,
|
||||||
timestamp: block.block.header.timestamp,
|
timestamp: block.block.header.timestamp,
|
||||||
block_hash: block.block_hash,
|
block_hash: block.block_hash,
|
||||||
// INVARIANT: #[cfg] @ lib.rs asserts `usize == u64`
|
weight: block.weight,
|
||||||
weight: block.weight as u64,
|
long_term_weight: block.long_term_weight,
|
||||||
long_term_weight: block.long_term_weight as u64,
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -135,17 +139,15 @@ pub fn add_block(
|
||||||
/// will be returned if there are no blocks left.
|
/// will be returned if there are no blocks left.
|
||||||
// no inline, too big
|
// no inline, too big
|
||||||
pub fn pop_block(
|
pub fn pop_block(
|
||||||
|
move_to_alt_chain: Option<ChainId>,
|
||||||
tables: &mut impl TablesMut,
|
tables: &mut impl TablesMut,
|
||||||
) -> Result<(BlockHeight, BlockHash, Block), RuntimeError> {
|
) -> Result<(BlockHeight, BlockHash, Block), RuntimeError> {
|
||||||
//------------------------------------------------------ Block Info
|
//------------------------------------------------------ Block Info
|
||||||
// Remove block data from tables.
|
// Remove block data from tables.
|
||||||
let (block_height, block_hash) = {
|
let (block_height, block_info) = tables.block_infos_mut().pop_last()?;
|
||||||
let (block_height, block_info) = tables.block_infos_mut().pop_last()?;
|
|
||||||
(block_height, block_info.block_hash)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Block heights.
|
// Block heights.
|
||||||
tables.block_heights_mut().delete(&block_hash)?;
|
tables.block_heights_mut().delete(&block_info.block_hash)?;
|
||||||
|
|
||||||
// Block blobs.
|
// Block blobs.
|
||||||
// We deserialize the block blob into a `Block`, such
|
// We deserialize the block blob into a `Block`, such
|
||||||
|
@ -154,12 +156,42 @@ pub fn pop_block(
|
||||||
let block = Block::read(&mut block_blob.as_slice())?;
|
let block = Block::read(&mut block_blob.as_slice())?;
|
||||||
|
|
||||||
//------------------------------------------------------ Transaction / Outputs / Key Images
|
//------------------------------------------------------ Transaction / Outputs / Key Images
|
||||||
|
let mut txs = Vec::with_capacity(block.transactions.len());
|
||||||
|
|
||||||
remove_tx(&block.miner_transaction.hash(), tables)?;
|
remove_tx(&block.miner_transaction.hash(), tables)?;
|
||||||
for tx_hash in &block.transactions {
|
for tx_hash in &block.transactions {
|
||||||
remove_tx(tx_hash, tables)?;
|
let (_, tx) = remove_tx(tx_hash, tables)?;
|
||||||
|
|
||||||
|
if move_to_alt_chain.is_some() {
|
||||||
|
txs.push(VerifiedTransactionInformation {
|
||||||
|
tx_weight: tx.weight(),
|
||||||
|
tx_blob: tx.serialize(),
|
||||||
|
tx_hash: tx.hash(),
|
||||||
|
fee: tx_fee(&tx),
|
||||||
|
tx,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((block_height, block_hash, block))
|
if let Some(chain_id) = move_to_alt_chain {
|
||||||
|
alt_block::add_alt_block(
|
||||||
|
&AltBlockInformation {
|
||||||
|
block: block.clone(),
|
||||||
|
block_blob,
|
||||||
|
txs,
|
||||||
|
block_hash: block_info.block_hash,
|
||||||
|
pow_hash: [255; 32],
|
||||||
|
height: block_height,
|
||||||
|
weight: block_info.weight,
|
||||||
|
long_term_weight: block_info.long_term_weight,
|
||||||
|
cumulative_difficulty: 0,
|
||||||
|
chain_id,
|
||||||
|
},
|
||||||
|
tables,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((block_height, block_info.block_hash, block))
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- `get_block_extended_header_*`
|
//---------------------------------------------------------------------------------------------------- `get_block_extended_header_*`
|
||||||
|
@ -205,8 +237,8 @@ pub fn get_block_extended_header_from_height(
|
||||||
.expect("Stored block must have a valid hard-fork"),
|
.expect("Stored block must have a valid hard-fork"),
|
||||||
vote: block_header.hardfork_signal,
|
vote: block_header.hardfork_signal,
|
||||||
timestamp: block_header.timestamp,
|
timestamp: block_header.timestamp,
|
||||||
block_weight: block_info.weight as usize,
|
block_weight: block_info.weight,
|
||||||
long_term_weight: block_info.long_term_weight as usize,
|
long_term_weight: block_info.long_term_weight,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,7 +444,8 @@ mod test {
|
||||||
for block_hash in block_hashes.into_iter().rev() {
|
for block_hash in block_hashes.into_iter().rev() {
|
||||||
println!("pop_block(): block_hash: {}", hex::encode(block_hash));
|
println!("pop_block(): block_hash: {}", hex::encode(block_hash));
|
||||||
|
|
||||||
let (_popped_height, popped_hash, _popped_block) = pop_block(&mut tables).unwrap();
|
let (_popped_height, popped_hash, _popped_block) =
|
||||||
|
pop_block(None, &mut tables).unwrap();
|
||||||
|
|
||||||
assert_eq!(block_hash, popped_hash);
|
assert_eq!(block_hash, popped_hash);
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cuprate_database::{ConcreteEnv, InitError};
|
|
||||||
|
|
||||||
use crate::service::{init_read_service, init_write_service};
|
use crate::service::{init_read_service, init_write_service};
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
service::types::{BlockchainReadHandle, BlockchainWriteHandle},
|
service::types::{BlockchainReadHandle, BlockchainWriteHandle},
|
||||||
};
|
};
|
||||||
|
use cuprate_database::{ConcreteEnv, InitError};
|
||||||
|
use cuprate_types::{AltBlockInformation, VerifiedBlockInformation};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Init
|
//---------------------------------------------------------------------------------------------------- Init
|
||||||
#[cold]
|
#[cold]
|
||||||
|
@ -81,6 +81,39 @@ pub(super) const fn compact_history_genesis_not_included<const INITIAL_BLOCKS: u
|
||||||
top_block_height > INITIAL_BLOCKS && !(top_block_height - INITIAL_BLOCKS + 2).is_power_of_two()
|
top_block_height > INITIAL_BLOCKS && !(top_block_height - INITIAL_BLOCKS + 2).is_power_of_two()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Compact history
|
||||||
|
pub(super) fn map_valid_alt_block_to_verified_block(
|
||||||
|
alt_block: AltBlockInformation,
|
||||||
|
) -> VerifiedBlockInformation {
|
||||||
|
let total_fees = alt_block.txs.iter().map(|tx| tx.fee).sum::<u64>();
|
||||||
|
let total_miner_output = alt_block
|
||||||
|
.block
|
||||||
|
.miner_transaction
|
||||||
|
.prefix()
|
||||||
|
.outputs
|
||||||
|
.iter()
|
||||||
|
.map(|out| out.amount.unwrap_or(0))
|
||||||
|
.sum::<u64>();
|
||||||
|
|
||||||
|
VerifiedBlockInformation {
|
||||||
|
block: alt_block.block,
|
||||||
|
block_blob: alt_block.block_blob,
|
||||||
|
txs: alt_block
|
||||||
|
.txs
|
||||||
|
.into_iter()
|
||||||
|
.map(TryInto::try_into)
|
||||||
|
.collect::<Result<_, _>>()
|
||||||
|
.unwrap(),
|
||||||
|
block_hash: alt_block.block_hash,
|
||||||
|
pow_hash: alt_block.pow_hash,
|
||||||
|
height: alt_block.height,
|
||||||
|
generated_coins: total_miner_output - total_fees,
|
||||||
|
weight: alt_block.weight,
|
||||||
|
long_term_weight: alt_block.long_term_weight,
|
||||||
|
cumulative_difficulty: alt_block.cumulative_difficulty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
//! Database writer thread definitions and logic.
|
//! Database writer thread definitions and logic.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cuprate_database::{ConcreteEnv, Env, EnvInner, RuntimeError, TxRw};
|
use cuprate_database::{ConcreteEnv, DatabaseRo, DatabaseRw, Env, EnvInner, RuntimeError, TxRw};
|
||||||
use cuprate_database_service::DatabaseWriteHandle;
|
use cuprate_database_service::DatabaseWriteHandle;
|
||||||
use cuprate_types::{
|
use cuprate_types::{
|
||||||
blockchain::{BlockchainResponse, BlockchainWriteRequest},
|
blockchain::{BlockchainResponse, BlockchainWriteRequest},
|
||||||
AltBlockInformation, VerifiedBlockInformation,
|
AltBlockInformation, Chain, ChainId, VerifiedBlockInformation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::service::free::map_valid_alt_block_to_verified_block;
|
||||||
|
use crate::types::AltBlockHeight;
|
||||||
use crate::{
|
use crate::{
|
||||||
service::types::{BlockchainWriteHandle, ResponseResult},
|
service::types::{BlockchainWriteHandle, ResponseResult},
|
||||||
tables::OpenTables,
|
tables::{OpenTables, Tables, TablesMut},
|
||||||
|
types::AltChainInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- init_write_service
|
//---------------------------------------------------------------------------------------------------- init_write_service
|
||||||
|
@ -30,8 +32,10 @@ fn handle_blockchain_request(
|
||||||
match req {
|
match req {
|
||||||
BlockchainWriteRequest::WriteBlock(block) => write_block(env, block),
|
BlockchainWriteRequest::WriteBlock(block) => write_block(env, block),
|
||||||
BlockchainWriteRequest::WriteAltBlock(alt_block) => write_alt_block(env, alt_block),
|
BlockchainWriteRequest::WriteAltBlock(alt_block) => write_alt_block(env, alt_block),
|
||||||
BlockchainWriteRequest::StartReorg(_) => todo!(),
|
BlockchainWriteRequest::PopBlocks(numb_blocks) => pop_blocks(env, *numb_blocks),
|
||||||
BlockchainWriteRequest::ReverseReorg(_) => todo!(),
|
BlockchainWriteRequest::ReverseReorg(old_main_chain_id) => {
|
||||||
|
reverse_reorg(env, *old_main_chain_id)
|
||||||
|
}
|
||||||
BlockchainWriteRequest::FlushAltBlocks => flush_alt_blocks(env),
|
BlockchainWriteRequest::FlushAltBlocks => flush_alt_blocks(env),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +101,108 @@ fn write_alt_block(env: &ConcreteEnv, block: &AltBlockInformation) -> ResponseRe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [`BlockchainWriteRequest::PopBlocks`].
|
||||||
|
fn pop_blocks(env: &ConcreteEnv, numb_blocks: usize) -> ResponseResult {
|
||||||
|
let env_inner = env.env_inner();
|
||||||
|
let mut tx_rw = env_inner.tx_rw()?;
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
crate::ops::alt_block::flush_alt_blocks(&env_inner, &mut tx_rw)?;
|
||||||
|
|
||||||
|
let mut tables_mut = env_inner.open_tables_mut(&tx_rw)?;
|
||||||
|
|
||||||
|
let old_main_chain_id = ChainId(rand::random());
|
||||||
|
|
||||||
|
let mut last_block_height = 0;
|
||||||
|
for _ in 0..numb_blocks {
|
||||||
|
(last_block_height, _, _) =
|
||||||
|
crate::ops::block::pop_block(Some(old_main_chain_id), &mut tables_mut)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tables_mut.alt_chain_infos_mut().put(
|
||||||
|
&old_main_chain_id.into(),
|
||||||
|
&AltChainInfo {
|
||||||
|
parent_chain: Chain::Main.into(),
|
||||||
|
common_ancestor_height: last_block_height - 1,
|
||||||
|
chain_height: last_block_height + numb_blocks,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(old_main_chain_id)
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(old_main_chain_id) => {
|
||||||
|
TxRw::commit(tx_rw)?;
|
||||||
|
Ok(BlockchainResponse::PopBlocks(old_main_chain_id))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// INVARIANT: ensure database atomicity by aborting
|
||||||
|
// the transaction on `add_block()` failures.
|
||||||
|
TxRw::abort(tx_rw)
|
||||||
|
.expect("could not maintain database atomicity by aborting write transaction");
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [`BlockchainWriteRequest::ReverseReorg`].
|
||||||
|
fn reverse_reorg(env: &ConcreteEnv, chain_id: ChainId) -> ResponseResult {
|
||||||
|
let env_inner = env.env_inner();
|
||||||
|
let tx_rw = env_inner.tx_rw()?;
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
let mut tables_mut = env_inner.open_tables_mut(&tx_rw)?;
|
||||||
|
|
||||||
|
let chain_info = tables_mut.alt_chain_infos().get(&chain_id.into())?;
|
||||||
|
assert_eq!(Chain::from(chain_info.parent_chain), Chain::Main);
|
||||||
|
|
||||||
|
let tob_block_height =
|
||||||
|
crate::ops::blockchain::top_block_height(tables_mut.block_heights())?;
|
||||||
|
|
||||||
|
for _ in chain_info.common_ancestor_height..tob_block_height {
|
||||||
|
crate::ops::block::pop_block(None, &mut tables_mut)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rust borrow rules requires us to collect into a Vec first before looping over the Vec.
|
||||||
|
let alt_blocks = (chain_info.common_ancestor_height..chain_info.chain_height)
|
||||||
|
.map(|height| {
|
||||||
|
crate::ops::alt_block::get_alt_block(
|
||||||
|
&AltBlockHeight {
|
||||||
|
chain_id: chain_id.into(),
|
||||||
|
height,
|
||||||
|
},
|
||||||
|
&tables_mut,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for res_alt_block in alt_blocks {
|
||||||
|
let alt_block = res_alt_block?;
|
||||||
|
|
||||||
|
let verified_block = map_valid_alt_block_to_verified_block(alt_block);
|
||||||
|
|
||||||
|
crate::ops::block::add_block(&verified_block, &mut tables_mut)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(()) => {
|
||||||
|
TxRw::commit(tx_rw)?;
|
||||||
|
Ok(BlockchainResponse::Ok)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// INVARIANT: ensure database atomicity by aborting
|
||||||
|
// the transaction on `add_block()` failures.
|
||||||
|
TxRw::abort(tx_rw)
|
||||||
|
.expect("could not maintain database atomicity by aborting write transaction");
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// [`BlockchainWriteRequest::FlushAltBlocks`].
|
/// [`BlockchainWriteRequest::FlushAltBlocks`].
|
||||||
#[inline]
|
#[inline]
|
||||||
fn flush_alt_blocks(env: &ConcreteEnv) -> ResponseResult {
|
fn flush_alt_blocks(env: &ConcreteEnv) -> ResponseResult {
|
||||||
|
|
|
@ -145,6 +145,9 @@ cuprate_database::define_tables! {
|
||||||
|
|
||||||
19 => AltTransactionBlobs,
|
19 => AltTransactionBlobs,
|
||||||
TxHash => TxBlob,
|
TxHash => TxBlob,
|
||||||
|
|
||||||
|
20 => AltTransactionInfos,
|
||||||
|
TxHash => AltTransactionInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
|
|
@ -189,7 +189,7 @@ pub struct BlockInfo {
|
||||||
/// The adjusted block size, in bytes.
|
/// The adjusted block size, in bytes.
|
||||||
///
|
///
|
||||||
/// See [`block_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#blocks-weight).
|
/// See [`block_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#blocks-weight).
|
||||||
pub weight: u64,
|
pub weight: usize,
|
||||||
/// Least-significant 64 bits of the 128-bit cumulative difficulty.
|
/// Least-significant 64 bits of the 128-bit cumulative difficulty.
|
||||||
pub cumulative_difficulty_low: u64,
|
pub cumulative_difficulty_low: u64,
|
||||||
/// Most-significant 64 bits of the 128-bit cumulative difficulty.
|
/// Most-significant 64 bits of the 128-bit cumulative difficulty.
|
||||||
|
@ -201,7 +201,7 @@ pub struct BlockInfo {
|
||||||
/// The long term block weight, based on the median weight of the preceding `100_000` blocks.
|
/// The long term block weight, based on the median weight of the preceding `100_000` blocks.
|
||||||
///
|
///
|
||||||
/// See [`long_term_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#long-term-block-weight).
|
/// See [`long_term_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#long-term-block-weight).
|
||||||
pub long_term_weight: u64,
|
pub long_term_weight: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- OutputFlags
|
//---------------------------------------------------------------------------------------------------- OutputFlags
|
||||||
|
@ -381,6 +381,7 @@ impl Key for RawChainId {}
|
||||||
pub struct AltChainInfo {
|
pub struct AltChainInfo {
|
||||||
pub parent_chain: RawChain,
|
pub parent_chain: RawChain,
|
||||||
pub common_ancestor_height: usize,
|
pub common_ancestor_height: usize,
|
||||||
|
pub chain_height: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- AltBlockHeight
|
//---------------------------------------------------------------------------------------------------- AltBlockHeight
|
||||||
|
|
|
@ -116,20 +116,17 @@ pub enum BlockchainWriteRequest {
|
||||||
///
|
///
|
||||||
/// Input is the alternative block.
|
/// Input is the alternative block.
|
||||||
WriteAltBlock(AltBlockInformation),
|
WriteAltBlock(AltBlockInformation),
|
||||||
/// A request to start the re-org process.
|
/// A request to pop some blocks from the top of the main chain
|
||||||
///
|
///
|
||||||
/// The inner value is the [`ChainId`] of the alt-chain we want to re-org to.
|
/// Input is the amount of blocks to pop.
|
||||||
///
|
///
|
||||||
/// This will:
|
/// This request flush all alt-chains from the cache before adding the popped blocks to the alt cache.
|
||||||
/// - pop blocks from the main chain
|
PopBlocks(usize),
|
||||||
/// - retrieve all alt-blocks in this alt-chain
|
|
||||||
/// - flush all other alt blocks
|
|
||||||
StartReorg(ChainId),
|
|
||||||
/// A request to reverse the re-org process.
|
/// A request to reverse the re-org process.
|
||||||
///
|
///
|
||||||
/// The inner value is the [`ChainId`] of the old main chain.
|
/// The inner value is the [`ChainId`] of the old main chain.
|
||||||
///
|
///
|
||||||
/// It is invalid to call this with a [`ChainId`] that was not returned from [`BlockchainWriteRequest::StartReorg`].
|
/// It is invalid to call this with a [`ChainId`] that was not returned from [`BlockchainWriteRequest::PopBlocks`].
|
||||||
ReverseReorg(ChainId),
|
ReverseReorg(ChainId),
|
||||||
/// A request to flush all alternative blocks.
|
/// A request to flush all alternative blocks.
|
||||||
FlushAltBlocks,
|
FlushAltBlocks,
|
||||||
|
@ -227,13 +224,10 @@ pub enum BlockchainResponse {
|
||||||
/// - [`BlockchainWriteRequest::ReverseReorg`]
|
/// - [`BlockchainWriteRequest::ReverseReorg`]
|
||||||
/// - [`BlockchainWriteRequest::FlushAltBlocks`]
|
/// - [`BlockchainWriteRequest::FlushAltBlocks`]
|
||||||
Ok,
|
Ok,
|
||||||
/// The response for [`BlockchainWriteRequest::StartReorg`].
|
/// The response for [`BlockchainWriteRequest::PopBlocks`].
|
||||||
StartReorg {
|
///
|
||||||
/// The [`ChainId`] of the old main chain blocks that were popped.
|
/// The inner value is the alt-chain ID for the old main chain blocks.
|
||||||
old_main_chain_id: ChainId,
|
PopBlocks(ChainId),
|
||||||
/// The next alt chain blocks.
|
|
||||||
alt_chain: Vec<AltBlockInformation>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
|
|
@ -79,6 +79,7 @@ pub struct VerifiedBlockInformation {
|
||||||
/// [`Block::hash`].
|
/// [`Block::hash`].
|
||||||
pub block_hash: [u8; 32],
|
pub block_hash: [u8; 32],
|
||||||
/// The block's proof-of-work hash.
|
/// The block's proof-of-work hash.
|
||||||
|
// TODO: make this an option.
|
||||||
pub pow_hash: [u8; 32],
|
pub pow_hash: [u8; 32],
|
||||||
/// The block's height.
|
/// The block's height.
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
|
@ -120,7 +121,7 @@ pub struct AltBlockInformation {
|
||||||
/// [`Block::serialize`].
|
/// [`Block::serialize`].
|
||||||
pub block_blob: Vec<u8>,
|
pub block_blob: Vec<u8>,
|
||||||
/// All the transactions in the block, excluding the [`Block::miner_transaction`].
|
/// All the transactions in the block, excluding the [`Block::miner_transaction`].
|
||||||
pub txs: Vec<Vec<u8>>,
|
pub txs: Vec<VerifiedTransactionInformation>,
|
||||||
/// The block's hash.
|
/// The block's hash.
|
||||||
///
|
///
|
||||||
/// [`Block::hash`].
|
/// [`Block::hash`].
|
||||||
|
|
Loading…
Reference in a new issue