Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i748 storage rent #749

Merged
merged 4 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading