Add blockstore skipped api (#14145)
* Add blockstore api to determine if a slot was skipped * Return custom rpc error if slot is skipped
This commit is contained in:
parent
636a455790
commit
ac0d32bc7e
|
@ -10,6 +10,7 @@ pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: i64
|
||||||
pub const JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: i64 = -32004;
|
pub const JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: i64 = -32004;
|
||||||
pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY: i64 = -32005;
|
pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY: i64 = -32005;
|
||||||
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64 = -32006;
|
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64 = -32006;
|
||||||
|
pub const JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: i64 = -32007;
|
||||||
|
|
||||||
pub enum RpcCustomError {
|
pub enum RpcCustomError {
|
||||||
BlockCleanedUp {
|
BlockCleanedUp {
|
||||||
|
@ -26,6 +27,9 @@ pub enum RpcCustomError {
|
||||||
},
|
},
|
||||||
RpcNodeUnhealthy,
|
RpcNodeUnhealthy,
|
||||||
TransactionPrecompileVerificationFailure(solana_sdk::transaction::TransactionError),
|
TransactionPrecompileVerificationFailure(solana_sdk::transaction::TransactionError),
|
||||||
|
SlotSkipped {
|
||||||
|
slot: Slot,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RpcCustomError> for Error {
|
impl From<RpcCustomError> for Error {
|
||||||
|
@ -73,6 +77,14 @@ impl From<RpcCustomError> for Error {
|
||||||
message: format!("Transaction precompile verification failure {:?}", e),
|
message: format!("Transaction precompile verification failure {:?}", e),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
|
RpcCustomError::SlotSkipped { slot } => Self {
|
||||||
|
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_SLOT_SKIPPED),
|
||||||
|
message: format!(
|
||||||
|
"Slot {} was skipped, or missing due to ledger jump to recent snapshot",
|
||||||
|
slot
|
||||||
|
),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -601,7 +601,7 @@ impl JsonRpcRequestProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_blockstore_max_root<T>(
|
fn check_blockstore_root<T>(
|
||||||
&self,
|
&self,
|
||||||
result: &std::result::Result<T, BlockstoreError>,
|
result: &std::result::Result<T, BlockstoreError>,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
|
@ -612,7 +612,7 @@ impl JsonRpcRequestProcessor {
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
let err = result.as_ref().unwrap_err();
|
let err = result.as_ref().unwrap_err();
|
||||||
debug!(
|
debug!(
|
||||||
"check_blockstore_max_root, slot: {:?}, max root: {:?}, err: {:?}",
|
"check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?}",
|
||||||
slot,
|
slot,
|
||||||
self.blockstore.max_root(),
|
self.blockstore.max_root(),
|
||||||
err
|
err
|
||||||
|
@ -620,6 +620,9 @@ impl JsonRpcRequestProcessor {
|
||||||
if slot >= self.blockstore.max_root() {
|
if slot >= self.blockstore.max_root() {
|
||||||
return Err(RpcCustomError::BlockNotAvailable { slot }.into());
|
return Err(RpcCustomError::BlockNotAvailable { slot }.into());
|
||||||
}
|
}
|
||||||
|
if self.blockstore.is_skipped(slot) {
|
||||||
|
return Err(RpcCustomError::SlotSkipped { slot }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -662,7 +665,7 @@ impl JsonRpcRequestProcessor {
|
||||||
.highest_confirmed_root()
|
.highest_confirmed_root()
|
||||||
{
|
{
|
||||||
let result = self.blockstore.get_confirmed_block(slot);
|
let result = self.blockstore.get_confirmed_block(slot);
|
||||||
self.check_blockstore_max_root(&result, slot)?;
|
self.check_blockstore_root(&result, slot)?;
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
return Ok(self
|
return Ok(self
|
||||||
|
@ -768,7 +771,7 @@ impl JsonRpcRequestProcessor {
|
||||||
.highest_confirmed_root()
|
.highest_confirmed_root()
|
||||||
{
|
{
|
||||||
let result = self.blockstore.get_block_time(slot);
|
let result = self.blockstore.get_block_time(slot);
|
||||||
self.check_blockstore_max_root(&result, slot)?;
|
self.check_blockstore_root(&result, slot)?;
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||||
return Ok(self
|
return Ok(self
|
||||||
|
|
|
@ -2649,6 +2649,21 @@ impl Blockstore {
|
||||||
matches!(self.db.get::<cf::Root>(slot), Ok(Some(true)))
|
matches!(self.db.get::<cf::Root>(slot), Ok(Some(true)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if a slot is between the rooted slot bounds of the ledger, but has not itself
|
||||||
|
/// been rooted. This is either because the slot was skipped, or due to a gap in ledger data,
|
||||||
|
/// as when booting from a newer snapshot.
|
||||||
|
pub fn is_skipped(&self, slot: Slot) -> bool {
|
||||||
|
let lowest_root = self
|
||||||
|
.rooted_slot_iterator(0)
|
||||||
|
.ok()
|
||||||
|
.and_then(|mut iter| iter.next())
|
||||||
|
.unwrap_or_default();
|
||||||
|
match self.db.get::<cf::Root>(slot).ok().flatten() {
|
||||||
|
Some(_) => false,
|
||||||
|
None => slot < self.max_root() && slot > lowest_root,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_roots(&self, rooted_slots: &[u64]) -> Result<()> {
|
pub fn set_roots(&self, rooted_slots: &[u64]) -> Result<()> {
|
||||||
let mut write_batch = self.db.batch()?;
|
let mut write_batch = self.db.batch()?;
|
||||||
for slot in rooted_slots {
|
for slot in rooted_slots {
|
||||||
|
@ -5523,6 +5538,25 @@ pub mod tests {
|
||||||
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_skipped() {
|
||||||
|
let blockstore_path = get_tmp_ledger_path!();
|
||||||
|
let blockstore = Blockstore::open(&blockstore_path).unwrap();
|
||||||
|
let roots = vec![2, 4, 7, 12, 15];
|
||||||
|
blockstore.set_roots(&roots).unwrap();
|
||||||
|
|
||||||
|
for i in 0..20 {
|
||||||
|
if i < 2 || roots.contains(&i) || i > 15 {
|
||||||
|
assert!(!blockstore.is_skipped(i));
|
||||||
|
} else {
|
||||||
|
assert!(blockstore.is_skipped(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(blockstore);
|
||||||
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter_bounds() {
|
fn test_iter_bounds() {
|
||||||
let blockstore_path = get_tmp_ledger_path!();
|
let blockstore_path = get_tmp_ledger_path!();
|
||||||
|
|
Loading…
Reference in New Issue