Skip to content

Commit

Permalink
Merge pull request #749 from Alesfatalis/i748-storage-rent
Browse files Browse the repository at this point in the history
i748 storage rent
  • Loading branch information
SethDusek authored May 21, 2024
2 parents 2161dfb + beeb4b7 commit 79bf18e
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 18 deletions.
14 changes: 14 additions & 0 deletions bindings/ergo-lib-c-core/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ pub unsafe fn constant_value_to_dbg_str(constant_ptr: ConstConstantPtr) -> Resul
Ok(s)
}

/// Create from i16 value
pub unsafe fn constant_from_i16(value: i16, constant_out: *mut ConstantPtr) -> Result<(), Error> {
let constant_out = mut_ptr_as_mut(constant_out, "constant_out")?;
*constant_out = Box::into_raw(Box::new(Constant(value.into())));
Ok(())
}

/// Extract i16 value, returning error if wrong type
pub unsafe fn constant_to_i16(constant_ptr: ConstConstantPtr) -> Result<i16, Error> {
let constant = const_ptr_as_ref(constant_ptr, "constant_ptr")?;
let i = i16::try_extract_from(constant.0.clone())?;
Ok(i)
}

/// Create from i32 value
pub unsafe fn constant_from_i32(value: i32, constant_out: *mut ConstantPtr) -> Result<(), Error> {
let constant_out = mut_ptr_as_mut(constant_out, "constant_out")?;
Expand Down
35 changes: 34 additions & 1 deletion bindings/ergo-lib-c-core/src/context_extension.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::constant::{ConstConstantPtr, Constant, ConstantPtr};
use crate::{
util::{const_ptr_as_ref, mut_ptr_as_mut},
Error,
Expand Down Expand Up @@ -40,4 +41,36 @@ pub unsafe fn context_extension_keys(
Ok(())
}

// TODO: get method (needs Constant)
/// Get value for key or fail if key is missing
pub unsafe fn context_extension_get(
context_extension_ptr: ConstContextExtensionPtr,
key: u8,
constant_out: *mut ConstantPtr,
) -> Result<bool, Error> {
let context_extension = const_ptr_as_ref(context_extension_ptr, "context_extension_ptr")?;
let constant_out = mut_ptr_as_mut(constant_out, "constant_out")?;
let constant = context_extension
.0
.values
.get(&key)
.map(|c| Constant(c.clone()));

if let Some(constant) = constant {
*constant_out = Box::into_raw(Box::new(constant));
Ok(true)
} else {
Ok(false)
}
}

/// Set the supplied pair in the ContextExtension
pub unsafe fn context_extension_set_pair(
constant_ptr: ConstConstantPtr,
key: u8,
context_extension_ptr: ContextExtensionPtr,
) -> Result<(), Error> {
let constant = const_ptr_as_ref(constant_ptr, "constant_ptr")?;
let context_extension = mut_ptr_as_mut(context_extension_ptr, "context_extension_ptr")?;
context_extension.0.values.insert(key, constant.0.clone());
Ok(())
}
8 changes: 8 additions & 0 deletions bindings/ergo-lib-c-core/src/ergo_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use std::convert::{TryFrom, TryInto};

use ergo_lib::ergotree_ir::chain::{self, ergo_box::NonMandatoryRegisters};
use ergo_lib::ergotree_ir::serialization::SigmaSerializable;

use crate::{
collections::{CollectionPtr, ConstCollectionPtr},
Expand Down Expand Up @@ -326,6 +327,13 @@ pub unsafe fn ergo_box_to_json_eip12(ergo_box_ptr: ConstErgoBoxPtr) -> Result<St
Ok(s)
}

/// Calculate serialized box size(in bytes)
pub unsafe fn ergo_box_bytes_size(ergo_box_ptr: ConstErgoBoxPtr) -> Result<usize, Error> {
let ergo_box = const_ptr_as_ref(ergo_box_ptr, "ergo_box_ptr")?;
let b = ergo_box.0.sigma_serialize_bytes()?.len();
Ok(b)
}

/// Pair of <value, tokens> for a box
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ErgoBoxAssetsData(pub(crate) ergo_lib::wallet::box_selector::ErgoBoxAssetsData);
Expand Down
24 changes: 24 additions & 0 deletions bindings/ergo-lib-c/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,30 @@ pub unsafe extern "C" fn ergo_lib_constant_value_to_dbg_str(
Error::c_api_from(res)
}

/// Create from i16 value
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_constant_from_i16(value: i16, constant_out: *mut ConstantPtr) {
#[allow(clippy::unwrap_used)]
constant_from_i16(value, constant_out).unwrap();
}

/// Extract i16 value, returning error if wrong type
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_constant_to_i16(
constant_ptr: ConstConstantPtr,
) -> ReturnNum<i16> {
match constant_to_i16(constant_ptr) {
Ok(value) => ReturnNum {
value,
error: std::ptr::null_mut(),
},
Err(e) => ReturnNum {
value: 0, // Just a dummy value
error: Error::c_api_from(Err(e)),
},
}
}

/// Create from i32 value
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_constant_from_i32(value: i32, constant_out: *mut ConstantPtr) {
Expand Down
36 changes: 35 additions & 1 deletion bindings/ergo-lib-c/src/context_extension.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use ergo_lib_c_core::constant::{ConstConstantPtr, ConstantPtr};
use ergo_lib_c_core::context_extension::*;
use ergo_lib_c_core::Error;

use crate::delete_ptr;
use crate::{delete_ptr, ReturnOption};

/// Create new empty ContextExtension instance
#[no_mangle]
Expand Down Expand Up @@ -30,6 +32,38 @@ pub unsafe extern "C" fn ergo_lib_context_extension_keys(
context_extension_keys(context_extension_ptr, output).unwrap();
}

/// Returns constant with given key
/// or None if key doesn't exist
/// or error if constants parsing were failed
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_context_extension_get(
context_extension_ptr: ConstContextExtensionPtr,
key: u8,
constant_out: *mut ConstantPtr,
) -> ReturnOption {
match context_extension_get(context_extension_ptr, key, constant_out) {
Ok(is_some) => ReturnOption {
is_some,
error: std::ptr::null_mut(),
},
Err(e) => ReturnOption {
is_some: false, // Just a dummy value
error: Error::c_api_from(Err(e)),
},
}
}

/// Set the supplied pair in the ContextExtension
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_context_extension_set_pair(
constant_ptr: ConstConstantPtr,
key: u8,
context_extension_ptr: ContextExtensionPtr,
) {
#[allow(clippy::unwrap_used)]
context_extension_set_pair(constant_ptr, key, context_extension_ptr).unwrap()
}

/// Drop `ContextExtension`
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_context_extension_delete(ptr: ContextExtensionPtr) {
Expand Down
7 changes: 7 additions & 0 deletions bindings/ergo-lib-c/src/ergo_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,13 @@ pub unsafe extern "C" fn ergo_lib_ergo_box_to_json_eip12(
Error::c_api_from(res)
}

/// Calculate serialized box size(in bytes)
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_ergo_box_bytes_size(ergo_box_ptr: ConstErgoBoxPtr) -> usize {
#[allow(clippy::unwrap_used)]
ergo_box_bytes_size(ergo_box_ptr).unwrap()
}

/// Drop `ErgoBox`
#[no_mangle]
pub unsafe extern "C" fn ergo_lib_ergo_box_delete(ptr: ErgoBoxPtr) {
Expand Down
1 change: 1 addition & 0 deletions bindings/ergo-lib-c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ pub unsafe fn delete_ptr<T>(ptr: *mut T) {
pub trait IntegerType {}

impl IntegerType for u8 {}
impl IntegerType for i16 {}
impl IntegerType for i32 {}
impl IntegerType for u32 {}
impl IntegerType for i64 {}
Expand Down
2 changes: 1 addition & 1 deletion ergo-lib/src/chain/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ pub fn verify_tx_input_proof(
let ctx = Rc::new(make_context(state_context, tx_context, input_idx)?);
let verifier = TestVerifier;
// Try spending in storage rent, if any condition is not satisfied fallback to normal script validation
match try_spend_storage_rent(input, state_context, &ctx) {
match try_spend_storage_rent(input, &input_box, state_context, &ctx) {
Some(()) => Ok(VerificationResult {
result: true,
cost: 0,
Expand Down
21 changes: 17 additions & 4 deletions ergo-lib/src/chain/transaction/storage_rent.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
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,
};
Expand All @@ -14,7 +15,20 @@ pub const STORAGE_EXTENSION_INDEX: u8 = i8::MAX as u8;

// Attempt to spend a box with storage rent. Returns None if any of the required conditions is not met
pub(crate) fn try_spend_storage_rent(
input_box: &Input,
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
}

// Checks if storage rent conditions are met. Returns None if any of the required conditions is not met
pub(crate) fn check_storage_rent_conditions(
input_box: &ErgoBox,
state_context: &ErgoStateContext,
context: &Context,
) -> Option<()> {
Expand All @@ -23,7 +37,6 @@ pub(crate) fn try_spend_storage_rent(
.height
.checked_sub(context.self_box.creation_height)?
>= STORAGE_PERIOD
&& matches!(input_box.spending_proof.proof, ProofBytes::Empty)
{
let output_idx: i16 = context
.extension
Expand All @@ -33,16 +46,16 @@ pub(crate) fn try_spend_storage_rent(
.clone()
.try_extract_into()
.ok()?;
let output_candidate = context.outputs.get(output_idx as usize)?;

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 the box's value is less than the required storage fee, the box can be spent without any further restrictions
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
|| *output_candidate.value.as_u64() < (context.self_box.value.as_u64() - storage_fee)
{
return None;
}
Expand Down
36 changes: 25 additions & 11 deletions ergo-lib/src/wallet/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
use std::rc::Rc;
use std::sync::Arc;

use crate::chain::transaction::storage_rent::check_storage_rent_conditions;
use crate::wallet::multi_sig::TransactionHintsBag;
use ergotree_interpreter::eval::context::Context;
use ergotree_interpreter::eval::env::Env;
use ergotree_interpreter::sigma_protocol::prover::Prover;
use ergotree_interpreter::sigma_protocol::prover::ProverError;
use ergotree_interpreter::sigma_protocol::prover::ProverResult;
use ergotree_interpreter::sigma_protocol::prover::{ProofBytes, Prover};
use thiserror::Error;

pub use super::tx_context::TransactionContext;
Expand Down Expand Up @@ -202,16 +203,29 @@ pub fn sign_tx_input(
if let Some(bag) = tx_hints {
hints_bag = bag.all_hints_for_input(input_idx);
}
prover
.prove(
&input_box.ergo_tree,
&Env::empty(),
ctx,
message_to_sign,
&hints_bag,
)
.map(|proof| Input::new(unsigned_input.box_id, proof.into()))
.map_err(|e| TxSigningError::ProverError(e, input_idx))

match check_storage_rent_conditions(&input_box, state_context, &ctx.clone()) {
// if input is storage rent set ProofBytes to empty because no proof is needed
Some(()) => Ok(Input::new(
unsigned_input.box_id,
ProverResult {
proof: ProofBytes::Empty,
extension: ctx.extension.clone(),
}
.into(),
)),
// if input is not storage rent use prover
None => prover
.prove(
&input_box.ergo_tree,
&Env::empty(),
ctx.clone(),
message_to_sign,
&hints_bag,
)
.map(|proof| Input::new(unsigned_input.box_id, proof.into()))
.map_err(|e| TxSigningError::ProverError(e, input_idx)),
}
}

#[cfg(test)]
Expand Down

0 comments on commit 79bf18e

Please sign in to comment.