use ergotree_interpreter::{eval::context::Context, sigma_protocol::prover::ProofBytes};
use ergotree_ir::chain::ergo_box::ErgoBox;
use ergotree_ir::{
chain::ergo_box::RegisterId, mir::constant::TryExtractInto, serialization::SigmaSerializable,
};
use crate::chain::ergo_state_context::ErgoStateContext;
use super::Input;
pub const STORAGE_PERIOD: u32 = 1051200;
pub const STORAGE_EXTENSION_INDEX: u8 = i8::MAX as u8;
pub(crate) fn try_spend_storage_rent(
input: &Input,
input_box: &ErgoBox,
state_context: &ErgoStateContext,
context: &Context,
) -> Option<()> {
if matches!(input.spending_proof.proof, ProofBytes::Empty) {
return check_storage_rent_conditions(input_box, state_context, context);
}
None
}
pub(crate) fn check_storage_rent_conditions(
input_box: &ErgoBox,
state_context: &ErgoStateContext,
context: &Context,
) -> Option<()> {
if context
.pre_header
.height
.checked_sub(context.self_box.creation_height)?
>= STORAGE_PERIOD
{
let output_idx: i16 = context
.extension
.values
.get(&STORAGE_EXTENSION_INDEX)?
.v
.clone()
.try_extract_into()
.ok()?;
let output_candidate = context.outputs.get(output_idx as usize)?;
let storage_fee = input_box.sigma_serialize_bytes().ok()?.len() as u64
* state_context.parameters.storage_fee_factor() as u64;
if context.self_box.value.as_u64() <= &storage_fee {
return Some(());
}
if output_candidate.creation_height != state_context.pre_header.height
|| *output_candidate.value.as_u64() < (context.self_box.value.as_u64() - storage_fee)
{
return None;
}
let registers_preserved =
(0..=9u8)
.map(RegisterId::try_from)
.map(Result::unwrap)
.all(|id| {
id == RegisterId::R0
|| id == RegisterId::R3
|| context.self_box.get_register(id) == output_candidate.get_register(id)
});
if registers_preserved {
return Some(());
}
}
None
}