diff --git a/massa-db-exports/src/constants.rs b/massa-db-exports/src/constants.rs index 771807b4a2f..b763a095174 100644 --- a/massa-db-exports/src/constants.rs +++ b/massa-db-exports/src/constants.rs @@ -61,3 +61,6 @@ pub const KEY_LEN_SER_ERROR: &str = "critical: key length serialization failed"; // deferred calls pub const DEFERRED_CALL_DESER_ERROR: &str = "critical: message deserialization failed"; pub const DEFERRED_CALL_SER_ERROR: &str = "critical: message serialization failed"; +pub const DEFERRED_CALL_TOTAL_GAS: &str = "deferred_call_total_gas"; + +pub const DEFERRED_CALL_TOTAL_REGISTERED: &str = "deferred_call_total_registered"; diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 99b11b8a717..24334d71d76 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -156,12 +156,12 @@ impl Serializer for DeferredCallSerializer { #[derive(Clone)] pub struct DeferredCallDeserializer { slot_deserializer: SlotDeserializer, - address_deserializer: AddressDeserializer, - string_deserializer: StringDeserializer, - vec_u8_deserializer: VecU8Deserializer, + pub(crate) address_deserializer: AddressDeserializer, + pub(crate) string_deserializer: StringDeserializer, + pub(crate) vec_u8_deserializer: VecU8Deserializer, pub(crate) amount_deserializer: AmountDeserializer, pub(crate) u64_var_int_deserializer: U64VarIntDeserializer, - bool_deserializer: BoolDeserializer, + pub(crate) bool_deserializer: BoolDeserializer, } impl DeferredCallDeserializer { diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index d6098aee8d9..7df2a19db8d 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,11 +1,17 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; use config::DeferredCallsConfig; -use macros::{DEFERRED_CALL_TOTAL_GAS, DEFERRED_CALL_TOTAL_REGISTERED}; +use macros::{ + CALL_FIELD_CANCELED, CALL_FIELD_COINS, CALL_FIELD_FEE, CALL_FIELD_MAX_GAS, + CALL_FIELD_PARAMETERS, CALL_FIELD_SENDER_ADDRESS, CALL_FIELD_TARGET_ADDRESS, + CALL_FIELD_TARGET_FUNCTION, CALL_FIELD_TARGET_SLOT, +}; use massa_db_exports::{ DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_PREFIX, - DEFERRED_CALL_DESER_ERROR, DEFERRED_CALL_SER_ERROR, KEY_DESER_ERROR, STATE_CF, + DEFERRED_CALL_DESER_ERROR, DEFERRED_CALL_SER_ERROR, DEFERRED_CALL_TOTAL_GAS, + DEFERRED_CALL_TOTAL_REGISTERED, KEY_DESER_ERROR, STATE_CF, }; -use massa_serialization::{DeserializeError, Deserializer, Serializer}; +use massa_models::address::Address; +use massa_serialization::{buf_to_array_ctr, DeserializeError, Deserializer, Serializer}; use registry_changes::{ DeferredCallRegistryChanges, DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, @@ -434,6 +440,128 @@ impl DeferredCallRegistry { DeferredRegistryGasChange::Keep => {} } } + + pub fn is_key_value_valid(&self, serialized_key: &[u8], serialized_value: &[u8]) -> bool { + if serialized_key.starts_with(DEFERRED_CALLS_PREFIX.as_bytes()) { + // check for [DEFERRED_CALLS_PREFIX][slot] + if let Some((_rest, slot)) = buf_to_array_ctr( + &serialized_key[DEFERRED_CALLS_PREFIX.len()..], + Slot::from_bytes_key, + ) { + // check for [DEFERRED_CALLS_PREFIX][slot][SLOT_TOTAL_GAS] + if serialized_key + .starts_with(&deferred_call_slot_total_gas_key!(&slot.to_bytes_key())) + { + return self + .call_deserializer + .u64_var_int_deserializer + .deserialize::(serialized_value) + .is_ok(); + } else if serialized_key + .starts_with(&deferred_call_slot_base_fee_key!(&slot.to_bytes_key())) + { + // check for [DEFERRED_CALLS_PREFIX][slot][SLOT_BASE_FEE] + return self + .call_deserializer + .amount_deserializer + .deserialize::(serialized_value) + .is_ok(); + } else { + // check for [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] + + // [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG] + let k = deferred_slot_call_prefix_key!(&slot.to_bytes_key()); + let rest_key = &serialized_key[k.len()..]; + + if let Ok((rest, _id)) = self + .call_id_deserializer + .deserialize::(rest_key) + { + match rest[0] { + CALL_FIELD_SENDER_ADDRESS => { + let res: Result<(&[u8], Address), nom::Err>> = + self.call_deserializer + .address_deserializer + .deserialize::(serialized_value); + + return res.is_ok(); + } + CALL_FIELD_TARGET_SLOT => { + return self + .registry_changes_deserializer + .slot_deserializer + .deserialize::(serialized_value) + .is_ok() + } + CALL_FIELD_TARGET_ADDRESS => { + let res: Result<(&[u8], Address), nom::Err>> = + self.call_deserializer + .address_deserializer + .deserialize::(serialized_value); + return res.is_ok(); + } + CALL_FIELD_TARGET_FUNCTION => { + return self + .call_deserializer + .string_deserializer + .deserialize::(serialized_value) + .is_ok() + } + CALL_FIELD_PARAMETERS => { + return self + .call_deserializer + .vec_u8_deserializer + .deserialize::(serialized_value) + .is_ok() + } + CALL_FIELD_MAX_GAS => { + return self + .call_deserializer + .u64_var_int_deserializer + .deserialize::(serialized_value) + .is_ok() + } + CALL_FIELD_FEE => { + return self + .call_deserializer + .amount_deserializer + .deserialize::(serialized_value) + .is_ok() + } + CALL_FIELD_CANCELED => { + return self + .call_deserializer + .bool_deserializer + .deserialize::(serialized_value) + .is_ok(); + } + CALL_FIELD_COINS => { + return self + .call_deserializer + .amount_deserializer + .deserialize::(serialized_value) + .is_ok(); + } + _ => {} + } + } + } + } + } else if serialized_key.eq(DEFERRED_CALL_TOTAL_GAS.as_bytes()) { + return self + .registry_changes_deserializer + .effective_total_gas_deserializer + .deserialize::(serialized_value) + .is_ok(); + } else if serialized_key.eq(DEFERRED_CALL_TOTAL_REGISTERED.as_bytes()) { + return self + .registry_changes_deserializer + .total_calls_registered_deserializer + .deserialize::(serialized_value) + .is_ok(); + } + false + } } pub type DeferredRegistryCallChange = SetOrDelete; diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs index 93b902b9760..5080a7c669f 100644 --- a/massa-deferred-calls/src/macros.rs +++ b/massa-deferred-calls/src/macros.rs @@ -1,7 +1,3 @@ -pub(crate) const DEFERRED_CALL_TOTAL_GAS: &str = "deferred_call_total_gas"; - -pub(crate) const DEFERRED_CALL_TOTAL_REGISTERED: &str = "deferred_call_total_registered"; - pub(crate) const CALLS_TAG: u8 = 0u8; // slot fields pub(crate) const SLOT_TOTAL_GAS: u8 = 1u8; diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index c6475df304f..8d80ae4aa06 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -176,7 +176,7 @@ impl Serializer for DeferredRegistryChangesSerializ pub struct DeferredRegistryChangesDeserializer { pub(crate) u64_deserializer: U64VarIntDeserializer, slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, - slot_deserializer: SlotDeserializer, + pub(crate) slot_deserializer: SlotDeserializer, pub(crate) effective_total_gas_deserializer: SetOrKeepDeserializer, pub(crate) total_calls_registered_deserializer: diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index faf31b34953..ba38dd34e2b 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -12,7 +12,8 @@ use anyhow::{anyhow, Result as AnyResult}; use massa_async_pool::AsyncPool; use massa_db_exports::{ DBBatch, MassaIteratorMode, ShareableMassaDBController, ASYNC_POOL_PREFIX, - CYCLE_HISTORY_PREFIX, DEFERRED_CREDITS_PREFIX, EXECUTED_DENUNCIATIONS_PREFIX, + CYCLE_HISTORY_PREFIX, DEFERRED_CALLS_PREFIX, DEFERRED_CALL_TOTAL_GAS, + DEFERRED_CALL_TOTAL_REGISTERED, DEFERRED_CREDITS_PREFIX, EXECUTED_DENUNCIATIONS_PREFIX, EXECUTED_OPS_PREFIX, LEDGER_PREFIX, MIP_STORE_PREFIX, STATE_CF, }; use massa_db_exports::{EXECUTION_TRAIL_HASH_PREFIX, MIP_STORE_STATS_PREFIX, VERSIONING_CF}; @@ -657,6 +658,20 @@ impl FinalState { } } else if serialized_key.starts_with(EXECUTION_TRAIL_HASH_PREFIX.as_bytes()) { // no checks here as they are performed above by direct reading + } else if serialized_key.starts_with(DEFERRED_CALLS_PREFIX.as_bytes()) + || serialized_key.eq(DEFERRED_CALL_TOTAL_GAS.as_bytes()) + || serialized_key.eq(DEFERRED_CALL_TOTAL_REGISTERED.as_bytes()) + { + if !self + .deferred_call_registry + .is_key_value_valid(&serialized_key, &serialized_value) + { + warn!("Wrong key/value for DEFERRED_CALLS_PREFIX serialized_key: {:?}, serialized_value: {:?}", serialized_key, serialized_value); + return Err(anyhow!( + "Wrong key/value for DEFERRED_CALLS_PREFIX serialized_key: {:?}, serialized_value: {:?}", + serialized_key, serialized_value + )); + } } else { warn!( "Key/value does not correspond to any prefix: serialized_key: {:?}, serialized_value: {:?}", diff --git a/massa-pos-exports/src/pos_final_state.rs b/massa-pos-exports/src/pos_final_state.rs index c7c336edd35..ccaf20cdf33 100644 --- a/massa-pos-exports/src/pos_final_state.rs +++ b/massa-pos-exports/src/pos_final_state.rs @@ -13,7 +13,9 @@ use massa_db_exports::{ use massa_hash::{Hash, HashXof, HASH_XOF_SIZE_BYTES}; use massa_models::amount::Amount; use massa_models::{address::Address, prehash::PreHashMap, slot::Slot}; -use massa_serialization::{DeserializeError, Deserializer, Serializer, U64VarIntSerializer}; +use massa_serialization::{ + buf_to_array_ctr, DeserializeError, Deserializer, Serializer, U64VarIntSerializer, +}; use nom::AsBytes; use std::collections::VecDeque; use std::ops::Bound::{Excluded, Included, Unbounded}; @@ -21,15 +23,6 @@ use std::ops::RangeBounds; use std::{collections::BTreeMap, path::PathBuf}; use tracing::debug; -// Helper function to convert a slice to an array of a given size, if possible, -// and then returning it with the rest of the slice. -fn buf_to_array_ctr V, V, const N: usize>( - buf: &[u8], - ctr: F, -) -> Option<(&[u8], V)> { - Some((&buf[N..], ctr(&buf.get(..N)?.try_into().ok()?))) -} - // General cycle info idents const COMPLETE_IDENT: u8 = 0u8; const RNG_SEED_IDENT: u8 = 1u8; diff --git a/massa-serialization/src/lib.rs b/massa-serialization/src/lib.rs index 5d06985663c..faeb73fd95f 100644 --- a/massa-serialization/src/lib.rs +++ b/massa-serialization/src/lib.rs @@ -481,6 +481,15 @@ where } } +// Helper function to convert a slice to an array of a given size, if possible, +// and then returning it with the rest of the slice. +pub fn buf_to_array_ctr V, V, const N: usize>( + buf: &[u8], + ctr: F, +) -> Option<(&[u8], V)> { + Some((&buf[N..], ctr(&buf.get(..N)?.try_into().ok()?))) +} + #[cfg(test)] mod tests { use crate::{DeserializeError, Deserializer, Serializer};