Convert blockstore TransactionStatus column family to protobufs (#15733)
* Prevent panic if TransactionStatus can't be deserialized * Convert Blockstore TransactionStatus column to protobuf * Add compatability test
This commit is contained in:
parent
bd13262b42
commit
7e65289729
|
@ -4710,6 +4710,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
"sha2 0.9.2",
|
"sha2 0.9.2",
|
||||||
|
"solana-account-decoder",
|
||||||
"solana-bpf-loader-program",
|
"solana-bpf-loader-program",
|
||||||
"solana-budget-program",
|
"solana-budget-program",
|
||||||
"solana-frozen-abi 1.6.0",
|
"solana-frozen-abi 1.6.0",
|
||||||
|
|
|
@ -124,7 +124,7 @@ impl TransactionStatusService {
|
||||||
transaction.signatures[0],
|
transaction.signatures[0],
|
||||||
writable_keys,
|
writable_keys,
|
||||||
readonly_keys,
|
readonly_keys,
|
||||||
&TransactionStatusMeta {
|
TransactionStatusMeta {
|
||||||
status,
|
status,
|
||||||
fee,
|
fee,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
|
|
|
@ -64,6 +64,7 @@ features = ["lz4"]
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
matches = "0.1.6"
|
matches = "0.1.6"
|
||||||
|
solana-account-decoder = { path = "../account-decoder", version = "1.6.0" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.6.0" }
|
solana-budget-program = { path = "../programs/budget", version = "1.6.0" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -35,7 +35,7 @@ use solana_sdk::{
|
||||||
timing::timestamp,
|
timing::timestamp,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_storage_proto::StoredExtendedRewards;
|
use solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Rewards,
|
ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Rewards,
|
||||||
TransactionStatusMeta, TransactionWithStatusMeta,
|
TransactionStatusMeta, TransactionWithStatusMeta,
|
||||||
|
@ -44,6 +44,7 @@ use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
cmp,
|
cmp,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
convert::TryInto,
|
||||||
fs,
|
fs,
|
||||||
io::{Error as IoError, ErrorKind},
|
io::{Error as IoError, ErrorKind},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -1783,7 +1784,8 @@ impl Blockstore {
|
||||||
transaction,
|
transaction,
|
||||||
meta: self
|
meta: self
|
||||||
.read_transaction_status((signature, slot))
|
.read_transaction_status((signature, slot))
|
||||||
.expect("Expect database get to succeed"),
|
.ok()
|
||||||
|
.flatten(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -1799,10 +1801,9 @@ impl Blockstore {
|
||||||
self.transaction_status_index_cf
|
self.transaction_status_index_cf
|
||||||
.put(1, &TransactionStatusIndexMeta::default())?;
|
.put(1, &TransactionStatusIndexMeta::default())?;
|
||||||
// This dummy status improves compaction performance
|
// This dummy status improves compaction performance
|
||||||
self.transaction_status_cf.put(
|
let default_status = TransactionStatusMeta::default().into();
|
||||||
cf::TransactionStatus::as_index(2),
|
self.transaction_status_cf
|
||||||
&TransactionStatusMeta::default(),
|
.put_protobuf(cf::TransactionStatus::as_index(2), &default_status)?;
|
||||||
)?;
|
|
||||||
self.address_signatures_cf.put(
|
self.address_signatures_cf.put(
|
||||||
cf::AddressSignatures::as_index(2),
|
cf::AddressSignatures::as_index(2),
|
||||||
&AddressSignatureMeta::default(),
|
&AddressSignatureMeta::default(),
|
||||||
|
@ -1878,11 +1879,16 @@ impl Blockstore {
|
||||||
index: (Signature, Slot),
|
index: (Signature, Slot),
|
||||||
) -> Result<Option<TransactionStatusMeta>> {
|
) -> Result<Option<TransactionStatusMeta>> {
|
||||||
let (signature, slot) = index;
|
let (signature, slot) = index;
|
||||||
let result = self.transaction_status_cf.get((0, signature, slot))?;
|
let result = self
|
||||||
|
.transaction_status_cf
|
||||||
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((0, signature, slot))?;
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
Ok(self.transaction_status_cf.get((1, signature, slot))?)
|
Ok(self
|
||||||
|
.transaction_status_cf
|
||||||
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((1, signature, slot))?
|
||||||
|
.and_then(|meta| meta.try_into().ok()))
|
||||||
} else {
|
} else {
|
||||||
Ok(result)
|
Ok(result.and_then(|meta| meta.try_into().ok()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1892,15 +1898,16 @@ impl Blockstore {
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
writable_keys: Vec<&Pubkey>,
|
writable_keys: Vec<&Pubkey>,
|
||||||
readonly_keys: Vec<&Pubkey>,
|
readonly_keys: Vec<&Pubkey>,
|
||||||
status: &TransactionStatusMeta,
|
status: TransactionStatusMeta,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let status = status.into();
|
||||||
// This write lock prevents interleaving issues with the transaction_status_index_cf by gating
|
// This write lock prevents interleaving issues with the transaction_status_index_cf by gating
|
||||||
// writes to that column
|
// writes to that column
|
||||||
let mut w_active_transaction_status_index =
|
let mut w_active_transaction_status_index =
|
||||||
self.active_transaction_status_index.write().unwrap();
|
self.active_transaction_status_index.write().unwrap();
|
||||||
let primary_index = self.get_primary_index(slot, &mut w_active_transaction_status_index)?;
|
let primary_index = self.get_primary_index(slot, &mut w_active_transaction_status_index)?;
|
||||||
self.transaction_status_cf
|
self.transaction_status_cf
|
||||||
.put((primary_index, signature, slot), status)?;
|
.put_protobuf((primary_index, signature, slot), &status)?;
|
||||||
for address in writable_keys {
|
for address in writable_keys {
|
||||||
self.address_signatures_cf.put(
|
self.address_signatures_cf.put(
|
||||||
(primary_index, *address, slot, signature),
|
(primary_index, *address, slot, signature),
|
||||||
|
@ -1928,14 +1935,18 @@ impl Blockstore {
|
||||||
(transaction_status_cf_primary_index, signature, 0),
|
(transaction_status_cf_primary_index, signature, 0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))?;
|
))?;
|
||||||
for ((i, sig, slot), data) in index_iterator {
|
for ((i, sig, slot), _data) in index_iterator {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
if i != transaction_status_cf_primary_index || sig != signature {
|
if i != transaction_status_cf_primary_index || sig != signature {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if self.is_root(slot) {
|
if self.is_root(slot) {
|
||||||
let status: TransactionStatusMeta = deserialize(&data)?;
|
let status = self
|
||||||
return Ok((Some((slot, status)), counter));
|
.transaction_status_cf
|
||||||
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((i, sig, slot))?
|
||||||
|
.and_then(|status| status.try_into().ok())
|
||||||
|
.map(|status| (slot, status));
|
||||||
|
return Ok((status, counter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3531,6 +3542,7 @@ pub mod tests {
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rand::{seq::SliceRandom, thread_rng};
|
use rand::{seq::SliceRandom, thread_rng};
|
||||||
|
use solana_account_decoder::parse_token::UiTokenAmount;
|
||||||
use solana_runtime::bank::{Bank, RewardType};
|
use solana_runtime::bank::{Bank, RewardType};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
hash::{self, hash, Hash},
|
hash::{self, hash, Hash},
|
||||||
|
@ -3541,7 +3553,7 @@ pub mod tests {
|
||||||
transaction::TransactionError,
|
transaction::TransactionError,
|
||||||
};
|
};
|
||||||
use solana_storage_proto::convert::generated;
|
use solana_storage_proto::convert::generated;
|
||||||
use solana_transaction_status::{InnerInstructions, Reward, Rewards};
|
use solana_transaction_status::{InnerInstructions, Reward, Rewards, TransactionTokenBalance};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// used for tests only
|
// used for tests only
|
||||||
|
@ -5706,11 +5718,7 @@ pub mod tests {
|
||||||
post_balances.push(i as u64 * 11);
|
post_balances.push(i as u64 * 11);
|
||||||
}
|
}
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
ledger
|
let status = TransactionStatusMeta {
|
||||||
.transaction_status_cf
|
|
||||||
.put(
|
|
||||||
(0, signature, slot),
|
|
||||||
&TransactionStatusMeta {
|
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances: pre_balances.clone(),
|
pre_balances: pre_balances.clone(),
|
||||||
|
@ -5719,14 +5727,13 @@ pub mod tests {
|
||||||
log_messages: Some(vec![]),
|
log_messages: Some(vec![]),
|
||||||
pre_token_balances: Some(vec![]),
|
pre_token_balances: Some(vec![]),
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
},
|
}
|
||||||
)
|
.into();
|
||||||
|
ledger
|
||||||
|
.transaction_status_cf
|
||||||
|
.put_protobuf((0, signature, slot), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ledger
|
let status = TransactionStatusMeta {
|
||||||
.transaction_status_cf
|
|
||||||
.put(
|
|
||||||
(0, signature, slot + 1),
|
|
||||||
&TransactionStatusMeta {
|
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances: pre_balances.clone(),
|
pre_balances: pre_balances.clone(),
|
||||||
|
@ -5735,8 +5742,11 @@ pub mod tests {
|
||||||
log_messages: Some(vec![]),
|
log_messages: Some(vec![]),
|
||||||
pre_token_balances: Some(vec![]),
|
pre_token_balances: Some(vec![]),
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
},
|
}
|
||||||
)
|
.into();
|
||||||
|
ledger
|
||||||
|
.transaction_status_cf
|
||||||
|
.put_protobuf((0, signature, slot + 1), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
TransactionWithStatusMeta {
|
TransactionWithStatusMeta {
|
||||||
transaction,
|
transaction,
|
||||||
|
@ -5826,17 +5836,18 @@ pub mod tests {
|
||||||
|
|
||||||
// result not found
|
// result not found
|
||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
.get((0, Signature::default(), 0))
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
|
||||||
|
0,
|
||||||
|
Signature::default(),
|
||||||
|
0
|
||||||
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_none());
|
.is_none());
|
||||||
|
|
||||||
// insert value
|
// insert value
|
||||||
assert!(transaction_status_cf
|
let status = TransactionStatusMeta {
|
||||||
.put(
|
|
||||||
(0, Signature::default(), 0),
|
|
||||||
&TransactionStatusMeta {
|
|
||||||
status: solana_sdk::transaction::Result::<()>::Err(
|
status: solana_sdk::transaction::Result::<()>::Err(
|
||||||
TransactionError::AccountNotFound
|
TransactionError::AccountNotFound,
|
||||||
),
|
),
|
||||||
fee: 5u64,
|
fee: 5u64,
|
||||||
pre_balances: pre_balances_vec.clone(),
|
pre_balances: pre_balances_vec.clone(),
|
||||||
|
@ -5844,9 +5855,11 @@ pub mod tests {
|
||||||
inner_instructions: Some(inner_instructions_vec.clone()),
|
inner_instructions: Some(inner_instructions_vec.clone()),
|
||||||
log_messages: Some(log_messages_vec.clone()),
|
log_messages: Some(log_messages_vec.clone()),
|
||||||
pre_token_balances: Some(pre_token_balances_vec.clone()),
|
pre_token_balances: Some(pre_token_balances_vec.clone()),
|
||||||
post_token_balances: Some(post_token_balances_vec.clone())
|
post_token_balances: Some(post_token_balances_vec.clone()),
|
||||||
},
|
}
|
||||||
)
|
.into();
|
||||||
|
assert!(transaction_status_cf
|
||||||
|
.put_protobuf((0, Signature::default(), 0), &status,)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// result found
|
// result found
|
||||||
|
@ -5860,8 +5873,14 @@ pub mod tests {
|
||||||
pre_token_balances,
|
pre_token_balances,
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
} = transaction_status_cf
|
} = transaction_status_cf
|
||||||
.get((0, Signature::default(), 0))
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
|
||||||
|
0,
|
||||||
|
Signature::default(),
|
||||||
|
0,
|
||||||
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(status, Err(TransactionError::AccountNotFound));
|
assert_eq!(status, Err(TransactionError::AccountNotFound));
|
||||||
assert_eq!(fee, 5u64);
|
assert_eq!(fee, 5u64);
|
||||||
|
@ -5873,10 +5892,7 @@ pub mod tests {
|
||||||
assert_eq!(post_token_balances.unwrap(), post_token_balances_vec);
|
assert_eq!(post_token_balances.unwrap(), post_token_balances_vec);
|
||||||
|
|
||||||
// insert value
|
// insert value
|
||||||
assert!(transaction_status_cf
|
let status = TransactionStatusMeta {
|
||||||
.put(
|
|
||||||
(0, Signature::new(&[2u8; 64]), 9),
|
|
||||||
&TransactionStatusMeta {
|
|
||||||
status: solana_sdk::transaction::Result::<()>::Ok(()),
|
status: solana_sdk::transaction::Result::<()>::Ok(()),
|
||||||
fee: 9u64,
|
fee: 9u64,
|
||||||
pre_balances: pre_balances_vec.clone(),
|
pre_balances: pre_balances_vec.clone(),
|
||||||
|
@ -5884,9 +5900,11 @@ pub mod tests {
|
||||||
inner_instructions: Some(inner_instructions_vec.clone()),
|
inner_instructions: Some(inner_instructions_vec.clone()),
|
||||||
log_messages: Some(log_messages_vec.clone()),
|
log_messages: Some(log_messages_vec.clone()),
|
||||||
pre_token_balances: Some(pre_token_balances_vec.clone()),
|
pre_token_balances: Some(pre_token_balances_vec.clone()),
|
||||||
post_token_balances: Some(post_token_balances_vec.clone())
|
post_token_balances: Some(post_token_balances_vec.clone()),
|
||||||
},
|
}
|
||||||
)
|
.into();
|
||||||
|
assert!(transaction_status_cf
|
||||||
|
.put_protobuf((0, Signature::new(&[2u8; 64]), 9), &status,)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// result found
|
// result found
|
||||||
|
@ -5900,8 +5918,14 @@ pub mod tests {
|
||||||
pre_token_balances,
|
pre_token_balances,
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
} = transaction_status_cf
|
} = transaction_status_cf
|
||||||
.get((0, Signature::new(&[2u8; 64]), 9))
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
|
||||||
|
0,
|
||||||
|
Signature::new(&[2u8; 64]),
|
||||||
|
9,
|
||||||
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// deserialize
|
// deserialize
|
||||||
|
@ -5938,7 +5962,7 @@ pub mod tests {
|
||||||
Signature::new(&random_bytes),
|
Signature::new(&random_bytes),
|
||||||
vec![&Pubkey::new(&random_bytes[0..32])],
|
vec![&Pubkey::new(&random_bytes[0..32])],
|
||||||
vec![&Pubkey::new(&random_bytes[32..])],
|
vec![&Pubkey::new(&random_bytes[32..])],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -6004,7 +6028,7 @@ pub mod tests {
|
||||||
Signature::new(&random_bytes),
|
Signature::new(&random_bytes),
|
||||||
vec![&Pubkey::new(&random_bytes[0..32])],
|
vec![&Pubkey::new(&random_bytes[0..32])],
|
||||||
vec![&Pubkey::new(&random_bytes[32..])],
|
vec![&Pubkey::new(&random_bytes[32..])],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -6143,7 +6167,8 @@ pub mod tests {
|
||||||
log_messages: Some(vec![]),
|
log_messages: Some(vec![]),
|
||||||
pre_token_balances: Some(vec![]),
|
pre_token_balances: Some(vec![]),
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
};
|
}
|
||||||
|
.into();
|
||||||
|
|
||||||
let signature1 = Signature::new(&[1u8; 64]);
|
let signature1 = Signature::new(&[1u8; 64]);
|
||||||
let signature2 = Signature::new(&[2u8; 64]);
|
let signature2 = Signature::new(&[2u8; 64]);
|
||||||
|
@ -6157,46 +6182,46 @@ pub mod tests {
|
||||||
// signature4 in 2 non-roots,
|
// signature4 in 2 non-roots,
|
||||||
// extra entries
|
// extra entries
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((0, signature2, 1), &status)
|
.put_protobuf((0, signature2, 1), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((0, signature2, 2), &status)
|
.put_protobuf((0, signature2, 2), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((0, signature4, 0), &status)
|
.put_protobuf((0, signature4, 0), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((0, signature4, 1), &status)
|
.put_protobuf((0, signature4, 1), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((0, signature5, 0), &status)
|
.put_protobuf((0, signature5, 0), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((0, signature5, 1), &status)
|
.put_protobuf((0, signature5, 1), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Initialize index 1, including:
|
// Initialize index 1, including:
|
||||||
// signature4 in non-root and root,
|
// signature4 in non-root and root,
|
||||||
// extra entries
|
// extra entries
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((1, signature4, 1), &status)
|
.put_protobuf((1, signature4, 1), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((1, signature4, 2), &status)
|
.put_protobuf((1, signature4, 2), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((1, signature5, 0), &status)
|
.put_protobuf((1, signature5, 0), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put((1, signature5, 1), &status)
|
.put_protobuf((1, signature5, 1), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
blockstore.set_roots(&[2]).unwrap();
|
blockstore.set_roots(&[2]).unwrap();
|
||||||
|
@ -6280,11 +6305,7 @@ pub mod tests {
|
||||||
let pre_token_balances = Some(vec![]);
|
let pre_token_balances = Some(vec![]);
|
||||||
let post_token_balances = Some(vec![]);
|
let post_token_balances = Some(vec![]);
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
blockstore
|
let status = TransactionStatusMeta {
|
||||||
.transaction_status_cf
|
|
||||||
.put(
|
|
||||||
(0, signature, slot),
|
|
||||||
&TransactionStatusMeta {
|
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances: pre_balances.clone(),
|
pre_balances: pre_balances.clone(),
|
||||||
|
@ -6293,8 +6314,11 @@ pub mod tests {
|
||||||
log_messages: log_messages.clone(),
|
log_messages: log_messages.clone(),
|
||||||
pre_token_balances: pre_token_balances.clone(),
|
pre_token_balances: pre_token_balances.clone(),
|
||||||
post_token_balances: post_token_balances.clone(),
|
post_token_balances: post_token_balances.clone(),
|
||||||
},
|
}
|
||||||
)
|
.into();
|
||||||
|
blockstore
|
||||||
|
.transaction_status_cf
|
||||||
|
.put_protobuf((0, signature, slot), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
TransactionWithStatusMeta {
|
TransactionWithStatusMeta {
|
||||||
transaction,
|
transaction,
|
||||||
|
@ -6366,7 +6390,7 @@ pub mod tests {
|
||||||
signature,
|
signature,
|
||||||
vec![&address0],
|
vec![&address0],
|
||||||
vec![&address1],
|
vec![&address1],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -6381,7 +6405,7 @@ pub mod tests {
|
||||||
signature,
|
signature,
|
||||||
vec![&address0],
|
vec![&address0],
|
||||||
vec![&address1],
|
vec![&address1],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -6474,7 +6498,7 @@ pub mod tests {
|
||||||
signature,
|
signature,
|
||||||
vec![&address0],
|
vec![&address0],
|
||||||
vec![&address1],
|
vec![&address1],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -6534,7 +6558,7 @@ pub mod tests {
|
||||||
transaction.signatures[0],
|
transaction.signatures[0],
|
||||||
transaction.message.account_keys.iter().collect(),
|
transaction.message.account_keys.iter().collect(),
|
||||||
vec![],
|
vec![],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -6740,10 +6764,7 @@ pub mod tests {
|
||||||
vec![solana_sdk::pubkey::new_rand()],
|
vec![solana_sdk::pubkey::new_rand()],
|
||||||
vec![CompiledInstruction::new(1, &(), vec![0])],
|
vec![CompiledInstruction::new(1, &(), vec![0])],
|
||||||
);
|
);
|
||||||
transaction_status_cf
|
let status = TransactionStatusMeta {
|
||||||
.put(
|
|
||||||
(0, transaction.signatures[0], slot),
|
|
||||||
&TransactionStatusMeta {
|
|
||||||
status: solana_sdk::transaction::Result::<()>::Err(
|
status: solana_sdk::transaction::Result::<()>::Err(
|
||||||
TransactionError::AccountNotFound,
|
TransactionError::AccountNotFound,
|
||||||
),
|
),
|
||||||
|
@ -6754,8 +6775,10 @@ pub mod tests {
|
||||||
log_messages: Some(vec![]),
|
log_messages: Some(vec![]),
|
||||||
pre_token_balances: Some(vec![]),
|
pre_token_balances: Some(vec![]),
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
},
|
}
|
||||||
)
|
.into();
|
||||||
|
transaction_status_cf
|
||||||
|
.put_protobuf((0, transaction.signatures[0], slot), &status)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
transactions.push(transaction);
|
transactions.push(transaction);
|
||||||
}
|
}
|
||||||
|
@ -7264,6 +7287,73 @@ pub mod tests {
|
||||||
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transaction_status_protobuf_backward_compatability() {
|
||||||
|
let blockstore_path = get_tmp_ledger_path!();
|
||||||
|
{
|
||||||
|
let blockstore = Blockstore::open(&blockstore_path).unwrap();
|
||||||
|
let status = TransactionStatusMeta {
|
||||||
|
status: Ok(()),
|
||||||
|
fee: 42,
|
||||||
|
pre_balances: vec![1, 2, 3],
|
||||||
|
post_balances: vec![1, 2, 3],
|
||||||
|
inner_instructions: Some(vec![]),
|
||||||
|
log_messages: Some(vec![]),
|
||||||
|
pre_token_balances: Some(vec![TransactionTokenBalance {
|
||||||
|
account_index: 0,
|
||||||
|
mint: Pubkey::new_unique().to_string(),
|
||||||
|
ui_token_amount: UiTokenAmount {
|
||||||
|
ui_amount: Some(1.1),
|
||||||
|
decimals: 1,
|
||||||
|
amount: "11".to_string(),
|
||||||
|
ui_amount_string: "1.1".to_string(),
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
post_token_balances: Some(vec![TransactionTokenBalance {
|
||||||
|
account_index: 0,
|
||||||
|
mint: Pubkey::new_unique().to_string(),
|
||||||
|
ui_token_amount: UiTokenAmount {
|
||||||
|
ui_amount: None,
|
||||||
|
decimals: 1,
|
||||||
|
amount: "11".to_string(),
|
||||||
|
ui_amount_string: "1.1".to_string(),
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
};
|
||||||
|
let deprecated_status: StoredTransactionStatusMeta = status.clone().into();
|
||||||
|
let protobuf_status: generated::TransactionStatusMeta = status.into();
|
||||||
|
|
||||||
|
for slot in 0..2 {
|
||||||
|
let data = serialize(&deprecated_status).unwrap();
|
||||||
|
blockstore
|
||||||
|
.transaction_status_cf
|
||||||
|
.put_bytes((0, Signature::default(), slot), &data)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
for slot in 2..4 {
|
||||||
|
blockstore
|
||||||
|
.transaction_status_cf
|
||||||
|
.put_protobuf((0, Signature::default(), slot), &protobuf_status)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
for slot in 0..4 {
|
||||||
|
assert_eq!(
|
||||||
|
blockstore
|
||||||
|
.transaction_status_cf
|
||||||
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
|
||||||
|
0,
|
||||||
|
Signature::default(),
|
||||||
|
slot
|
||||||
|
))
|
||||||
|
.unwrap()
|
||||||
|
.unwrap(),
|
||||||
|
protobuf_status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_remove_shred_data_complete_flag() {
|
fn test_remove_shred_data_complete_flag() {
|
||||||
let (mut shreds, entries) = make_slot_entries(0, 0, 1);
|
let (mut shreds, entries) = make_slot_entries(0, 0, 1);
|
||||||
|
|
|
@ -504,7 +504,7 @@ pub mod tests {
|
||||||
Signature::new(&random_bytes),
|
Signature::new(&random_bytes),
|
||||||
vec![&Pubkey::new(&random_bytes[0..32])],
|
vec![&Pubkey::new(&random_bytes[0..32])],
|
||||||
vec![&Pubkey::new(&random_bytes[32..])],
|
vec![&Pubkey::new(&random_bytes[32..])],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -519,7 +519,7 @@ pub mod tests {
|
||||||
Signature::new(&random_bytes),
|
Signature::new(&random_bytes),
|
||||||
vec![&Pubkey::new(&random_bytes[0..32])],
|
vec![&Pubkey::new(&random_bytes[0..32])],
|
||||||
vec![&Pubkey::new(&random_bytes[32..])],
|
vec![&Pubkey::new(&random_bytes[32..])],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -556,7 +556,7 @@ pub mod tests {
|
||||||
Signature::new(&random_bytes),
|
Signature::new(&random_bytes),
|
||||||
vec![&Pubkey::new(&random_bytes[0..32])],
|
vec![&Pubkey::new(&random_bytes[0..32])],
|
||||||
vec![&Pubkey::new(&random_bytes[32..])],
|
vec![&Pubkey::new(&random_bytes[32..])],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -745,7 +745,7 @@ pub mod tests {
|
||||||
signature,
|
signature,
|
||||||
vec![&Pubkey::new(&random_bytes[0..32])],
|
vec![&Pubkey::new(&random_bytes[0..32])],
|
||||||
vec![&Pubkey::new(&random_bytes[32..])],
|
vec![&Pubkey::new(&random_bytes[32..])],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -781,7 +781,7 @@ pub mod tests {
|
||||||
signature,
|
signature,
|
||||||
vec![&Pubkey::new(&random_bytes[0..32])],
|
vec![&Pubkey::new(&random_bytes[0..32])],
|
||||||
vec![&Pubkey::new(&random_bytes[32..])],
|
vec![&Pubkey::new(&random_bytes[32..])],
|
||||||
&TransactionStatusMeta::default(),
|
TransactionStatusMeta::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ use solana_sdk::{
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
};
|
};
|
||||||
use solana_storage_proto::convert::generated;
|
use solana_storage_proto::convert::generated;
|
||||||
use solana_transaction_status::TransactionStatusMeta;
|
|
||||||
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -418,10 +417,6 @@ pub trait TypedColumn: Column {
|
||||||
type Type: Serialize + DeserializeOwned;
|
type Type: Serialize + DeserializeOwned;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedColumn for columns::TransactionStatus {
|
|
||||||
type Type = TransactionStatusMeta;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypedColumn for columns::AddressSignatures {
|
impl TypedColumn for columns::AddressSignatures {
|
||||||
type Type = blockstore_meta::AddressSignatureMeta;
|
type Type = blockstore_meta::AddressSignatureMeta;
|
||||||
}
|
}
|
||||||
|
@ -492,6 +487,9 @@ impl Column for columns::TransactionStatus {
|
||||||
impl ColumnName for columns::TransactionStatus {
|
impl ColumnName for columns::TransactionStatus {
|
||||||
const NAME: &'static str = TRANSACTION_STATUS_CF;
|
const NAME: &'static str = TRANSACTION_STATUS_CF;
|
||||||
}
|
}
|
||||||
|
impl ProtobufColumn for columns::TransactionStatus {
|
||||||
|
type Type = generated::TransactionStatusMeta;
|
||||||
|
}
|
||||||
|
|
||||||
impl Column for columns::AddressSignatures {
|
impl Column for columns::AddressSignatures {
|
||||||
type Index = (u64, Pubkey, Slot, Signature);
|
type Index = (u64, Pubkey, Slot, Signature);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::StoredExtendedRewards;
|
use crate::{StoredExtendedRewards, StoredTransactionStatusMeta};
|
||||||
use solana_account_decoder::parse_token::{real_number_string_trimmed, UiTokenAmount};
|
use solana_account_decoder::parse_token::{real_number_string_trimmed, UiTokenAmount};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
|
@ -312,6 +312,13 @@ impl From<TransactionStatusMeta> for generated::TransactionStatusMeta {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<StoredTransactionStatusMeta> for generated::TransactionStatusMeta {
|
||||||
|
fn from(meta: StoredTransactionStatusMeta) -> Self {
|
||||||
|
let meta: TransactionStatusMeta = meta.into();
|
||||||
|
meta.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
|
impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
|
||||||
type Error = bincode::Error;
|
type Error = bincode::Error;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::deserialize_utils::default_on_eof;
|
use solana_account_decoder::{
|
||||||
use solana_transaction_status::{Reward, RewardType};
|
parse_token::{real_number_string_trimmed, UiTokenAmount},
|
||||||
|
StringAmount,
|
||||||
|
};
|
||||||
|
use solana_sdk::{deserialize_utils::default_on_eof, transaction::Result};
|
||||||
|
use solana_transaction_status::{
|
||||||
|
InnerInstructions, Reward, RewardType, TransactionStatusMeta, TransactionTokenBalance,
|
||||||
|
};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub mod convert;
|
pub mod convert;
|
||||||
|
|
||||||
|
@ -50,3 +57,151 @@ impl From<Reward> for StoredExtendedReward {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct StoredTokenAmount {
|
||||||
|
pub ui_amount: f64,
|
||||||
|
pub decimals: u8,
|
||||||
|
pub amount: StringAmount,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StoredTokenAmount> for UiTokenAmount {
|
||||||
|
fn from(value: StoredTokenAmount) -> Self {
|
||||||
|
let StoredTokenAmount {
|
||||||
|
ui_amount,
|
||||||
|
decimals,
|
||||||
|
amount,
|
||||||
|
} = value;
|
||||||
|
let ui_amount_string =
|
||||||
|
real_number_string_trimmed(u64::from_str(&amount).unwrap_or(0), decimals);
|
||||||
|
Self {
|
||||||
|
ui_amount: Some(ui_amount),
|
||||||
|
decimals,
|
||||||
|
amount,
|
||||||
|
ui_amount_string,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UiTokenAmount> for StoredTokenAmount {
|
||||||
|
fn from(value: UiTokenAmount) -> Self {
|
||||||
|
let UiTokenAmount {
|
||||||
|
ui_amount,
|
||||||
|
decimals,
|
||||||
|
amount,
|
||||||
|
..
|
||||||
|
} = value;
|
||||||
|
Self {
|
||||||
|
ui_amount: ui_amount.unwrap_or(0.0),
|
||||||
|
decimals,
|
||||||
|
amount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct StoredTransactionTokenBalance {
|
||||||
|
pub account_index: u8,
|
||||||
|
pub mint: String,
|
||||||
|
pub ui_token_amount: StoredTokenAmount,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StoredTransactionTokenBalance> for TransactionTokenBalance {
|
||||||
|
fn from(value: StoredTransactionTokenBalance) -> Self {
|
||||||
|
let StoredTransactionTokenBalance {
|
||||||
|
account_index,
|
||||||
|
mint,
|
||||||
|
ui_token_amount,
|
||||||
|
} = value;
|
||||||
|
Self {
|
||||||
|
account_index,
|
||||||
|
mint,
|
||||||
|
ui_token_amount: ui_token_amount.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TransactionTokenBalance> for StoredTransactionTokenBalance {
|
||||||
|
fn from(value: TransactionTokenBalance) -> Self {
|
||||||
|
let TransactionTokenBalance {
|
||||||
|
account_index,
|
||||||
|
mint,
|
||||||
|
ui_token_amount,
|
||||||
|
} = value;
|
||||||
|
Self {
|
||||||
|
account_index,
|
||||||
|
mint,
|
||||||
|
ui_token_amount: ui_token_amount.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct StoredTransactionStatusMeta {
|
||||||
|
pub status: Result<()>,
|
||||||
|
pub fee: u64,
|
||||||
|
pub pre_balances: Vec<u64>,
|
||||||
|
pub post_balances: Vec<u64>,
|
||||||
|
#[serde(deserialize_with = "default_on_eof")]
|
||||||
|
pub inner_instructions: Option<Vec<InnerInstructions>>,
|
||||||
|
#[serde(deserialize_with = "default_on_eof")]
|
||||||
|
pub log_messages: Option<Vec<String>>,
|
||||||
|
#[serde(deserialize_with = "default_on_eof")]
|
||||||
|
pub pre_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
|
||||||
|
#[serde(deserialize_with = "default_on_eof")]
|
||||||
|
pub post_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StoredTransactionStatusMeta> for TransactionStatusMeta {
|
||||||
|
fn from(value: StoredTransactionStatusMeta) -> Self {
|
||||||
|
let StoredTransactionStatusMeta {
|
||||||
|
status,
|
||||||
|
fee,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
inner_instructions,
|
||||||
|
log_messages,
|
||||||
|
pre_token_balances,
|
||||||
|
post_token_balances,
|
||||||
|
} = value;
|
||||||
|
Self {
|
||||||
|
status,
|
||||||
|
fee,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
inner_instructions,
|
||||||
|
log_messages,
|
||||||
|
pre_token_balances: pre_token_balances
|
||||||
|
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
|
||||||
|
post_token_balances: post_token_balances
|
||||||
|
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TransactionStatusMeta> for StoredTransactionStatusMeta {
|
||||||
|
fn from(value: TransactionStatusMeta) -> Self {
|
||||||
|
let TransactionStatusMeta {
|
||||||
|
status,
|
||||||
|
fee,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
inner_instructions,
|
||||||
|
log_messages,
|
||||||
|
pre_token_balances,
|
||||||
|
post_token_balances,
|
||||||
|
} = value;
|
||||||
|
Self {
|
||||||
|
status,
|
||||||
|
fee,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
inner_instructions,
|
||||||
|
log_messages,
|
||||||
|
pre_token_balances: pre_token_balances
|
||||||
|
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
|
||||||
|
post_token_balances: post_token_balances
|
||||||
|
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue