feat: add TransactionStatus column family and test (#6958)
This commit is contained in:
parent
c1b06817a2
commit
086e5da8d0
|
@ -68,6 +68,7 @@ pub struct Blocktree {
|
||||||
index_cf: LedgerColumn<cf::Index>,
|
index_cf: LedgerColumn<cf::Index>,
|
||||||
data_shred_cf: LedgerColumn<cf::ShredData>,
|
data_shred_cf: LedgerColumn<cf::ShredData>,
|
||||||
code_shred_cf: LedgerColumn<cf::ShredCode>,
|
code_shred_cf: LedgerColumn<cf::ShredCode>,
|
||||||
|
transaction_status_cf: LedgerColumn<cf::TransactionStatus>,
|
||||||
last_root: Arc<RwLock<u64>>,
|
last_root: Arc<RwLock<u64>>,
|
||||||
insert_shreds_lock: Arc<Mutex<()>>,
|
insert_shreds_lock: Arc<Mutex<()>>,
|
||||||
pub new_shreds_signals: Vec<SyncSender<bool>>,
|
pub new_shreds_signals: Vec<SyncSender<bool>>,
|
||||||
|
@ -171,6 +172,7 @@ impl Blocktree {
|
||||||
|
|
||||||
let data_shred_cf = db.column();
|
let data_shred_cf = db.column();
|
||||||
let code_shred_cf = db.column();
|
let code_shred_cf = db.column();
|
||||||
|
let transaction_status_cf = db.column();
|
||||||
|
|
||||||
let db = Arc::new(db);
|
let db = Arc::new(db);
|
||||||
|
|
||||||
|
@ -192,6 +194,7 @@ impl Blocktree {
|
||||||
index_cf,
|
index_cf,
|
||||||
data_shred_cf,
|
data_shred_cf,
|
||||||
code_shred_cf,
|
code_shred_cf,
|
||||||
|
transaction_status_cf,
|
||||||
new_shreds_signals: vec![],
|
new_shreds_signals: vec![],
|
||||||
completed_slots_senders: vec![],
|
completed_slots_senders: vec![],
|
||||||
insert_shreds_lock: Arc::new(Mutex::new(())),
|
insert_shreds_lock: Arc::new(Mutex::new(())),
|
||||||
|
@ -283,6 +286,10 @@ impl Blocktree {
|
||||||
.code_shred_cf
|
.code_shred_cf
|
||||||
.delete_slot(&mut write_batch, from_slot, batch_end)
|
.delete_slot(&mut write_batch, from_slot, batch_end)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
|
&& self
|
||||||
|
.transaction_status_cf
|
||||||
|
.delete_slot(&mut write_batch, from_slot, batch_end)
|
||||||
|
.unwrap_or(false)
|
||||||
&& self
|
&& self
|
||||||
.orphans_cf
|
.orphans_cf
|
||||||
.delete_slot(&mut write_batch, from_slot, batch_end)
|
.delete_slot(&mut write_batch, from_slot, batch_end)
|
||||||
|
@ -1985,6 +1992,7 @@ pub mod tests {
|
||||||
use rand::{seq::SliceRandom, thread_rng};
|
use rand::{seq::SliceRandom, thread_rng};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
hash::Hash, instruction::CompiledInstruction, packet::PACKET_DATA_SIZE, pubkey::Pubkey,
|
hash::Hash, instruction::CompiledInstruction, packet::PACKET_DATA_SIZE, pubkey::Pubkey,
|
||||||
|
signature::Signature, transaction::TransactionError,
|
||||||
};
|
};
|
||||||
use std::{iter::FromIterator, time::Duration};
|
use std::{iter::FromIterator, time::Duration};
|
||||||
|
|
||||||
|
@ -4071,4 +4079,59 @@ pub mod tests {
|
||||||
drop(ledger);
|
drop(ledger);
|
||||||
Blocktree::destroy(&ledger_path).expect("Expected successful database destruction");
|
Blocktree::destroy(&ledger_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_persist_transaction_status() {
|
||||||
|
let blocktree_path = get_tmp_ledger_path!();
|
||||||
|
{
|
||||||
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
||||||
|
let transaction_status_cf = blocktree.db.column::<cf::TransactionStatus>();
|
||||||
|
|
||||||
|
// result not found
|
||||||
|
assert!(transaction_status_cf
|
||||||
|
.get((0, Signature::default()))
|
||||||
|
.unwrap()
|
||||||
|
.is_none());
|
||||||
|
|
||||||
|
// insert value
|
||||||
|
assert!(transaction_status_cf
|
||||||
|
.put(
|
||||||
|
(0, Signature::default()),
|
||||||
|
&(
|
||||||
|
solana_sdk::transaction::Result::<()>::Err(
|
||||||
|
TransactionError::AccountNotFound
|
||||||
|
),
|
||||||
|
5u64
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
// result found
|
||||||
|
let (status, fee) = transaction_status_cf
|
||||||
|
.get((0, Signature::default()))
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(status, Err(TransactionError::AccountNotFound));
|
||||||
|
assert_eq!(fee, 5u64);
|
||||||
|
|
||||||
|
// insert value
|
||||||
|
assert!(transaction_status_cf
|
||||||
|
.put(
|
||||||
|
(9, Signature::default()),
|
||||||
|
&(solana_sdk::transaction::Result::<()>::Ok(()), 9u64)
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
// result found
|
||||||
|
let (status, fee) = transaction_status_cf
|
||||||
|
.get((9, Signature::default()))
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// deserialize
|
||||||
|
assert_eq!(status, Ok(()));
|
||||||
|
assert_eq!(fee, 9u64);
|
||||||
|
}
|
||||||
|
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rocksdb::{
|
||||||
};
|
};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_sdk::clock::Slot;
|
use solana_sdk::{clock::Slot, signature::Signature};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -35,6 +35,8 @@ const INDEX_CF: &str = "index";
|
||||||
const DATA_SHRED_CF: &str = "data_shred";
|
const DATA_SHRED_CF: &str = "data_shred";
|
||||||
/// Column family for Code Shreds
|
/// Column family for Code Shreds
|
||||||
const CODE_SHRED_CF: &str = "code_shred";
|
const CODE_SHRED_CF: &str = "code_shred";
|
||||||
|
/// Column family for Transaction Status
|
||||||
|
const TRANSACTION_STATUS_CF: &str = "transaction_status";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BlocktreeError {
|
pub enum BlocktreeError {
|
||||||
|
@ -111,6 +113,10 @@ pub mod columns {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// The shred erasure code column
|
/// The shred erasure code column
|
||||||
pub struct ShredCode;
|
pub struct ShredCode;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// The transaction status column
|
||||||
|
pub struct TransactionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -120,6 +126,7 @@ impl Rocks {
|
||||||
fn open(path: &Path) -> Result<Rocks> {
|
fn open(path: &Path) -> Result<Rocks> {
|
||||||
use columns::{
|
use columns::{
|
||||||
DeadSlots, ErasureMeta, Index, Orphans, Root, ShredCode, ShredData, SlotMeta,
|
DeadSlots, ErasureMeta, Index, Orphans, Root, ShredCode, ShredData, SlotMeta,
|
||||||
|
TransactionStatus,
|
||||||
};
|
};
|
||||||
|
|
||||||
fs::create_dir_all(&path)?;
|
fs::create_dir_all(&path)?;
|
||||||
|
@ -140,6 +147,8 @@ impl Rocks {
|
||||||
ColumnFamilyDescriptor::new(ShredData::NAME, get_cf_options());
|
ColumnFamilyDescriptor::new(ShredData::NAME, get_cf_options());
|
||||||
let shred_code_cf_descriptor =
|
let shred_code_cf_descriptor =
|
||||||
ColumnFamilyDescriptor::new(ShredCode::NAME, get_cf_options());
|
ColumnFamilyDescriptor::new(ShredCode::NAME, get_cf_options());
|
||||||
|
let transaction_status_cf_descriptor =
|
||||||
|
ColumnFamilyDescriptor::new(TransactionStatus::NAME, get_cf_options());
|
||||||
|
|
||||||
let cfs = vec![
|
let cfs = vec![
|
||||||
meta_cf_descriptor,
|
meta_cf_descriptor,
|
||||||
|
@ -150,6 +159,7 @@ impl Rocks {
|
||||||
index_cf_descriptor,
|
index_cf_descriptor,
|
||||||
shred_data_cf_descriptor,
|
shred_data_cf_descriptor,
|
||||||
shred_code_cf_descriptor,
|
shred_code_cf_descriptor,
|
||||||
|
transaction_status_cf_descriptor,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Open the database
|
// Open the database
|
||||||
|
@ -161,6 +171,7 @@ impl Rocks {
|
||||||
fn columns(&self) -> Vec<&'static str> {
|
fn columns(&self) -> Vec<&'static str> {
|
||||||
use columns::{
|
use columns::{
|
||||||
DeadSlots, ErasureMeta, Index, Orphans, Root, ShredCode, ShredData, SlotMeta,
|
DeadSlots, ErasureMeta, Index, Orphans, Root, ShredCode, ShredData, SlotMeta,
|
||||||
|
TransactionStatus,
|
||||||
};
|
};
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
|
@ -172,6 +183,7 @@ impl Rocks {
|
||||||
SlotMeta::NAME,
|
SlotMeta::NAME,
|
||||||
ShredData::NAME,
|
ShredData::NAME,
|
||||||
ShredCode::NAME,
|
ShredCode::NAME,
|
||||||
|
TransactionStatus::NAME,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,6 +260,36 @@ pub trait TypedColumn: Column {
|
||||||
type Type: Serialize + DeserializeOwned;
|
type Type: Serialize + DeserializeOwned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypedColumn for columns::TransactionStatus {
|
||||||
|
type Type = (solana_sdk::transaction::Result<()>, u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Column for columns::TransactionStatus {
|
||||||
|
const NAME: &'static str = TRANSACTION_STATUS_CF;
|
||||||
|
type Index = (Slot, Signature);
|
||||||
|
|
||||||
|
fn key((slot, index): (Slot, Signature)) -> Vec<u8> {
|
||||||
|
let mut key = vec![0; 8 + 64];
|
||||||
|
BigEndian::write_u64(&mut key[..8], slot);
|
||||||
|
key[8..72].clone_from_slice(&index.as_ref()[0..64]);
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index<'a>(key: &[u8]) -> (Slot, Signature) {
|
||||||
|
let slot = BigEndian::read_u64(&key[..8]);
|
||||||
|
let index = Signature::new(&key[8..72]);
|
||||||
|
(slot, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slot(index: Self::Index) -> Slot {
|
||||||
|
index.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_index(slot: Slot) -> Self::Index {
|
||||||
|
(slot, Signature::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Column for columns::ShredCode {
|
impl Column for columns::ShredCode {
|
||||||
const NAME: &'static str = CODE_SHRED_CF;
|
const NAME: &'static str = CODE_SHRED_CF;
|
||||||
type Index = (u64, u64);
|
type Index = (u64, u64);
|
||||||
|
|
Loading…
Reference in New Issue