From 4b85de9dfad50adef77a99cbcc018bea6f9cbd19 Mon Sep 17 00:00:00 2001 From: Kamal Ahmad Date: Wed, 10 Apr 2024 02:55:40 +0500 Subject: [PATCH 1/6] Arcanize interpreter + Re-use context in validation This change reworks how ergotree-interpreter stores data and reduces cloning/heap allocations significantly. Variables can now borrow from their context instead of cloning. Instead of deep-copying types repeatedly we wrap types in Arc. Also optimized certain interpreter ops like Coll.length --- bindings/ergo-lib-wasm/src/ast/js_conv.rs | 6 +- ergo-lib/src/chain/json/context_extension.rs | 6 +- ergo-lib/src/chain/transaction.rs | 14 +- .../src/chain/transaction/ergo_transaction.rs | 25 +- ergo-lib/src/chain/transaction/reduced.rs | 8 +- ergo-lib/src/chain/transaction/unsigned.rs | 20 + ergo-lib/src/lib.rs | 2 +- ergo-lib/src/wallet.rs | 5 + ergo-lib/src/wallet/multi_sig.rs | 349 ++++-------------- ergo-lib/src/wallet/signing.rs | 114 +++--- ergo-lib/src/wallet/tx_context.rs | 8 +- ergotree-interpreter/src/eval.rs | 102 +++-- ergotree-interpreter/src/eval/and.rs | 14 +- ergotree-interpreter/src/eval/apply.rs | 24 +- ergotree-interpreter/src/eval/atleast.rs | 23 +- ergotree-interpreter/src/eval/bin_op.rs | 87 ++--- .../src/eval/bit_inversion.rs | 10 +- ergotree-interpreter/src/eval/block.rs | 8 +- .../src/eval/bool_to_sigma.rs | 8 +- .../src/eval/byte_array_to_bigint.rs | 8 +- .../src/eval/byte_array_to_long.rs | 8 +- .../src/eval/calc_blake2b256.rs | 13 +- ergotree-interpreter/src/eval/calc_sha256.rs | 13 +- ergotree-interpreter/src/eval/coll_append.rs | 19 +- .../src/eval/coll_by_index.rs | 26 +- ergotree-interpreter/src/eval/coll_exists.rs | 12 +- ergotree-interpreter/src/eval/coll_filter.rs | 41 +- ergotree-interpreter/src/eval/coll_fold.rs | 15 +- ergotree-interpreter/src/eval/coll_forall.rs | 12 +- ergotree-interpreter/src/eval/coll_map.rs | 23 +- ergotree-interpreter/src/eval/coll_size.rs | 23 +- ergotree-interpreter/src/eval/coll_slice.rs | 12 +- ergotree-interpreter/src/eval/collection.rs | 17 +- ergotree-interpreter/src/eval/context.rs | 32 +- ergotree-interpreter/src/eval/cost_accum.rs | 2 + .../src/eval/create_avl_tree.rs | 8 +- .../src/eval/create_prove_dh_tuple.rs | 8 +- .../src/eval/create_provedlog.rs | 10 +- ergotree-interpreter/src/eval/decode_point.rs | 8 +- .../src/eval/deserialize_context.rs | 22 +- .../src/eval/deserialize_register.rs | 37 +- ergotree-interpreter/src/eval/downcast.rs | 8 +- ergotree-interpreter/src/eval/env.rs | 26 +- ergotree-interpreter/src/eval/error.rs | 18 +- ergotree-interpreter/src/eval/exponentiate.rs | 17 +- ergotree-interpreter/src/eval/expr.rs | 16 +- .../src/eval/extract_amount.rs | 16 +- .../src/eval/extract_bytes.rs | 13 +- .../src/eval/extract_bytes_with_no_ref.rs | 13 +- .../src/eval/extract_creation_info.rs | 13 +- ergotree-interpreter/src/eval/extract_id.rs | 13 +- .../src/eval/extract_reg_as.rs | 17 +- .../src/eval/extract_script_bytes.rs | 13 +- ergotree-interpreter/src/eval/func_value.rs | 8 +- ergotree-interpreter/src/eval/get_var.rs | 19 +- ergotree-interpreter/src/eval/global_vars.rs | 65 ++-- ergotree-interpreter/src/eval/if_op.rs | 8 +- ergotree-interpreter/src/eval/logical_not.rs | 8 +- .../src/eval/long_to_byte_array.rs | 8 +- ergotree-interpreter/src/eval/method_call.rs | 14 +- .../src/eval/multiply_group.rs | 19 +- ergotree-interpreter/src/eval/negation.rs | 16 +- ergotree-interpreter/src/eval/option_get.rs | 13 +- .../src/eval/option_get_or_else.rs | 17 +- .../src/eval/option_is_defined.rs | 13 +- ergotree-interpreter/src/eval/or.rs | 13 +- .../src/eval/property_call.rs | 18 +- ergotree-interpreter/src/eval/savltree.rs | 175 ++++----- ergotree-interpreter/src/eval/sbox.rs | 23 +- ergotree-interpreter/src/eval/scoll.rs | 58 +-- ergotree-interpreter/src/eval/scontext.rs | 65 ++-- ergotree-interpreter/src/eval/select_field.rs | 8 +- ergotree-interpreter/src/eval/sglobal.rs | 23 +- ergotree-interpreter/src/eval/sgroup_elem.rs | 5 +- ergotree-interpreter/src/eval/sheader.rs | 67 ++-- ergotree-interpreter/src/eval/sigma_and.rs | 13 +- ergotree-interpreter/src/eval/sigma_or.rs | 13 +- .../src/eval/sigma_prop_bytes.rs | 8 +- ergotree-interpreter/src/eval/soption.rs | 25 +- ergotree-interpreter/src/eval/spreheader.rs | 33 +- ergotree-interpreter/src/eval/subst_const.rs | 14 +- ergotree-interpreter/src/eval/tree_lookup.rs | 8 +- ergotree-interpreter/src/eval/tuple.rs | 8 +- ergotree-interpreter/src/eval/upcast.rs | 8 +- ergotree-interpreter/src/eval/val_use.rs | 8 +- ergotree-interpreter/src/eval/xor.rs | 46 +-- ergotree-interpreter/src/eval/xor_of.rs | 13 +- ergotree-interpreter/src/lib.rs | 2 +- .../src/sigma_protocol/prover.rs | 44 +-- .../src/sigma_protocol/verifier.rs | 72 ++-- ergotree-interpreter/src/util.rs | 19 - .../tests/signing_spec_tests.rs | 30 +- ergotree-ir/src/chain/address.rs | 3 +- ergotree-ir/src/chain/json/ergo_box.rs | 2 +- ergotree-ir/src/ergo_tree.rs | 3 +- ergotree-ir/src/lib.rs | 2 + ergotree-ir/src/mir.rs | 2 + ergotree-ir/src/mir/byte_array_to_bigint.rs | 4 +- ergotree-ir/src/mir/byte_array_to_long.rs | 4 +- ergotree-ir/src/mir/calc_blake2b256.rs | 8 +- ergotree-ir/src/mir/calc_sha256.rs | 8 +- ergotree-ir/src/mir/coll_by_index.rs | 14 +- ergotree-ir/src/mir/coll_exists.rs | 11 +- ergotree-ir/src/mir/coll_filter.rs | 13 +- ergotree-ir/src/mir/coll_fold.rs | 7 +- ergotree-ir/src/mir/coll_forall.rs | 11 +- ergotree-ir/src/mir/coll_map.rs | 18 +- ergotree-ir/src/mir/constant.rs | 129 ++++--- ergotree-ir/src/mir/create_avl_tree.rs | 6 +- ergotree-ir/src/mir/decode_point.rs | 4 +- ergotree-ir/src/mir/expr.rs | 11 +- ergotree-ir/src/mir/extract_reg_as.rs | 8 +- ergotree-ir/src/mir/global_vars.rs | 7 +- ergotree-ir/src/mir/option_get.rs | 8 +- ergotree-ir/src/mir/option_get_or_else.rs | 7 +- ergotree-ir/src/mir/tree_lookup.rs | 5 +- ergotree-ir/src/mir/value.rs | 237 ++++++++---- ergotree-ir/src/mir/xor.rs | 9 +- ergotree-ir/src/pretty_printer/print.rs | 2 +- ergotree-ir/src/reference.rs | 76 ++++ ergotree-ir/src/serialization/constant.rs | 3 +- ergotree-ir/src/serialization/data.rs | 18 +- ergotree-ir/src/types/savltree.rs | 40 +- ergotree-ir/src/types/sbox.rs | 5 +- ergotree-ir/src/types/scoll.rs | 3 +- ergotree-ir/src/types/sfunc.rs | 5 +- ergotree-ir/src/types/sgroup_elem.rs | 3 +- ergotree-ir/src/types/stuple.rs | 4 +- ergotree-ir/src/types/stype.rs | 23 +- ergotree-ir/src/types/type_unify.rs | 26 +- ergotree-ir/src/util.rs | 30 +- gf2_192/src/gf2_192.rs | 1 - sigma-util/src/vec_ext.rs | 19 + 133 files changed, 1748 insertions(+), 1463 deletions(-) delete mode 100644 ergotree-interpreter/src/util.rs create mode 100644 ergotree-ir/src/reference.rs diff --git a/bindings/ergo-lib-wasm/src/ast/js_conv.rs b/bindings/ergo-lib-wasm/src/ast/js_conv.rs index ef5d1a149..d80ccb1d1 100644 --- a/bindings/ergo-lib-wasm/src/ast/js_conv.rs +++ b/bindings/ergo-lib-wasm/src/ast/js_conv.rs @@ -66,7 +66,7 @@ pub(crate) fn constant_from_js(val: &JsValue) -> Result { Ok(Constant { tpe: SType::SColl(SType::SByte.into()), v: Literal::Coll(CollKind::NativeColl(NativeColl::CollByte( - bytes.to_vec().as_vec_i8(), + bytes.to_vec().as_vec_i8().into(), ))), }) } else if let Ok(arr) = val.clone().dyn_into::() { @@ -164,10 +164,10 @@ pub(crate) fn constant_to_js(c: Constant) -> Result { } Literal::Coll(CollKind::WrappedColl { elem_tpe, items }) => { let arr = Array::new(); - for item in items { + for item in items.iter() { arr.push(&constant_to_js(Constant { tpe: elem_tpe.clone(), - v: item, + v: item.clone(), })?); } arr.into() diff --git a/ergo-lib/src/chain/json/context_extension.rs b/ergo-lib/src/chain/json/context_extension.rs index f75411efc..4b74f6233 100644 --- a/ergo-lib/src/chain/json/context_extension.rs +++ b/ergo-lib/src/chain/json/context_extension.rs @@ -103,7 +103,7 @@ mod tests { ], "creationHeight" : 693475, "additionalRegisters" : { - + }, "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4", "index" : 0 @@ -116,7 +116,7 @@ mod tests { ], "creationHeight" : 693475, "additionalRegisters" : { - + }, "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4", "index" : 1 @@ -129,7 +129,7 @@ mod tests { ], "creationHeight" : 693475, "additionalRegisters" : { - + }, "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4", "index" : 2 diff --git a/ergo-lib/src/chain/transaction.rs b/ergo-lib/src/chain/transaction.rs index cbb4c2e15..adbb9ac16 100644 --- a/ergo-lib/src/chain/transaction.rs +++ b/ergo-lib/src/chain/transaction.rs @@ -9,6 +9,7 @@ pub mod unsigned; use bounded_vec::BoundedVec; use ergo_chain_types::blake2b256_hash; +use ergotree_interpreter::eval::context::Context; pub use ergotree_interpreter::eval::context::TxIoVec; use ergotree_interpreter::eval::env::Env; use ergotree_interpreter::eval::extract_sigma_boolean; @@ -38,6 +39,7 @@ use ergotree_ir::serialization::SigmaSerializeResult; pub use input::*; use crate::wallet::signing::make_context; +use crate::wallet::signing::update_context; use crate::wallet::signing::TransactionContext; use crate::wallet::tx_context::TransactionContextError; @@ -342,8 +344,9 @@ pub enum TransactionError { } /// Verify transaction input's proof -pub fn verify_tx_input_proof( - tx_context: &TransactionContext, +pub fn verify_tx_input_proof<'ctx>( + tx_context: &'ctx TransactionContext, + ctx: &mut Context<'ctx>, state_context: &ErgoStateContext, input_idx: usize, bytes_to_sign: &[u8], @@ -356,10 +359,10 @@ pub fn verify_tx_input_proof( let input_box = tx_context .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(input_idx))?; - let ctx = Rc::new(make_context(state_context, tx_context, input_idx)?); + update_context(ctx, 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, &input_box, state_context, &ctx) { + match try_spend_storage_rent(input, input_box, state_context, ctx) { Some(()) => Ok(VerificationResult { result: true, cost: 0, @@ -371,8 +374,7 @@ pub fn verify_tx_input_proof( None => verifier .verify( &input_box.ergo_tree, - &Env::empty(), - ctx, + &ctx, input.spending_proof.proof.clone(), bytes_to_sign, ) diff --git a/ergo-lib/src/chain/transaction/ergo_transaction.rs b/ergo-lib/src/chain/transaction/ergo_transaction.rs index c43a6e588..50de2682e 100644 --- a/ergo-lib/src/chain/transaction/ergo_transaction.rs +++ b/ergo-lib/src/chain/transaction/ergo_transaction.rs @@ -89,9 +89,9 @@ pub trait ErgoTransaction { /// input boxes ids fn inputs_ids(&self) -> TxIoVec; /// data input boxes - fn data_inputs(&self) -> Option>; + fn data_inputs(&self) -> Option<&[DataInput]>; /// output boxes - fn outputs(&self) -> TxIoVec; + fn outputs(&self) -> &[ErgoBox]; /// ContextExtension for the given input index fn context_extension(&self, input_index: usize) -> Option; @@ -121,17 +121,12 @@ impl ErgoTransaction for UnsignedTransaction { self.inputs.clone().mapped(|input| input.box_id) } - fn data_inputs(&self) -> Option> { - self.data_inputs.clone() + fn data_inputs(&self) -> Option<&[DataInput]> { + self.data_inputs.as_ref().map(|di| di.as_slice()) } - fn outputs(&self) -> TxIoVec { - #[allow(clippy::unwrap_used)] // box serialization cannot fail? - self.output_candidates - .clone() - .enumerated() - .try_mapped(|(idx, b)| ErgoBox::from_box_candidate(&b, self.id(), idx as u16)) - .unwrap() + fn outputs(&self) -> &[ErgoBox] { + self.outputs.as_slice() } fn context_extension(&self, input_index: usize) -> Option { @@ -146,12 +141,12 @@ impl ErgoTransaction for Transaction { self.inputs.clone().mapped(|input| input.box_id) } - fn data_inputs(&self) -> Option> { - self.data_inputs.clone() + fn data_inputs(&self) -> Option<&[DataInput]> { + self.data_inputs.as_ref().map(|di| di.as_slice()) } - fn outputs(&self) -> TxIoVec { - self.outputs.clone() + fn outputs(&self) -> &[ErgoBox] { + self.outputs.as_slice() } fn context_extension(&self, input_index: usize) -> Option { diff --git a/ergo-lib/src/chain/transaction/reduced.rs b/ergo-lib/src/chain/transaction/reduced.rs index ab7c84ffe..a145fe44b 100644 --- a/ergo-lib/src/chain/transaction/reduced.rs +++ b/ergo-lib/src/chain/transaction/reduced.rs @@ -1,9 +1,6 @@ //! Represent `reduced` transaction, i.e. unsigned transaction where each unsigned input //! is augmented with ReducedInput which contains a script reduction result. -use std::rc::Rc; - -use ergotree_interpreter::eval::env::Env; use ergotree_interpreter::eval::reduce_to_crypto; use ergotree_interpreter::sigma_protocol::prover::ContextExtension; use ergotree_interpreter::sigma_protocol::prover::ProverError; @@ -70,21 +67,22 @@ pub fn reduce_tx( state_context: &ErgoStateContext, ) -> Result { let tx = &tx_context.spending_tx; + let ctx = make_context(state_context, &tx_context, 0)?; let reduced_inputs = tx .inputs .clone() .enumerated() .try_mapped::<_, _, TxSigningError>(|(idx, input)| { + // TODO: use Context::with_self_box_index let input_box = tx_context .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(idx))?; - let ctx = Rc::new(make_context(state_context, &tx_context, idx)?); let expr = input_box .ergo_tree .proposition() .map_err(ProverError::ErgoTreeError) .map_err(|e| TxSigningError::ProverError(e, idx))?; - let reduction_result = reduce_to_crypto(&expr, &Env::empty(), ctx) + let reduction_result = reduce_to_crypto(&expr, &ctx) .map_err(ProverError::EvalError) .map_err(|e| TxSigningError::ProverError(e, idx))?; Ok(ReducedInput { diff --git a/ergo-lib/src/chain/transaction/unsigned.rs b/ergo-lib/src/chain/transaction/unsigned.rs index fbd298b3d..507287b57 100644 --- a/ergo-lib/src/chain/transaction/unsigned.rs +++ b/ergo-lib/src/chain/transaction/unsigned.rs @@ -9,6 +9,7 @@ use super::{distinct_token_ids, TransactionError}; use bounded_vec::BoundedVec; use ergo_chain_types::blake2b256_hash; +use ergotree_ir::chain::ergo_box::ErgoBox; use ergotree_ir::chain::ergo_box::ErgoBoxCandidate; use ergotree_ir::chain::token::TokenId; use ergotree_ir::chain::tx_id::TxId; @@ -36,6 +37,7 @@ pub struct UnsignedTransaction { pub data_inputs: Option>, /// box candidates to be created by this transaction pub output_candidates: TxIoVec, + pub(crate) outputs: TxIoVec, } impl UnsignedTransaction { @@ -63,15 +65,33 @@ impl UnsignedTransaction { data_inputs: Option>, output_candidates: TxIoVec, ) -> Result { + #[allow(clippy::unwrap_used)] // box serialization cannot fail + let outputs = output_candidates + .iter() + .enumerate() + .map(|(idx, b)| ErgoBox::from_box_candidate(b, TxId::zero(), idx as u16).unwrap()) + .collect::>() + .try_into() + .unwrap(); + let tx_to_sign = UnsignedTransaction { tx_id: TxId::zero(), inputs, data_inputs, output_candidates, + outputs, }; let tx_id = tx_to_sign.calc_tx_id()?; + + let outputs = tx_to_sign + .output_candidates + .clone() + .enumerated() + .try_mapped_ref(|(idx, bc)| ErgoBox::from_box_candidate(bc, tx_id, *idx as u16))?; + Ok(UnsignedTransaction { tx_id, + outputs, ..tx_to_sign }) } diff --git a/ergo-lib/src/lib.rs b/ergo-lib/src/lib.rs index a629bc845..68f3a4c96 100644 --- a/ergo-lib/src/lib.rs +++ b/ergo-lib/src/lib.rs @@ -7,7 +7,7 @@ #![deny(non_snake_case)] #![deny(unused_mut)] #![deny(dead_code)] -#![deny(unused_imports)] +//#![deny(unused_imports)] #![deny(missing_docs)] // Clippy exclusions #![allow(clippy::unit_arg)] diff --git a/ergo-lib/src/wallet.rs b/ergo-lib/src/wallet.rs index b0e1b9fd7..197e64dc7 100644 --- a/ergo-lib/src/wallet.rs +++ b/ergo-lib/src/wallet.rs @@ -35,6 +35,7 @@ use crate::wallet::multi_sig::{ use self::ext_secret_key::ExtSecretKey; use self::ext_secret_key::ExtSecretKeyError; +use self::signing::make_context; use self::signing::sign_message; use self::signing::sign_reduced_transaction; use self::signing::sign_tx_input; @@ -164,10 +165,14 @@ impl Wallet { ) -> Result { let tx = tx_context.spending_tx.clone(); let message_to_sign = tx.bytes_to_sign().map_err(TxSigningError::from)?; + // TODO: re-use, disable unwrap + #[allow(clippy::unwrap_used)] + let context = make_context(state_context, &tx_context, input_idx).unwrap(); Ok(sign_tx_input( self.prover.as_ref(), &tx_context, state_context, + &context, tx_hints, input_idx, message_to_sign.as_slice(), diff --git a/ergo-lib/src/wallet/multi_sig.rs b/ergo-lib/src/wallet/multi_sig.rs index 64285151f..536f1e555 100644 --- a/ergo-lib/src/wallet/multi_sig.rs +++ b/ergo-lib/src/wallet/multi_sig.rs @@ -2,7 +2,6 @@ use crate::chain::ergo_state_context::ErgoStateContext; use crate::chain::transaction::unsigned::UnsignedTransaction; use crate::chain::transaction::Transaction; -use crate::ergotree_interpreter::eval::env::Env; use crate::ergotree_interpreter::eval::reduce_to_crypto; use crate::ergotree_interpreter::sigma_protocol::dht_protocol::interactive_prover as dht_interactive_prover; use crate::ergotree_interpreter::sigma_protocol::dlog_protocol::interactive_prover as dlog_interactive_prover; @@ -24,7 +23,6 @@ use ergotree_interpreter::sigma_protocol::sig_serializer::parse_sig_compute_chal use ergotree_interpreter::sigma_protocol::unchecked_tree::UncheckedTree; use ergotree_interpreter::sigma_protocol::verifier::compute_commitments; use std::collections::HashMap; -use std::rc::Rc; use super::tx_context::TransactionContextError; @@ -250,13 +248,13 @@ pub fn generate_commitments( let input_box = tx_context .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(i))?; - let ctx = Rc::new(make_context(state_context, &tx_context, i)?); + let ctx = make_context(state_context, &tx_context, i)?; // TODO: Remove Rc, use Context::with_self_box_index let tree = input_box.ergo_tree.clone(); let exp = tree .proposition() .map_err(ProverError::ErgoTreeError) .map_err(|e| TxSigningError::ProverError(e, i))?; - let reduction_result = reduce_to_crypto(&exp, &Env::empty(), ctx) + let reduction_result = reduce_to_crypto(&exp, &ctx) .map_err(ProverError::EvalError) .map_err(|e| TxSigningError::ProverError(e, i))?; @@ -278,13 +276,13 @@ pub fn extract_hints( let input_box = tx_ctx .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(i))?; - let ctx = Rc::new(make_context(state_context, tx_ctx, i)?); + let ctx = make_context(state_context, tx_ctx, i)?; // TODO: remove Rc, use with_self_box let tree = input_box.ergo_tree.clone(); let exp = tree .proposition() .map_err(ProverError::ErgoTreeError) .map_err(|e| TxSigningError::ProverError(e, i))?; - let reduction_result = reduce_to_crypto(&exp, &Env::empty(), ctx) + let reduction_result = reduce_to_crypto(&exp, &ctx) .map_err(ProverError::EvalError) .map_err(|e| TxSigningError::ProverError(e, i))?; let sigma_tree = reduction_result.sigma_prop; @@ -389,7 +387,6 @@ mod tests { use super::*; use crate::chain::transaction::Transaction; use crate::ergotree_interpreter::eval::context::Context; - use crate::ergotree_interpreter::eval::env::Env; use crate::ergotree_interpreter::eval::reduce_to_crypto; use crate::ergotree_interpreter::sigma_protocol::private_input::{ DlogProverInput, PrivateInput, @@ -414,7 +411,6 @@ mod tests { use ergotree_ir::types::stype::SType; use sigma_test_util::force_any_val; use std::convert::{TryFrom, TryInto}; - use std::rc::Rc; #[test] fn extract_hint() { @@ -466,9 +462,9 @@ mod tests { let bytes_m = Base16DecodedBytes::try_from("100208cd03c847c306a2f9a8087b4ae63261cc5acea9034000ba8d033b0fb033247e8aade908cd02f4b05f44eb9703db7fcf9c94b89566787a7188c7e48964821d485d9ef2f9e4c4ea0273007301").unwrap(); let tree_m: ErgoTree = ErgoTree::sigma_parse_bytes(&bytes_m.0).unwrap(); - let contx = Rc::new(force_any_val::()); + let contx = force_any_val::(); let exp = tree_m.proposition().unwrap(); - let reduction_result = reduce_to_crypto(&exp, &Env::empty(), contx).unwrap(); + let reduction_result = reduce_to_crypto(&exp, &contx).unwrap(); let sigma_tree = reduction_result.sigma_prop; let stx: Transaction = serde_json::from_str(signed_tx).unwrap(); let test: ProofBytes = stx.inputs.first().clone().spending_proof.proof; @@ -656,7 +652,7 @@ mod tests { #[test] fn multi_sig_2() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let secret1 = DlogProverInput::random(); let secret2 = DlogProverInput::random(); @@ -676,9 +672,7 @@ mod tests { .into(); let tree_and = ErgoTree::try_from(expr.clone()).unwrap(); - let cand = reduce_to_crypto(&expr, &Env::empty(), ctx.clone()) - .unwrap() - .sigma_prop; + let cand = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop; let generate_for: Vec = vec![SigmaBoolean::ProofOfKnowledge( SigmaProofOfKnowledgeTree::ProveDlog(pk2), )]; @@ -692,13 +686,7 @@ mod tests { ))); let proof1 = prover1 - .prove( - &tree_and, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_a, - ) + .prove(&tree_and, &ctx, message.as_slice(), &bag_a) .unwrap(); let proof: Vec = Vec::from(proof1.proof); let real_proposition: Vec = vec![SigmaBoolean::ProofOfKnowledge( @@ -711,26 +699,14 @@ mod tests { own.first().unwrap().clone(), ))); let proof2 = prover2 - .prove( - &tree_and, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_b, - ) + .prove(&tree_and, &ctx, message.as_slice(), &bag_b) .unwrap(); let proof_byte: ProofBytes = proof2.proof; let verifier = TestVerifier; assert!( verifier - .verify( - &tree_and, - &Env::empty(), - ctx, - proof_byte, - message.as_slice(), - ) + .verify(&tree_and, &ctx, proof_byte, message.as_slice(),) .unwrap() .result, "{}", @@ -740,7 +716,7 @@ mod tests { #[test] fn multi_sig_and_3() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let secret1 = DlogProverInput::random(); let secret2 = DlogProverInput::random(); @@ -768,9 +744,7 @@ mod tests { let tree_expr = ErgoTree::try_from(expr.clone()).unwrap(); - let expr_reduced = reduce_to_crypto(&expr, &Env::empty(), ctx.clone()) - .unwrap() - .sigma_prop; + let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop; let mut generate_for: Vec = vec![SigmaBoolean::ProofOfKnowledge( SigmaProofOfKnowledgeTree::ProveDlog(pk2), )]; @@ -792,13 +766,7 @@ mod tests { bag3.first().unwrap().clone(), ))); let proof1 = prover1 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_a, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_a) .unwrap(); let mut proof: Vec = Vec::from(proof1.proof.clone()); let proof_byte1: ProofBytes = proof1.proof; @@ -820,13 +788,7 @@ mod tests { bag2.first().unwrap().clone(), ))); let proof3 = prover3 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_c, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_c) .unwrap(); proof = Vec::from(proof3.proof.clone()); let proof_byte3: ProofBytes = proof3.proof; @@ -845,26 +807,14 @@ mod tests { bob_secret_commitment.first().unwrap().clone(), ))); let proof2 = prover2 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_b, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_b) .unwrap(); let proof_byte2: ProofBytes = proof2.proof; let verifier = TestVerifier; assert!( !verifier - .verify( - &tree_expr, - &Env::empty(), - ctx.clone(), - proof_byte1, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_byte1, message.as_slice(),) .unwrap() .result, "{}", @@ -873,13 +823,7 @@ mod tests { assert!( !verifier - .verify( - &tree_expr, - &Env::empty(), - ctx.clone(), - proof_byte3, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_byte3, message.as_slice(),) .unwrap() .result, "{}", @@ -888,13 +832,7 @@ mod tests { assert!( verifier - .verify( - &tree_expr, - &Env::empty(), - ctx, - proof_byte2, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_byte2, message.as_slice(),) .unwrap() .result, "{}", @@ -904,7 +842,7 @@ mod tests { #[test] fn multi_dlog_dht() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let secret_alice = DlogProverInput::random(); let secret_bob = DlogProverInput::random(); @@ -941,9 +879,7 @@ mod tests { .into(); let exp: Expr = SigmaAnd::new(vec![first_expr, second_expr]).unwrap().into(); let tree = ErgoTree::try_from(exp.clone()).unwrap(); - let ctree = reduce_to_crypto(&exp, &Env::empty(), ctx.clone()) - .unwrap() - .sigma_prop; + let ctree = reduce_to_crypto(&exp, &ctx).unwrap().sigma_prop; let mut generate_for: Vec = vec![SigmaBoolean::ProofOfKnowledge( SigmaProofOfKnowledgeTree::ProveDlog(pk_alice.clone()), )]; @@ -964,13 +900,7 @@ mod tests { dave_known.first().unwrap().clone(), ))); let proof_a = prover_a - .prove( - &tree, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_a, - ) + .prove(&tree, &ctx, message.as_slice(), &bag_a) .unwrap(); let proof: Vec = Vec::from(proof_a.proof.clone()); let proof_byte_a: ProofBytes = proof_a.proof; @@ -978,13 +908,7 @@ mod tests { assert!( !verifier - .verify( - &tree, - &Env::empty(), - ctx.clone(), - proof_byte_a, - message.as_slice(), - ) + .verify(&tree, &ctx, proof_byte_a, message.as_slice(),) .unwrap() .result, "{}", @@ -1010,13 +934,13 @@ mod tests { ))); let proof_d = _prover_d - .prove(&tree, &Env::empty(), ctx.clone(), message.as_slice(), &bag) + .prove(&tree, &ctx, message.as_slice(), &bag) .unwrap(); let proof_byte_d: ProofBytes = proof_d.proof; assert!( verifier - .verify(&tree, &Env::empty(), ctx, proof_byte_d, message.as_slice(),) + .verify(&tree, &ctx, proof_byte_d, message.as_slice()) .unwrap() .result, "{}", @@ -1027,7 +951,7 @@ mod tests { #[test] fn multi_sig_atleast_2_out_of_3() { // from https://github.com/ScorexFoundation/sigmastate-interpreter/blob/78dd1e715038c2f95c518fb56977c6591b76e20c/sc/src/test/scala/sigmastate/utxo/DistributedSigSpecification.scala#L124 - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let alice_secret = DlogProverInput::random(); let bob_secret = DlogProverInput::random(); @@ -1047,9 +971,9 @@ mod tests { let bound = Expr::Const(2i32.into()); let inputs = Literal::Coll( - CollKind::from_vec( + CollKind::from_collection( SType::SSigmaProp, - vec![ + [ SigmaProp::from(alice_pk.clone()).into(), SigmaProp::from(bob_pk.clone()).into(), SigmaProp::from(carol_pk.clone()).into(), @@ -1066,9 +990,7 @@ mod tests { let tree_expr = ErgoTree::try_from(expr.clone()).unwrap(); - let expr_reduced = reduce_to_crypto(&expr, &Env::empty(), ctx.clone()) - .unwrap() - .sigma_prop; + let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop; let message = vec![0u8; 100]; let hints_from_bob: HintsBag = generate_commitments_for(&expr_reduced, &[bob_pk.into()]); @@ -1081,13 +1003,7 @@ mod tests { ))); let proof_alice = alice_prover - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_a, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_a) .unwrap(); let mut bag_b = bag_for_multi_sig( @@ -1102,26 +1018,14 @@ mod tests { ))); let proof_bob = bob_prover - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_b, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_b) .unwrap(); let verifier = TestVerifier; assert!( !verifier - .verify( - &tree_expr, - &Env::empty(), - ctx.clone(), - proof_alice.proof, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_alice.proof, message.as_slice()) .unwrap() .result, "Proof generated by Alice without getting Bob's part is not correct" @@ -1129,13 +1033,7 @@ mod tests { assert!( verifier - .verify( - &tree_expr, - &Env::empty(), - ctx, - proof_bob.proof, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_bob.proof, message.as_slice()) .unwrap() .result, "Compound proof from Bob is correct" @@ -1146,7 +1044,7 @@ mod tests { fn multi_sig_atleast_3_out_of_4() { // from https://github.com/ScorexFoundation/sigmastate-interpreter/blob/78dd1e715038c2f95c518fb56977c6591b76e20c/sc/src/test/scala/sigmastate/utxo/DistributedSigSpecification.scala#L160-L205 - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let alice_secret = DlogProverInput::random(); let bob_secret = DlogProverInput::random(); @@ -1168,9 +1066,9 @@ mod tests { let bound = Expr::Const(3i32.into()); let inputs = Literal::Coll( - CollKind::from_vec( + CollKind::from_collection( SType::SSigmaProp, - vec![ + [ SigmaProp::from(alice_pk.clone()).into(), SigmaProp::from(bob_pk.clone()).into(), SigmaProp::from(carol_pk.clone()).into(), @@ -1188,9 +1086,7 @@ mod tests { let tree_expr = ErgoTree::try_from(expr.clone()).unwrap(); - let expr_reduced = reduce_to_crypto(&expr, &Env::empty(), ctx.clone()) - .unwrap() - .sigma_prop; + let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop; let message = vec![0u8; 100]; let bob_hints: HintsBag = generate_commitments_for(&expr_reduced, &[bob_pk.into()]); @@ -1205,13 +1101,7 @@ mod tests { }; let proof_alice = alice_prover - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_a, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_a) .unwrap(); let mut bag_c = bag_for_multi_sig( @@ -1232,13 +1122,7 @@ mod tests { ); let proof_carol = _carol_prover - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_c, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_c) .unwrap(); let bag_b_1 = bag_for_multi_sig( @@ -1262,26 +1146,14 @@ mod tests { bag_b.add_hint(bob_hints.own_commitments().first().unwrap().clone().into()); let proof_bob = bob_prover - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - message.as_slice(), - &bag_b, - ) + .prove(&tree_expr, &ctx, message.as_slice(), &bag_b) .unwrap(); let verifier = TestVerifier; assert!( !verifier - .verify( - &tree_expr, - &Env::empty(), - ctx.clone(), - proof_alice.proof, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_alice.proof, message.as_slice(),) .unwrap() .result, "Proof generated by Alice without getting Bob's part is not correct" @@ -1289,13 +1161,7 @@ mod tests { assert!( !verifier - .verify( - &tree_expr, - &Env::empty(), - ctx.clone(), - proof_carol.proof, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_carol.proof, message.as_slice(),) .unwrap() .result, "Proof generated by Carol without getting Bob's part is not correct" @@ -1303,13 +1169,7 @@ mod tests { assert!( verifier - .verify( - &tree_expr, - &Env::empty(), - ctx, - proof_bob.proof, - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_bob.proof, message.as_slice()) .unwrap() .result, "Compound proof from Bob is correct" @@ -1320,7 +1180,7 @@ mod tests { fn multi_sig_atleast_7_out_of_10_i692() { // based on // https://github.com/ScorexFoundation/sigmastate-interpreter/blob/78dd1e715038c2f95c518fb56977c6591b76e20c/sc/src/test/scala/sigmastate/utxo/DistributedSigSpecification.scala#L299-L389 - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let sk1 = DlogProverInput::random(); let pk1 = sk1.public_image(); @@ -1378,9 +1238,9 @@ mod tests { let input = Constant { tpe: SType::SColl(SType::SSigmaProp.into()), v: Literal::Coll( - CollKind::from_vec( + CollKind::from_collection( SType::SSigmaProp, - vec![ + [ SigmaProp::from(pk1.clone()).into(), SigmaProp::from(pk2.clone()).into(), SigmaProp::from(pk3.clone()).into(), @@ -1399,9 +1259,7 @@ mod tests { .into(); let expr: Expr = Atleast::new(bound, input).unwrap().into(); let tree_expr = ErgoTree::try_from(expr.clone()).unwrap(); - let expr_reduced = reduce_to_crypto(&expr, &Env::empty(), ctx.clone()) - .unwrap() - .sigma_prop; + let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop; let message = vec![0u8; 100]; // only actors 1, 2, 3, 4, 5, 6, 7 are signing, others are simulated (see bag_one below) @@ -1445,21 +1303,13 @@ mod tests { ], }; - let proof_7 = prover7 - .prove(&tree_expr, &Env::empty(), ctx.clone(), &message, &bag_7) - .unwrap(); + let proof_7 = prover7.prove(&tree_expr, &ctx, &message, &bag_7).unwrap(); let verifier = TestVerifier; assert!( !verifier - .verify( - &tree_expr, - &Env::empty(), - ctx.clone(), - proof_7.proof.clone(), - message.as_slice(), - ) + .verify(&tree_expr, &ctx, proof_7.proof.clone(), message.as_slice(),) .unwrap() .result, "Proof generated by Prover7 only is not correct" @@ -1482,9 +1332,7 @@ mod tests { bag_2.add_hint(dl_4_known.clone().into()); bag_2.add_hint(dl_5_known.clone().into()); bag_2.add_hint(dl_6_known.clone().into()); - let proof_2 = prover2 - .prove(&tree_expr, &Env::empty(), ctx.clone(), &message, &bag_2) - .unwrap(); + let proof_2 = prover2.prove(&tree_expr, &ctx, &message, &bag_2).unwrap(); let partial_proof_2 = bag_for_multi_sig(&expr_reduced, &[pk2.into()], &[], proof_2.proof.as_ref()) .unwrap() @@ -1501,9 +1349,7 @@ mod tests { bag_1.add_hint(dl_5_known.clone().into()); bag_1.add_hint(dl_6_known.clone().into()); - let proof_1 = prover1 - .prove(&tree_expr, &Env::empty(), ctx.clone(), &message, &bag_1) - .unwrap(); + let proof_1 = prover1.prove(&tree_expr, &ctx, &message, &bag_1).unwrap(); let partial_proof_1 = bag_for_multi_sig(&expr_reduced, &[pk1.into()], &[], proof_1.proof.as_ref()) .unwrap() @@ -1519,9 +1365,7 @@ mod tests { bag_3.add_hint(dl_4_known.clone().into()); bag_3.add_hint(dl_5_known.clone().into()); bag_3.add_hint(dl_6_known.clone().into()); - let proof_3 = prover3 - .prove(&tree_expr, &Env::empty(), ctx.clone(), &message, &bag_3) - .unwrap(); + let proof_3 = prover3.prove(&tree_expr, &ctx, &message, &bag_3).unwrap(); let partial_proof_3 = bag_for_multi_sig(&expr_reduced, &[pk3.into()], &[], proof_3.proof.as_ref()) .unwrap() @@ -1537,9 +1381,7 @@ mod tests { bag_4.add_hint(dl_3_known.clone().into()); bag_4.add_hint(dl_5_known.clone().into()); bag_4.add_hint(dl_6_known.clone().into()); - let proof_4 = prover4 - .prove(&tree_expr, &Env::empty(), ctx.clone(), &message, &bag_4) - .unwrap(); + let proof_4 = prover4.prove(&tree_expr, &ctx, &message, &bag_4).unwrap(); let partial_proof_4 = bag_for_multi_sig(&expr_reduced, &[pk4.into()], &[], proof_4.proof.as_ref()) .unwrap() @@ -1555,9 +1397,7 @@ mod tests { bag_5.add_hint(dl_3_known.clone().into()); bag_5.add_hint(dl_4_known.clone().into()); bag_5.add_hint(dl_6_known.clone().into()); - let proof_5 = prover5 - .prove(&tree_expr, &Env::empty(), ctx.clone(), &message, &bag_5) - .unwrap(); + let proof_5 = prover5.prove(&tree_expr, &ctx, &message, &bag_5).unwrap(); let partial_proof_5 = bag_for_multi_sig(&expr_reduced, &[pk5.into()], &[], proof_5.proof.as_ref()) .unwrap() @@ -1573,9 +1413,7 @@ mod tests { bag_6.add_hint(dl_3_known.clone().into()); bag_6.add_hint(dl_4_known.clone().into()); bag_6.add_hint(dl_5_known.clone().into()); - let proof_6 = prover6 - .prove(&tree_expr, &Env::empty(), ctx.clone(), &message, &bag_6) - .unwrap(); + let proof_6 = prover6.prove(&tree_expr, &ctx, &message, &bag_6).unwrap(); let partial_proof_6 = bag_for_multi_sig(&expr_reduced, &[pk6.into()], &[], proof_6.proof.as_ref()) .unwrap() @@ -1601,21 +1439,14 @@ mod tests { let mut valid_bag_1 = bag.clone(); valid_bag_1.add_hint(secret_cmt_1.into()); let valid_proof_1 = prover1 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - &message, - &valid_bag_1, - ) + .prove(&tree_expr, &ctx, &message, &valid_bag_1) .unwrap(); assert!( verifier .verify( &tree_expr, - &Env::empty(), - ctx.clone(), + &ctx, valid_proof_1.proof.clone(), message.as_slice(), ) @@ -1626,20 +1457,13 @@ mod tests { let mut valid_bag_2 = bag.clone(); valid_bag_2.add_hint(secret_cmt_2.into()); let valid_proof_2 = prover2 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - &message, - &valid_bag_2, - ) + .prove(&tree_expr, &ctx, &message, &valid_bag_2) .unwrap(); assert!( verifier .verify( &tree_expr, - &Env::empty(), - ctx.clone(), + &ctx, valid_proof_2.proof.clone(), message.as_slice(), ) @@ -1650,20 +1474,13 @@ mod tests { let mut valid_bag_3 = bag.clone(); valid_bag_3.add_hint(secret_cmt_3.into()); let valid_proof_3 = prover3 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - &message, - &valid_bag_3, - ) + .prove(&tree_expr, &ctx, &message, &valid_bag_3) .unwrap(); assert!( verifier .verify( &tree_expr, - &Env::empty(), - ctx.clone(), + &ctx, valid_proof_3.proof.clone(), message.as_slice() ) @@ -1674,20 +1491,13 @@ mod tests { let mut valid_bag_4 = bag.clone(); valid_bag_4.add_hint(secret_cmt_4.into()); let valid_proof_4 = prover4 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - &message, - &valid_bag_4, - ) + .prove(&tree_expr, &ctx, &message, &valid_bag_4) .unwrap(); assert!( verifier .verify( &tree_expr, - &Env::empty(), - ctx.clone(), + &ctx, valid_proof_4.proof.clone(), message.as_slice() ) @@ -1698,20 +1508,13 @@ mod tests { let mut valid_bag_5 = bag.clone(); valid_bag_5.add_hint(secret_cmt_5.into()); let valid_proof_5 = prover5 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - &message, - &valid_bag_5, - ) + .prove(&tree_expr, &ctx, &message, &valid_bag_5) .unwrap(); assert!( verifier .verify( &tree_expr, - &Env::empty(), - ctx.clone(), + &ctx, valid_proof_5.proof.clone(), message.as_slice() ) @@ -1722,20 +1525,13 @@ mod tests { let mut valid_bag_6 = bag.clone(); valid_bag_6.add_hint(secret_cmt_6.into()); let valid_proof_6 = prover6 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - &message, - &valid_bag_6, - ) + .prove(&tree_expr, &ctx, &message, &valid_bag_6) .unwrap(); assert!( verifier .verify( &tree_expr, - &Env::empty(), - ctx.clone(), + &ctx, valid_proof_6.proof.clone(), message.as_slice() ) @@ -1746,20 +1542,13 @@ mod tests { let mut valid_bag_7 = bag.clone(); valid_bag_7.add_hint(secret_cmt_7.into()); let valid_proof_7 = prover7 - .prove( - &tree_expr, - &Env::empty(), - ctx.clone(), - &message, - &valid_bag_7, - ) + .prove(&tree_expr, &ctx, &message, &valid_bag_7) .unwrap(); assert!( verifier .verify( &tree_expr, - &Env::empty(), - ctx, + &ctx, valid_proof_7.proof.clone(), message.as_slice() ) diff --git a/ergo-lib/src/wallet/signing.rs b/ergo-lib/src/wallet/signing.rs index b7938f3db..c1d36f45e 100644 --- a/ergo-lib/src/wallet/signing.rs +++ b/ergo-lib/src/wallet/signing.rs @@ -11,16 +11,14 @@ use ergotree_interpreter::sigma_protocol::prover::hint::HintsBag; use ergotree_interpreter::sigma_protocol::sig_serializer::SigParsingError; use ergotree_ir::serialization::SigmaSerializationError; 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::ProofBytes; +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; @@ -44,11 +42,11 @@ pub enum TxSigningError { } /// `self_index` - index of the SELF box in the tx_ctx.spending_tx.inputs -pub fn make_context( - state_ctx: &ErgoStateContext, - tx_ctx: &TransactionContext, +pub fn make_context<'ctx, T: ErgoTransaction>( + state_ctx: &'ctx ErgoStateContext, + tx_ctx: &'ctx TransactionContext, self_index: usize, -) -> Result { +) -> Result, TransactionContextError> { let height = state_ctx.pre_header.height; // Find self_box by matching BoxIDs @@ -63,22 +61,28 @@ pub fn make_context( .ok_or(TransactionContextError::InputBoxNotFound(self_index))?; let outputs = tx_ctx.spending_tx.outputs(); - let data_inputs_ir = if let Some(data_inputs) = tx_ctx.spending_tx.data_inputs().as_ref() { - Some(data_inputs.clone().enumerated().try_mapped(|(idx, di)| { - tx_ctx - .data_boxes - .as_ref() - .ok_or(TransactionContextError::DataInputBoxNotFound(idx))? + let data_inputs_ir = if let Some(data_inputs) = tx_ctx.spending_tx.data_inputs() { + Some( + #[allow(clippy::unwrap_used)] + data_inputs .iter() - .find(|b| di.box_id == b.box_id()) - .map(|b| Arc::new(b.clone())) - .ok_or(TransactionContextError::DataInputBoxNotFound(idx)) - })?) + .enumerate() + .map(|(idx, di)| { + tx_ctx + .data_boxes + .as_ref() + .ok_or(TransactionContextError::DataInputBoxNotFound(idx))? + .iter() + .find(|b| di.box_id == b.box_id()) + .ok_or(TransactionContextError::DataInputBoxNotFound(idx)) + }) + .collect::, _>>()? + .try_into() + .unwrap(), + ) } else { None }; - let self_box_ir = Arc::new(self_box); - let outputs_ir = outputs.into_iter().map(Arc::new).collect(); let inputs_ir = tx_ctx .spending_tx .inputs_ids() @@ -86,7 +90,6 @@ pub fn make_context( .try_mapped(|(idx, u)| { tx_ctx .get_input_box(&u) - .map(Arc::new) .ok_or(TransactionContextError::InputBoxNotFound(idx)) })?; let extension = tx_ctx @@ -95,8 +98,8 @@ pub fn make_context( .ok_or(TransactionError::InputNofFound(self_index))?; Ok(Context { height, - self_box: self_box_ir, - outputs: outputs_ir, + self_box, + outputs, data_inputs: data_inputs_ir, inputs: inputs_ir, pre_header: state_ctx.pre_header.clone(), @@ -104,6 +107,30 @@ pub fn make_context( headers: state_ctx.headers.clone(), }) } +// Updates a Context, changing its self box and context extension to transaction.inputs[i] +pub(crate) fn update_context<'ctx, T: ErgoTransaction>( + ctx: &mut Context<'ctx>, + tx_ctx: &'ctx TransactionContext, + self_index: usize, +) -> Result<(), TransactionContextError> { + // Find self_box by matching BoxIDs + let self_box = tx_ctx + .get_input_box( + tx_ctx + .spending_tx + .inputs_ids() + .get(self_index) + .ok_or(TransactionError::InputNofFound(self_index))?, + ) + .ok_or(TransactionContextError::InputBoxNotFound(self_index))?; + let extension = tx_ctx + .spending_tx + .context_extension(self_index) + .ok_or(TransactionError::InputNofFound(self_index))?; + ctx.self_box = self_box; + ctx.extension = extension; + Ok(()) +} /// Signs a transaction (generating proofs for inputs) pub fn sign_transaction( @@ -114,11 +141,13 @@ pub fn sign_transaction( ) -> Result { let tx = tx_context.spending_tx.clone(); let message_to_sign = tx.bytes_to_sign()?; + let ctx = make_context(state_context, &tx_context, 0)?; let signed_inputs = tx.inputs.enumerated().try_mapped(|(idx, _)| { sign_tx_input( prover, &tx_context, state_context, + &ctx, // TODO: use with_self_box_index tx_hints, idx, message_to_sign.as_slice(), @@ -186,6 +215,7 @@ pub fn sign_tx_input( prover: &dyn Prover, tx_context: &TransactionContext, state_context: &ErgoStateContext, + context: &Context, tx_hints: Option<&TransactionHintsBag>, input_idx: usize, message_to_sign: &[u8], @@ -198,31 +228,24 @@ pub fn sign_tx_input( let input_box = tx_context .get_input_box(&unsigned_input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(input_idx))?; - let ctx = Rc::new(make_context(state_context, tx_context, input_idx)?); let mut hints_bag = HintsBag::empty(); if let Some(bag) = tx_hints { hints_bag = bag.all_hints_for_input(input_idx); } - match check_storage_rent_conditions(&input_box, state_context, &ctx.clone()) { + match check_storage_rent_conditions(input_box, state_context, context) { // 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(), + extension: context.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, - ) + .prove(&input_box.ergo_tree, context, message_to_sign, &hints_bag) .map(|proof| Input::new(unsigned_input.box_id, proof.into())) .map_err(|e| TxSigningError::ProverError(e, input_idx)), } @@ -281,8 +304,7 @@ mod tests { .unwrap(); let res = verifier.verify( &b.ergo_tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), input.spending_proof.proof.clone(), &message, )?; @@ -379,12 +401,21 @@ mod tests { ) .unwrap(); - let expected_data_input_boxes = Some(TxIoVec::from_vec(expected_data_input_boxes).unwrap().mapped(Arc::new)); - let expected_input_boxes = TxIoVec::from_vec(expected_input_boxes).unwrap().mapped(Arc::new); + let expected_data_input_boxes = Some(TxIoVec::from_vec(expected_data_input_boxes).unwrap()); + let expected_input_boxes = TxIoVec::from_vec(expected_input_boxes).unwrap(); for i in 0..num_inputs { - let context = make_context(&force_any_val::(), &tx_context, i).unwrap(); - assert_eq!(expected_data_input_boxes, context.data_inputs); - assert_eq!(expected_input_boxes, context.inputs); + let state_ctx = force_any_val::(); + let context = make_context(&state_ctx, &tx_context, i).unwrap(); + expected_data_input_boxes + .iter() + .flatten() + .zip(context.data_inputs.iter().flatten()) + .for_each(|(left, right)| assert_eq!(&left, right)); + + expected_input_boxes + .iter() + .zip(context.inputs.iter()) + .for_each(|(left, right)| assert_eq!(&left, right)); assert_eq!(tx_context.spending_tx.inputs.as_vec()[i].box_id, context.self_box.box_id()); } } @@ -518,8 +549,7 @@ mod tests { let verifier = TestVerifier; let ver_res = verifier.verify( &ergo_tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), tx.inputs.get(1).unwrap().spending_proof.proof.clone(), message.as_slice(), ); diff --git a/ergo-lib/src/wallet/tx_context.rs b/ergo-lib/src/wallet/tx_context.rs index 286503407..9d0fde6fc 100644 --- a/ergo-lib/src/wallet/tx_context.rs +++ b/ergo-lib/src/wallet/tx_context.rs @@ -15,6 +15,8 @@ use ergotree_ir::chain::token::{TokenAmount, TokenId}; use ergotree_ir::serialization::SigmaSerializable; use thiserror::Error; +use super::signing::make_context; + /// Transaction and an additional info required for signing or verification #[derive(PartialEq, Eq, Debug, Clone)] pub struct TransactionContext { @@ -89,11 +91,10 @@ impl TransactionContext { } /// Returns box with given id, if it exists. - pub fn get_input_box(&self, box_id: &BoxId) -> Option { + pub fn get_input_box(&self, box_id: &BoxId) -> Option<&ErgoBox> { self.box_index .get(box_id) .and_then(|&idx| self.boxes_to_spend.get(idx as usize)) - .cloned() } } @@ -149,9 +150,10 @@ impl TransactionContext { )?; // Verify input proofs. This is usually the most expensive check so it's done last let bytes_to_sign = self.spending_tx.bytes_to_sign()?; + let mut context = make_context(state_context, self, 0)?; for input_idx in 0..self.spending_tx.inputs.len() { if let res @ VerificationResult { result: false, .. } = - verify_tx_input_proof(self, state_context, input_idx, &bytes_to_sign)? + verify_tx_input_proof(self, &mut context, state_context, input_idx, &bytes_to_sign)? { return Err(TxValidationError::ReducedToFalse(input_idx, res)); } diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index 6d28f4e28..2a4ab05d4 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -2,13 +2,11 @@ use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; use std::fmt::Display; -use std::rc::Rc; use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::value::Value; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean; -use cost_accum::CostAccumulator; use ergotree_ir::types::smethod::SMethod; use self::context::Context; @@ -100,7 +98,7 @@ pub use error::EvalError; #[derive(PartialEq, Eq, Debug, Clone)] pub struct ReductionDiagnosticInfo { /// environment after the evaluation - pub env: Env, + pub env: Env<'static>, /// expression pretty-printed pub pretty_printed_expr: Option, } @@ -126,24 +124,17 @@ pub struct ReductionResult { } /// Evaluate the given expression by reducing it to SigmaBoolean value. -pub fn reduce_to_crypto( - expr: &Expr, - env: &Env, - ctx: Rc, -) -> Result { - let ctx_clone = ctx.clone(); - fn inner(expr: &Expr, env: &Env, ctx: Rc) -> Result { - let cost_accum = CostAccumulator::new(0, None); - let mut ectx = EvalContext::new(ctx, cost_accum); - let mut env_mut = env.clone(); - expr.eval(&mut env_mut, &mut ectx) +pub fn reduce_to_crypto(expr: &Expr, ctx: &Context) -> Result { + fn inner<'ctx>(expr: &'ctx Expr, ctx: &Context<'ctx>) -> Result { + let mut env_mut = Env::empty(); + expr.eval(&mut env_mut, ctx) .and_then(|v| -> Result { match v { Value::Boolean(b) => Ok(ReductionResult { sigma_prop: SigmaBoolean::TrivialProp(b), cost: 0, diag: ReductionDiagnosticInfo { - env: env_mut.clone(), + env: env_mut.to_static(), pretty_printed_expr: None, }, }), @@ -151,7 +142,7 @@ pub fn reduce_to_crypto( sigma_prop: sp.value().clone(), cost: 0, diag: ReductionDiagnosticInfo { - env: env_mut.clone(), + env: env_mut.to_static(), pretty_printed_expr: None, }, }), @@ -160,7 +151,7 @@ pub fn reduce_to_crypto( }) } - let res = inner(expr, env, ctx); + let res = inner(expr, ctx); if let Ok(reduction) = res { if reduction.sigma_prop == SigmaBoolean::TrivialProp(false) { let (_, printed_expr_str) = expr @@ -182,8 +173,7 @@ pub fn reduce_to_crypto( let (spanned_expr, printed_expr_str) = expr .pretty_print() .map_err(|e| EvalError::Misc(e.to_string()))?; - inner(&spanned_expr, env, ctx_clone) - .map_err(|e| e.wrap_spanned_with_src(printed_expr_str.to_string())) + inner(&spanned_expr, ctx).map_err(|e| e.wrap_spanned_with_src(printed_expr_str.to_string())) } /// Expects SigmaProp constant value and returns it's value. Otherwise, returns an error. @@ -194,27 +184,24 @@ pub fn extract_sigma_boolean(expr: &Expr) -> Result { } } -#[derive(Debug)] -pub(crate) struct EvalContext { - pub(crate) ctx: Rc, - pub(crate) cost_accum: CostAccumulator, -} - -impl EvalContext { - pub fn new(ctx: Rc, cost_accum: CostAccumulator) -> Self { - EvalContext { ctx, cost_accum } - } -} - /// Expression evaluation. /// Should be implemented by every node that can be evaluated. pub(crate) trait Evaluable { /// Evaluation routine to be implement by each node - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result; + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + // TODO cost_accum: &mut CostAccumulator, + ) -> Result, EvalError>; } -type EvalFn = - fn(env: &mut Env, ctx: &mut EvalContext, Value, Vec) -> Result; +type EvalFn = for<'ctx> fn( + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + Value<'ctx>, + Vec>, +) -> Result, EvalError>; fn smethod_eval_fn(method: &SMethod) -> Result { use ergotree_ir::types::*; @@ -271,7 +258,7 @@ fn smethod_eval_fn(method: &SMethod) -> Result { }, scoll::TYPE_CODE => match method.method_id() { scoll::INDEX_OF_METHOD_ID => self::scoll::INDEX_OF_EVAL_FN, - scoll::FLATMAP_METHOD_ID => self::scoll::FLATMAP_EVAL_FN, + scoll::FLATMAP_METHOD_ID => self::scoll::flatmap_eval, scoll::ZIP_METHOD_ID => self::scoll::ZIP_EVAL_FN, scoll::INDICES_METHOD_ID => self::scoll::INDICES_EVAL_FN, scoll::PATCH_METHOD_ID => self::scoll::PATCH_EVAL_FN, @@ -295,8 +282,8 @@ fn smethod_eval_fn(method: &SMethod) -> Result { } }, soption::TYPE_CODE => match method.method_id() { - soption::MAP_METHOD_ID => self::soption::MAP_EVAL_FN, - soption::FILTER_METHOD_ID => self::soption::FILTER_EVAL_FN, + soption::MAP_METHOD_ID => self::soption::map_eval, + soption::FILTER_METHOD_ID => self::soption::filter_eval, method_id => { return Err(EvalError::NotFound(format!( "Eval fn: unknown method id in SOption: {:?}", @@ -386,35 +373,40 @@ pub(crate) mod tests { use expect_test::expect; use sigma_test_util::force_any_val; - pub fn eval_out_wo_ctx>(expr: &Expr) -> T { - let ctx = Rc::new(force_any_val::()); - eval_out(expr, ctx) + pub fn eval_out_wo_ctx> + 'static>(expr: &Expr) -> T { + let ctx = force_any_val::(); + eval_out(expr, &ctx) } - pub fn eval_out>(expr: &Expr, ctx: Rc) -> T { - let cost_accum = CostAccumulator::new(0, None); - let mut ectx = EvalContext::new(ctx, cost_accum); + pub fn eval_out> + 'static>( + expr: &Expr, + ctx: &Context<'static>, + ) -> T { let mut env = Env::empty(); - expr.eval(&mut env, &mut ectx) + expr.eval(&mut env, ctx) .unwrap() + .to_static() .try_extract_into::() .unwrap() } - pub fn try_eval_out>( + pub fn try_eval_out<'ctx, T: TryExtractFrom> + 'static>( expr: &Expr, - ctx: Rc, + ctx: &'ctx Context<'ctx>, ) -> Result { - let cost_accum = CostAccumulator::new(0, None); - let mut ectx = EvalContext::new(ctx, cost_accum); let mut env = Env::empty(); - expr.eval(&mut env, &mut ectx) - .and_then(|v| v.try_extract_into::().map_err(EvalError::TryExtractFrom)) + expr.eval(&mut env, ctx).and_then(|v| { + v.to_static() + .try_extract_into::() + .map_err(EvalError::TryExtractFrom) + }) } - pub fn try_eval_out_wo_ctx>(expr: &Expr) -> Result { - let ctx = Rc::new(force_any_val::()); - try_eval_out(expr, ctx) + pub fn try_eval_out_wo_ctx> + 'static>( + expr: &Expr, + ) -> Result { + let ctx = force_any_val::(); + try_eval_out(expr, &ctx) } #[test] @@ -442,8 +434,8 @@ pub(crate) mod tests { } .into(), ); - let ctx = Rc::new(force_any_val::()); - let res = reduce_to_crypto(&block, &Env::empty(), ctx).unwrap(); + let ctx = force_any_val::(); + let res = reduce_to_crypto(&block, &ctx).unwrap(); assert!(res.sigma_prop == SigmaBoolean::TrivialProp(false)); expect![[r#" Pretty printed expr: diff --git a/ergotree-interpreter/src/eval/and.rs b/ergotree-interpreter/src/eval/and.rs index 882227600..6be736e27 100644 --- a/ergotree-interpreter/src/eval/and.rs +++ b/ergotree-interpreter/src/eval/and.rs @@ -3,12 +3,16 @@ use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for And { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let input_v_bools = input_v.try_extract_into::>()?; Ok(input_v_bools.iter().all(|b| *b).into()) @@ -18,8 +22,6 @@ impl Evaluable for And { #[allow(clippy::panic)] #[cfg(test)] mod tests { - use std::rc::Rc; - use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -35,8 +37,8 @@ mod tests { #[test] fn eval(bools in collection::vec(any::(), 0..10)) { let expr: Expr = And {input: Expr::Const(bools.clone().into()).into()}.into(); - let ctx = Rc::new(force_any_val::()); - let res = eval_out::(&expr, ctx); + let ctx = force_any_val::(); + let res = eval_out::(&expr, &ctx); prop_assert_eq!(res, bools.iter().all(|b| *b)); } } diff --git a/ergotree-interpreter/src/eval/apply.rs b/ergotree-interpreter/src/eval/apply.rs index 0bcb7392f..e9bc71785 100644 --- a/ergotree-interpreter/src/eval/apply.rs +++ b/ergotree-interpreter/src/eval/apply.rs @@ -4,16 +4,22 @@ use ergotree_ir::mir::value::Value; use hashbrown::HashMap; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Apply { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { - let func_v = self.func.eval(env, ctx)?; - let args_v_res: Result, EvalError> = - self.args.iter().map(|arg| arg.eval(env, ctx)).collect(); - let args_v = args_v_res?; + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { + let func_v: Value<'ctx> = self.func.eval(env, ctx)?; + let args_v: Vec = self + .args + .iter() + .map(|arg| arg.eval(env, ctx)) + .collect::>()?; match func_v { Value::Lambda(fv) => { let arg_ids: Vec = fv.args.iter().map(|a| a.idx).collect(); @@ -50,8 +56,6 @@ impl Evaluable for Apply { #[cfg(test)] #[allow(clippy::unwrap_used)] mod tests { - use std::rc::Rc; - use ergotree_ir::mir::bin_op::BinOp; use ergotree_ir::mir::bin_op::RelationOp; use ergotree_ir::mir::block::BlockValue; @@ -115,7 +119,7 @@ mod tests { ) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - assert!(eval_out::(&apply, ctx)); + let ctx = force_any_val::(); + assert!(eval_out::(&apply, &ctx)); } } diff --git a/ergotree-interpreter/src/eval/atleast.rs b/ergotree-interpreter/src/eval/atleast.rs index 93b56ff36..6d7d925e9 100644 --- a/ergotree-interpreter/src/eval/atleast.rs +++ b/ergotree-interpreter/src/eval/atleast.rs @@ -9,12 +9,16 @@ use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Atleast { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let bound_v = self.bound.eval(env, ctx)?; let input_v = self.input.eval(env, ctx)?; @@ -55,6 +59,8 @@ impl Evaluable for Atleast { #[allow(clippy::panic)] #[cfg(test)] mod tests { + use std::sync::Arc; + use crate::eval::tests::try_eval_out_wo_ctx; use ergotree_ir::mir::constant::Constant; use ergotree_ir::mir::constant::Literal; @@ -62,7 +68,6 @@ mod tests { use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture; use ergotree_ir::types::stype::SType; - use std::rc::Rc; use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -80,12 +85,12 @@ mod tests { #[test] fn eval(sigmaprops in collection::vec(any::(), 4..8)) { - let items = Literal::Coll(CollKind::from_vec(SType::SSigmaProp, - sigmaprops.into_iter().map(|s| s.into()).collect::>()).unwrap()); + let items = Literal::Coll(CollKind::from_collection(SType::SSigmaProp, + sigmaprops.into_iter().map(|s| s.into()).collect::>()).unwrap()); let expr: Expr = Atleast::new(2i32.into(), Constant {tpe: SType::SColl(SType::SSigmaProp.into()), v: items}.into()).unwrap().into(); - let ctx = Rc::new(force_any_val::()); - let res = eval_out::(&expr, ctx); + let ctx = force_any_val::(); + let res = eval_out::(&expr, &ctx); prop_assert!(matches!(res.into(), SigmaBoolean::SigmaConjecture(SigmaConjecture::Cthreshold(_)))); } @@ -95,12 +100,12 @@ mod tests { fn bound_error() { let sigmaprops = vec![force_any_val::(), force_any_val::()]; let items = Literal::Coll( - CollKind::from_vec( + CollKind::from_collection( SType::SSigmaProp, sigmaprops .into_iter() .map(|s| s.into()) - .collect::>(), + .collect::>(), ) .unwrap(), ); diff --git a/ergotree-interpreter/src/eval/bin_op.rs b/ergotree-interpreter/src/eval/bin_op.rs index 2a47f9ceb..1344891b4 100644 --- a/ergotree-interpreter/src/eval/bin_op.rs +++ b/ergotree-interpreter/src/eval/bin_op.rs @@ -8,7 +8,6 @@ use ergotree_ir::mir::bin_op::{BinOp, BitOp}; use ergotree_ir::mir::constant::TryExtractFrom; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::Value; -use eval::costs::Costs; use num_traits::CheckedAdd; use num_traits::CheckedDiv; use num_traits::CheckedMul; @@ -16,9 +15,8 @@ use num_traits::CheckedRem; use num_traits::CheckedSub; use num_traits::Num; -use crate::eval; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; @@ -34,9 +32,9 @@ fn arithmetic_err( )) } -fn eval_plus(lv_raw: T, rv: Value) -> Result +fn eval_plus<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result, EvalError> where - T: Num + CheckedAdd + TryExtractFrom + Into + std::fmt::Display, + T: Num + CheckedAdd + TryExtractFrom> + Into> + std::fmt::Display, { let rv_raw = rv.try_extract_into::()?; lv_raw @@ -45,9 +43,9 @@ where .map(|t| t.into()) // convert T to Value } -fn eval_minus(lv_raw: T, rv: Value) -> Result +fn eval_minus<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result, EvalError> where - T: Num + CheckedSub + TryExtractFrom + Into + std::fmt::Display, + T: Num + CheckedSub + TryExtractFrom> + Into> + std::fmt::Display, { let rv_raw = rv.try_extract_into::()?; lv_raw @@ -56,9 +54,9 @@ where .map(|t| t.into()) // convert T to Value } -fn eval_mul(lv_raw: T, rv: Value) -> Result +fn eval_mul<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result, EvalError> where - T: Num + CheckedMul + TryExtractFrom + Into + std::fmt::Display, + T: Num + CheckedMul + TryExtractFrom> + Into> + std::fmt::Display, { let rv_raw = rv.try_extract_into::()?; lv_raw @@ -67,9 +65,9 @@ where .map(|t| t.into()) // convert T to Value } -fn eval_div(lv_raw: T, rv: Value) -> Result +fn eval_div<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result, EvalError> where - T: Num + CheckedDiv + TryExtractFrom + Into + std::fmt::Display, + T: Num + CheckedDiv + TryExtractFrom> + Into> + std::fmt::Display, { let rv_raw = rv.try_extract_into::()?; lv_raw @@ -78,9 +76,9 @@ where .map(|t| t.into()) // convert T to Value } -fn eval_mod(lv_raw: T, rv: Value) -> Result +fn eval_mod<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result, EvalError> where - T: Num + CheckedRem + TryExtractFrom + Into + std::fmt::Display, + T: Num + CheckedRem + TryExtractFrom> + Into> + std::fmt::Display, { let rv_raw = rv.try_extract_into::()?; lv_raw @@ -89,16 +87,16 @@ where .map(|t| t.into()) // convert T to Value } -fn eval_bit_op(lv_raw: T, rv: Value, op: F) -> Result +fn eval_bit_op<'ctx, T, F>(lv_raw: T, rv: Value<'ctx>, op: F) -> Result, EvalError> where - T: Num + TryExtractFrom + Into + std::fmt::Display, + T: Num + TryExtractFrom> + Into> + std::fmt::Display, F: FnOnce(T, T) -> T, { let rv_raw = rv.try_extract_into::()?; Ok(op(lv_raw, rv_raw).into()) } -fn eval_ge(lv: Value, rv: Value) -> Result { +fn eval_ge<'ctx>(lv: Value<'ctx>, rv: Value<'ctx>) -> Result, EvalError> { match lv { Value::Byte(lv_raw) => Ok((lv_raw >= rv.try_extract_into::()?).into()), Value::Short(lv_raw) => Ok((lv_raw >= rv.try_extract_into::()?).into()), @@ -112,7 +110,7 @@ fn eval_ge(lv: Value, rv: Value) -> Result { } } -fn eval_gt(lv: Value, rv: Value) -> Result { +fn eval_gt<'ctx>(lv: Value<'ctx>, rv: Value<'ctx>) -> Result, EvalError> { match lv { Value::Byte(lv_raw) => Ok((lv_raw > rv.try_extract_into::()?).into()), Value::Short(lv_raw) => Ok((lv_raw > rv.try_extract_into::()?).into()), @@ -126,7 +124,7 @@ fn eval_gt(lv: Value, rv: Value) -> Result { } } -fn eval_lt(lv: Value, rv: Value) -> Result { +fn eval_lt<'ctx>(lv: Value<'ctx>, rv: Value<'ctx>) -> Result, EvalError> { match lv { Value::Byte(lv_raw) => Ok((lv_raw < rv.try_extract_into::()?).into()), Value::Short(lv_raw) => Ok((lv_raw < rv.try_extract_into::()?).into()), @@ -140,7 +138,7 @@ fn eval_lt(lv: Value, rv: Value) -> Result { } } -fn eval_le(lv: Value, rv: Value) -> Result { +fn eval_le<'ctx>(lv: Value<'ctx>, rv: Value<'ctx>) -> Result, EvalError> { match lv { Value::Byte(lv_raw) => Ok((lv_raw <= rv.try_extract_into::()?).into()), Value::Short(lv_raw) => Ok((lv_raw <= rv.try_extract_into::()?).into()), @@ -154,25 +152,29 @@ fn eval_le(lv: Value, rv: Value) -> Result { } } -fn eval_max(lv_raw: T, rv: Value) -> Result +fn eval_max<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result, EvalError> where - T: Num + Ord + TryExtractFrom + Into, + T: Num + Ord + TryExtractFrom> + Into>, { let rv_raw = rv.try_extract_into::()?; Ok((lv_raw.max(rv_raw)).into()) } -fn eval_min(lv_raw: T, rv: Value) -> Result +fn eval_min<'ctx, T>(lv_raw: T, rv: Value<'ctx>) -> Result, EvalError> where - T: Num + Ord + TryExtractFrom + Into, + T: Num + Ord + TryExtractFrom> + Into>, { let rv_raw = rv.try_extract_into::()?; Ok((lv_raw.min(rv_raw)).into()) } impl Evaluable for BinOp { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { - ctx.cost_accum.add(Costs::DEFAULT.eq_const_size)?; + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { + //ctx.cost_accum.add(Costs::DEFAULT.eq_const_size)?; let lv = self.left.eval(env, ctx)?; // using closure to keep right value from evaluation (for lazy AND, OR, XOR) let mut rv = || self.right.eval(env, ctx); @@ -332,7 +334,6 @@ mod tests { use num_traits::Bounded; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; fn check_eq_neq(left: Constant, right: Constant) -> bool { let eq_op: Expr = BinOp { @@ -341,15 +342,15 @@ mod tests { right: Box::new(right.clone().into()), } .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let neq_op: Expr = BinOp { kind: BinOpKind::Relation(RelationOp::NEq), left: Box::new(left.into()), right: Box::new(right.into()), } .into(); - let ctx1 = Rc::new(force_any_val::()); - eval_out::(&eq_op, ctx) && !eval_out::(&neq_op, ctx1) + let ctx1 = force_any_val::(); + eval_out::(&eq_op, &ctx) && !eval_out::(&neq_op, &ctx1) } #[test] @@ -417,8 +418,8 @@ mod tests { ), } .into(); - let ctx = Rc::new(force_any_val::()); - assert!(eval_out::(&e, ctx)); + let ctx = force_any_val::(); + assert!(eval_out::(&e, &ctx)); } #[test] @@ -437,11 +438,11 @@ mod tests { ), } .into(); - let ctx = Rc::new(force_any_val::()); - assert!(!eval_out::(&e, ctx)); + let ctx = force_any_val::(); + assert!(!eval_out::(&e, &ctx)); } - fn eval_arith_op + Into>( + fn eval_arith_op> + Into + 'static>( op: ArithOp, left: T, right: T, @@ -452,11 +453,11 @@ mod tests { right: Box::new(right.into().into()), } .into(); - let ctx = Rc::new(force_any_val::()); - try_eval_out::(&expr, ctx) + let ctx = force_any_val::(); + try_eval_out::(&expr, &ctx) } - fn eval_bit_op + Into>( + fn eval_bit_op> + Into + 'static>( op: BitOp, left: T, right: T, @@ -467,8 +468,8 @@ mod tests { right: Box::new(right.into().into()), } .into(); - let ctx = Rc::new(force_any_val::()); - try_eval_out::(&expr, ctx) + let ctx = force_any_val::(); + try_eval_out::(&expr, &ctx) } fn eval_relation_op>(op: RelationOp, left: T, right: T) -> bool { @@ -478,8 +479,8 @@ mod tests { right: Box::new(right.into().into()), } .into(); - let ctx = Rc::new(force_any_val::()); - eval_out::(&expr, ctx) + let ctx = force_any_val::(); + eval_out::(&expr, &ctx) } fn eval_logical_op>(op: LogicalOp, left: T, right: T) -> bool { @@ -489,8 +490,8 @@ mod tests { right: Box::new(right.into().into()), } .into(); - let ctx = Rc::new(force_any_val::()); - eval_out::(&expr, ctx) + let ctx = force_any_val::(); + eval_out::(&expr, &ctx) } #[test] diff --git a/ergotree-interpreter/src/eval/bit_inversion.rs b/ergotree-interpreter/src/eval/bit_inversion.rs index 18541f474..fb6c7b6a1 100644 --- a/ergotree-interpreter/src/eval/bit_inversion.rs +++ b/ergotree-interpreter/src/eval/bit_inversion.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::bit_inversion::BitInversion; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for BitInversion { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::Byte(v) => Ok(Value::Byte(!v)), @@ -36,7 +40,7 @@ mod tests { use ergotree_ir::mir::unary_op::OneArgOpTryBuild; use num_traits::Num; - fn run_eval + TryExtractFrom>(input: T) -> T { + fn run_eval + TryExtractFrom> + 'static>(input: T) -> T { let expr: Expr = BitInversion::try_build(Expr::Const(input.into())) .unwrap() .into(); diff --git a/ergotree-interpreter/src/eval/block.rs b/ergotree-interpreter/src/eval/block.rs index 265b51f49..cc696cef8 100644 --- a/ergotree-interpreter/src/eval/block.rs +++ b/ergotree-interpreter/src/eval/block.rs @@ -6,12 +6,16 @@ use ergotree_ir::source_span::Spanned; use hashbrown::HashMap; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for BlockValue { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { // The start of the top-level block of statements does not contain any // pre-existing `ValDef`s. let is_top_level_block = env.is_empty(); diff --git a/ergotree-interpreter/src/eval/bool_to_sigma.rs b/ergotree-interpreter/src/eval/bool_to_sigma.rs index 3f249c052..bccce4c97 100644 --- a/ergotree-interpreter/src/eval/bool_to_sigma.rs +++ b/ergotree-interpreter/src/eval/bool_to_sigma.rs @@ -5,12 +5,16 @@ use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for BoolToSigmaProp { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let input_v_bool = input_v.try_extract_into::()?; Ok((SigmaProp::new(SigmaBoolean::TrivialProp(input_v_bool))).into()) diff --git a/ergotree-interpreter/src/eval/byte_array_to_bigint.rs b/ergotree-interpreter/src/eval/byte_array_to_bigint.rs index 695607cc4..ef6d65ee8 100644 --- a/ergotree-interpreter/src/eval/byte_array_to_bigint.rs +++ b/ergotree-interpreter/src/eval/byte_array_to_bigint.rs @@ -6,13 +6,17 @@ use ergotree_ir::mir::value::Value; use std::convert::TryFrom; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::EvalError::UnexpectedValue; use crate::eval::Evaluable; impl Evaluable for ByteArrayToBigInt { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input = self.input.eval(env, ctx)?.try_extract_into::>()?; if input.is_empty() { return Err(UnexpectedValue( diff --git a/ergotree-interpreter/src/eval/byte_array_to_long.rs b/ergotree-interpreter/src/eval/byte_array_to_long.rs index 6e037b7cd..98d3af2a5 100644 --- a/ergotree-interpreter/src/eval/byte_array_to_long.rs +++ b/ergotree-interpreter/src/eval/byte_array_to_long.rs @@ -2,14 +2,18 @@ use ergotree_ir::mir::byte_array_to_long::ByteArrayToLong; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::EvalError::UnexpectedValue; use crate::eval::Evaluable; use ergotree_ir::mir::constant::TryExtractInto; impl Evaluable for ByteArrayToLong { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input = self.input.eval(env, ctx)?.try_extract_into::>()?; if input.len() < 8 { return Err(UnexpectedValue( diff --git a/ergotree-interpreter/src/eval/calc_blake2b256.rs b/ergotree-interpreter/src/eval/calc_blake2b256.rs index 4c97ef5c6..a32820318 100644 --- a/ergotree-interpreter/src/eval/calc_blake2b256.rs +++ b/ergotree-interpreter/src/eval/calc_blake2b256.rs @@ -6,12 +6,16 @@ use sigma_util::hash::blake2b256_hash; use sigma_util::AsVecU8; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CalcBlake2b256 { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v.clone() { Value::Coll(CollKind::NativeColl(NativeColl::CollByte(coll_byte))) => { @@ -36,7 +40,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; proptest! { @@ -47,8 +50,8 @@ mod tests { input: Box::new(Expr::Const(byte_array.into())), } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx).as_vec_u8(), expected_hash); + let ctx = force_any_val::(); + assert_eq!(eval_out::>(&expr, &ctx).as_vec_u8(), expected_hash); } } diff --git a/ergotree-interpreter/src/eval/calc_sha256.rs b/ergotree-interpreter/src/eval/calc_sha256.rs index 3cefa834c..c5f6fa749 100644 --- a/ergotree-interpreter/src/eval/calc_sha256.rs +++ b/ergotree-interpreter/src/eval/calc_sha256.rs @@ -6,12 +6,16 @@ use sigma_util::hash::sha256_hash; use sigma_util::AsVecU8; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CalcSha256 { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v.clone() { Value::Coll(CollKind::NativeColl(NativeColl::CollByte(coll_byte))) => { @@ -35,7 +39,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; proptest! { @@ -46,8 +49,8 @@ mod tests { input: Box::new(Expr::Const(byte_array.into())), } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx).as_vec_u8(), expected_hash); + let ctx = force_any_val::(); + assert_eq!(eval_out::>(&expr, &ctx).as_vec_u8(), expected_hash); } } diff --git a/ergotree-interpreter/src/eval/coll_append.rs b/ergotree-interpreter/src/eval/coll_append.rs index 9e0f5a423..ffdb1f387 100644 --- a/ergotree-interpreter/src/eval/coll_append.rs +++ b/ergotree-interpreter/src/eval/coll_append.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use ergotree_ir::mir::coll_append::Append; // use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::CollKind; @@ -5,13 +7,12 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::types::stype::SType; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; -fn concat(mut e1: Vec, e2: Vec) -> Vec { - e1.extend(e2); - e1 +fn concat(e1: Vec, e2: Vec) -> Arc<[T]> { + e1.into_iter().chain(e2).collect() } fn extract_vecval(inp: Value) -> Result, EvalError> { @@ -35,7 +36,11 @@ fn extract_elem_tpe(inp: &Value) -> Result { } impl Evaluable for Append { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let col2_v = self.col_2.eval(env, ctx)?; let input_elem_tpe = extract_elem_tpe(&input_v)?; @@ -48,8 +53,8 @@ impl Evaluable for Append { } let input_vecval: Vec = extract_vecval(input_v)?; let col_2_vecval: Vec = extract_vecval(col2_v)?; - let concat_vecval: Vec = concat(input_vecval, col_2_vecval); - Ok(Value::Coll(CollKind::from_vec( + let concat_vecval = concat(input_vecval, col_2_vecval); + Ok(Value::Coll(CollKind::from_collection( input_elem_tpe, concat_vecval, )?)) diff --git a/ergotree-interpreter/src/eval/coll_by_index.rs b/ergotree-interpreter/src/eval/coll_by_index.rs index fd31f520e..59398333e 100644 --- a/ergotree-interpreter/src/eval/coll_by_index.rs +++ b/ergotree-interpreter/src/eval/coll_by_index.rs @@ -1,18 +1,23 @@ use ergotree_ir::mir::coll_by_index::ByIndex; use ergotree_ir::mir::constant::TryExtractInto; +use ergotree_ir::mir::value::CollKind; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ByIndex { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let index_v = self.index.eval(env, ctx)?; - let normalized_input_vals: Vec = match input_v { - Value::Coll(coll) => Ok(coll.as_vec()), + let normalized_input_vals: &CollKind> = match &input_v { + Value::Coll(coll) => Ok(coll), _ => Err(EvalError::UnexpectedValue(format!( "ByIndex: expected input to be Value::Coll, got: {0:?}", input_v @@ -22,13 +27,11 @@ impl Evaluable for ByIndex { Some(default) => { let default_v = default.eval(env, ctx)?; Ok(normalized_input_vals - .get(index_v.try_extract_into::()? as usize) - .cloned() + .get_val(index_v.try_extract_into::()? as usize) .unwrap_or(default_v)) } None => normalized_input_vals - .get(index_v.clone().try_extract_into::()? as usize) - .cloned() + .get_val(index_v.clone().try_extract_into::()? as usize) .ok_or_else(|| { EvalError::Misc(format!( "ByIndex: index {0:?} out of bounds for collection size {1:?}", @@ -46,23 +49,22 @@ mod tests { use ergotree_ir::chain::ergo_box::ErgoBox; use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::global_vars::GlobalVars; + use ergotree_ir::reference::Ref; use sigma_test_util::force_any_val; use super::*; use crate::eval::context::Context; use crate::eval::tests::eval_out; use crate::eval::tests::eval_out_wo_ctx; - use std::rc::Rc; - use std::sync::Arc; #[test] fn eval() { let expr: Expr = ByIndex::new(GlobalVars::Outputs.into(), Expr::Const(0i32.into()), None) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::>(&expr, ctx.clone()).box_id(), + eval_out::>(&expr, &ctx).box_id(), ctx.outputs.first().unwrap().box_id() ); } diff --git a/ergotree-interpreter/src/eval/coll_exists.rs b/ergotree-interpreter/src/eval/coll_exists.rs index ee5260499..7a1eb1d16 100644 --- a/ergotree-interpreter/src/eval/coll_exists.rs +++ b/ergotree-interpreter/src/eval/coll_exists.rs @@ -3,16 +3,20 @@ use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Exists { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let condition_v = self.condition.eval(env, ctx)?; let input_v_clone = input_v.clone(); - let mut condition_call = |arg: Value| match &condition_v { + let mut condition_call = |arg: Value<'ctx>| match &condition_v { Value::Lambda(func_value) => { let func_arg = func_value.args.first().ok_or_else(|| { EvalError::NotFound( @@ -36,7 +40,7 @@ impl Evaluable for Exists { }; let normalized_input_vals: Vec = match input_v { Value::Coll(coll) => { - if *coll.elem_tpe() != self.elem_tpe { + if coll.elem_tpe() != &*self.elem_tpe { return Err(EvalError::UnexpectedValue(format!( "expected Exists input element type to be {0:?}, got: {1:?}", self.elem_tpe, diff --git a/ergotree-interpreter/src/eval/coll_filter.rs b/ergotree-interpreter/src/eval/coll_filter.rs index 033120996..faa8a0da8 100644 --- a/ergotree-interpreter/src/eval/coll_filter.rs +++ b/ergotree-interpreter/src/eval/coll_filter.rs @@ -1,19 +1,25 @@ +use std::sync::Arc; + use ergotree_ir::mir::coll_filter::Filter; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::CollKind; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Filter { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let condition_v = self.condition.eval(env, ctx)?; let input_v_clone = input_v.clone(); - let mut condition_call = |arg: Value| match &condition_v { + let mut condition_call = |arg: Value<'ctx>| match &condition_v { Value::Lambda(func_value) => { let func_arg = func_value.args.first().ok_or_else(|| { EvalError::NotFound( @@ -37,7 +43,7 @@ impl Evaluable for Filter { }; let normalized_input_vals: Vec = match input_v { Value::Coll(coll) => { - if *coll.elem_tpe() != self.elem_tpe { + if coll.elem_tpe() != &*self.elem_tpe { return Err(EvalError::UnexpectedValue(format!( "expected Filter input element type to be {0:?}, got: {1:?}", self.elem_tpe, @@ -67,9 +73,9 @@ impl Evaluable for Filter { .zip(items_conditions) .filter(|(_, condition)| *condition) .map(|(item, _)| item) - .collect(); - Ok(Value::Coll(CollKind::from_vec( - self.elem_tpe.clone(), + .collect::>(); + Ok(Value::Coll(CollKind::from_collection( + (*self.elem_tpe).clone(), filtered_items, )?)) } @@ -79,8 +85,6 @@ impl Evaluable for Filter { #[allow(clippy::panic)] #[cfg(test)] mod tests { - use std::rc::Rc; - use std::sync::Arc; use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -97,6 +101,7 @@ mod tests { use ergotree_ir::mir::property_call::PropertyCall; use ergotree_ir::mir::unary_op::OneArgOpTryBuild; use ergotree_ir::mir::val_use::ValUse; + use ergotree_ir::reference::Ref; use ergotree_ir::types::scontext; use ergotree_ir::types::stype::SType; use proptest::prelude::*; @@ -136,21 +141,23 @@ mod tests { ) .unwrap() .into(); - let ctx = Rc::new(ctx); let expected: Vec<_> = ctx .data_inputs .clone() .map_or( vec![], |d| d - .as_vec() - .iter().filter(|& b| 1 <= b.value.as_i64()).cloned() + .iter() + .cloned() + .filter(|b| 1 <= b.value.as_i64()) .collect() ); - assert_eq!( - eval_out::>>(&expr, ctx), - expected, - ); - } + + + eval_out::>>(&expr, &ctx) + .into_iter() + .zip(expected) + .for_each(|(left, right)| assert_eq!(&*left, right)); + } } } diff --git a/ergotree-interpreter/src/eval/coll_fold.rs b/ergotree-interpreter/src/eval/coll_fold.rs index 7bf20e453..c9820a7c8 100644 --- a/ergotree-interpreter/src/eval/coll_fold.rs +++ b/ergotree-interpreter/src/eval/coll_fold.rs @@ -4,17 +4,21 @@ use ergotree_ir::mir::value::NativeColl; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Fold { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let zero_v = self.zero.eval(env, ctx)?; let fold_op_v = self.fold_op.eval(env, ctx)?; let input_v_clone = input_v.clone(); - let mut fold_op_call = |arg: Value| match &fold_op_v { + let mut fold_op_call = |arg: Value<'ctx>| match &fold_op_v { Value::Lambda(func_value) => { let func_arg = func_value .args @@ -64,7 +68,6 @@ impl Evaluable for Fold { #[cfg(test)] mod tests { use std::convert::TryInto; - use std::rc::Rc; use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -130,9 +133,9 @@ mod tests { ) .unwrap() .into(); - let ctx = Rc::new(ctx); + let ctx = ctx; assert_eq!( - eval_out::(&expr, ctx.clone()), + eval_out::(&expr, &ctx), ctx.data_inputs.clone() .map_or(0i64, |d| d.iter().fold(0i64, |acc, b| acc + b.value.as_i64())) ); diff --git a/ergotree-interpreter/src/eval/coll_forall.rs b/ergotree-interpreter/src/eval/coll_forall.rs index 9dfb815b0..ccdc22076 100644 --- a/ergotree-interpreter/src/eval/coll_forall.rs +++ b/ergotree-interpreter/src/eval/coll_forall.rs @@ -3,16 +3,20 @@ use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ForAll { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let condition_v = self.condition.eval(env, ctx)?; let input_v_clone = input_v.clone(); - let mut condition_call = |arg: Value| match &condition_v { + let mut condition_call = |arg: Value<'ctx>| match &condition_v { Value::Lambda(func_value) => { let func_arg = func_value.args.first().ok_or_else(|| { EvalError::NotFound( @@ -36,7 +40,7 @@ impl Evaluable for ForAll { }; let normalized_input_vals: Vec = match input_v { Value::Coll(coll) => { - if *coll.elem_tpe() != self.elem_tpe { + if coll.elem_tpe() != &*self.elem_tpe { return Err(EvalError::UnexpectedValue(format!( "expected ForAll input element type to be {0:?}, got: {1:?}", self.elem_tpe, diff --git a/ergotree-interpreter/src/eval/coll_map.rs b/ergotree-interpreter/src/eval/coll_map.rs index 384a6771b..4b1ccd311 100644 --- a/ergotree-interpreter/src/eval/coll_map.rs +++ b/ergotree-interpreter/src/eval/coll_map.rs @@ -1,18 +1,24 @@ +use std::sync::Arc; + use ergotree_ir::mir::coll_map::Map; use ergotree_ir::mir::value::CollKind; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Map { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let mapper_v = self.mapper.eval(env, ctx)?; let input_v_clone = input_v.clone(); - let mut mapper_call = |arg: Value| match &mapper_v { + let mut mapper_call = |arg: Value<'ctx>| match &mapper_v { Value::Lambda(func_value) => { let func_arg = func_value.args.first().ok_or_else(|| { EvalError::NotFound( @@ -63,9 +69,10 @@ impl Evaluable for Map { normalized_input_vals .iter() .map(|item| mapper_call(item.clone())) - .collect::, EvalError>>() + .collect::, EvalError>>() .map(|values| { - CollKind::from_vec(self.out_elem_tpe(), values).map_err(EvalError::TryExtractFrom) + CollKind::from_collection(self.out_elem_tpe(), values) + .map_err(EvalError::TryExtractFrom) }) .and_then(|v| v) // flatten , _> .map(Value::Coll) @@ -76,7 +83,6 @@ impl Evaluable for Map { #[allow(clippy::unwrap_used)] #[cfg(test)] mod tests { - use std::rc::Rc; use crate::eval::context::Context; use crate::eval::context::TxIoVec; @@ -132,9 +138,8 @@ mod tests { ) .unwrap() .into(); - let ctx = Rc::new(ctx); let output = { - let e = eval_out::>(&expr, ctx.clone()); + let e = eval_out::>(&expr, &ctx); if e.is_empty() { None } else { @@ -144,7 +149,7 @@ mod tests { assert_eq!( output, - ctx.data_inputs.clone().map(|d| d.mapped(| b| b.value.as_i64() + 1)) + ctx.data_inputs.clone().map(|d| d.iter().map(| b| b.value.as_i64() + 1).collect::>().try_into().unwrap()) ); } diff --git a/ergotree-interpreter/src/eval/coll_size.rs b/ergotree-interpreter/src/eval/coll_size.rs index 2f8cb4614..91650df3d 100644 --- a/ergotree-interpreter/src/eval/coll_size.rs +++ b/ergotree-interpreter/src/eval/coll_size.rs @@ -2,21 +2,24 @@ use ergotree_ir::mir::coll_size::SizeOf; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SizeOf { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; - let normalized_input_vals: Vec = match input_v { - Value::Coll(coll) => Ok(coll.as_vec()), + match input_v { + Value::Coll(coll) => Ok((coll.len() as i32).into()), _ => Err(EvalError::UnexpectedValue(format!( "SizeOf: expected input to be Value::Coll, got: {0:?}", input_v ))), - }?; - Ok((normalized_input_vals.len() as i32).into()) + } } } @@ -30,17 +33,13 @@ mod tests { use ergotree_ir::mir::global_vars::GlobalVars; use ergotree_ir::mir::unary_op::OneArgOpTryBuild; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval() { let expr: Expr = SizeOf::try_build(GlobalVars::Outputs.into()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!( - eval_out::(&expr, ctx.clone()), - ctx.outputs.len() as i32 - ); + let ctx = force_any_val::(); + assert_eq!(eval_out::(&expr, &ctx), ctx.outputs.len() as i32); } } diff --git a/ergotree-interpreter/src/eval/coll_slice.rs b/ergotree-interpreter/src/eval/coll_slice.rs index 6094eacd7..02c04e543 100644 --- a/ergotree-interpreter/src/eval/coll_slice.rs +++ b/ergotree-interpreter/src/eval/coll_slice.rs @@ -4,12 +4,16 @@ use ergotree_ir::mir::value::CollKind; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Slice { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let from_v = self.from.eval(env, ctx)?; let until_v = self.until.eval(env, ctx)?; @@ -27,9 +31,9 @@ impl Evaluable for Slice { // see https://github.com/ergoplatform/sigma-rust/issues/724 let range = from.max(0) as usize..until.min(input_vec.len() as i32) as usize; match input_vec.get(range) { - Some(slice) => Ok(Value::Coll(CollKind::from_vec(elem_tpe, slice.to_vec())?)), + Some(slice) => Ok(Value::Coll(CollKind::from_collection(elem_tpe, slice)?)), // Scala version returns empty collection if the range is out of bounds - None => Ok(Value::Coll(CollKind::from_vec(elem_tpe, vec![])?)), + None => Ok(Value::Coll(CollKind::from_collection(elem_tpe, [])?)), } } } diff --git a/ergotree-interpreter/src/eval/collection.rs b/ergotree-interpreter/src/eval/collection.rs index e497e22f6..c7061c7b9 100644 --- a/ergotree-interpreter/src/eval/collection.rs +++ b/ergotree-interpreter/src/eval/collection.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use ergotree_ir::mir::collection::Collection; use ergotree_ir::mir::constant::TryExtractFromError; use ergotree_ir::mir::constant::TryExtractInto; @@ -7,21 +9,26 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::types::stype::SType; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Collection { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { Ok(match self { Collection::BoolConstants(bools) => bools.clone().into(), Collection::Exprs { elem_tpe, items } => { - let items_v: Result, EvalError> = + let items_v: Result, EvalError> = items.iter().map(|i| i.eval(env, ctx)).collect(); match elem_tpe { SType::SByte => { - let bytes: Result, TryExtractFromError> = items_v? - .into_iter() + let bytes: Result, TryExtractFromError> = items_v? + .iter() + .cloned() .map(|i| i.try_extract_into::()) .collect(); Value::Coll(CollKind::NativeColl(NativeColl::CollByte(bytes?))) diff --git a/ergotree-interpreter/src/eval/context.rs b/ergotree-interpreter/src/eval/context.rs index 2bf8d1045..779af629d 100644 --- a/ergotree-interpreter/src/eval/context.rs +++ b/ergotree-interpreter/src/eval/context.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use crate::sigma_protocol::prover::ContextExtension; use bounded_vec::BoundedVec; use ergo_chain_types::{Header, PreHeader}; @@ -10,17 +8,17 @@ pub type TxIoVec = BoundedVec; /// Interpreter's context (blockchain state) #[derive(Debug)] -pub struct Context { +pub struct Context<'ctx> { /// Current height pub height: u32, /// Box that contains the script we're evaluating (from spending transaction inputs) - pub self_box: Arc, + pub self_box: &'ctx ErgoBox, /// Spending transaction outputs - pub outputs: Vec>, + pub outputs: &'ctx [ErgoBox], /// Spending transaction data inputs - pub data_inputs: Option>>, + pub data_inputs: Option>, /// Spending transaction inputs - pub inputs: TxIoVec>, + pub inputs: TxIoVec<&'ctx ErgoBox>, /// Pre header of current block pub pre_header: PreHeader, /// Fixed number of last block headers in descending order (first header is the newest one) @@ -29,7 +27,7 @@ pub struct Context { pub extension: ContextExtension, } -impl Context { +impl<'ctx> Context<'ctx> { /// Return a new Context with given context extension pub fn with_extension(self, ext: ContextExtension) -> Self { Context { @@ -46,7 +44,7 @@ mod arbitrary { use super::*; use proptest::{collection::vec, option::of, prelude::*}; - impl Arbitrary for Context { + impl Arbitrary for Context<'static> { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { @@ -73,12 +71,20 @@ mod arbitrary { )| { Self { height, - self_box: Arc::new(self_box), - outputs: outputs.into_iter().map(Arc::new).collect(), + self_box: Box::leak(Box::new(self_box)), + outputs: Vec::leak(outputs), data_inputs: data_inputs.map(|v| { - TxIoVec::from_vec(v.into_iter().map(Arc::new).collect()).unwrap() + v.into_iter() + .map(|i| &*Box::leak(Box::new(i))) + .collect::>() + .try_into() + .unwrap() }), - inputs: TxIoVec::from_vec(inputs.into_iter().map(Arc::new).collect()) + inputs: inputs + .into_iter() + .map(|i| &*Box::leak(Box::new(i))) + .collect::>() + .try_into() .unwrap(), pre_header, extension, diff --git a/ergotree-interpreter/src/eval/cost_accum.rs b/ergotree-interpreter/src/eval/cost_accum.rs index c47ebb56b..17626e94d 100644 --- a/ergotree-interpreter/src/eval/cost_accum.rs +++ b/ergotree-interpreter/src/eval/cost_accum.rs @@ -3,6 +3,7 @@ use ergotree_ir::mir::expr::Expr; use thiserror::Error; #[derive(Debug)] +#[allow(dead_code)] // TODO: Reintroduce this type for JIT costing pub struct CostAccumulator { costs: Costs, accum: u64, @@ -15,6 +16,7 @@ pub enum CostError { LimitExceeded(u64), } +#[allow(dead_code)] // TODO: Reintroduce this type for JIT costing impl CostAccumulator { pub fn new(initial_cost: u64, cost_limit: Option) -> CostAccumulator { CostAccumulator { diff --git a/ergotree-interpreter/src/eval/create_avl_tree.rs b/ergotree-interpreter/src/eval/create_avl_tree.rs index 84bea4358..02bd94f68 100644 --- a/ergotree-interpreter/src/eval/create_avl_tree.rs +++ b/ergotree-interpreter/src/eval/create_avl_tree.rs @@ -1,6 +1,6 @@ use super::Evaluable; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use ergo_chain_types::ADDigest; use ergotree_ir::mir::avl_tree_data::{AvlTreeData, AvlTreeFlags}; @@ -11,7 +11,11 @@ use sigma_util::AsVecU8; use std::convert::TryFrom; impl Evaluable for CreateAvlTree { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let flags_v = self.flags.eval(env, ctx)?.try_extract_into::()? as u8; let digest_v = self.digest.eval(env, ctx)?.try_extract_into::>()?; let key_length = self.key_length.eval(env, ctx)?.try_extract_into::()? as u32; diff --git a/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs b/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs index e58311b16..7bda43a86 100644 --- a/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs +++ b/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs @@ -5,12 +5,16 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::sigma_protocol::sigma_boolean::ProveDhTuple; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CreateProveDhTuple { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let g = self.g.eval(env, ctx)?.try_extract_into::()?; let h = self.h.eval(env, ctx)?.try_extract_into::()?; let u = self.u.eval(env, ctx)?.try_extract_into::()?; diff --git a/ergotree-interpreter/src/eval/create_provedlog.rs b/ergotree-interpreter/src/eval/create_provedlog.rs index dc0036a1b..15838791d 100644 --- a/ergotree-interpreter/src/eval/create_provedlog.rs +++ b/ergotree-interpreter/src/eval/create_provedlog.rs @@ -3,16 +3,20 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CreateProveDlog { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let value_v = self.input.eval(env, ctx)?; match value_v { Value::GroupElement(ecpoint) => { - let prove_dlog = ProveDlog::new(*ecpoint); + let prove_dlog = ProveDlog::new((*ecpoint).clone()); Ok(prove_dlog.into()) } _ => Err(EvalError::UnexpectedValue(format!( diff --git a/ergotree-interpreter/src/eval/decode_point.rs b/ergotree-interpreter/src/eval/decode_point.rs index f088e6078..627b9d625 100644 --- a/ergotree-interpreter/src/eval/decode_point.rs +++ b/ergotree-interpreter/src/eval/decode_point.rs @@ -2,7 +2,7 @@ use ergotree_ir::mir::decode_point::DecodePoint; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::EvalError::Misc; use crate::eval::Evaluable; @@ -11,7 +11,11 @@ use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::serialization::SigmaSerializable; impl Evaluable for DecodePoint { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let point_bytes = self.input.eval(env, ctx)?.try_extract_into::>()?; let point: EcPoint = SigmaSerializable::sigma_parse_bytes(&point_bytes).map_err(|_| { Misc(format!( diff --git a/ergotree-interpreter/src/eval/deserialize_context.rs b/ergotree-interpreter/src/eval/deserialize_context.rs index 6a4e48f6e..0d566f271 100644 --- a/ergotree-interpreter/src/eval/deserialize_context.rs +++ b/ergotree-interpreter/src/eval/deserialize_context.rs @@ -6,13 +6,17 @@ use ergotree_ir::serialization::SigmaSerializable; use ergotree_ir::types::stype::SType; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for DeserializeContext { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { - match ctx.ctx.extension.values.get(&self.id) { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { + match ctx.extension.values.get(&self.id) { Some(c) => { let expected_tpe = SType::SColl(SType::SByte.into()); if c.tpe != expected_tpe { @@ -31,7 +35,7 @@ impl Evaluable for DeserializeContext { } None => Err(EvalError::NotFound(format!( "DeserializeContext: no value with id {} in context extension map {}", - self.id, ctx.ctx.extension + self.id, ctx.extension ))), } } @@ -40,8 +44,6 @@ impl Evaluable for DeserializeContext { #[allow(clippy::unwrap_used)] #[cfg(test)] mod tests { - use std::rc::Rc; - use ergotree_ir::mir::constant::Constant; use ergotree_ir::mir::global_vars::GlobalVars; use sigma_test_util::force_any_val; @@ -67,7 +69,7 @@ mod tests { .collect(), }; let ctx = force_any_val::().with_extension(ctx_ext); - assert!(try_eval_out::(&expr, Rc::new(ctx)).unwrap()); + assert!(try_eval_out::(&expr, &ctx).unwrap()); } #[test] @@ -78,7 +80,7 @@ mod tests { } .into(); let ctx = force_any_val::().with_extension(ContextExtension::empty()); - assert!(try_eval_out::(&expr, Rc::new(ctx)).is_err()); + assert!(try_eval_out::(&expr, &ctx).is_err()); } #[test] @@ -94,7 +96,7 @@ mod tests { values: [(1u8, ctx_ext_val)].iter().cloned().collect(), }; let ctx = force_any_val::().with_extension(ctx_ext); - assert!(try_eval_out::(&expr, Rc::new(ctx)).is_err()); + assert!(try_eval_out::(&expr, &ctx).is_err()); } #[test] @@ -113,6 +115,6 @@ mod tests { .collect(), }; let ctx = force_any_val::().with_extension(ctx_ext); - assert!(try_eval_out::(&expr, Rc::new(ctx)).is_err()); + assert!(try_eval_out::(&expr, &ctx).is_err()); } } diff --git a/ergotree-interpreter/src/eval/deserialize_register.rs b/ergotree-interpreter/src/eval/deserialize_register.rs index 10ee394a9..ca1f68a00 100644 --- a/ergotree-interpreter/src/eval/deserialize_register.rs +++ b/ergotree-interpreter/src/eval/deserialize_register.rs @@ -9,16 +9,20 @@ use ergotree_ir::serialization::SigmaSerializable; use ergotree_ir::types::stype::SType; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for DeserializeRegister { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let reg_id: RegisterId = self.reg.try_into().map_err(|e| { EvalError::RegisterIdOutOfBounds(format!("register index is out of bounds: {:?} ", e)) })?; - match ctx.ctx.self_box.get_register(reg_id) { + match ctx.self_box.get_register(reg_id) { Ok(Some(c)) => { if c.tpe != SType::SColl(SType::SByte.into()) { Err(EvalError::UnexpectedExpr(format!( @@ -52,12 +56,12 @@ impl Evaluable for DeserializeRegister { } } -fn eval_default( +fn eval_default<'ctx>( deserialize_reg_tpe: &SType, default_expr: &Expr, - env: &mut Env, - ctx: &mut EvalContext, -) -> Result { + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, +) -> Result, EvalError> { if &default_expr.tpe() != deserialize_reg_tpe { Err(EvalError::UnexpectedExpr(format!( "DeserializeRegister: expected default expr to have type {:?}, got {:?}", @@ -74,9 +78,6 @@ fn eval_default( #[cfg(test)] mod tests { - use std::rc::Rc; - use std::sync::Arc; - use ergotree_ir::chain::ergo_box::ErgoBox; use ergotree_ir::chain::ergo_box::NonMandatoryRegisters; use ergotree_ir::mir::bin_op::BinOp; @@ -93,11 +94,11 @@ mod tests { use super::*; - fn make_ctx_with_self_box(self_box: ErgoBox) -> Context { + fn make_ctx_with_self_box(self_box: ErgoBox) -> Context<'static> { let ctx = force_any_val::(); Context { height: 0u32, - self_box: Arc::new(self_box), + self_box: Box::leak(Box::new(self_box)), ..ctx } } @@ -122,7 +123,7 @@ mod tests { } .into(); let ctx = make_ctx_with_self_box(b); - assert!(try_eval_out::(&expr, Rc::new(ctx)).unwrap()); + assert!(try_eval_out::(&expr, &ctx).unwrap()); } #[test] @@ -137,7 +138,7 @@ mod tests { } .into(); let ctx = make_ctx_with_self_box(b.clone()); - assert!(try_eval_out::(&expr, Rc::new(ctx)).is_err()); + assert!(try_eval_out::(&expr, &ctx).is_err()); // default with wrong type provided let expr: Expr = DeserializeRegister { @@ -147,7 +148,7 @@ mod tests { } .into(); let ctx = make_ctx_with_self_box(b.clone()); - assert!(try_eval_out::(&expr, Rc::new(ctx)).is_err()); + assert!(try_eval_out::(&expr, &ctx).is_err()); // default provided let expr: Expr = DeserializeRegister { @@ -157,7 +158,7 @@ mod tests { } .into(); let ctx = make_ctx_with_self_box(b); - assert_eq!(try_eval_out::(&expr, Rc::new(ctx)).unwrap(), 1i32); + assert_eq!(try_eval_out::(&expr, &ctx).unwrap(), 1i32); } #[test] @@ -173,7 +174,7 @@ mod tests { } .into(); let ctx = make_ctx_with_self_box(b); - assert!(try_eval_out::(&expr, Rc::new(ctx)).is_err()); + assert!(try_eval_out::(&expr, &ctx).is_err()); } #[test] @@ -191,6 +192,6 @@ mod tests { } .into(); let ctx = make_ctx_with_self_box(b); - assert!(try_eval_out::(&expr, Rc::new(ctx)).is_err()); + assert!(try_eval_out::(&expr, &ctx).is_err()); } } diff --git a/ergotree-interpreter/src/eval/downcast.rs b/ergotree-interpreter/src/eval/downcast.rs index 003c5f1b4..8dba979f3 100644 --- a/ergotree-interpreter/src/eval/downcast.rs +++ b/ergotree-interpreter/src/eval/downcast.rs @@ -4,7 +4,7 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::types::stype::SType; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; use std::convert::TryFrom; @@ -104,7 +104,11 @@ fn downcast_to_byte(in_v: Value) -> Result { } impl Evaluable for Downcast { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match self.tpe { SType::SBigInt => downcast_to_bigint(input_v), diff --git a/ergotree-interpreter/src/eval/env.rs b/ergotree-interpreter/src/eval/env.rs index 78aba5259..43b7cdc4e 100644 --- a/ergotree-interpreter/src/eval/env.rs +++ b/ergotree-interpreter/src/eval/env.rs @@ -6,13 +6,13 @@ use ergotree_ir::mir::value::Value; /// Environment for the interpreter #[derive(PartialEq, Eq, Debug, Clone)] -pub struct Env { - store: HashMap, +pub struct Env<'ctx> { + store: HashMap>, } -impl Env { +impl<'ctx> Env<'ctx> { /// Empty environment - pub fn empty() -> Env { + pub fn empty() -> Env<'ctx> { Env { store: HashMap::new(), } @@ -24,14 +24,14 @@ impl Env { } /// Extend this environment (create new) with added element - pub fn extend(&self, idx: ValId, v: Value) -> Env { + pub fn extend(&self, idx: ValId, v: Value<'ctx>) -> Env<'ctx> { let mut new_store = self.store.clone(); new_store.insert(idx, v); Env { store: new_store } } /// Insert a Value for the given ValId - pub fn insert(&mut self, idx: ValId, v: Value) { + pub fn insert(&mut self, idx: ValId, v: Value<'ctx>) { self.store.insert(idx, v); } @@ -41,12 +41,22 @@ impl Env { } /// Get an element - pub fn get(&self, idx: ValId) -> Option<&Value> { + pub fn get(&self, idx: ValId) -> Option<&Value<'ctx>> { self.store.get(&idx) } + /// Convert borrowed data to Arc + pub(crate) fn to_static(&'ctx self) -> Env<'static> { + Env { + store: self + .store + .iter() + .map(|(&k, v)| (k, v.to_static())) + .collect(), + } + } } -impl Display for Env { +impl Display for Env<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut keys: Vec<&ValId> = self.store.keys().collect(); keys.sort(); diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index 28bb990fc..61cc2e474 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -84,7 +84,7 @@ pub struct SpannedEvalError { /// source span for the expression where error occurred source_span: SourceSpan, /// environment at the time when error occurred - env: Env, + env: Env<'static>, } /// Wrapped error with source span and source code @@ -95,7 +95,7 @@ pub struct SpannedWithSourceEvalError { /// source span for the expression where error occurred source_span: SourceSpan, /// environment at the time when error occurred - env: Env, + env: Env<'static>, /// source code source: String, } @@ -155,7 +155,7 @@ impl EvalError { EvalError::Spanned(SpannedEvalError { error: Box::new(self), source_span, - env, + env: env.to_static(), }) } @@ -179,7 +179,7 @@ pub trait ExtResultEvalError { } impl ExtResultEvalError for Result { - fn enrich_err(self, span: SourceSpan, env: &Env) -> Result { + fn enrich_err<'ctx>(self, span: SourceSpan, env: &Env<'ctx>) -> Result { self.map_err(|e| match e { // skip already wrapped errors w @ EvalError::Spanned { .. } => w, @@ -191,8 +191,6 @@ impl ExtResultEvalError for Result { #[allow(clippy::unwrap_used, unused_imports, dead_code)] #[cfg(test)] mod tests { - use std::rc::Rc; - use ergotree_ir::mir::coll_by_index::ByIndex; use ergotree_ir::mir::global_vars::GlobalVars; use ergotree_ir::source_span::SourceSpan; @@ -218,8 +216,8 @@ mod tests { let mut w = PosTrackingWriter::new(); let spanned_expr = expr.print(&mut w).unwrap(); dbg!(&spanned_expr); - let ctx = Rc::new(force_any_val::()); - let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, ctx) + let ctx = force_any_val::(); + let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, &ctx) .err() .unwrap() .try_into() @@ -237,8 +235,8 @@ mod tests { let mut w = PosTrackingWriter::new(); let spanned_expr = expr.print(&mut w).unwrap(); dbg!(&spanned_expr); - let ctx = Rc::new(force_any_val::()); - let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, ctx) + let ctx = force_any_val::(); + let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, &ctx) .err() .unwrap() .try_into() diff --git a/ergotree-interpreter/src/eval/exponentiate.rs b/ergotree-interpreter/src/eval/exponentiate.rs index dc00bd0f7..b7698d510 100644 --- a/ergotree-interpreter/src/eval/exponentiate.rs +++ b/ergotree-interpreter/src/eval/exponentiate.rs @@ -4,12 +4,16 @@ use ergotree_ir::sigma_protocol::dlog_group; use k256::Scalar; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Exponentiate { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let left_v = self.left.eval(env, ctx)?; let right_v = self.right.eval(env, ctx)?; @@ -46,7 +50,6 @@ mod tests { use num_traits::Num; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; proptest! { @@ -67,8 +70,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::(&expr, ctx), expected_exp); + let ctx = force_any_val::(); + assert_eq!(eval_out::(&expr, &ctx), expected_exp); } } @@ -82,7 +85,7 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert!(try_eval_out::(&expr, ctx).is_err()); + let ctx = force_any_val::(); + assert!(try_eval_out::(&expr, &ctx).is_err()); } } diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 70aa77bde..2ef42cbd4 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -5,14 +5,18 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::source_span::Spanned; use super::error::ExtResultEvalError; +use super::Context; use super::Env; -use super::EvalContext; use super::EvalError; use super::Evaluable; impl Evaluable for Expr { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { - ctx.cost_accum.add_cost_of(self)?; + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { + //ctx.cost_accum.add_cost_of(self)?; let res = match self { Expr::Const(c) => Ok(Value::from(c.v.clone())), Expr::SubstConstants(op) => op.expr().eval(env, ctx), @@ -90,7 +94,11 @@ impl Evaluable for Expr { } impl Evaluable for Spanned { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { self.expr.eval(env, ctx) } } diff --git a/ergotree-interpreter/src/eval/extract_amount.rs b/ergotree-interpreter/src/eval/extract_amount.rs index 25c4e3cce..f27fdca41 100644 --- a/ergotree-interpreter/src/eval/extract_amount.rs +++ b/ergotree-interpreter/src/eval/extract_amount.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::extract_amount::ExtractAmount; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractAmount { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(Value::Long(b.value.as_i64())), @@ -28,7 +32,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::global_vars::GlobalVars; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval() { @@ -36,10 +39,7 @@ mod tests { input: Box::new(GlobalVars::SelfBox.into()), } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!( - eval_out::(&e, ctx.clone()), - ctx.self_box.value.as_i64() - ) + let ctx = force_any_val::(); + assert_eq!(eval_out::(&e, &ctx), ctx.self_box.value.as_i64()) } } diff --git a/ergotree-interpreter/src/eval/extract_bytes.rs b/ergotree-interpreter/src/eval/extract_bytes.rs index 060fe203e..01e9bc9ec 100644 --- a/ergotree-interpreter/src/eval/extract_bytes.rs +++ b/ergotree-interpreter/src/eval/extract_bytes.rs @@ -3,12 +3,16 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::serialization::SigmaSerializable; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractBytes { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.sigma_serialize_bytes()?.into()), @@ -30,7 +34,6 @@ mod tests { use ergotree_ir::mir::global_vars::GlobalVars; use sigma_test_util::force_any_val; use sigma_util::AsVecI8; - use std::rc::Rc; #[test] fn eval() { @@ -38,9 +41,9 @@ mod tests { input: Box::new(GlobalVars::SelfBox.into()), } .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::>(&e, ctx.clone()), + eval_out::>(&e, &ctx), ctx.self_box.sigma_serialize_bytes().unwrap().as_vec_i8() ); } diff --git a/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs b/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs index f97e8fd1e..6de0c5944 100644 --- a/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs +++ b/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::extract_bytes_with_no_ref::ExtractBytesWithNoRef; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractBytesWithNoRef { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.bytes_without_ref()?.into()), @@ -28,7 +32,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::global_vars::GlobalVars; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval() { @@ -36,9 +39,9 @@ mod tests { input: Box::new(GlobalVars::SelfBox.into()), } .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::>(&e, ctx.clone()), + eval_out::>(&e, &ctx), ctx.self_box.bytes_without_ref().unwrap() ); } diff --git a/ergotree-interpreter/src/eval/extract_creation_info.rs b/ergotree-interpreter/src/eval/extract_creation_info.rs index 0cebb3376..84badbe5b 100644 --- a/ergotree-interpreter/src/eval/extract_creation_info.rs +++ b/ergotree-interpreter/src/eval/extract_creation_info.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::extract_creation_info::ExtractCreationInfo; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractCreationInfo { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.creation_info().into()), @@ -24,7 +28,6 @@ impl Evaluable for ExtractCreationInfo { mod tests { use crate::eval::tests::eval_out; use crate::eval::Context; - use std::rc::Rc; use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::global_vars::GlobalVars; @@ -38,8 +41,8 @@ mod tests { let expr: Expr = ExtractCreationInfo::try_build(GlobalVars::SelfBox.into()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - let v = eval_out::<(i32, Vec)>(&expr, ctx.clone()); + let ctx = force_any_val::(); + let v = eval_out::<(i32, Vec)>(&expr, &ctx); assert_eq!(v, ctx.self_box.creation_info()); } } diff --git a/ergotree-interpreter/src/eval/extract_id.rs b/ergotree-interpreter/src/eval/extract_id.rs index ce7d9c18d..2031ee6ca 100644 --- a/ergotree-interpreter/src/eval/extract_id.rs +++ b/ergotree-interpreter/src/eval/extract_id.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::extract_id::ExtractId; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractId { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => { @@ -31,7 +35,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::global_vars::GlobalVars; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval() { @@ -39,8 +42,8 @@ mod tests { input: Box::new(GlobalVars::SelfBox.into()), } .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let bytes: Vec = ctx.self_box.box_id().into(); - assert_eq!(eval_out::>(&e, ctx), bytes); + assert_eq!(eval_out::>(&e, &ctx), bytes); } } diff --git a/ergotree-interpreter/src/eval/extract_reg_as.rs b/ergotree-interpreter/src/eval/extract_reg_as.rs index 656220c63..3d68fa738 100644 --- a/ergotree-interpreter/src/eval/extract_reg_as.rs +++ b/ergotree-interpreter/src/eval/extract_reg_as.rs @@ -1,22 +1,26 @@ use std::convert::TryInto; -use std::sync::Arc; use ergotree_ir::chain::ergo_box::ErgoBox; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::extract_reg_as::ExtractRegisterAs; use ergotree_ir::mir::value::Value; +use ergotree_ir::reference::Ref; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractRegisterAs { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let ir_box = self .input .eval(env, ctx)? - .try_extract_into::>()?; + .try_extract_into::>()?; let id = self.register_id.try_into().map_err(|e| { EvalError::RegisterIdOutOfBounds(format!( "register index {} is out of bounds: {:?} ", @@ -44,7 +48,6 @@ mod tests { use ergotree_ir::mir::unary_op::OneArgOpTryBuild; use ergotree_ir::types::stype::SType; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval_box_get_reg_r0() { @@ -56,8 +59,8 @@ mod tests { .unwrap() .into(); let option_get_expr: Expr = OptionGet::try_build(get_reg_expr).unwrap().into(); - let ctx = Rc::new(force_any_val::()); - let v = eval_out::(&option_get_expr, ctx.clone()); + let ctx = force_any_val::(); + let v = eval_out::(&option_get_expr, &ctx); assert_eq!(v, ctx.self_box.value.as_i64()); } } diff --git a/ergotree-interpreter/src/eval/extract_script_bytes.rs b/ergotree-interpreter/src/eval/extract_script_bytes.rs index 71075ced4..4281ea7c4 100644 --- a/ergotree-interpreter/src/eval/extract_script_bytes.rs +++ b/ergotree-interpreter/src/eval/extract_script_bytes.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::extract_script_bytes::ExtractScriptBytes; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractScriptBytes { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.script_bytes()?.into()), @@ -28,7 +32,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::global_vars::GlobalVars; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval() { @@ -36,9 +39,9 @@ mod tests { input: Box::new(GlobalVars::SelfBox.into()), } .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::>(&e, ctx.clone()), + eval_out::>(&e, &ctx), ctx.self_box.script_bytes().unwrap() ); } diff --git a/ergotree-interpreter/src/eval/func_value.rs b/ergotree-interpreter/src/eval/func_value.rs index 1cf0d944a..bb459ed58 100644 --- a/ergotree-interpreter/src/eval/func_value.rs +++ b/ergotree-interpreter/src/eval/func_value.rs @@ -3,12 +3,16 @@ use ergotree_ir::mir::value::Lambda; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for FuncValue { - fn eval(&self, _env: &mut Env, _ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + _env: &mut Env, + _ctx: &Context<'ctx>, + ) -> Result, EvalError> { Ok(Value::Lambda(Lambda { args: self.args().to_vec(), body: self.body().clone().into(), diff --git a/ergotree-interpreter/src/eval/get_var.rs b/ergotree-interpreter/src/eval/get_var.rs index 1ac5e34e6..0e5dfa5d5 100644 --- a/ergotree-interpreter/src/eval/get_var.rs +++ b/ergotree-interpreter/src/eval/get_var.rs @@ -3,18 +3,18 @@ use ergotree_ir::mir::get_var::GetVar; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for GetVar { - fn eval(&self, _env: &mut Env, ctx: &mut EvalContext) -> Result { - match ctx.ctx.extension.values.get(&self.var_id) { + fn eval<'ctx>(&self, _env: &mut Env, ctx: &Context<'ctx>) -> Result, EvalError> { + match ctx.extension.values.get(&self.var_id) { None => Ok(Value::Opt(None.into())), Some(v) if v.tpe == self.var_tpe => Ok((Some(v.v.clone())).into()), Some(v) => Err(TryExtractFromError(format!( "GetVar: expected extension value id {} to have type {:?}, found {:?} in context extension map {}", - self.var_id, self.var_tpe, v, ctx.ctx.extension + self.var_id, self.var_tpe, v, ctx.extension )) .into()), } @@ -29,17 +29,16 @@ mod tests { use ergotree_ir::mir::expr::Expr; use ergotree_ir::types::stype::SType; use sigma_test_util::force_any_val; - use std::rc::Rc; const VAR_IDX: u8 = 3; const VAR_VAL: i32 = 123; /// Prepare context with single extension variable - fn prepare_context() -> Rc { + fn prepare_context() -> Context<'static> { let mut ctx = force_any_val::(); ctx.extension.values.clear(); ctx.extension.values.insert(VAR_IDX, VAR_VAL.into()); - Rc::new(ctx) + ctx } /// Normal evaluation @@ -51,7 +50,7 @@ mod tests { var_tpe: SType::SInt, } .into(); - let res = eval_out::>(&expr, ctx); + let res = eval_out::>(&expr, &ctx); assert_eq!(res, Some(VAR_VAL)); } @@ -64,7 +63,7 @@ mod tests { var_tpe: SType::SInt, } .into(); - let res = eval_out::>(&expr, ctx); + let res = eval_out::>(&expr, &ctx); assert_eq!(res, None); } @@ -77,7 +76,7 @@ mod tests { var_tpe: SType::SBoolean, } .into(); - let res = try_eval_out::(&expr, ctx); + let res = try_eval_out::(&expr, &ctx); assert!(res.is_err()); } } diff --git a/ergotree-interpreter/src/eval/global_vars.rs b/ergotree-interpreter/src/eval/global_vars.rs index 148c6e7de..964466305 100644 --- a/ergotree-interpreter/src/eval/global_vars.rs +++ b/ergotree-interpreter/src/eval/global_vars.rs @@ -1,22 +1,31 @@ use crate::eval::Env; use ergotree_ir::mir::global_vars::GlobalVars; use ergotree_ir::mir::value::Value; +use ergotree_ir::reference::Ref; use ergotree_ir::serialization::SigmaSerializable; -use super::EvalContext; +use super::Context; use super::EvalError; use super::Evaluable; impl Evaluable for GlobalVars { - fn eval(&self, _env: &mut Env, ectx: &mut EvalContext) -> Result { + fn eval<'ctx>(&self, _env: &mut Env, ctx: &Context<'ctx>) -> Result, EvalError> { match self { - GlobalVars::Height => Ok((ectx.ctx.height as i32).into()), - GlobalVars::SelfBox => Ok(ectx.ctx.self_box.clone().into()), - GlobalVars::Outputs => Ok(ectx.ctx.outputs.clone().into()), - GlobalVars::Inputs => Ok(ectx.ctx.inputs.as_vec().clone().into()), - GlobalVars::MinerPubKey => { - Ok(ectx.ctx.pre_header.miner_pk.sigma_serialize_bytes()?.into()) - } + GlobalVars::Height => Ok((ctx.height as i32).into()), + GlobalVars::SelfBox => Ok(Value::CBox(Ref::from(ctx.self_box))), + GlobalVars::Outputs => Ok(ctx + .outputs + .iter() + .map(Ref::Borrowed) + .collect::>() + .into()), + GlobalVars::Inputs => Ok(ctx + .inputs + .iter() + .map(|&i| Ref::Borrowed(i)) + .collect::>() + .into()), + GlobalVars::MinerPubKey => Ok(ctx.pre_header.miner_pk.sigma_serialize_bytes()?.into()), GlobalVars::GroupGenerator => Ok(ergo_chain_types::ec_point::generator().into()), } } @@ -25,8 +34,6 @@ impl Evaluable for GlobalVars { #[allow(clippy::unwrap_used)] #[cfg(test)] mod tests { - use std::rc::Rc; - use std::sync::Arc; use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -40,43 +47,45 @@ mod tests { #[test] fn eval_height() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expr = compile_expr("HEIGHT", ScriptEnv::new()).unwrap(); - assert_eq!(eval_out::(&expr, ctx.clone()), ctx.height as i32); + assert_eq!(eval_out::(&expr, &ctx), ctx.height as i32); } #[test] fn eval_self_box() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::>(&GlobalVars::SelfBox.into(), ctx.clone()).as_ref(), - ctx.self_box.as_ref() + &*eval_out::>(&GlobalVars::SelfBox.into(), &ctx), + ctx.self_box ); } #[test] fn eval_outputs() { - let ctx = Rc::new(force_any_val::()); - assert_eq!( - eval_out::>>(&GlobalVars::Outputs.into(), ctx.clone()), - ctx.outputs - ); + let ctx = force_any_val::(); + + eval_out::>>(&GlobalVars::Outputs.into(), &ctx) + .iter() + .zip(ctx.outputs) + .for_each(|(a, b)| assert_eq!(&**a, b)); } #[test] fn eval_inputs() { - let ctx = Rc::new(force_any_val::()); - assert_eq!( - eval_out::>>(&GlobalVars::Inputs.into(), ctx.clone()), - *ctx.inputs.as_vec() - ); + let ctx = force_any_val::(); + + eval_out::>>(&GlobalVars::Inputs.into(), &ctx) + .iter() + .zip(ctx.inputs) + .for_each(|(a, b)| assert_eq!(&**a, b)); } #[test] fn eval_group_generator() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::(&GlobalVars::GroupGenerator.into(), ctx), + eval_out::(&GlobalVars::GroupGenerator.into(), &ctx), ergo_chain_types::ec_point::generator() ); } diff --git a/ergotree-interpreter/src/eval/if_op.rs b/ergotree-interpreter/src/eval/if_op.rs index fce7a6ede..d4704d1dc 100644 --- a/ergotree-interpreter/src/eval/if_op.rs +++ b/ergotree-interpreter/src/eval/if_op.rs @@ -3,12 +3,16 @@ use ergotree_ir::mir::if_op::If; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for If { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let condition_v = self.condition.eval(env, ctx)?; if condition_v.try_extract_into::()? { self.true_branch.eval(env, ctx) diff --git a/ergotree-interpreter/src/eval/logical_not.rs b/ergotree-interpreter/src/eval/logical_not.rs index 2e2c8ec62..885aed2de 100644 --- a/ergotree-interpreter/src/eval/logical_not.rs +++ b/ergotree-interpreter/src/eval/logical_not.rs @@ -3,12 +3,16 @@ use ergotree_ir::mir::logical_not::LogicalNot; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for LogicalNot { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let input_v_bool = input_v.try_extract_into::()?; Ok((!input_v_bool).into()) diff --git a/ergotree-interpreter/src/eval/long_to_byte_array.rs b/ergotree-interpreter/src/eval/long_to_byte_array.rs index 57ce9e5f4..4bc654335 100644 --- a/ergotree-interpreter/src/eval/long_to_byte_array.rs +++ b/ergotree-interpreter/src/eval/long_to_byte_array.rs @@ -2,13 +2,17 @@ use ergotree_ir::mir::long_to_byte_array::LongToByteArray; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; use ergotree_ir::mir::constant::TryExtractInto; impl Evaluable for LongToByteArray { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let mut val = self.input.eval(env, ctx)?.try_extract_into::()?; let mut buf = vec![42_i8; 8]; for i in (0..8).rev() { diff --git a/ergotree-interpreter/src/eval/method_call.rs b/ergotree-interpreter/src/eval/method_call.rs index fe6ac8174..1c1af8a42 100644 --- a/ergotree-interpreter/src/eval/method_call.rs +++ b/ergotree-interpreter/src/eval/method_call.rs @@ -3,12 +3,16 @@ use ergotree_ir::mir::value::Value; use super::smethod_eval_fn; use super::Env; -use super::EvalContext; +use super::Context; use super::EvalError; use super::Evaluable; impl Evaluable for MethodCall { - fn eval(&self, env: &mut Env, ectx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ectx: &Context<'ctx>, + ) -> Result, EvalError> { let ov = self.obj.eval(env, ectx)?; let argsv: Result, EvalError> = self.args.iter().map(|arg| arg.eval(env, ectx)).collect(); @@ -20,8 +24,6 @@ impl Evaluable for MethodCall { #[cfg(test)] #[cfg(feature = "arbitrary")] mod tests { - use std::rc::Rc; - use ergotree_ir::mir::constant::Constant; use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::global_vars::GlobalVars; @@ -45,9 +47,9 @@ mod tests { .unwrap() .into(); let option_get_expr: Expr = OptionGet::try_build(mc).unwrap().into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::(&option_get_expr, ctx.clone()), + eval_out::(&option_get_expr, &ctx), ctx.self_box.value.as_i64() ); } diff --git a/ergotree-interpreter/src/eval/multiply_group.rs b/ergotree-interpreter/src/eval/multiply_group.rs index aa1973f52..0f0311722 100644 --- a/ergotree-interpreter/src/eval/multiply_group.rs +++ b/ergotree-interpreter/src/eval/multiply_group.rs @@ -2,17 +2,23 @@ use ergotree_ir::mir::multiply_group::MultiplyGroup; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for MultiplyGroup { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let left_v = self.left.eval(env, ctx)?; let right_v = self.right.eval(env, ctx)?; - match (left_v.clone(), right_v.clone()) { - (Value::GroupElement(left), Value::GroupElement(right)) => Ok((*left * &*right).into()), + match (&left_v, &right_v) { + (Value::GroupElement(left), Value::GroupElement(right)) => { + Ok(((**left).clone() * right).into()) + } _ => Err(EvalError::UnexpectedValue(format!( "Expected MultiplyGroup input to be GroupElement, got: {0:?}", (left_v, right_v) @@ -33,7 +39,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; proptest! { @@ -48,8 +53,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::(&expr, ctx), expected_mul); + let ctx = force_any_val::(); + assert_eq!(eval_out::(&expr, &ctx), expected_mul); } } } diff --git a/ergotree-interpreter/src/eval/negation.rs b/ergotree-interpreter/src/eval/negation.rs index 5a6b15129..ed2f47c43 100644 --- a/ergotree-interpreter/src/eval/negation.rs +++ b/ergotree-interpreter/src/eval/negation.rs @@ -2,19 +2,25 @@ use ergotree_ir::mir::negation::Negation; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; use num_traits::CheckedNeg; impl Evaluable for Negation { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; fn overflow_err(v: &T) -> EvalError { EvalError::ArithmeticException(format!("Overflow on Negation of value {}", *v)) } - fn neg + std::fmt::Display>(v: &T) -> Result { + fn neg<'ctx, T: CheckedNeg + Into> + std::fmt::Display>( + v: &T, + ) -> Result, EvalError> { v.checked_neg() .map(|v| v.into()) .ok_or_else(|| overflow_err(v)) @@ -46,7 +52,7 @@ mod tests { use ergotree_ir::mir::unary_op::OneArgOpTryBuild; use num_traits::{Bounded, Num}; - fn try_run_eval + TryExtractFrom>( + fn try_run_eval + TryExtractFrom> + 'static>( input: T, ) -> Result { let expr: Expr = Negation::try_build(Expr::Const(input.into())) @@ -54,7 +60,7 @@ mod tests { .into(); try_eval_out_wo_ctx::(&expr) } - fn run_eval + TryExtractFrom>(input: T) -> T { + fn run_eval + TryExtractFrom> + 'static>(input: T) -> T { try_run_eval(input).unwrap() } diff --git a/ergotree-interpreter/src/eval/option_get.rs b/ergotree-interpreter/src/eval/option_get.rs index bcbace334..efd8b5ba1 100644 --- a/ergotree-interpreter/src/eval/option_get.rs +++ b/ergotree-interpreter/src/eval/option_get.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::option_get::OptionGet; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for OptionGet { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let v = self.input.eval(env, ctx)?; match v { Value::Opt(opt_v) => { @@ -33,7 +37,6 @@ mod tests { use ergotree_ir::mir::unary_op::OneArgOpTryBuild; use ergotree_ir::types::stype::SType; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval_get() { @@ -45,8 +48,8 @@ mod tests { .unwrap() .into(); let option_get_expr: Expr = OptionGet::try_build(get_reg_expr).unwrap().into(); - let ctx = Rc::new(force_any_val::()); - let v = eval_out::(&option_get_expr, ctx.clone()); + let ctx = force_any_val::(); + let v = eval_out::(&option_get_expr, &ctx); assert_eq!(v, ctx.self_box.value.as_i64()); } } diff --git a/ergotree-interpreter/src/eval/option_get_or_else.rs b/ergotree-interpreter/src/eval/option_get_or_else.rs index 5e307518a..66f1341aa 100644 --- a/ergotree-interpreter/src/eval/option_get_or_else.rs +++ b/ergotree-interpreter/src/eval/option_get_or_else.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::option_get_or_else::OptionGetOrElse; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for OptionGetOrElse { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let v = self.input.eval(env, ctx)?; let default_v = self.default.eval(env, ctx)?; match v { @@ -33,7 +37,6 @@ mod tests { use ergotree_ir::mir::global_vars::GlobalVars; use ergotree_ir::types::stype::SType; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval_non_empty() { @@ -48,8 +51,8 @@ mod tests { let option_get_expr: Expr = OptionGetOrElse::new(get_reg_expr, default_expr.into()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - let v = eval_out::(&option_get_expr, ctx.clone()); + let ctx = force_any_val::(); + let v = eval_out::(&option_get_expr, &ctx); assert_eq!(v, ctx.self_box.value.as_i64()); } @@ -64,8 +67,8 @@ mod tests { let option_get_expr: Expr = OptionGetOrElse::new(get_var_expr, default_expr.into()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - let v = eval_out::(&option_get_expr, ctx); + let ctx = force_any_val::(); + let v = eval_out::(&option_get_expr, &ctx); assert_eq!(v, 1i64); } } diff --git a/ergotree-interpreter/src/eval/option_is_defined.rs b/ergotree-interpreter/src/eval/option_is_defined.rs index 814667ab9..4fb69bed0 100644 --- a/ergotree-interpreter/src/eval/option_is_defined.rs +++ b/ergotree-interpreter/src/eval/option_is_defined.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::option_is_defined::OptionIsDefined; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for OptionIsDefined { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let v = self.input.eval(env, ctx)?; match v { Value::Opt(opt_v) => Ok(opt_v.is_some().into()), @@ -30,7 +34,6 @@ mod tests { use ergotree_ir::mir::global_vars::GlobalVars; use ergotree_ir::types::stype::SType; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval() { @@ -45,8 +48,8 @@ mod tests { input: Box::new(get_reg_expr), } .into(); - let ctx = Rc::new(force_any_val::()); - let v = eval_out::(&option_expr, ctx); + let ctx = force_any_val::(); + let v = eval_out::(&option_expr, &ctx); // R0 is always defined (box value) assert!(v); } diff --git a/ergotree-interpreter/src/eval/or.rs b/ergotree-interpreter/src/eval/or.rs index 561fb4dc7..289581943 100644 --- a/ergotree-interpreter/src/eval/or.rs +++ b/ergotree-interpreter/src/eval/or.rs @@ -3,12 +3,16 @@ use ergotree_ir::mir::or::Or; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Or { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let input_v_bools = input_v.try_extract_into::>()?; Ok(input_v_bools.iter().any(|b| *b).into()) @@ -25,15 +29,14 @@ mod tests { use proptest::collection; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; proptest! { #[test] fn eval(bools in collection::vec(any::(), 0..10)) { let expr: Expr = Or {input: Expr::Const(bools.clone().into()).into()}.into(); - let ctx = Rc::new(force_any_val::()); - let res = eval_out::(&expr, ctx); + let ctx = force_any_val::(); + let res = eval_out::(&expr, &ctx); prop_assert_eq!(res, bools.iter().any(|b| *b)); } } diff --git a/ergotree-interpreter/src/eval/property_call.rs b/ergotree-interpreter/src/eval/property_call.rs index 79996caa3..6f1554014 100644 --- a/ergotree-interpreter/src/eval/property_call.rs +++ b/ergotree-interpreter/src/eval/property_call.rs @@ -2,13 +2,17 @@ use ergotree_ir::mir::property_call::PropertyCall; use ergotree_ir::mir::value::Value; use super::smethod_eval_fn; +use super::Context; use super::Env; -use super::EvalContext; use super::EvalError; use super::Evaluable; impl Evaluable for PropertyCall { - fn eval(&self, env: &mut Env, ectx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ectx: &Context<'ctx>, + ) -> Result, EvalError> { let ov = self.obj.eval(env, ectx)?; smethod_eval_fn(&self.method)?(env, ectx, ov, vec![]) } @@ -22,21 +26,23 @@ mod tests { use crate::eval::tests::eval_out; use ergotree_ir::chain::ergo_box::ErgoBox; use ergotree_ir::mir::expr::Expr; + use ergotree_ir::reference::Ref; use ergotree_ir::types::scontext; use sigma_test_util::force_any_val; - use std::rc::Rc; - use std::sync::Arc; #[test] fn eval_context_data_inputs() { let pc: Expr = PropertyCall::new(Expr::Context, scontext::DATA_INPUTS_PROPERTY.clone()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx .data_inputs .clone() .map_or(vec![], |d| d.as_vec().clone()); - assert_eq!(eval_out::>>(&pc, ctx), expected,); + eval_out::>>(&pc, &ctx) + .into_iter() + .zip(expected) + .for_each(|(a, b)| assert_eq!(&*a, b)); } } diff --git a/ergotree-interpreter/src/eval/savltree.rs b/ergotree-interpreter/src/eval/savltree.rs index 34f6e85f8..ab7076f64 100644 --- a/ergotree-interpreter/src/eval/savltree.rs +++ b/ergotree-interpreter/src/eval/savltree.rs @@ -1,4 +1,5 @@ use std::convert::TryFrom; +use std::sync::Arc; use bytes::Bytes; use ergo_avltree_rust::authenticated_tree_ops::AuthenticatedTreeOps; @@ -18,12 +19,12 @@ use sigma_ser::ScorexSerializable; use super::EvalError; use super::EvalFn; use ergotree_ir::types::stype::SType; -use sigma_util::AsVecI8; pub(crate) static DIGEST_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { let avl_tree_data = obj.try_extract_into::()?; Ok(Value::Coll(CollKind::NativeColl(NativeColl::CollByte( - avl_tree_data.digest.into(), + // TODO: From for Rc<[i8]> + avl_tree_data.digest.0.iter().map(|&b| b as i8).collect(), )))) }; @@ -86,53 +87,53 @@ pub(crate) static UPDATE_DIGEST_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { Ok(Value::AvlTree(Box::new(avl_tree_data))) }; -pub(crate) static GET_EVAL_FN: EvalFn = - |_env, _ctx, obj, args| { - let avl_tree_data = obj.try_extract_into::()?; - - let key = { - let v = args.first().cloned().ok_or_else(|| { - EvalError::AvlTree("eval is missing first arg (entries)".to_string()) - })?; - v.try_extract_into::>()? - }; - let proof = { - let v = args.get(1).cloned().ok_or_else(|| { - EvalError::AvlTree("eval is missing second arg (proof)".to_string()) - })?; - Bytes::from(v.try_extract_into::>()?) - }; +pub(crate) static GET_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { + let avl_tree_data = obj.try_extract_into::()?; + let key = { + let v = args + .first() + .cloned() + .ok_or_else(|| EvalError::AvlTree("eval is missing first arg (entries)".to_string()))?; + v.try_extract_into::>()? + }; + let proof = { + let v = args + .get(1) + .cloned() + .ok_or_else(|| EvalError::AvlTree("eval is missing second arg (proof)".to_string()))?; + Bytes::from(v.try_extract_into::>()?) + }; - let starting_digest = Bytes::from(avl_tree_data.digest.0.to_vec()); - let mut bv = BatchAVLVerifier::new( - &starting_digest, - &proof, - AVLTree::new( - |digest| Node::LabelOnly(NodeHeader::new(Some(*digest), None)), - avl_tree_data.key_length as usize, - avl_tree_data - .value_length_opt - .as_ref() - .map(|v| **v as usize), - ), - None, - None, - ) - .map_err(map_eval_err)?; + let starting_digest = Bytes::from(avl_tree_data.digest.0.to_vec()); + let mut bv = BatchAVLVerifier::new( + &starting_digest, + &proof, + AVLTree::new( + |digest| Node::LabelOnly(NodeHeader::new(Some(*digest), None)), + avl_tree_data.key_length as usize, + avl_tree_data + .value_length_opt + .as_ref() + .map(|v| **v as usize), + ), + None, + None, + ) + .map_err(map_eval_err)?; - match bv.perform_one_operation(&Operation::Lookup(Bytes::from(key))) { - Ok(opt) => match opt { - Some(v) => Ok(Value::Opt(Box::new(Some(Value::Coll( - CollKind::NativeColl(NativeColl::CollByte(v.to_vec().as_vec_i8())), - ))))), - _ => Ok(Value::Opt(Box::new(None))), - }, - Err(_) => Err(EvalError::AvlTree(format!( - "Tree proof is incorrect {:?}", - avl_tree_data - ))), - } - }; + match bv.perform_one_operation(&Operation::Lookup(Bytes::from(key))) { + Ok(opt) => match opt { + Some(v) => Ok(Value::Opt(Box::new(Some(Value::Coll( + CollKind::NativeColl(NativeColl::CollByte(v.iter().map(|&b| b as i8).collect())), + ))))), + _ => Ok(Value::Opt(Box::new(None))), + }, + Err(_) => Err(EvalError::AvlTree(format!( + "Tree proof is incorrect {:?}", + avl_tree_data + ))), + } +}; pub(crate) static GET_MANY_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { @@ -168,26 +169,30 @@ pub(crate) static GET_MANY_EVAL_FN: EvalFn = ) .map_err(map_eval_err)?; - let mut res = vec![]; - for key in keys { - if let Ok(r) = bv.perform_one_operation(&Operation::Lookup(Bytes::from(key))) { - if let Some(v) = r { - res.push(Value::Opt(Box::new(Some(Value::Coll( - CollKind::NativeColl(NativeColl::CollByte(v.to_vec().as_vec_i8())), - ))))) + let res = keys + .into_iter() + .map(|key| { + if let Ok(r) = bv.perform_one_operation(&Operation::Lookup(Bytes::from(key))) { + if let Some(v) = r { + Ok(Value::Opt(Box::new(Some(Value::Coll( + CollKind::NativeColl(NativeColl::CollByte( + v.iter().map(|&b| b as i8).collect(), + )), + ))))) + } else { + Ok(Value::Opt(Box::new(None))) + } } else { - res.push(Value::Opt(Box::new(None))) + Err(EvalError::AvlTree(format!( + "Tree proof is incorrect {:?}", + avl_tree_data + ))) } - } else { - return Err(EvalError::AvlTree(format!( - "Tree proof is incorrect {:?}", - avl_tree_data - ))); - } - } + }) + .collect::, _>>()?; Ok(Value::Coll(CollKind::WrappedColl { - elem_tpe: SType::SOption(Box::new(SType::SColl(Box::new(SType::SByte)))), + elem_tpe: SType::SOption(Arc::new(SType::SColl(Arc::new(SType::SByte)))), items: res, })) }; @@ -433,6 +438,8 @@ fn map_eval_err(e: T) -> EvalError { #[cfg(test)] #[cfg(feature = "arbitrary")] mod tests { + use std::sync::Arc; + use ergo_avltree_rust::batch_avl_prover::BatchAVLProver; use ergotree_ir::{ mir::{ @@ -449,7 +456,7 @@ mod tests { use crate::eval::tests::eval_out_wo_ctx; use super::*; - use sigma_util::AsVecU8; + use sigma_util::{AsVecI8, AsVecU8}; #[test] fn eval_avl_get() { @@ -563,10 +570,10 @@ mod tests { let search_key_3 = Literal::from(vec![3u8]); let keys = Constant { - tpe: SType::SColl(Box::new(SType::SColl(Box::new(SType::SByte)))), + tpe: SType::SColl(Arc::new(SType::SColl(Arc::new(SType::SByte)))), v: Literal::Coll(CollKind::WrappedColl { - items: vec![search_key_1, search_key_2, search_key_3], - elem_tpe: SType::SColl(Box::new(SType::SByte)), + items: Arc::new([search_key_1, search_key_2, search_key_3]), + elem_tpe: SType::SColl(Arc::new(SType::SByte)), }), }; @@ -586,7 +593,7 @@ mod tests { match *opt { None => assert!(expected.is_none()), Some(Value::Coll(CollKind::NativeColl(NativeColl::CollByte(b)))) => { - assert_eq!(b, expected.unwrap().to_vec().as_vec_i8()); + assert_eq!(&b[..], &expected.unwrap().to_vec().as_vec_i8()[..]); } Some(_) => unreachable!(), } @@ -654,15 +661,15 @@ mod tests { let pair2 = Literal::Tup(mk_pair(2u8, 20u64).into()); let pair3 = Literal::Tup(mk_pair(3u8, 30u64).into()); let entries = Constant { - tpe: SType::SColl(Box::new(SType::STuple(STuple::pair( - SType::SColl(Box::new(SType::SByte)), - SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::STuple(STuple::pair( + SType::SColl(Arc::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), )))), v: Literal::Coll(CollKind::WrappedColl { - items: vec![pair1, pair2, pair3], + items: Arc::new([pair1, pair2, pair3]), elem_tpe: SType::STuple(STuple::pair( - SType::SColl(Box::new(SType::SByte)), - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), )), }), }; @@ -701,7 +708,7 @@ mod tests { let res = eval_out_wo_ctx::(&expr); if let Value::Coll(CollKind::NativeColl(NativeColl::CollByte(b))) = res { - assert_eq!(b, digest); + assert_eq!(&b[..], digest.as_slice()); } else { unreachable!(); } @@ -941,10 +948,10 @@ mod tests { let key1 = Literal::from(vec![1u8]); let keys = Constant { - tpe: SType::SColl(Box::new(SType::SColl(Box::new(SType::SByte)))), + tpe: SType::SColl(Arc::new(SType::SColl(Arc::new(SType::SByte)))), v: Literal::Coll(CollKind::WrappedColl { - items: vec![key1], - elem_tpe: SType::SColl(Box::new(SType::SByte)), + items: Arc::new([key1]), + elem_tpe: SType::SColl(Arc::new(SType::SByte)), }), }; let expr: Expr = MethodCall::new( @@ -1012,15 +1019,15 @@ mod tests { let pair1 = Literal::Tup(mk_pair(2u8, 40u64).into()); let pair2 = Literal::Tup(mk_pair(3u8, 50u64).into()); let entries = Constant { - tpe: SType::SColl(Box::new(SType::STuple(STuple::pair( - SType::SColl(Box::new(SType::SByte)), - SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::STuple(STuple::pair( + SType::SColl(Arc::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), )))), v: Literal::Coll(CollKind::WrappedColl { - items: vec![pair1, pair2], + items: Arc::new([pair1, pair2]), elem_tpe: SType::STuple(STuple::pair( - SType::SColl(Box::new(SType::SByte)), - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), )), }), }; diff --git a/ergotree-interpreter/src/eval/sbox.rs b/ergotree-interpreter/src/eval/sbox.rs index 7ea1016be..a14c4bab5 100644 --- a/ergotree-interpreter/src/eval/sbox.rs +++ b/ergotree-interpreter/src/eval/sbox.rs @@ -1,17 +1,17 @@ use std::convert::TryInto; -use std::sync::Arc; use crate::eval::EvalError; use ergotree_ir::chain::ergo_box::ErgoBox; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::Value; +use ergotree_ir::reference::Ref; use super::EvalFn; pub(crate) static VALUE_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { Ok(Value::Long( - obj.try_extract_into::>()?.value.as_i64(), + obj.try_extract_into::>()?.value.as_i64(), )) }; @@ -29,7 +29,7 @@ pub(crate) static GET_REG_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { })?; Ok(Value::Opt(Box::new( - obj.try_extract_into::>()? + obj.try_extract_into::>()? .get_register(reg_id) .map_err(|e| { EvalError::NotFound(format!( @@ -41,7 +41,10 @@ pub(crate) static GET_REG_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { }; pub(crate) static TOKENS_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { - let res: Value = obj.try_extract_into::>()?.tokens_raw().into(); + let res: Value = obj + .try_extract_into::>()? + .tokens_raw() + .into(); Ok(res) }; @@ -57,18 +60,14 @@ mod tests { use crate::eval::context::Context; use crate::eval::tests::eval_out; - use std::rc::Rc; #[test] fn eval_box_value() { let expr: Expr = PropertyCall::new(GlobalVars::SelfBox.into(), sbox::VALUE_METHOD.clone()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!( - eval_out::(&expr, ctx.clone()), - ctx.self_box.value.as_i64() - ); + let ctx = force_any_val::(); + assert_eq!(eval_out::(&expr, &ctx), ctx.self_box.value.as_i64()); } #[test] @@ -76,9 +75,9 @@ mod tests { let expr: Expr = PropertyCall::new(GlobalVars::SelfBox.into(), sbox::TOKENS_METHOD.clone()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::, i64)>>(&expr, ctx.clone()), + eval_out::, i64)>>(&expr, &ctx), ctx.self_box.tokens_raw() ); } diff --git a/ergotree-interpreter/src/eval/scoll.rs b/ergotree-interpreter/src/eval/scoll.rs index 80b791acb..c0d54a517 100644 --- a/ergotree-interpreter/src/eval/scoll.rs +++ b/ergotree-interpreter/src/eval/scoll.rs @@ -8,8 +8,11 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::types::stuple::STuple; use ergotree_ir::types::stype::SType::SInt; +use super::env::Env; +use super::Context; use super::EvalFn; use std::convert::TryFrom; +use std::sync::Arc; pub(crate) static INDEX_OF_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { Ok(Value::Int({ @@ -40,7 +43,12 @@ pub(crate) static INDEX_OF_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { })) }; -pub(crate) static FLATMAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { +pub(crate) fn flatmap_eval<'ctx>( + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + obj: Value<'ctx>, + args: Vec>, +) -> Result, EvalError> { let input_v = obj; let lambda_v = args .first() @@ -67,7 +75,7 @@ pub(crate) static FLATMAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { return Err(EvalError::UnexpectedValue(unsupported_msg)); } } - let mut lambda_call = |arg: Value| { + let mut lambda_call = |arg: Value<'ctx>| { let func_arg = lambda.args.first().ok_or_else(|| { EvalError::NotFound("flatmap: lambda has empty arguments list".to_string()) })?; @@ -116,7 +124,7 @@ pub(crate) static FLATMAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { }) .and_then(|v| v) // flatten , _> .map(Value::Coll) -}; +} pub(crate) static ZIP_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { let (type_1, coll_1) = match obj { @@ -141,8 +149,8 @@ pub(crate) static ZIP_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { .into_iter() .zip(coll_2) .map(|(a, b)| Value::Tup([a, b].into())) - .collect::>(); - let coll_zip = CollKind::from_vec(STuple::pair(type_1, type_2).into(), zip); + .collect::>(); + let coll_zip = CollKind::from_collection(STuple::pair(type_1, type_2).into(), zip); match coll_zip { Ok(coll) => Ok(Value::Coll(coll)), Err(e) => Err(EvalError::TryExtractFrom(e)), @@ -150,22 +158,18 @@ pub(crate) static ZIP_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { }; pub(crate) static INDICES_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { - let normalized_input_vals: Vec = match obj { - Value::Coll(coll) => Ok(coll.as_vec()), + let input_len = match obj { + Value::Coll(coll) => Ok(coll.len()), _ => Err(EvalError::UnexpectedValue(format!( "expected obj to be Value::Coll, got: {0:?}", obj ))), }?; - let indices_i32 = normalized_input_vals - .into_iter() - .enumerate() - .map(|(i, _)| i32::try_from(i)) - .collect::, _>>(); - let indices_val = - indices_i32.map(|vec_i32| vec_i32.into_iter().map(Value::Int).collect::>()); - match indices_val { - Ok(vec_val) => match CollKind::from_vec(SInt, vec_val) { + let indices_i32 = (0..input_len) + .map(|i| Ok(Value::Int(i32::try_from(i)?))) + .collect::, std::num::TryFromIntError>>(); + match indices_i32 { + Ok(vec_val) => match CollKind::from_collection(SInt, vec_val) { Ok(coll) => Ok(Value::Coll(coll)), Err(e) => Err(EvalError::TryExtractFrom(e)), }, @@ -213,8 +217,8 @@ pub(crate) static PATCH_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { .chain(patch.iter()) .chain(normalized_input_vals.iter().skip(from + replaced)) .cloned() - .collect(); - Ok(Value::Coll(CollKind::from_vec(input_tpe, res)?)) + .collect::>(); + Ok(Value::Coll(CollKind::from_collection(input_tpe, res)?)) }; pub(crate) static UPDATED_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { @@ -241,7 +245,7 @@ pub(crate) static UPDATED_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { match res.get_mut(target_index_usize) { Some(elem) => { *elem = update_val; - Ok(Value::Coll(CollKind::from_vec(input_tpe, res)?)) + Ok(Value::Coll(CollKind::from_collection(input_tpe, &res[..])?)) } None => Err(EvalError::UnexpectedValue(format!( "updated: target index out of bounds, got: {:?}", @@ -323,13 +327,15 @@ pub(crate) static UPDATE_MANY_EVAL_FN: EvalFn = } i += 1; } - Ok(Value::Coll(CollKind::from_vec(input_tpe, res)?)) + Ok(Value::Coll(CollKind::from_collection(input_tpe, &res[..])?)) }; #[allow(clippy::unwrap_used)] #[cfg(test)] #[cfg(feature = "arbitrary")] mod tests { + use std::sync::Arc; + use ergotree_ir::mir::constant::Constant; use ergotree_ir::mir::constant::Literal; use ergotree_ir::mir::expr::Expr; @@ -393,16 +399,16 @@ mod tests { #[test] fn eval_flatmap() { let coll_const = Constant { - tpe: SType::SColl(Box::new(SType::SColl(Box::new(SType::SLong)))), + tpe: SType::SColl(Arc::new(SType::SColl(Arc::new(SType::SLong)))), v: Literal::Coll(CollKind::WrappedColl { - items: vec![vec![4i64, 5i64].into(), vec![3i64].into()], - elem_tpe: SType::SColl(Box::new(SType::SLong)), + items: Arc::new([vec![4i64, 5i64].into(), vec![3i64].into()]), + elem_tpe: SType::SColl(Arc::new(SType::SLong)), }), }; let body: Expr = MethodCall::new( ValUse { val_id: 1.into(), - tpe: SType::SColl(Box::new(SType::SLong)), + tpe: SType::SColl(Arc::new(SType::SLong)), } .into(), scoll::INDICES_METHOD @@ -416,7 +422,7 @@ mod tests { coll_const.into(), scoll::FLATMAP_METHOD.clone().with_concrete_types( &[ - (STypeVar::iv(), SType::SColl(Box::new(SType::SLong))), + (STypeVar::iv(), SType::SColl(Arc::new(SType::SLong))), (STypeVar::ov(), SType::SInt), ] .iter() @@ -426,7 +432,7 @@ mod tests { vec![FuncValue::new( vec![FuncArg { idx: 1.into(), - tpe: SType::SColl(Box::new(SType::SLong)), + tpe: SType::SColl(Arc::new(SType::SLong)), }], body, ) diff --git a/ergotree-interpreter/src/eval/scontext.rs b/ergotree-interpreter/src/eval/scontext.rs index 73e4951d0..dab58da19 100644 --- a/ergotree-interpreter/src/eval/scontext.rs +++ b/ergotree-interpreter/src/eval/scontext.rs @@ -1,7 +1,10 @@ +use std::sync::Arc; + use ergotree_ir::mir::avl_tree_data::AvlTreeData; use ergotree_ir::mir::avl_tree_data::AvlTreeFlags; use ergotree_ir::mir::value::CollKind; use ergotree_ir::mir::value::Value; +use ergotree_ir::reference::Ref; use ergotree_ir::serialization::SigmaSerializable; use ergotree_ir::types::stype::SType; @@ -16,11 +19,9 @@ pub(crate) static DATA_INPUTS_EVAL_FN: EvalFn = |_env, ctx, obj, _args| { ))); } Ok(Value::Coll(CollKind::WrappedColl { - items: ctx - .ctx - .data_inputs - .clone() - .map_or(vec![], |d| d.mapped(Value::CBox).as_vec().clone()), + items: ctx.data_inputs.clone().map_or(Arc::new([]), |d| { + d.iter().map(|&di| Ref::from(di)).map(Value::CBox).collect() + }), elem_tpe: SType::SBox, })) }; @@ -33,11 +34,9 @@ pub(crate) static SELF_BOX_INDEX_EVAL_FN: EvalFn = |_env, ctx, obj, _args| { ))); } let box_index = ctx - .ctx .inputs - .clone() .iter() - .position(|it| it == &ctx.ctx.self_box) + .position(|it| *it == ctx.self_box) .ok_or_else(|| EvalError::NotFound("Context.selfBoxIndex: box not found".to_string()))?; Ok(Value::Int(box_index as i32)) }; @@ -50,13 +49,7 @@ pub(crate) static HEADERS_EVAL_FN: EvalFn = |_env, ctx, obj, _args| { ))); } Ok(Value::Coll(CollKind::WrappedColl { - items: ctx - .ctx - .headers - .clone() - .map(Box::new) - .map(Value::Header) - .to_vec(), + items: Arc::new(ctx.headers.clone().map(Box::new).map(Value::Header)), elem_tpe: SType::SHeader, })) }; @@ -68,7 +61,7 @@ pub(crate) static PRE_HEADER_EVAL_FN: EvalFn = |_env, ctx, obj, _args| { obj ))); } - Ok(Box::from(ctx.ctx.pre_header.clone()).into()) + Ok(Box::from(ctx.pre_header.clone()).into()) }; pub(crate) static LAST_BLOCK_UTXO_ROOT_HASH_EVAL_FN: EvalFn = |_env, ctx, obj, _args| { @@ -78,7 +71,7 @@ pub(crate) static LAST_BLOCK_UTXO_ROOT_HASH_EVAL_FN: EvalFn = |_env, ctx, obj, _ obj ))); } - let digest = ctx.ctx.headers[0].state_root; + let digest = ctx.headers[0].state_root; let tree_flags = AvlTreeFlags::new(true, true, true); Ok(Value::AvlTree(Box::from(AvlTreeData { digest, @@ -96,7 +89,6 @@ pub(crate) static MINER_PUBKEY_EVAL_FN: EvalFn = |_env, ctx, obj, _args| { ))); } Ok(ctx - .ctx .pre_header .miner_pk .clone() @@ -108,7 +100,7 @@ pub(crate) static MINER_PUBKEY_EVAL_FN: EvalFn = |_env, ctx, obj, _args| { #[cfg(feature = "arbitrary")] #[allow(clippy::unwrap_used, clippy::expect_used)] mod tests { - use crate::eval::context::{Context, TxIoVec}; + use crate::eval::context::Context; use crate::eval::tests::eval_out; use ergo_chain_types::{Header, PreHeader}; use ergotree_ir::chain::ergo_box::ErgoBox; @@ -118,19 +110,16 @@ mod tests { use ergotree_ir::serialization::SigmaSerializable; use ergotree_ir::types::scontext; use sigma_test_util::force_any_val; - use std::rc::Rc; - fn make_ctx_inputs_includes_self_box() -> Context { + fn make_ctx_inputs_includes_self_box() -> Context<'static> { let ctx = force_any_val::(); - let self_box = force_any_val::(); - let inputs = TxIoVec::from_vec(vec![ - force_any_val::().into(), - self_box.clone().into(), - ]) - .unwrap(); + let self_box = &*Box::leak(Box::new(force_any_val::())); + let inputs = vec![&*Box::leak(Box::new(force_any_val::())), self_box] + .try_into() + .unwrap(); Context { height: 0u32, - self_box: self_box.into(), + self_box, inputs, ..ctx } @@ -142,8 +131,8 @@ mod tests { PropertyCall::new(Expr::Context, scontext::SELF_BOX_INDEX_PROPERTY.clone()) .unwrap() .into(); - let rc = Rc::new(make_ctx_inputs_includes_self_box()); - assert_eq!(eval_out::(&expr, rc), 1); + let context = make_ctx_inputs_includes_self_box(); + assert_eq!(eval_out::(&expr, &context), 1); } #[test] @@ -151,8 +140,8 @@ mod tests { let expr: Expr = PropertyCall::new(Expr::Context, scontext::HEADERS_PROPERTY.clone()) .expect("internal error: `headers` method has parameters length != 1") .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::<[Header; 10]>(&expr, ctx.clone()), ctx.headers); + let ctx = force_any_val::(); + assert_eq!(eval_out::<[Header; 10]>(&expr, &ctx), ctx.headers); } #[test] @@ -160,8 +149,8 @@ mod tests { let expr: Expr = PropertyCall::new(Expr::Context, scontext::PRE_HEADER_PROPERTY.clone()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::(&expr, ctx.clone()), ctx.pre_header); + let ctx = force_any_val::(); + assert_eq!(eval_out::(&expr, &ctx), ctx.pre_header); } #[test] @@ -169,9 +158,9 @@ mod tests { let expr: Expr = PropertyCall::new(Expr::Context, scontext::MINER_PUBKEY_PROPERTY.clone()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::>(&expr, ctx.clone()), + eval_out::>(&expr, &ctx), ctx.pre_header.miner_pk.sigma_serialize_bytes().unwrap() ); } @@ -184,7 +173,7 @@ mod tests { ) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let digest = ctx.headers[0].state_root; let tree_flags = AvlTreeFlags::new(true, true, true); let avl_tree_data = AvlTreeData { @@ -193,6 +182,6 @@ mod tests { key_length: 32, value_length_opt: None, }; - assert_eq!(eval_out::(&expr, ctx), avl_tree_data); + assert_eq!(eval_out::(&expr, &ctx), avl_tree_data); } } diff --git a/ergotree-interpreter/src/eval/select_field.rs b/ergotree-interpreter/src/eval/select_field.rs index 9bb4ebbf9..36c816f10 100644 --- a/ergotree-interpreter/src/eval/select_field.rs +++ b/ergotree-interpreter/src/eval/select_field.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::select_field::SelectField; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SelectField { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::Tup(items) => items diff --git a/ergotree-interpreter/src/eval/sglobal.rs b/ergotree-interpreter/src/eval/sglobal.rs index d4e47a670..70ae6563c 100644 --- a/ergotree-interpreter/src/eval/sglobal.rs +++ b/ergotree-interpreter/src/eval/sglobal.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::eval::EvalError; use ergotree_ir::mir::value::{CollKind, NativeColl, Value}; @@ -6,9 +8,8 @@ use ergo_chain_types::ec_point::generator; use super::EvalFn; -fn helper_xor(mut x: Vec, y: Vec) -> Vec { - x.iter_mut().zip(y.iter()).for_each(|(x1, x2)| *x1 ^= *x2); - x +fn helper_xor(x: &[i8], y: &[i8]) -> Arc<[i8]> { + x.iter().zip(y.iter()).map(|(x1, x2)| *x1 ^ *x2).collect() } pub(crate) static GROUP_GENERATOR_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { @@ -42,8 +43,8 @@ pub(crate) static XOR_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { Value::Coll(CollKind::NativeColl(NativeColl::CollByte(l_byte))), Value::Coll(CollKind::NativeColl(NativeColl::CollByte(r_byte))), ) => { - let xor = helper_xor(l_byte, r_byte); - Ok(xor.into()) + let xor = helper_xor(&l_byte, &r_byte); + Ok(CollKind::NativeColl(NativeColl::CollByte(xor)).into()) } _ => Err(EvalError::UnexpectedValue(format!( "expected Xor input to be byte array, got: {0:?}", @@ -60,7 +61,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::method_call::MethodCall; use ergotree_ir::mir::property_call::PropertyCall; - use std::rc::Rc; use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -72,9 +72,9 @@ mod tests { let expr: Expr = PropertyCall::new(Expr::Global, sglobal::GROUP_GENERATOR_METHOD.clone()) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); assert_eq!( - eval_out::(&expr, ctx), + eval_out::(&expr, &ctx), ergo_chain_types::ec_point::generator() ); } @@ -92,7 +92,10 @@ mod tests { ) .unwrap() .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx), expected_xor); + let ctx = force_any_val::(); + assert_eq!( + eval_out::>(&expr, &ctx).as_slice(), + expected_xor.as_slice() + ); } } diff --git a/ergotree-interpreter/src/eval/sgroup_elem.rs b/ergotree-interpreter/src/eval/sgroup_elem.rs index 1a57139c9..9b45addcd 100644 --- a/ergotree-interpreter/src/eval/sgroup_elem.rs +++ b/ergotree-interpreter/src/eval/sgroup_elem.rs @@ -2,6 +2,7 @@ use crate::eval::EvalError; use ergo_chain_types::EcPoint; use ergotree_ir::mir::value::Value; +use ergotree_ir::reference::Ref; use ergotree_ir::serialization::SigmaSerializable; use super::EvalFn; @@ -20,13 +21,13 @@ pub(crate) static GET_ENCODED_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { pub(crate) static NEGATE_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { let negated: EcPoint = match obj { - Value::GroupElement(ec_point) => Ok(-(*ec_point)), + Value::GroupElement(ec_point) => Ok(-(*ec_point).clone()), _ => Err(EvalError::UnexpectedValue(format!( "expected obj to be Value::GroupElement, got: {0:?}", obj ))), }?; - Ok(Value::GroupElement(Box::new(negated))) + Ok(Value::GroupElement(Ref::from(negated))) }; #[allow(clippy::unwrap_used)] diff --git a/ergotree-interpreter/src/eval/sheader.rs b/ergotree-interpreter/src/eval/sheader.rs index 6d7e09761..e98e1e317 100644 --- a/ergotree-interpreter/src/eval/sheader.rs +++ b/ergotree-interpreter/src/eval/sheader.rs @@ -1,6 +1,6 @@ //! Evaluating predefined `Header` (or SHeader) type properties -use std::convert::TryInto; +use std::{convert::TryInto, sync::Arc}; use ergo_chain_types::Header; use ergotree_ir::{bigint256::BigInt256, mir::constant::TryExtractInto}; @@ -59,16 +59,12 @@ pub(crate) static HEIGHT_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { pub(crate) static MINER_PK_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { let header = obj.try_extract_into::
()?; - Ok(header.autolykos_solution.miner_pk.into()) + Ok(Arc::new(*header.autolykos_solution.miner_pk).into()) }; pub(crate) static POW_ONETIME_PK_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { let header = obj.try_extract_into::
()?; - Ok(header - .autolykos_solution - .pow_onetime_pk - .unwrap_or_default() - .into()) + Ok((*header.autolykos_solution.pow_onetime_pk.unwrap_or_default()).into()) }; pub(crate) static POW_NONCE_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { @@ -97,7 +93,6 @@ pub(crate) static VOTES_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { #[allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)] mod tests { use std::convert::{TryFrom, TryInto}; - use std::rc::Rc; use ergo_chain_types::{BlockId, Digest, Digest32, EcPoint, Votes}; use ergotree_ir::{ @@ -117,10 +112,10 @@ mod tests { const HEADER_INDEX: usize = 0; // Evaluates `Header.minerPk`, `Header.powOnetimePk` - fn eval_header_pks(ctx: Rc) -> [Box; 2] { + fn eval_header_pks(ctx: &Context<'static>) -> [Box; 2] { let miner_pk = eval_out::( &create_get_header_property_expr(sheader::MINER_PK_PROPERTY.clone()), - ctx.clone(), + ctx, ); let pow_onetime_pk = eval_out::( &create_get_header_property_expr(sheader::POW_ONETIME_PK_PROPERTY.clone()), @@ -130,14 +125,14 @@ mod tests { } // Evaluates `Header.AdProofsRoot`, `Header.transactionRoot`, `Header.extensionRoot` - fn eval_header_roots(ctx: Rc) -> [Digest32; 3] { + fn eval_header_roots(ctx: &Context<'static>) -> [Digest32; 3] { vec![ sheader::AD_PROOFS_ROOT_PROPERTY.clone(), sheader::TRANSACTIONS_ROOT_PROPERTY.clone(), sheader::EXTENSION_ROOT_PROPERTY.clone(), ] .into_iter() - .map(|smethod| eval_out::>(&create_get_header_property_expr(smethod), ctx.clone())) + .map(|smethod| eval_out::>(&create_get_header_property_expr(smethod), ctx)) .map(digest_from_bytes_signed::<32>) .collect::>() .try_into() @@ -145,10 +140,10 @@ mod tests { } // Evaluates `Header.id` and `Header.parentId` - fn eval_header_ids(ctx: Rc) -> [BlockId; 2] { + fn eval_header_ids(ctx: &Context<'static>) -> [BlockId; 2] { let id = eval_out::>( &create_get_header_property_expr(sheader::ID_PROPERTY.clone()), - ctx.clone(), + ctx, ); let parent_id = eval_out::>( &create_get_header_property_expr(sheader::PARENT_ID_PROPERTY.clone()), @@ -198,74 +193,74 @@ mod tests { #[test] fn test_eval_version() { let expr = create_get_header_property_expr(sheader::VERSION_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let version = ctx.headers[HEADER_INDEX].version as i8; - assert_eq!(version, eval_out::(&expr, ctx)); + assert_eq!(version, eval_out::(&expr, &ctx)); } #[test] fn test_eval_ids() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx .headers .get(HEADER_INDEX) .map(|h| [h.id, h.parent_id]) .expect("internal error: empty headers array"); - let actual = eval_header_ids(ctx); + let actual = eval_header_ids(&ctx); assert_eq!(expected, actual); } #[test] fn test_eval_roots() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx .headers .get(HEADER_INDEX) .map(|h| [h.ad_proofs_root, h.transaction_root, h.extension_root]) .expect("internal error: empty headers array"); - let actual = eval_header_roots(ctx); + let actual = eval_header_roots(&ctx); assert_eq!(expected, actual); } #[test] fn test_eval_state_root() { let expr = create_get_header_property_expr(sheader::STATE_ROOT_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.headers[HEADER_INDEX].state_root; - let actual = digest_from_bytes_signed::<33>(eval_out::>(&expr, ctx)); + let actual = digest_from_bytes_signed::<33>(eval_out::>(&expr, &ctx)); assert_eq!(expected, actual); } #[test] fn test_eval_timestamp() { let expr = create_get_header_property_expr(sheader::TIMESTAMP_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.headers[HEADER_INDEX].timestamp as i64; - let actual = eval_out::(&expr, ctx); + let actual = eval_out::(&expr, &ctx); assert_eq!(expected, actual); } #[test] fn test_eval_n_bits() { let expr = create_get_header_property_expr(sheader::N_BITS_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.headers[HEADER_INDEX].n_bits as i64; - let actual = eval_out::(&expr, ctx); + let actual = eval_out::(&expr, &ctx); assert_eq!(expected, actual); } #[test] fn test_eval_height() { let expr = create_get_header_property_expr(sheader::HEIGHT_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.headers[HEADER_INDEX].height as i32; - let actual = eval_out::(&expr, ctx); + let actual = eval_out::(&expr, &ctx); assert_eq!(expected, actual); } #[test] fn test_eval_pks() { - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx .headers .get(HEADER_INDEX) @@ -279,21 +274,21 @@ mod tests { ] }) .expect("internal error: empty headers array"); - let actual = eval_header_pks(ctx); + let actual = eval_header_pks(&ctx); assert_eq!(expected, actual); } #[test] fn test_eval_pow_distance() { let expr = create_get_header_property_expr(sheader::POW_DISTANCE_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.headers[HEADER_INDEX] .autolykos_solution .pow_distance .clone() .unwrap_or_default(); let actual = { - let bi = eval_out::(&expr, ctx); + let bi = eval_out::(&expr, &ctx); bi.into() }; assert_eq!(expected, actual); @@ -302,19 +297,19 @@ mod tests { #[test] fn test_eval_pow_nonce() { let expr = create_get_header_property_expr(sheader::POW_NONCE_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.headers[HEADER_INDEX].autolykos_solution.nonce.clone(); - let actual = eval_out::>(&expr, ctx).as_vec_u8(); + let actual = eval_out::>(&expr, &ctx).as_vec_u8(); assert_eq!(expected, actual); } #[test] fn test_eval_votes() { let expr = create_get_header_property_expr(sheader::VOTES_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.headers[HEADER_INDEX].votes.clone(); let actual = { - let votes_bytes = eval_out::>(&expr, ctx).as_vec_u8(); + let votes_bytes = eval_out::>(&expr, &ctx).as_vec_u8(); Votes::try_from(votes_bytes) .expect("internal error: votes bytes buffer length isn't equal to 3") }; diff --git a/ergotree-interpreter/src/eval/sigma_and.rs b/ergotree-interpreter/src/eval/sigma_and.rs index de9437520..921ae86e8 100644 --- a/ergotree-interpreter/src/eval/sigma_and.rs +++ b/ergotree-interpreter/src/eval/sigma_and.rs @@ -5,12 +5,16 @@ use ergotree_ir::sigma_protocol::sigma_boolean::cand::Cand; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SigmaAnd { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let items_v_res = self.items.try_mapped_ref(|it| it.eval(env, ctx)); let items_sigmabool = items_v_res? .try_mapped(|it| it.try_extract_into::())? @@ -28,7 +32,6 @@ mod tests { use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture; use std::convert::TryInto; - use std::rc::Rc; use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -48,8 +51,8 @@ mod tests { fn eval(sigmaprops in collection::vec(any::(), 2..10)) { let items = sigmaprops.clone().into_iter().map(|sp| Expr::Const(sp.into())).collect(); let expr: Expr = SigmaAnd::new(items).unwrap().into(); - let ctx = Rc::new(force_any_val::()); - let res = eval_out::(&expr, ctx); + let ctx = force_any_val::(); + let res = eval_out::(&expr, &ctx); let expected_sb: Vec = sigmaprops.into_iter().map(|sp| sp.into()).collect(); prop_assert!(matches!(res.clone().into(), SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(_)))); if let SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(Cand {items: actual_sb})) = res.into() { diff --git a/ergotree-interpreter/src/eval/sigma_or.rs b/ergotree-interpreter/src/eval/sigma_or.rs index b2324e06a..94d91970f 100644 --- a/ergotree-interpreter/src/eval/sigma_or.rs +++ b/ergotree-interpreter/src/eval/sigma_or.rs @@ -5,12 +5,16 @@ use ergotree_ir::sigma_protocol::sigma_boolean::cor::Cor; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SigmaOr { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let items_v_res = self.items.try_mapped_ref(|it| it.eval(env, ctx)); let items_sigmabool = items_v_res? .try_mapped(|it| it.try_extract_into::())? @@ -28,7 +32,6 @@ mod tests { use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture; use std::convert::TryInto; - use std::rc::Rc; use crate::eval::context::Context; use crate::eval::tests::eval_out; @@ -48,8 +51,8 @@ mod tests { fn eval(sigmaprops in collection::vec(any::(), 2..10)) { let items = sigmaprops.clone().into_iter().map(|sp| Expr::Const(sp.into())).collect(); let expr: Expr = SigmaOr::new(items).unwrap().into(); - let ctx = Rc::new(force_any_val::()); - let res = eval_out::(&expr, ctx); + let ctx = force_any_val::(); + let res = eval_out::(&expr, &ctx); let expected_sb: Vec = sigmaprops.into_iter().map(|sp| sp.into()).collect(); prop_assert!(matches!(res.clone().into(), SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(_)))); if let SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(Cor {items: actual_sb})) = res.into() { diff --git a/ergotree-interpreter/src/eval/sigma_prop_bytes.rs b/ergotree-interpreter/src/eval/sigma_prop_bytes.rs index 11cbde0ed..b99df3432 100644 --- a/ergotree-interpreter/src/eval/sigma_prop_bytes.rs +++ b/ergotree-interpreter/src/eval/sigma_prop_bytes.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::sigma_prop_bytes::SigmaPropBytes; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SigmaPropBytes { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match input_v { Value::SigmaProp(sigma_prop) => Ok(sigma_prop.prop_bytes()?.into()), diff --git a/ergotree-interpreter/src/eval/soption.rs b/ergotree-interpreter/src/eval/soption.rs index 1bf09c94f..4105bc08f 100644 --- a/ergotree-interpreter/src/eval/soption.rs +++ b/ergotree-interpreter/src/eval/soption.rs @@ -3,9 +3,15 @@ use crate::eval::Evaluable; use ergotree_ir::mir::value::Value; -use super::EvalFn; +use super::env::Env; +use super::Context; -pub(crate) static MAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { +pub fn map_eval<'ctx>( + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + obj: Value<'ctx>, + args: Vec>, +) -> Result, EvalError> { let input_v = obj; let lambda_v = args .first() @@ -19,7 +25,7 @@ pub(crate) static MAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { input_v_clone ))), }?; - let mut lambda_call = |arg: Value| { + let mut lambda_call = |arg: Value<'ctx>| { let func_arg = lambda.args.first().ok_or_else(|| { EvalError::NotFound("map: lambda has empty arguments list".to_string()) })?; @@ -45,9 +51,14 @@ pub(crate) static MAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { Some(t) => Ok(Value::Opt(Box::new(lambda_call(t)?.into()))), _ => Ok(Value::Opt(Box::new(None))), } -}; +} -pub(crate) static FILTER_EVAL_FN: EvalFn = |env, ctx, obj, args| { +pub fn filter_eval<'ctx>( + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + obj: Value<'ctx>, + args: Vec>, +) -> Result, EvalError> { let input_v = obj; let lambda_v = args .first() @@ -61,7 +72,7 @@ pub(crate) static FILTER_EVAL_FN: EvalFn = |env, ctx, obj, args| { input_v_clone ))), }?; - let mut predicate_call = |arg: Value| { + let mut predicate_call = |arg: Value<'ctx>| { let func_arg = lambda.args.first().ok_or_else(|| { EvalError::NotFound("filter: lambda has empty arguments list".to_string()) })?; @@ -96,7 +107,7 @@ pub(crate) static FILTER_EVAL_FN: EvalFn = |env, ctx, obj, args| { }, None => Ok(Value::Opt(Box::new(None))), } -}; +} #[allow(clippy::unwrap_used)] #[cfg(test)] diff --git a/ergotree-interpreter/src/eval/spreheader.rs b/ergotree-interpreter/src/eval/spreheader.rs index 61ea1ee45..d09a64514 100644 --- a/ergotree-interpreter/src/eval/spreheader.rs +++ b/ergotree-interpreter/src/eval/spreheader.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use ergo_chain_types::PreHeader; use ergotree_ir::mir::constant::TryExtractInto; @@ -30,7 +32,7 @@ pub(crate) static HEIGHT_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { pub(crate) static MINER_PK_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { let preheader = obj.try_extract_into::()?; - Ok(preheader.miner_pk.into()) + Ok(Arc::new(*preheader.miner_pk).into()) }; pub(crate) static VOTES_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { @@ -43,7 +45,6 @@ pub(crate) static VOTES_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { #[allow(clippy::expect_used)] mod tests { use std::convert::{TryFrom, TryInto}; - use std::rc::Rc; use ergo_chain_types::{BlockId, EcPoint, Votes}; use ergotree_ir::{ @@ -87,18 +88,18 @@ mod tests { #[test] fn test_eval_version() { let expr = create_get_preheader_property_expr(spreheader::VERSION_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.pre_header.version as i8; - assert_eq!(expected, eval_out::(&expr, ctx)); + assert_eq!(expected, eval_out::(&expr, &ctx)); } #[test] fn test_eval_parent_id() { let expr = create_get_preheader_property_expr(spreheader::PARENT_ID_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.pre_header.parent_id; let actual = { - let bs = eval_out::>(&expr, ctx); + let bs = eval_out::>(&expr, &ctx); block_id_from_bytes_signed(bs) }; assert_eq!(expected, actual); @@ -107,37 +108,37 @@ mod tests { #[test] fn test_eval_timestamp() { let expr = create_get_preheader_property_expr(spreheader::TIMESTAMP_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.pre_header.timestamp as i64; - let actual = eval_out::(&expr, ctx); + let actual = eval_out::(&expr, &ctx); assert_eq!(expected, actual); } #[test] fn test_eval_n_bits() { let expr = create_get_preheader_property_expr(spreheader::N_BITS_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.pre_header.n_bits as i64; - let actual = eval_out::(&expr, ctx); + let actual = eval_out::(&expr, &ctx); assert_eq!(expected, actual); } #[test] fn test_eval_height() { let expr = create_get_preheader_property_expr(spreheader::HEIGHT_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.pre_header.height as i32; - let actual = eval_out::(&expr, ctx); + let actual = eval_out::(&expr, &ctx); assert_eq!(expected, actual); } #[test] fn test_eval_miner_pk() { let expr = create_get_preheader_property_expr(spreheader::MINER_PK_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.pre_header.miner_pk.clone(); let actual = { - let pk = eval_out::(&expr, ctx); + let pk = eval_out::(&expr, &ctx); Box::new(pk) }; assert_eq!(expected, actual); @@ -146,10 +147,10 @@ mod tests { #[test] fn test_eval_votes() { let expr = create_get_preheader_property_expr(spreheader::VOTES_PROPERTY.clone()); - let ctx = Rc::new(force_any_val::()); + let ctx = force_any_val::(); let expected = ctx.pre_header.votes.clone(); let actual = { - let votes_bytes = eval_out::>(&expr, ctx).as_vec_u8(); + let votes_bytes = eval_out::>(&expr, &ctx).as_vec_u8(); Votes::try_from(votes_bytes) .expect("internal error: votes bytes buffer length isn't equal to 3") }; diff --git a/ergotree-interpreter/src/eval/subst_const.rs b/ergotree-interpreter/src/eval/subst_const.rs index c92943f1f..36a3c745b 100644 --- a/ergotree-interpreter/src/eval/subst_const.rs +++ b/ergotree-interpreter/src/eval/subst_const.rs @@ -1,5 +1,5 @@ use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; use ergotree_ir::ergo_tree::ErgoTree; @@ -15,7 +15,11 @@ use sigma_util::AsVecU8; use std::convert::TryFrom; impl Evaluable for SubstConstants { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let script_bytes_v = self.script_bytes.eval(env, ctx)?; let positions_v = self.positions.eval(env, ctx)?; let new_values_v = self.new_values.eval(env, ctx)?; @@ -28,8 +32,8 @@ impl Evaluable for SubstConstants { let new_constants = if let Value::Coll(CollKind::WrappedColl { items, .. }) = new_values_v { let mut items_const = vec![]; - for v in items { - let c = Constant::try_from(v).map_err(EvalError::Misc)?; + for v in &*items { + let c = Constant::try_from(v.to_static()).map_err(EvalError::Misc)?; items_const.push(c); } items_const @@ -67,7 +71,7 @@ impl Evaluable for SubstConstants { } } Ok(Value::Coll(CollKind::NativeColl(NativeColl::CollByte( - ergo_tree.sigma_serialize_bytes()?.as_vec_i8(), + ergo_tree.sigma_serialize_bytes()?.as_vec_i8().into(), // TODO: optimize )))) } else { Err(EvalError::Misc(format!( diff --git a/ergotree-interpreter/src/eval/tree_lookup.rs b/ergotree-interpreter/src/eval/tree_lookup.rs index a71fe2718..b633ff863 100644 --- a/ergotree-interpreter/src/eval/tree_lookup.rs +++ b/ergotree-interpreter/src/eval/tree_lookup.rs @@ -3,7 +3,7 @@ use ergotree_ir::mir::tree_lookup::TreeLookup; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; use ergo_avltree_rust::batch_avl_verifier::BatchAVLVerifier; @@ -14,7 +14,11 @@ use ergotree_ir::mir::constant::TryExtractInto; use sigma_util::AsVecU8; impl Evaluable for TreeLookup { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let normalized_tree_val = self .tree .eval(env, ctx)? diff --git a/ergotree-interpreter/src/eval/tuple.rs b/ergotree-interpreter/src/eval/tuple.rs index 7ed505b22..df4307777 100644 --- a/ergotree-interpreter/src/eval/tuple.rs +++ b/ergotree-interpreter/src/eval/tuple.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::tuple::Tuple; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Tuple { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let items_v = self.items.try_mapped_ref(|i| i.eval(env, ctx)); Ok(Value::Tup(items_v?)) } diff --git a/ergotree-interpreter/src/eval/upcast.rs b/ergotree-interpreter/src/eval/upcast.rs index 647cdf1f1..e3cf40a41 100644 --- a/ergotree-interpreter/src/eval/upcast.rs +++ b/ergotree-interpreter/src/eval/upcast.rs @@ -4,7 +4,7 @@ use ergotree_ir::mir::value::Value; use ergotree_ir::types::stype::SType; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; @@ -69,7 +69,11 @@ fn upcast_to_byte(in_v: Value) -> Result { } impl Evaluable for Upcast { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; match self.tpe { SType::SBigInt => upcast_to_bigint(input_v), diff --git a/ergotree-interpreter/src/eval/val_use.rs b/ergotree-interpreter/src/eval/val_use.rs index 53ddfa9ae..d565e1456 100644 --- a/ergotree-interpreter/src/eval/val_use.rs +++ b/ergotree-interpreter/src/eval/val_use.rs @@ -2,12 +2,16 @@ use ergotree_ir::mir::val_use::ValUse; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ValUse { - fn eval(&self, env: &mut Env, _ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + _ctx: &Context<'ctx>, + ) -> Result, EvalError> { env.get(self.val_id).cloned().ok_or_else(|| { EvalError::NotFound(format!("no value in env for id: {0:?}", self.val_id)) }) diff --git a/ergotree-interpreter/src/eval/xor.rs b/ergotree-interpreter/src/eval/xor.rs index 254c3e208..ea07101a0 100644 --- a/ergotree-interpreter/src/eval/xor.rs +++ b/ergotree-interpreter/src/eval/xor.rs @@ -1,20 +1,25 @@ +use std::sync::Arc; + use ergotree_ir::mir::value::CollKind; use ergotree_ir::mir::value::NativeColl; use ergotree_ir::mir::value::Value; use ergotree_ir::mir::xor::Xor; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; -fn helper_xor(mut x: Vec, y: Vec) -> Vec { - x.iter_mut().zip(y.iter()).for_each(|(x1, x2)| *x1 ^= *x2); - x +fn helper_xor(x: &[i8], y: &[i8]) -> Arc<[i8]> { + x.iter().zip(y.iter()).map(|(x1, x2)| *x1 ^ *x2).collect() } impl Evaluable for Xor { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let left_v = self.left.eval(env, ctx)?; let right_v = self.right.eval(env, ctx)?; @@ -23,8 +28,8 @@ impl Evaluable for Xor { Value::Coll(CollKind::NativeColl(NativeColl::CollByte(l_byte))), Value::Coll(CollKind::NativeColl(NativeColl::CollByte(r_byte))), ) => { - let xor = helper_xor(l_byte, r_byte); - Ok(xor.into()) + let xor = helper_xor(&l_byte, &r_byte); + Ok(CollKind::NativeColl(NativeColl::CollByte(xor)).into()) } _ => Err(EvalError::UnexpectedValue(format!( "expected Xor input to be byte array, got: {0:?}", @@ -44,7 +49,6 @@ mod tests { use ergotree_ir::mir::expr::Expr; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; #[test] fn eval_1_xor_0() { @@ -58,8 +62,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx), expected_xor); + let ctx = force_any_val::(); + assert_eq!(eval_out::>(&expr, &ctx), expected_xor); } #[test] @@ -74,8 +78,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx), expected_xor); + let ctx = force_any_val::(); + assert_eq!(eval_out::>(&expr, &ctx), expected_xor); } #[test] @@ -90,8 +94,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx), expected_xor); + let ctx = force_any_val::(); + assert_eq!(eval_out::>(&expr, &ctx), expected_xor); } #[test] @@ -106,8 +110,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx), expected_xor); + let ctx = force_any_val::(); + assert_eq!(eval_out::>(&expr, &ctx), expected_xor); } #[test] @@ -122,8 +126,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx), expected_xor); + let ctx = force_any_val::(); + assert_eq!(eval_out::>(&expr, &ctx), expected_xor); } proptest! { @@ -131,7 +135,7 @@ mod tests { #[test] fn eval_any(left_bytes in any::>(), right_bytes in any::>()) { - let expected_xor = helper_xor(left_bytes.clone(), right_bytes.clone()); + let expected_xor = helper_xor(&left_bytes, &right_bytes); let expr: Expr = Xor { left: Box::new(Expr::Const(left_bytes.into())), @@ -139,8 +143,8 @@ mod tests { } .into(); - let ctx = Rc::new(force_any_val::()); - assert_eq!(eval_out::>(&expr, ctx), expected_xor); + let ctx = force_any_val::(); + assert_eq!(&eval_out::>(&expr, &ctx)[..], &expected_xor[..]); } } } diff --git a/ergotree-interpreter/src/eval/xor_of.rs b/ergotree-interpreter/src/eval/xor_of.rs index 8e7ca385c..5b70159f9 100644 --- a/ergotree-interpreter/src/eval/xor_of.rs +++ b/ergotree-interpreter/src/eval/xor_of.rs @@ -2,13 +2,17 @@ use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; -use crate::eval::EvalContext; +use crate::eval::Context; use crate::eval::EvalError; use crate::eval::Evaluable; use ergotree_ir::mir::xor_of::XorOf; impl Evaluable for XorOf { - fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + fn eval<'ctx>( + &self, + env: &mut Env<'ctx>, + ctx: &Context<'ctx>, + ) -> Result, EvalError> { let input_v = self.input.eval(env, ctx)?; let input_v_bools = input_v.try_extract_into::>()?; Ok(input_v_bools.into_iter().fold(false, |a, b| a ^ b).into()) @@ -25,15 +29,14 @@ mod tests { use proptest::collection; use proptest::prelude::*; use sigma_test_util::force_any_val; - use std::rc::Rc; proptest! { #[test] fn eval(bools in collection::vec(any::(), 0..=10)) { let expr: Expr = XorOf {input: Expr::Const(bools.clone().into()).into()}.into(); - let ctx = Rc::new(force_any_val::()); - let res = eval_out::(&expr, ctx); + let ctx = force_any_val::(); + let res = eval_out::(&expr, &ctx); // eval is true when collection has odd number of "true" values let expected = bools.into_iter().filter(|x| *x).count() & 1 == 1; prop_assert_eq!(res, expected); diff --git a/ergotree-interpreter/src/lib.rs b/ergotree-interpreter/src/lib.rs index 00410c56b..57cfd2cee 100644 --- a/ergotree-interpreter/src/lib.rs +++ b/ergotree-interpreter/src/lib.rs @@ -2,6 +2,7 @@ // Coding conventions #![forbid(unsafe_code)] +#![allow(clippy::needless_lifetimes)] // Leads to better code clarity #![deny(non_upper_case_globals)] #![deny(non_camel_case_types)] #![deny(non_snake_case)] @@ -20,7 +21,6 @@ #![deny(clippy::panic)] mod contracts; -mod util; pub mod eval; pub mod sigma_protocol; diff --git a/ergotree-interpreter/src/sigma_protocol/prover.rs b/ergotree-interpreter/src/sigma_protocol/prover.rs index 4dee08edc..4d5658308 100644 --- a/ergotree-interpreter/src/sigma_protocol/prover.rs +++ b/ergotree-interpreter/src/sigma_protocol/prover.rs @@ -27,7 +27,6 @@ use gf2_192::gf2_192poly::Gf2_192Poly; use gf2_192::gf2_192poly::Gf2_192PolyError; use gf2_192::Gf2_192Error; use std::convert::TryInto; -use std::rc::Rc; pub use context_extension::*; use ergotree_ir::ergo_tree::ErgoTree; @@ -55,7 +54,6 @@ use super::FirstProverMessage::FirstDhtProverMessage; use super::FirstProverMessage::FirstDlogProverMessage; use crate::eval::context::Context; -use crate::eval::env::Env; use crate::eval::EvalError; use crate::sigma_protocol::dht_protocol::SecondDhTupleProverMessage; @@ -138,17 +136,16 @@ pub trait Prover { /// , Appendix A /// /// Generate proofs for the given message for ErgoTree reduced to Sigma boolean expression - fn prove( + fn prove<'ctx>( &self, tree: &ErgoTree, - env: &Env, - ctx: Rc, + ctx: &'ctx Context, message: &[u8], hints_bag: &HintsBag, ) -> Result { let expr = tree.proposition()?; let ctx_ext = ctx.extension.clone(); - let reduction_result = reduce_to_crypto(&expr, env, ctx).map_err(ProverError::EvalError)?; + let reduction_result = reduce_to_crypto(&expr, ctx).map_err(ProverError::EvalError)?; self.generate_proof(reduction_result.sigma_prop, message, hints_bag) .map(|p| ProverResult { proof: p, @@ -1222,7 +1219,6 @@ mod tests { use ergotree_ir::types::stype::SType; use sigma_test_util::force_any_val; use std::convert::TryFrom; - use std::rc::Rc; #[test] fn test_prove_true_prop() { @@ -1236,8 +1232,7 @@ mod tests { let prover = TestProver { secrets: vec![] }; let res = prover.prove( &bool_true_tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1257,8 +1252,7 @@ mod tests { let prover = TestProver { secrets: vec![] }; let res = prover.prove( &bool_false_tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1277,8 +1271,7 @@ mod tests { }; let res = prover.prove( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1303,8 +1296,7 @@ mod tests { }; let res = prover.prove( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1335,8 +1327,7 @@ mod tests { }; let res = prover.prove( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1360,8 +1351,7 @@ mod tests { }; let res = prover.prove( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1392,8 +1382,7 @@ mod tests { }; let res = prover.prove( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1412,8 +1401,7 @@ mod tests { }; let res = prover.prove( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty(), ); @@ -1461,14 +1449,8 @@ mod tests { }; let message = vec![0u8; 100]; - let ctx: Rc = force_any_val::().into(); - let res = prover.prove( - &tree, - &Env::empty(), - ctx, - message.as_slice(), - &HintsBag::empty(), - ); + let ctx: Context = force_any_val::(); + let res = prover.prove(&tree, &ctx, message.as_slice(), &HintsBag::empty()); assert!(res.is_err()); } } diff --git a/ergotree-interpreter/src/sigma_protocol/verifier.rs b/ergotree-interpreter/src/sigma_protocol/verifier.rs index 5e97ddb41..5d2ba9c32 100644 --- a/ergotree-interpreter/src/sigma_protocol/verifier.rs +++ b/ergotree-interpreter/src/sigma_protocol/verifier.rs @@ -1,7 +1,5 @@ //! Verifier -use std::rc::Rc; - use super::dht_protocol; use super::dht_protocol::FirstDhTupleProverMessage; use super::fiat_shamir::FiatShamirTreeSerializationError; @@ -16,7 +14,6 @@ use super::{ SigmaBoolean, UncheckedTree, }; use crate::eval::context::Context; -use crate::eval::env::Env; use crate::eval::EvalError; use crate::eval::{reduce_to_crypto, ReductionDiagnosticInfo}; use dlog_protocol::FirstDlogProverMessage; @@ -60,16 +57,15 @@ pub trait Verifier { /// Step 1: Deserialize context variables /// Step 2: Evaluate expression and produce SigmaProp value, which is zero-knowledge statement (see also `SigmaBoolean`). /// Step 3: Verify that the proof is presented to satisfy SigmaProp conditions. - fn verify( + fn verify<'ctx>( &self, tree: &ErgoTree, - env: &Env, - ctx: Rc, + ctx: &Context<'ctx>, proof: ProofBytes, message: &[u8], ) -> Result { let expr = tree.proposition()?; - let reduction_result = reduce_to_crypto(&expr, env, ctx)?; + let reduction_result = reduce_to_crypto(&expr, ctx)?; let res: bool = match reduction_result.sigma_prop { SigmaBoolean::TrivialProp(b) => b, sb => { @@ -219,15 +215,13 @@ mod tests { secrets: vec![PrivateInput::DlogProverInput(secret)], }; let res = prover.prove(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty()); let proof = res.unwrap().proof; let verifier = TestVerifier; prop_assert_eq!(verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof.clone(), message.as_slice()) .unwrap().result, @@ -235,8 +229,7 @@ mod tests { // possible to append bytes prop_assert_eq!(verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof_append_some_byte(&proof), message.as_slice()) .unwrap().result, @@ -244,8 +237,7 @@ mod tests { // wrong message prop_assert_eq!(verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof, vec![1u8; 100].as_slice()) .unwrap().result, @@ -261,15 +253,13 @@ mod tests { secrets: vec![PrivateInput::DhTupleProverInput(secret)], }; let res = prover.prove(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty()); let proof = res.unwrap().proof; let verifier = TestVerifier; prop_assert_eq!(verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof.clone(), message.as_slice()) .unwrap().result, @@ -277,8 +267,7 @@ mod tests { // possible to append bytes prop_assert_eq!(verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof_append_some_byte(&proof), message.as_slice()) .unwrap().result, @@ -286,8 +275,7 @@ mod tests { // wrong message prop_assert_eq!(verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof, vec![1u8; 100].as_slice()) .unwrap().result, @@ -308,15 +296,13 @@ mod tests { secrets: vec![secret1, secret2], }; let res = prover.prove(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty()); let proof = res.unwrap().proof; let verifier = TestVerifier; let ver_res = verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof, message.as_slice()); prop_assert_eq!(ver_res.unwrap().result, true); @@ -339,15 +325,13 @@ mod tests { let tree = ErgoTree::try_from(expr).unwrap(); let prover = TestProver { secrets: vec![secret1, secret2, secret3] }; let res = prover.prove(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty()); let proof = res.unwrap().proof; let verifier = TestVerifier; let ver_res = verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof, message.as_slice()); prop_assert_eq!(ver_res.unwrap().result, true); @@ -370,15 +354,13 @@ mod tests { secrets: vec![secret.clone()], }; let res = prover.prove(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty()); let proof = res.unwrap_or_else(|_| panic!("proof failed for secret: {:?}", secret)).proof; let verifier = TestVerifier; let ver_res = verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof, message.as_slice()); prop_assert_eq!(ver_res.unwrap().result, true, "verify failed on secret: {:?}", &secret); @@ -407,15 +389,13 @@ mod tests { secrets: vec![secret.clone()], }; let res = prover.prove(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty()); let proof = res.unwrap_or_else(|_| panic!("proof failed for secret: {:?}", secret)).proof; let verifier = TestVerifier; let ver_res = verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), proof, message.as_slice()); prop_assert_eq!(ver_res.unwrap().result, true, "verify failed on secret: {:?}", &secret); @@ -429,9 +409,9 @@ mod tests { message in vec(any::(), 100..200)) { let bound = Expr::Const(2i32.into()); let inputs = Literal::Coll( - CollKind::from_vec( + CollKind::from_collection( SType::SSigmaProp, - vec![ + [ SigmaProp::from(secret1.public_image()).into(), SigmaProp::from(secret2.public_image()).into(), SigmaProp::from(secret3.public_image()).into(), @@ -451,17 +431,15 @@ mod tests { }; let res = prover.prove(&tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), message.as_slice(), &HintsBag::empty()); let proof = res.unwrap().proof; let verifier = TestVerifier; let ver_res = verifier.verify(&tree, - &Env::empty(), - Rc::new(force_any_val::()), - proof, - message.as_slice()); + &force_any_val::(), + proof, + message.as_slice()); prop_assert_eq!(ver_res.unwrap().result, true) } } diff --git a/ergotree-interpreter/src/util.rs b/ergotree-interpreter/src/util.rs deleted file mode 100644 index 21102c911..000000000 --- a/ergotree-interpreter/src/util.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Utilities - -use elliptic_curve::subtle::CtOption; - -/// Convert to Option -pub(crate) trait IntoOption { - /// Get Option - fn into_option(self) -> Option; -} - -impl IntoOption for CtOption { - fn into_option(self) -> Option { - if self.is_some().into() { - Some(self.unwrap()) - } else { - None - } - } -} diff --git a/ergotree-interpreter/tests/signing_spec_tests.rs b/ergotree-interpreter/tests/signing_spec_tests.rs index 4f16682dd..86f9af337 100644 --- a/ergotree-interpreter/tests/signing_spec_tests.rs +++ b/ergotree-interpreter/tests/signing_spec_tests.rs @@ -1,5 +1,4 @@ use ergotree_interpreter::eval::context::Context; -use ergotree_interpreter::eval::env::Env; use ergotree_interpreter::sigma_protocol::private_input::DlogProverInput; use ergotree_interpreter::sigma_protocol::verifier::{TestVerifier, Verifier}; use ergotree_ir::ergo_tree::ErgoTree; @@ -15,7 +14,6 @@ use ergotree_ir::types::stype::SType; use num_bigint::BigUint; use sigma_test_util::force_any_val; use std::convert::TryInto; -use std::rc::Rc; #[test] fn sig_test_vector_provedlog() { @@ -43,8 +41,7 @@ fn sig_test_vector_provedlog() { let verifier = TestVerifier; let ver_res = verifier.verify( &expr.try_into().unwrap(), - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); @@ -81,8 +78,7 @@ fn sig_test_vector_prove_dht() { let verifier = TestVerifier; let ver_res = verifier.verify( &expr.try_into().unwrap(), - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); @@ -138,8 +134,7 @@ fn sig_test_vector_conj_and() { let verifier = TestVerifier; let ver_res = verifier.verify( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); @@ -195,8 +190,7 @@ fn sig_test_vector_conj_or() { let verifier = TestVerifier; let ver_res = verifier.verify( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); @@ -246,8 +240,7 @@ fn sig_test_vector_conj_or_prove_dht() { let verifier = TestVerifier; let ver_res = verifier.verify( &expr.try_into().unwrap(), - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); @@ -317,8 +310,7 @@ fn sig_test_vector_conj_and_or() { let verifier = TestVerifier; let ver_res = verifier.verify( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); @@ -388,8 +380,7 @@ fn sig_test_vector_conj_or_and() { let verifier = TestVerifier; let ver_res = verifier.verify( &tree, - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); @@ -436,9 +427,9 @@ fn sig_test_vector_threshold() { let bound = Expr::Const(2i32.into()); let inputs = Literal::Coll( - CollKind::from_vec( + CollKind::from_collection( SType::SSigmaProp, - vec![ + [ SigmaProp::from(sk1.public_image()).into(), SigmaProp::from(sk2.public_image()).into(), SigmaProp::from(sk3.public_image()).into(), @@ -457,8 +448,7 @@ fn sig_test_vector_threshold() { let verifier = TestVerifier; let ver_res = verifier.verify( &expr.try_into().unwrap(), - &Env::empty(), - Rc::new(force_any_val::()), + &force_any_val::(), signature.into(), msg.as_slice(), ); diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs index 43e2b9b5f..8a1d981b3 100644 --- a/ergotree-ir/src/chain/address.rs +++ b/ergotree-ir/src/chain/address.rs @@ -29,6 +29,7 @@ use ergo_chain_types::EcPoint; use sigma_util::hash::blake2b256_hash; use sigma_util::AsVecU8; use std::convert::{TryFrom, TryInto}; +use std::sync::Arc; use thiserror::Error; /** @@ -213,7 +214,7 @@ impl Address { let get_var_expr = Expr::GetVar( GetVar { var_id: 1, - var_tpe: SType::SColl(Box::new(SType::SByte)), + var_tpe: SType::SColl(Arc::new(SType::SByte)), } .into(), ); diff --git a/ergotree-ir/src/chain/json/ergo_box.rs b/ergotree-ir/src/chain/json/ergo_box.rs index d8ab61989..e55d337c1 100644 --- a/ergotree-ir/src/chain/json/ergo_box.rs +++ b/ergotree-ir/src/chain/json/ergo_box.rs @@ -437,7 +437,7 @@ mod tests { #[test] fn parse_token_amount_as_str() { - let token_json = r#" + let token_json = r#" { "tokenId": "2d554219a80c011cc51509e34fa4950965bb8e01de4d012536e766c9ca08bc2c", "amount": "99999999998" diff --git a/ergotree-ir/src/ergo_tree.rs b/ergotree-ir/src/ergo_tree.rs index 6859bc6f9..8cdddabcc 100644 --- a/ergotree-ir/src/ergo_tree.rs +++ b/ergotree-ir/src/ergo_tree.rs @@ -177,7 +177,8 @@ impl ErgoTree { Ok(if header.is_constant_segregation() { let mut data = Vec::new(); let cs = ConstantStore::empty(); - let mut w = SigmaByteWriter::new(&mut data, Some(cs)); + let ww = &mut data; + let mut w = SigmaByteWriter::new(ww, Some(cs)); expr.sigma_serialize(&mut w)?; #[allow(clippy::unwrap_used)] // We set constant store earlier diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs index b30bff3ae..657baf961 100644 --- a/ergotree-ir/src/lib.rs +++ b/ergotree-ir/src/lib.rs @@ -27,6 +27,8 @@ pub mod chain; pub mod ergo_tree; pub mod mir; pub mod pretty_printer; +/// TODO +pub mod reference; pub mod serialization; pub mod sigma_protocol; pub mod source_span; diff --git a/ergotree-ir/src/mir.rs b/ergotree-ir/src/mir.rs index 1113dad3f..6903d3df0 100644 --- a/ergotree-ir/src/mir.rs +++ b/ergotree-ir/src/mir.rs @@ -28,6 +28,8 @@ pub mod coll_filter; pub mod coll_fold; /// Tests whether a predicate holds for all elements of this collection pub mod coll_forall; +/// Operations over Coll +pub mod coll_iter; /// Collection.map pub mod coll_map; /// Collection.size diff --git a/ergotree-ir/src/mir/byte_array_to_bigint.rs b/ergotree-ir/src/mir/byte_array_to_bigint.rs index f52314440..df4a0c7dc 100644 --- a/ergotree-ir/src/mir/byte_array_to_bigint.rs +++ b/ergotree-ir/src/mir/byte_array_to_bigint.rs @@ -1,4 +1,6 @@ //! Convert byte array to SBigInt +use std::sync::Arc; + use crate::serialization::op_code::OpCode; use crate::types::stype::SType; @@ -34,7 +36,7 @@ impl OneArgOp for ByteArrayToBigInt { impl OneArgOpTryBuild for ByteArrayToBigInt { fn try_build(input: Expr) -> Result { - input.check_post_eval_tpe(&SType::SColl(Box::new(SType::SByte)))?; + input.check_post_eval_tpe(&SType::SColl(Arc::new(SType::SByte)))?; Ok(ByteArrayToBigInt { input: Box::new(input), }) diff --git a/ergotree-ir/src/mir/byte_array_to_long.rs b/ergotree-ir/src/mir/byte_array_to_long.rs index d0ca41fbf..68e67b0a6 100644 --- a/ergotree-ir/src/mir/byte_array_to_long.rs +++ b/ergotree-ir/src/mir/byte_array_to_long.rs @@ -1,4 +1,6 @@ //! Convert byte array to SLong +use std::sync::Arc; + use crate::serialization::op_code::OpCode; use crate::types::stype::SType; @@ -34,7 +36,7 @@ impl OneArgOp for ByteArrayToLong { impl OneArgOpTryBuild for ByteArrayToLong { fn try_build(input: Expr) -> Result { - input.check_post_eval_tpe(&SType::SColl(Box::new(SType::SByte)))?; + input.check_post_eval_tpe(&SType::SColl(Arc::new(SType::SByte)))?; Ok(ByteArrayToLong { input: Box::new(input), }) diff --git a/ergotree-ir/src/mir/calc_blake2b256.rs b/ergotree-ir/src/mir/calc_blake2b256.rs index d86db8f1b..20b6a4427 100644 --- a/ergotree-ir/src/mir/calc_blake2b256.rs +++ b/ergotree-ir/src/mir/calc_blake2b256.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::has_opcode::HasStaticOpCode; use crate::serialization::op_code::OpCode; use crate::types::stype::SType; @@ -17,7 +19,7 @@ pub struct CalcBlake2b256 { impl CalcBlake2b256 { /// Type pub fn tpe(&self) -> SType { - SType::SColl(Box::new(SType::SByte)) + SType::SColl(Arc::new(SType::SByte)) } } @@ -33,7 +35,7 @@ impl OneArgOp for CalcBlake2b256 { impl OneArgOpTryBuild for CalcBlake2b256 { fn try_build(input: Expr) -> Result { - input.check_post_eval_tpe(&SType::SColl(Box::new(SType::SByte)))?; + input.check_post_eval_tpe(&SType::SColl(Arc::new(SType::SByte)))?; Ok(CalcBlake2b256 { input: Box::new(input), }) @@ -54,7 +56,7 @@ mod arbitrary { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { any_with::(ArbExprParams { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), depth: 0, }) .prop_map(|input| Self { diff --git a/ergotree-ir/src/mir/calc_sha256.rs b/ergotree-ir/src/mir/calc_sha256.rs index 2cbe5f2fd..2f43b80fe 100644 --- a/ergotree-ir/src/mir/calc_sha256.rs +++ b/ergotree-ir/src/mir/calc_sha256.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::has_opcode::HasStaticOpCode; use crate::serialization::op_code::OpCode; use crate::types::stype::SType; @@ -17,7 +19,7 @@ pub struct CalcSha256 { impl CalcSha256 { /// Type pub fn tpe(&self) -> SType { - SType::SColl(Box::new(SType::SByte)) + SType::SColl(Arc::new(SType::SByte)) } } @@ -33,7 +35,7 @@ impl OneArgOp for CalcSha256 { impl OneArgOpTryBuild for CalcSha256 { fn try_build(input: Expr) -> Result { - input.check_post_eval_tpe(&SType::SColl(Box::new(SType::SByte)))?; + input.check_post_eval_tpe(&SType::SColl(Arc::new(SType::SByte)))?; Ok(CalcSha256 { input: Box::new(input), }) @@ -54,7 +56,7 @@ mod arbitrary { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { any_with::(ArbExprParams { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), depth: 0, }) .prop_map(|input| Self { diff --git a/ergotree-ir/src/mir/coll_by_index.rs b/ergotree-ir/src/mir/coll_by_index.rs index 26f3fd7bb..836afd574 100644 --- a/ergotree-ir/src/mir/coll_by_index.rs +++ b/ergotree-ir/src/mir/coll_by_index.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::serialization::op_code::OpCode; use crate::serialization::sigma_byte_reader::SigmaByteRead; use crate::serialization::sigma_byte_writer::SigmaByteWrite; @@ -20,7 +22,7 @@ pub struct ByIndex { /// Default value, returned if index is out of bounds in "Coll.getOrElse()" op pub default: Option>, /// Input collection element type - input_elem_tpe: SType, + input_elem_tpe: Arc, } impl ByIndex { @@ -30,8 +32,8 @@ impl ByIndex { index: Expr, default: Option>, ) -> Result { - let input_elem_type: SType = match input.post_eval_tpe() { - SType::SColl(elem_type) => Ok(*elem_type), + let input_elem_type = match input.post_eval_tpe() { + SType::SColl(elem_type) => Ok(elem_type), _ => Err(InvalidArgumentError(format!( "Expected ByIndex input to be SColl, got {0:?}", input.tpe() @@ -44,8 +46,8 @@ impl ByIndex { ))); } if !default - .clone() - .map(|expr| expr.post_eval_tpe() == input_elem_type) + .as_ref() + .map(|expr| expr.post_eval_tpe() == *input_elem_type) .unwrap_or(true) { return Err(InvalidArgumentError(format!( @@ -63,7 +65,7 @@ impl ByIndex { /// Type pub fn tpe(&self) -> SType { - self.input_elem_tpe.clone() + (*self.input_elem_tpe).clone() } } diff --git a/ergotree-ir/src/mir/coll_exists.rs b/ergotree-ir/src/mir/coll_exists.rs index ff5483770..4092d3c44 100644 --- a/ergotree-ir/src/mir/coll_exists.rs +++ b/ergotree-ir/src/mir/coll_exists.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use super::expr::Expr; use super::expr::InvalidArgumentError; use crate::has_opcode::HasStaticOpCode; @@ -17,14 +19,14 @@ pub struct Exists { /// Function (lambda) to test each element pub condition: Box, /// Collection element type - pub elem_tpe: SType, + pub elem_tpe: Arc, } impl Exists { /// Create new object, returns an error if any of the requirements failed pub fn new(input: Expr, condition: Expr) -> Result { - let input_elem_type: SType = match input.post_eval_tpe() { - SType::SColl(elem_type) => Ok(*elem_type), + let input_elem_type = match input.post_eval_tpe() { + SType::SColl(elem_type) => Ok(elem_type), _ => Err(InvalidArgumentError(format!( "Expected Exists input to be SColl, got {0:?}", input.tpe() @@ -32,7 +34,8 @@ impl Exists { }?; match condition.tpe() { SType::SFunc(sfunc) - if sfunc.t_dom == vec![input_elem_type.clone()] + if sfunc.t_dom.len() == 1 + && sfunc.t_dom[0] == *input_elem_type && *sfunc.t_range == SType::SBoolean => { Ok(Exists { diff --git a/ergotree-ir/src/mir/coll_filter.rs b/ergotree-ir/src/mir/coll_filter.rs index e82135025..9b5e5f777 100644 --- a/ergotree-ir/src/mir/coll_filter.rs +++ b/ergotree-ir/src/mir/coll_filter.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use super::expr::Expr; use super::expr::InvalidArgumentError; use crate::has_opcode::HasStaticOpCode; @@ -17,14 +19,14 @@ pub struct Filter { /// Function (lambda) to test each element pub condition: Box, /// Collection element type - pub elem_tpe: SType, + pub elem_tpe: Arc, } impl Filter { /// Create new object, returns an error if any of the requirements failed pub fn new(input: Expr, condition: Expr) -> Result { - let input_elem_type: SType = match input.post_eval_tpe() { - SType::SColl(elem_type) => Ok(*elem_type), + let input_elem_type = match input.post_eval_tpe() { + SType::SColl(elem_type) => Ok(elem_type), _ => Err(InvalidArgumentError(format!( "Expected Map input to be SColl, got {0:?}", input.tpe() @@ -32,7 +34,8 @@ impl Filter { }?; match condition.tpe() { SType::SFunc(sfunc) - if sfunc.t_dom == vec![input_elem_type.clone()] + if sfunc.t_dom.len() == 1 + && sfunc.t_dom[0] == *input_elem_type && *sfunc.t_range == SType::SBoolean => { Ok(Filter { @@ -50,7 +53,7 @@ impl Filter { /// Type pub fn tpe(&self) -> SType { - SType::SColl(self.elem_tpe.clone().into()) + SType::SColl(self.elem_tpe.clone()) } } diff --git a/ergotree-ir/src/mir/coll_fold.rs b/ergotree-ir/src/mir/coll_fold.rs index 0b6258f6d..15d2b8ba6 100644 --- a/ergotree-ir/src/mir/coll_fold.rs +++ b/ergotree-ir/src/mir/coll_fold.rs @@ -26,8 +26,8 @@ pub struct Fold { impl Fold { /// Create new object, returns an error if any of the requirements failed pub fn new(input: Expr, zero: Expr, fold_op: Expr) -> Result { - let input_elem_type: SType = match input.post_eval_tpe() { - SType::SColl(elem_type) => Ok(*elem_type), + let input_elem_type = match input.post_eval_tpe() { + SType::SColl(elem_type) => Ok(elem_type), _ => Err(InvalidArgumentError(format!( "Expected Fold input to be SColl, got {0:?}", input.tpe() @@ -35,7 +35,8 @@ impl Fold { }?; match fold_op.tpe() { SType::SFunc(sfunc) - if sfunc.t_dom == vec![STuple::pair(zero.tpe(), input_elem_type).into()] => + if sfunc.t_dom + == vec![STuple::pair(zero.tpe(), (*input_elem_type).clone()).into()] => { Ok(Fold { input: input.into(), diff --git a/ergotree-ir/src/mir/coll_forall.rs b/ergotree-ir/src/mir/coll_forall.rs index 29b098efe..75ea1cb4c 100644 --- a/ergotree-ir/src/mir/coll_forall.rs +++ b/ergotree-ir/src/mir/coll_forall.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use super::expr::Expr; use super::expr::InvalidArgumentError; use crate::has_opcode::HasStaticOpCode; @@ -17,14 +19,14 @@ pub struct ForAll { /// Function (lambda) to test each element pub condition: Box, /// Collection element type - pub elem_tpe: SType, + pub elem_tpe: Arc, } impl ForAll { /// Create new object, returns an error if any of the requirements failed pub fn new(input: Expr, condition: Expr) -> Result { - let input_elem_type: SType = match input.post_eval_tpe() { - SType::SColl(elem_type) => Ok(*elem_type), + let input_elem_type = match input.post_eval_tpe() { + SType::SColl(elem_type) => Ok(elem_type), _ => Err(InvalidArgumentError(format!( "Expected ForAll input to be SColl, got {0:?}", input.tpe() @@ -32,7 +34,8 @@ impl ForAll { }?; match condition.tpe() { SType::SFunc(sfunc) - if sfunc.t_dom == vec![input_elem_type.clone()] + if sfunc.t_dom.len() == 1 + && sfunc.t_dom[0] == *input_elem_type.clone() && *sfunc.t_range == SType::SBoolean => { Ok(ForAll { diff --git a/ergotree-ir/src/mir/coll_map.rs b/ergotree-ir/src/mir/coll_map.rs index 7b73a350f..d252d40b5 100644 --- a/ergotree-ir/src/mir/coll_map.rs +++ b/ergotree-ir/src/mir/coll_map.rs @@ -25,19 +25,21 @@ pub struct Map { impl Map { /// Create new object, returns an error if any of the requirements failed pub fn new(input: Expr, mapper: Expr) -> Result { - let input_elem_type: SType = match input.post_eval_tpe() { - SType::SColl(elem_type) => Ok(*elem_type), + let input_elem_type = match input.post_eval_tpe() { + SType::SColl(elem_type) => Ok(elem_type), _ => Err(InvalidArgumentError(format!( "Expected Map input to be SColl, got {0:?}", input.tpe() ))), }?; match mapper.tpe() { - SType::SFunc(sfunc) if sfunc.t_dom == vec![input_elem_type] => Ok(Map { - input: input.into(), - mapper: mapper.into(), - mapper_sfunc: sfunc, - }), + SType::SFunc(sfunc) if sfunc.t_dom.len() == 1 && sfunc.t_dom[0] == *input_elem_type => { + Ok(Map { + input: input.into(), + mapper: mapper.into(), + mapper_sfunc: sfunc, + }) + } _ => Err(InvalidArgumentError(format!( "Invalid mapper tpe: {0:?}", mapper.tpe() @@ -47,7 +49,7 @@ impl Map { /// Type pub fn tpe(&self) -> SType { - SType::SColl(self.mapper_sfunc.t_range.clone()) + SType::SColl(self.mapper_sfunc.t_range.clone().into()) } /// Type of the element in the resulted collection diff --git a/ergotree-ir/src/mir/constant.rs b/ergotree-ir/src/mir/constant.rs index 78f51a549..ae61153e9 100644 --- a/ergotree-ir/src/mir/constant.rs +++ b/ergotree-ir/src/mir/constant.rs @@ -5,6 +5,7 @@ use crate::bigint256::BigInt256; use crate::chain::ergo_box::ErgoBox; use crate::chain::token::TokenId; use crate::mir::value::CollKind; +use crate::reference::Ref; use crate::serialization::SigmaParsingError; use crate::serialization::SigmaSerializable; use crate::serialization::SigmaSerializationError; @@ -69,11 +70,11 @@ pub enum Literal { /// Sigma property SigmaProp(Box), /// GroupElement - GroupElement(Box), + GroupElement(Arc), /// AVL tree AvlTree(Box), /// Ergo box - CBox(Arc), + CBox(Ref<'static, ErgoBox>), /// Collection Coll(CollKind), /// Option type @@ -225,25 +226,33 @@ impl From for Literal { impl From for Literal { fn from(v: EcPoint) -> Literal { - Literal::GroupElement(Box::new(v)) + Literal::GroupElement(Arc::new(v)) } } -impl From> for Literal { - fn from(b: Arc) -> Self { +impl From> for Literal { + fn from(value: Ref<'_, EcPoint>) -> Self { + Literal::GroupElement(value.to_arc()) + } +} + +impl From> for Literal { + fn from(b: Ref<'static, ErgoBox>) -> Self { Literal::CBox(b) } } impl From for Literal { fn from(b: ErgoBox) -> Self { - Literal::CBox(Arc::new(b)) + Literal::CBox(Arc::new(b).into()) } } impl From> for Literal { fn from(v: Vec) -> Self { - Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(v.as_vec_i8()))) + Literal::Coll(CollKind::NativeColl(NativeColl::CollByte( + v.as_vec_i8().into(), + ))) // TODO: optimize } } @@ -251,7 +260,7 @@ impl From for Literal { fn from(v: Digest32) -> Self { let bytes: Vec = v.into(); Literal::Coll(CollKind::NativeColl(NativeColl::CollByte( - bytes.as_vec_i8(), + bytes.as_vec_i8().into(), // TODO: optimize ))) } } @@ -263,8 +272,8 @@ impl From for Literal { } impl From> for Literal { - fn from(v: Vec) -> Literal { - Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(v))) + fn from(v: Vec) -> Self { + Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(v.into()))) // TODO } } @@ -283,10 +292,10 @@ impl> From> for Literal { } } -impl TryFrom for Constant { +impl<'ctx> TryFrom> for Constant { type Error = String; #[allow(clippy::unwrap_used)] - fn try_from(value: Value) -> Result { + fn try_from(value: Value<'ctx>) -> Result { match value { Value::Boolean(b) => Ok(Constant::from(b)), Value::Byte(b) => Ok(Constant::from(b)), @@ -299,26 +308,26 @@ impl TryFrom for Constant { v: Literal::Unit, }), Value::SigmaProp(s) => Ok(Constant::from(*s)), - Value::GroupElement(e) => Ok(Constant::from(*e)), - Value::CBox(i) => Ok(Constant::from(i)), + Value::GroupElement(e) => Ok(Constant::from(e)), + Value::CBox(i) => Ok(Constant::from(i.to_static())), Value::Coll(coll) => { let (v, tpe) = match coll { CollKind::NativeColl(n) => ( Literal::Coll(CollKind::NativeColl(n)), - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), ), CollKind::WrappedColl { elem_tpe, items } => { - let mut new_items = Vec::with_capacity(items.len()); - for v in items { - let c = Constant::try_from(v)?; - new_items.push(c.v); - } + let new_items = items + .iter() + .map(|v| Ok(Constant::try_from(v.clone())?.v)) + .collect::, String>>()?; + ( Literal::Coll(CollKind::WrappedColl { elem_tpe: elem_tpe.clone(), items: new_items, }), - SType::SColl(Box::new(elem_tpe)), + SType::SColl(Arc::new(elem_tpe)), ) } }; @@ -362,7 +371,7 @@ impl TryFrom for Constant { } impl From<()> for Constant { - fn from(_: ()) -> Constant { + fn from(_: ()) -> Self { Constant { tpe: SType::SUnit, v: Literal::Unit, @@ -371,7 +380,7 @@ impl From<()> for Constant { } impl From for Constant { - fn from(v: bool) -> Constant { + fn from(v: bool) -> Self { Constant { tpe: bool::stype(), v: v.into(), @@ -380,7 +389,7 @@ impl From for Constant { } impl From for Constant { - fn from(v: i8) -> Constant { + fn from(v: i8) -> Self { Constant { tpe: i8::stype(), v: v.into(), @@ -389,7 +398,7 @@ impl From for Constant { } impl From for Constant { - fn from(v: i16) -> Constant { + fn from(v: i16) -> Self { Constant { tpe: i16::stype(), v: v.into(), @@ -398,7 +407,7 @@ impl From for Constant { } impl From for Constant { - fn from(v: i32) -> Constant { + fn from(v: i32) -> Self { Constant { tpe: i32::stype(), v: v.into(), @@ -407,7 +416,7 @@ impl From for Constant { } impl From for Constant { - fn from(v: i64) -> Constant { + fn from(v: i64) -> Self { Constant { tpe: i64::stype(), v: v.into(), @@ -416,7 +425,7 @@ impl From for Constant { } impl From for Constant { - fn from(v: SigmaProp) -> Constant { + fn from(v: SigmaProp) -> Self { Constant { tpe: SType::SSigmaProp, v: v.into(), @@ -433,11 +442,20 @@ impl From for Constant { } } -impl From> for Constant { - fn from(b: Arc) -> Self { +impl From> for Constant { + fn from(v: Ref<'_, EcPoint>) -> Self { + Constant { + tpe: SType::SGroupElement, + v: v.into(), + } + } +} + +impl From<&'static ErgoBox> for Constant { + fn from(b: &'static ErgoBox) -> Self { Constant { tpe: SType::SBox, - v: b.into(), + v: Literal::CBox(Ref::Borrowed(b)), } } } @@ -446,7 +464,16 @@ impl From for Constant { fn from(b: ErgoBox) -> Self { Constant { tpe: SType::SBox, - v: b.into(), + v: Literal::CBox(Arc::new(b).into()), + } + } +} + +impl From> for Constant { + fn from(b: Ref<'static, ErgoBox>) -> Self { + Constant { + tpe: SType::SBox, + v: Literal::CBox(b), } } } @@ -454,7 +481,7 @@ impl From for Constant { impl From> for Constant { fn from(v: Vec) -> Self { Constant { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), v: v.into(), } } @@ -463,7 +490,7 @@ impl From> for Constant { impl From for Constant { fn from(v: Digest32) -> Self { Constant { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), v: v.into(), } } @@ -476,9 +503,9 @@ impl From for Constant { } impl From> for Constant { - fn from(v: Vec) -> Constant { + fn from(v: Vec) -> Self { Constant { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), v: v.into(), } } @@ -499,7 +526,7 @@ impl> From> for Constant impl> From> for Constant { fn from(opt: Option) -> Self { Constant { - tpe: SType::SOption(Box::new(T::stype())), + tpe: SType::SOption(Arc::new(T::stype())), v: Literal::Opt(Box::new(opt.map(|e| e.into().v))), } } @@ -557,8 +584,10 @@ impl From for Constant { impl From for Constant { fn from(a: ADDigest) -> Self { Constant { - tpe: SType::SColl(Box::new(SType::SByte)), - v: Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(a.into()))), + tpe: SType::SColl(Arc::new(SType::SByte)), + v: Literal::Coll(CollKind::NativeColl(NativeColl::CollByte( + a.0.iter().map(|&i| i as i8).collect(), + ))), } } } @@ -671,7 +700,7 @@ impl TryExtractFrom for i64 { impl TryExtractFrom for EcPoint { fn try_extract_from(cv: Literal) -> Result { match cv { - Literal::GroupElement(v) => Ok(*v), + Literal::GroupElement(v) => Ok((*v).clone()), _ => Err(TryExtractFromError(format!( "expected EcPoint, found {:?}", cv @@ -692,7 +721,7 @@ impl TryExtractFrom for SigmaProp { } } -impl TryExtractFrom for Arc { +impl TryExtractFrom for Ref<'static, ErgoBox> { fn try_extract_from(c: Literal) -> Result { match c { Literal::CBox(b) => Ok(b), @@ -723,7 +752,7 @@ impl + StoreWrapped> TryExtractFrom for Vec< CollKind::WrappedColl { elem_tpe: _, items: v, - } => v.into_iter().map(T::try_extract_from).collect(), + } => v.iter().cloned().map(T::try_extract_from).collect(), _ => Err(TryExtractFromError(format!( "expected {:?}, found {:?}", std::any::type_name::(), @@ -743,7 +772,7 @@ impl TryExtractFrom for Vec { fn try_extract_from(v: Literal) -> Result { match v { Literal::Coll(v) => match v { - CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs), + CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), // TODO: optimize _ => Err(TryExtractFromError(format!( "expected {:?}, found {:?}", std::any::type_name::(), @@ -927,14 +956,14 @@ pub(crate) mod arbitrary { fn coll_from_constant(c: Constant, length: usize) -> Constant { Constant { - tpe: SType::SColl(Box::new(c.tpe.clone())), + tpe: SType::SColl(Arc::new(c.tpe.clone())), v: Literal::Coll(if c.tpe == SType::SByte { let mut values: Vec = Vec::with_capacity(length); let byte: i8 = c.v.try_extract_into().unwrap(); for _ in 0..length { values.push(byte); } - CollKind::NativeColl(NativeColl::CollByte(values)) + CollKind::NativeColl(NativeColl::CollByte(values.into())) // TODO: optimize } else { let mut values: Vec = Vec::with_capacity(length); for _ in 0..length { @@ -942,7 +971,7 @@ pub(crate) mod arbitrary { } CollKind::WrappedColl { elem_tpe: c.tpe, - items: values, + items: values.into(), } }), } @@ -1071,7 +1100,13 @@ pub mod tests { fn test_constant_roundtrip(v: T) where - T: TryExtractInto + TryExtractFrom + Into + fmt::Debug + Eq + Clone, + T: TryExtractInto + + TryExtractFrom + + Into + + fmt::Debug + + Eq + + Clone + + 'static, { let constant: Constant = v.clone().into(); let v_extracted: T = constant.try_extract_into::().unwrap(); diff --git a/ergotree-ir/src/mir/create_avl_tree.rs b/ergotree-ir/src/mir/create_avl_tree.rs index 820d4e52f..48678300c 100644 --- a/ergotree-ir/src/mir/create_avl_tree.rs +++ b/ergotree-ir/src/mir/create_avl_tree.rs @@ -31,7 +31,7 @@ impl CreateAvlTree { value_length: Option>, ) -> Result { flags.check_post_eval_tpe(&SType::SByte)?; - digest.check_post_eval_tpe(&SType::SColl(Box::new(SType::SByte)))?; + digest.check_post_eval_tpe(&SType::SColl(std::sync::Arc::new(SType::SByte)))?; key_length.check_post_eval_tpe(&SType::SInt)?; if !value_length .clone() @@ -83,6 +83,8 @@ impl SigmaSerializable for CreateAvlTree { #[cfg(feature = "arbitrary")] /// Arbitrary impl mod arbitrary { + use std::sync::Arc; + use crate::mir::expr::arbitrary::ArbExprParams; use super::*; @@ -100,7 +102,7 @@ mod arbitrary { depth: 0, }), any_with::(ArbExprParams { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), depth: 0, }), any_with::(ArbExprParams { diff --git a/ergotree-ir/src/mir/decode_point.rs b/ergotree-ir/src/mir/decode_point.rs index 2cbe5e3e3..31cc1750b 100644 --- a/ergotree-ir/src/mir/decode_point.rs +++ b/ergotree-ir/src/mir/decode_point.rs @@ -1,5 +1,7 @@ //! Decode byte array to EC point +use std::sync::Arc; + use crate::serialization::op_code::OpCode; use crate::types::stype::SType; @@ -35,7 +37,7 @@ impl OneArgOp for DecodePoint { impl OneArgOpTryBuild for DecodePoint { fn try_build(input: Expr) -> Result { - input.check_post_eval_tpe(&SType::SColl(Box::new(SType::SByte)))?; + input.check_post_eval_tpe(&SType::SColl(Arc::new(SType::SByte)))?; Ok(Self { input: input.into(), }) diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index f508c5009..3744af858 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -396,6 +396,7 @@ pub(crate) mod arbitrary { use crate::types::sfunc::SFunc; use proptest::collection::*; use proptest::prelude::*; + use std::sync::Arc; /// Parameters for arbitrary Expr generation #[derive(PartialEq, Eq, Debug, Clone)] @@ -535,19 +536,19 @@ pub(crate) mod arbitrary { fn coll_non_nested_expr(elem_tpe: &SType) -> BoxedStrategy { match elem_tpe { - SType::SBoolean => any_with::(SType::SColl(Box::new(SType::SBoolean)).into()) + SType::SBoolean => any_with::(SType::SColl(Arc::new(SType::SBoolean)).into()) .prop_map(Expr::Const) .boxed(), - SType::SByte => any_with::(SType::SColl(Box::new(SType::SByte)).into()) + SType::SByte => any_with::(SType::SColl(Arc::new(SType::SByte)).into()) .prop_map(Expr::Const) .boxed(), - SType::SShort => any_with::(SType::SColl(Box::new(SType::SShort)).into()) + SType::SShort => any_with::(SType::SColl(Arc::new(SType::SShort)).into()) .prop_map(Expr::Const) .boxed(), - SType::SInt => any_with::(SType::SColl(Box::new(SType::SInt)).into()) + SType::SInt => any_with::(SType::SColl(Arc::new(SType::SInt)).into()) .prop_map(Expr::Const) .boxed(), - SType::SLong => any_with::(SType::SColl(Box::new(SType::SLong)).into()) + SType::SLong => any_with::(SType::SColl(Arc::new(SType::SLong)).into()) .prop_map(Expr::Const) .boxed(), _ => todo!("Collection of {0:?} is not yet implemented", elem_tpe), diff --git a/ergotree-ir/src/mir/extract_reg_as.rs b/ergotree-ir/src/mir/extract_reg_as.rs index e77483225..b00ad3904 100644 --- a/ergotree-ir/src/mir/extract_reg_as.rs +++ b/ergotree-ir/src/mir/extract_reg_as.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::serialization::op_code::OpCode; use crate::serialization::sigma_byte_reader::SigmaByteRead; use crate::serialization::sigma_byte_writer::SigmaByteWrite; @@ -18,7 +20,7 @@ pub struct ExtractRegisterAs { /// Register id to extract value from (0 is R0 .. 9 for R9) pub register_id: i8, /// Result type, to be wrapped in SOption - pub elem_tpe: SType, + pub elem_tpe: Arc, } impl ExtractRegisterAs { @@ -31,7 +33,7 @@ impl ExtractRegisterAs { ))); } let elem_tpe = match tpe { - SType::SOption(t) => Ok(*t), + SType::SOption(t) => Ok(t), _ => Err(InvalidArgumentError(format!( "expected tpe to be SOption, got {0:?}", tpe @@ -47,7 +49,7 @@ impl ExtractRegisterAs { /// Type pub fn tpe(&self) -> SType { - SType::SOption(self.elem_tpe.clone().into()) + SType::SOption(self.elem_tpe.clone()) } } diff --git a/ergotree-ir/src/mir/global_vars.rs b/ergotree-ir/src/mir/global_vars.rs index ce5a35708..b8ca7ab4a 100644 --- a/ergotree-ir/src/mir/global_vars.rs +++ b/ergotree-ir/src/mir/global_vars.rs @@ -1,6 +1,7 @@ //! Global variables use std::fmt::Display; +use std::sync::Arc; use crate::has_opcode::HasOpCode; use crate::serialization::op_code::OpCode; @@ -27,11 +28,11 @@ impl GlobalVars { /// Type pub fn tpe(&self) -> SType { match self { - GlobalVars::Inputs => SType::SColl(Box::new(SType::SBox)), - GlobalVars::Outputs => SType::SColl(Box::new(SType::SBox)), + GlobalVars::Inputs => SType::SColl(Arc::new(SType::SBox)), + GlobalVars::Outputs => SType::SColl(Arc::new(SType::SBox)), GlobalVars::Height => SType::SInt, GlobalVars::SelfBox => SType::SBox, - GlobalVars::MinerPubKey => SType::SColl(Box::new(SType::SByte)), + GlobalVars::MinerPubKey => SType::SColl(Arc::new(SType::SByte)), GlobalVars::GroupGenerator => SType::SGroupElement, } } diff --git a/ergotree-ir/src/mir/option_get.rs b/ergotree-ir/src/mir/option_get.rs index 76dd316fb..594e641ab 100644 --- a/ergotree-ir/src/mir/option_get.rs +++ b/ergotree-ir/src/mir/option_get.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use super::expr::Expr; use super::expr::InvalidArgumentError; use super::unary_op::OneArgOp; @@ -12,13 +14,13 @@ pub struct OptionGet { /// Object of SOption type pub input: Box, /// Option element type - elem_tpe: SType, + elem_tpe: Arc, } impl OptionGet { /// Type pub fn tpe(&self) -> SType { - self.elem_tpe.clone() + (*self.elem_tpe).clone() } } @@ -37,7 +39,7 @@ impl OneArgOpTryBuild for OptionGet { match input.post_eval_tpe() { SType::SOption(elem_tpe) => Ok(OptionGet { input: Box::new(input), - elem_tpe: *elem_tpe, + elem_tpe, }), _ => Err(InvalidArgumentError(format!( "expected OptionGet::input type to be SOption, got: {0:?}", diff --git a/ergotree-ir/src/mir/option_get_or_else.rs b/ergotree-ir/src/mir/option_get_or_else.rs index 25c25d328..0be7635e1 100644 --- a/ergotree-ir/src/mir/option_get_or_else.rs +++ b/ergotree-ir/src/mir/option_get_or_else.rs @@ -8,6 +8,7 @@ use crate::serialization::SigmaParsingError; use crate::serialization::SigmaSerializable; use crate::serialization::SigmaSerializeResult; use crate::types::stype::SType; +use std::sync::Arc; /// Returns the Option's value or error if no value #[derive(PartialEq, Eq, Debug, Clone)] @@ -17,7 +18,7 @@ pub struct OptionGetOrElse { /// Default value if option is empty pub default: Box, /// Option element type - elem_tpe: SType, + elem_tpe: Arc, } impl OptionGetOrElse { @@ -29,7 +30,7 @@ impl OptionGetOrElse { Ok(OptionGetOrElse { input: Box::new(input), default: Box::new(default), - elem_tpe: *elem_tpe, + elem_tpe, }) } _ => Err(InvalidArgumentError(format!( @@ -41,7 +42,7 @@ impl OptionGetOrElse { /// Type pub fn tpe(&self) -> SType { - self.elem_tpe.clone() + (*self.elem_tpe).clone() } } diff --git a/ergotree-ir/src/mir/tree_lookup.rs b/ergotree-ir/src/mir/tree_lookup.rs index e57b3ca47..95e85eb46 100644 --- a/ergotree-ir/src/mir/tree_lookup.rs +++ b/ergotree-ir/src/mir/tree_lookup.rs @@ -63,6 +63,7 @@ impl SigmaSerializable for TreeLookup { /// Arbitrary impl mod arbitrary { use crate::mir::expr::arbitrary::ArbExprParams; + use std::sync::Arc; use super::*; use proptest::prelude::*; @@ -78,11 +79,11 @@ mod arbitrary { depth: 0, }), any_with::(ArbExprParams { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), depth: 0, }), any_with::(ArbExprParams { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), depth: 0, }), ) diff --git a/ergotree-ir/src/mir/value.rs b/ergotree-ir/src/mir/value.rs index c772ec4bc..193887616 100644 --- a/ergotree-ir/src/mir/value.rs +++ b/ergotree-ir/src/mir/value.rs @@ -9,6 +9,7 @@ use sigma_util::AsVecI8; use crate::bigint256::BigInt256; use crate::chain::ergo_box::ErgoBox; +use crate::reference::Ref; use crate::sigma_protocol::sigma_boolean::SigmaProp; use crate::types::stuple::TupleItems; use crate::types::stype::LiftIntoSType; @@ -30,7 +31,7 @@ use derive_more::From; /// Collection for primitive values (i.e byte array) pub enum NativeColl { /// Collection of bytes - CollByte(Vec), + CollByte(Arc<[i8]>), } impl NativeColl { @@ -52,7 +53,7 @@ pub enum CollKind { /// Collection element type elem_tpe: SType, /// Collection elements - items: Vec, + items: Arc<[T]>, }, } @@ -65,14 +66,22 @@ where Vec: TryExtractFrom, { /// Build a collection from items, storing them as Rust types values when neccessary - pub fn from_vec(elem_tpe: SType, items: Vec) -> Result, TryExtractFromError> { + pub fn from_collection( + elem_tpe: SType, + items: impl Into>, + ) -> Result, TryExtractFromError> { match elem_tpe { SType::SByte => items - .into_iter() + .into() + .iter() + .cloned() .map(|v| v.try_extract_into::()) - .collect::, _>>() + .collect::, _>>() .map(|bytes| CollKind::NativeColl(NativeColl::CollByte(bytes))), - _ => Ok(CollKind::WrappedColl { elem_tpe, items }), + _ => Ok(CollKind::WrappedColl { + elem_tpe, + items: items.into(), + }), } } @@ -87,14 +96,14 @@ where .into_iter() .map(|v| v.try_extract_into::>()) .collect::, _>>() - .map(|bytes| CollKind::NativeColl(NativeColl::CollByte(bytes.concat()))), + .map(|bytes| CollKind::NativeColl(NativeColl::CollByte(bytes.concat().into()))), SType::SColl(flat_type) => items .into_iter() .map(|v| v.try_extract_into::>()) .collect::, _>>() .map(|v| CollKind::WrappedColl { - elem_tpe: *flat_type, - items: v.concat(), + elem_tpe: (*flat_type).clone(), + items: v.into_iter().flat_map(Vec::into_iter).collect(), }), _ => Err(TryExtractFromError(format!( "Expected Value::Coll, got: {:?}", @@ -116,15 +125,31 @@ where /// Return items, as vector of Values pub fn as_vec(&self) -> Vec { match self { - CollKind::NativeColl(NativeColl::CollByte(coll_byte)) => coll_byte - .clone() - .into_iter() - .map(|byte| byte.into()) - .collect(), + CollKind::NativeColl(NativeColl::CollByte(coll_byte)) => { + coll_byte.clone().iter().map(|&byte| byte.into()).collect() + } CollKind::WrappedColl { elem_tpe: _, items: v, - } => v.clone(), + } => v.clone().to_vec(), + } + } + /// Return size of Coll + #[allow(clippy::len_without_is_empty)] + pub fn len(&self) -> usize { + match self { + CollKind::NativeColl(NativeColl::CollByte(coll_byte)) => coll_byte.len(), + CollKind::WrappedColl { elem_tpe: _, items } => items.len(), + } + } + + /// Index the array. Returns None if out of bounds + pub fn get_val(&self, index: usize) -> Option { + match self { + CollKind::NativeColl(NativeColl::CollByte(coll_byte)) => { + coll_byte.get(index).map(|&byte| byte.into()) + } + CollKind::WrappedColl { elem_tpe: _, items } => items.get(index).cloned(), } } } @@ -140,7 +165,7 @@ pub struct Lambda { /// Runtime value #[derive(PartialEq, Eq, Debug, Clone, From)] -pub enum Value { +pub enum Value<'ctx> { /// Boolean Boolean(bool), /// Byte @@ -156,17 +181,17 @@ pub enum Value { /// Big integer BigInt(BigInt256), /// GroupElement - GroupElement(Box), + GroupElement(Ref<'ctx, EcPoint>), /// Sigma property SigmaProp(Box), /// Ergo box - CBox(Arc), + CBox(Ref<'ctx, ErgoBox>), /// AVL tree AvlTree(Box), /// Collection of values of the same type - Coll(CollKind), + Coll(CollKind>), /// Tuple (arbitrary type values) - Tup(TupleItems), + Tup(TupleItems>), /// Transaction(and blockchain) context info Context, /// Block header @@ -176,49 +201,105 @@ pub enum Value { /// Global which is used to define global methods Global, /// Optional value - Opt(Box>), + Opt(Box>>), /// lambda Lambda(Lambda), } -impl Value { +impl<'ctx> Value<'ctx> { + /// Convert a Value<'ctx> to a Value<'static>. + /// Useful for returning errors especially in bindings where we can't return borrowed values + pub fn to_static(&'ctx self) -> Value<'static> { + match self { + Value::Boolean(b) => Value::Boolean(*b), + Value::Byte(b) => Value::Byte(*b), + Value::Short(b) => Value::Short(*b), + Value::Int(b) => Value::Int(*b), + Value::Long(b) => Value::Long(*b), + Value::Unit => Value::Unit, + Value::BigInt(b) => Value::BigInt(b.clone()), + Value::GroupElement(b) => Value::GroupElement(b.to_static()), + Value::SigmaProp(p) => Value::SigmaProp(p.clone()), + Value::AvlTree(t) => Value::AvlTree(t.clone()), + Value::Coll(coll) => match coll { + CollKind::NativeColl(c) => Value::Coll(CollKind::NativeColl(c.clone())), + CollKind::WrappedColl { elem_tpe, items } => Value::Coll(CollKind::WrappedColl { + items: items.iter().map(|v| v.to_static()).collect(), + elem_tpe: elem_tpe.clone(), + }), + }, + Value::Tup(tup) => Value::Tup( + #[allow(clippy::unwrap_used)] + // The resulting tuple will be of the same length, so BoundedVec creation won't fail + tup.iter() + .map(|v| v.to_static()) + .collect::>() + .try_into() + .unwrap(), + ), + Value::Context => Value::Context, + Value::Header(h) => Value::Header(h.clone()), + Value::PreHeader(h) => Value::PreHeader(h.clone()), + Value::Global => Value::Global, + Value::CBox(c) => Value::CBox(c.to_static()), + Value::Opt(opt) => Value::Opt(Box::new(Option::as_ref(opt).map(|o| o.to_static()))), + Value::Lambda(l) => Value::Lambda(l.clone()), + } + } +} + +impl<'ctx> Value<'ctx> { /// Create Sigma property constant - pub fn sigma_prop(prop: SigmaProp) -> Value { + pub fn sigma_prop(prop: SigmaProp) -> Value<'ctx> { Value::SigmaProp(Box::new(prop)) } } -impl> From for Value { +impl<'ctx, T: Into> From for Value<'ctx> { fn from(t: T) -> Self { Value::SigmaProp(Box::new(t.into())) } } -impl From for Value { +impl From for Value<'static> { fn from(v: EcPoint) -> Self { - Value::GroupElement(Box::new(v)) + Value::GroupElement(Ref::from(v)) + } +} + +impl From> for Value<'static> { + fn from(v: Arc) -> Self { + Value::GroupElement(Ref::from(v)) + } +} + +impl<'ctx> From<&'ctx EcPoint> for Value<'ctx> { + fn from(v: &'ctx EcPoint) -> Self { + Value::GroupElement(Ref::from(v)) } } -impl From> for Value { +impl<'ctx> From> for Value<'ctx> { fn from(v: Vec) -> Self { - Value::Coll(CollKind::NativeColl(NativeColl::CollByte(v))) + Value::Coll(CollKind::NativeColl(NativeColl::CollByte(v.into()))) } } -impl From> for Value { +impl<'ctx> From> for Value<'ctx> { fn from(v: Vec) -> Self { - Value::Coll(CollKind::NativeColl(NativeColl::CollByte(v.as_vec_i8()))) + Value::Coll(CollKind::NativeColl(NativeColl::CollByte( + v.as_vec_i8().into(), + ))) } } -impl> From> for Value { +impl<'ctx, T: Into>> From> for Value<'ctx> { fn from(opt: Option) -> Self { Value::Opt(Box::new(opt.map(|v| v.into()))) } } -impl From for Value { +impl From for Value<'static> { fn from(lit: Literal) -> Self { match lit { Literal::Boolean(b) => Value::Boolean(b), @@ -229,14 +310,14 @@ impl From for Value { Literal::BigInt(b) => Value::BigInt(b), Literal::Unit => Value::Unit, Literal::SigmaProp(s) => Value::SigmaProp(s), - Literal::GroupElement(e) => Value::GroupElement(e), + Literal::GroupElement(e) => Value::GroupElement(e.into()), Literal::CBox(b) => Value::CBox(b), Literal::Coll(coll) => { let converted_coll = match coll { CollKind::NativeColl(n) => CollKind::NativeColl(n), CollKind::WrappedColl { elem_tpe, items } => CollKind::WrappedColl { elem_tpe, - items: items.into_iter().map(Value::from).collect(), + items: items.iter().cloned().map(Value::from).collect(), }, }; Value::Coll(converted_coll) @@ -248,7 +329,7 @@ impl From for Value { } } -impl std::fmt::Display for Value { +impl std::fmt::Display for Value<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Value::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => { @@ -319,18 +400,19 @@ impl StoreWrapped for i32 {} impl StoreWrapped for i64 {} impl StoreWrapped for BigInt256 {} impl StoreWrapped for Header {} -impl StoreWrapped for Arc {} +impl StoreWrapped for ErgoBox {} +impl StoreWrapped for Ref<'_, ErgoBox> {} impl StoreWrapped for EcPoint {} impl StoreWrapped for SigmaProp {} impl StoreWrapped for Option {} impl StoreWrapped for Vec {} -impl StoreWrapped for Value {} +impl StoreWrapped for Value<'_> {} impl StoreWrapped for Literal {} #[impl_for_tuples(2, 4)] impl StoreWrapped for Tuple {} -impl> From> for Value { +impl<'ctx, T: LiftIntoSType + StoreWrapped + Into>> From> for Value<'ctx> { fn from(v: Vec) -> Self { Value::Coll(CollKind::WrappedColl { elem_tpe: T::stype(), @@ -342,15 +424,15 @@ impl> From> for Value { #[allow(clippy::from_over_into)] #[allow(clippy::unwrap_used)] #[impl_for_tuples(2, 4)] -impl Into for Tuple { - fn into(self) -> Value { +impl<'ctx> Into> for Tuple { + fn into(self) -> Value<'ctx> { let v: Vec = [for_tuples!( #( Tuple.into() ),* )].to_vec(); Value::Tup(v.try_into().unwrap()) } } -impl From>> for Value { - fn from(v: Vec>) -> Self { +impl<'ctx> From>> for Value<'ctx> { + fn from(v: Vec>) -> Self { Value::Coll(CollKind::WrappedColl { elem_tpe: SType::SBox, items: v.into_iter().map(|i| i.into()).collect(), @@ -358,7 +440,7 @@ impl From>> for Value { } } -impl TryExtractFrom for bool { +impl TryExtractFrom> for bool { fn try_extract_from(cv: Value) -> Result { match cv { Value::Boolean(v) => Ok(v), @@ -370,7 +452,7 @@ impl TryExtractFrom for bool { } } -impl TryExtractFrom for i8 { +impl TryExtractFrom> for i8 { fn try_extract_from(cv: Value) -> Result { match cv { Value::Byte(v) => Ok(v), @@ -379,7 +461,7 @@ impl TryExtractFrom for i8 { } } -impl TryExtractFrom for i16 { +impl TryExtractFrom> for i16 { fn try_extract_from(cv: Value) -> Result { match cv { Value::Short(v) => Ok(v), @@ -388,7 +470,7 @@ impl TryExtractFrom for i16 { } } -impl TryExtractFrom for i32 { +impl TryExtractFrom> for i32 { fn try_extract_from(cv: Value) -> Result { match cv { Value::Int(v) => Ok(v), @@ -397,7 +479,7 @@ impl TryExtractFrom for i32 { } } -impl TryExtractFrom for i64 { +impl TryExtractFrom> for i64 { fn try_extract_from(cv: Value) -> Result { match cv { Value::Long(v) => Ok(v), @@ -406,10 +488,10 @@ impl TryExtractFrom for i64 { } } -impl TryExtractFrom for EcPoint { +impl TryExtractFrom> for EcPoint { fn try_extract_from(cv: Value) -> Result { match cv { - Value::GroupElement(v) => Ok(*v), + Value::GroupElement(v) => Ok((*v).clone()), _ => Err(TryExtractFromError(format!( "expected EcPoint, found {:?}", cv @@ -418,7 +500,7 @@ impl TryExtractFrom for EcPoint { } } -impl TryExtractFrom for SigmaProp { +impl TryExtractFrom> for SigmaProp { fn try_extract_from(cv: Value) -> Result { match cv { Value::SigmaProp(v) => Ok(*v), @@ -430,8 +512,8 @@ impl TryExtractFrom for SigmaProp { } } -impl TryExtractFrom for Arc { - fn try_extract_from(c: Value) -> Result { +impl<'ctx> TryExtractFrom> for Ref<'ctx, ErgoBox> { + fn try_extract_from(c: Value<'ctx>) -> Result { match c { Value::CBox(b) => Ok(b), _ => Err(TryExtractFromError(format!( @@ -442,7 +524,7 @@ impl TryExtractFrom for Arc { } } -impl TryExtractFrom for Header { +impl TryExtractFrom> for Header { fn try_extract_from(c: Value) -> Result { match c { Value::Header(h) => Ok(*h), @@ -454,7 +536,7 @@ impl TryExtractFrom for Header { } } -impl TryExtractFrom for PreHeader { +impl TryExtractFrom> for PreHeader { fn try_extract_from(c: Value) -> Result { match c { Value::PreHeader(ph) => Ok(*ph), @@ -466,14 +548,14 @@ impl TryExtractFrom for PreHeader { } } -impl + StoreWrapped> TryExtractFrom for Vec { - fn try_extract_from(c: Value) -> Result { +impl<'ctx, T: TryExtractFrom> + StoreWrapped> TryExtractFrom> for Vec { + fn try_extract_from(c: Value<'ctx>) -> Result { match c { Value::Coll(coll) => match coll { CollKind::WrappedColl { elem_tpe: _, items: v, - } => v.into_iter().map(T::try_extract_from).collect(), + } => v.iter().cloned().map(T::try_extract_from).collect(), _ => Err(TryExtractFromError(format!( "expected {:?}, found {:?}", std::any::type_name::(), @@ -489,8 +571,10 @@ impl + StoreWrapped> TryExtractFrom for Vec { } } -impl + StoreWrapped, const N: usize> TryExtractFrom for [T; N] { - fn try_extract_from(c: Value) -> Result { +impl<'ctx, T: TryExtractFrom> + StoreWrapped, const N: usize> + TryExtractFrom> for [T; N] +{ + fn try_extract_from(c: Value<'ctx>) -> Result { match c { Value::Coll(coll) => match coll { CollKind::WrappedColl { @@ -498,7 +582,8 @@ impl + StoreWrapped, const N: usize> TryExtractFrom { let v = v - .into_iter() + .iter() + .cloned() .map(T::try_extract_from) .collect::, _>>()?; let len = v.len(); @@ -519,11 +604,11 @@ impl + StoreWrapped, const N: usize> TryExtractFrom for Vec { +impl TryExtractFrom> for Vec { fn try_extract_from(v: Value) -> Result { match v { Value::Coll(v) => match v { - CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs), + CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), // TODO _ => Err(TryExtractFromError(format!( "expected {:?}, found {:?}", std::any::type_name::(), @@ -539,20 +624,20 @@ impl TryExtractFrom for Vec { } } -impl TryExtractFrom for Vec { +impl TryExtractFrom> for Vec { fn try_extract_from(v: Value) -> Result { use sigma_util::FromVecI8; Vec::::try_extract_from(v).map(Vec::::from_vec_i8) } } -impl TryExtractFrom for Value { - fn try_extract_from(v: Value) -> Result { +impl<'ctx> TryExtractFrom> for Value<'ctx> { + fn try_extract_from(v: Value<'ctx>) -> Result { Ok(v) } } -impl TryExtractFrom for BigInt256 { +impl TryExtractFrom> for BigInt256 { fn try_extract_from(v: Value) -> Result { match v { Value::BigInt(bi) => Ok(bi), @@ -565,7 +650,7 @@ impl TryExtractFrom for BigInt256 { } } -impl TryExtractFrom for AvlTreeData { +impl TryExtractFrom> for AvlTreeData { fn try_extract_from(v: Value) -> Result { match v { Value::AvlTree(a) => Ok(*a), @@ -578,8 +663,10 @@ impl TryExtractFrom for AvlTreeData { } } -impl + StoreWrapped> TryExtractFrom> for Vec { - fn try_extract_from(v: Vec) -> Result { +impl<'ctx, T: TryExtractFrom> + StoreWrapped> TryExtractFrom>> + for Vec +{ + fn try_extract_from(v: Vec>) -> Result { v.into_iter().map(|it| it.try_extract_into::()).collect() } } @@ -596,8 +683,8 @@ impl + StoreWrapped> TryExtractFrom> for Vec // } // } -impl> TryExtractFrom for Option { - fn try_extract_from(v: Value) -> Result { +impl<'ctx, T: TryExtractFrom>> TryExtractFrom> for Option { + fn try_extract_from(v: Value<'ctx>) -> Result { match v { Value::Opt(opt) => opt.map(T::try_extract_from).transpose(), _ => Err(TryExtractFromError(format!( @@ -609,8 +696,8 @@ impl> TryExtractFrom for Option { } #[impl_for_tuples(2, 4)] -impl TryExtractFrom for Tuple { - fn try_extract_from(v: Value) -> Result { +impl<'ctx> TryExtractFrom> for Tuple { + fn try_extract_from(v: Value<'ctx>) -> Result { match v { Value::Tup(items) => { let mut iter = items.iter(); @@ -661,7 +748,7 @@ mod tests { fn byte_from_vec_roundtrip() { let bytes = vec![1i8, 2i8, 3i8]; let wrapped: Vec = bytes.into_iter().map(|b| b.into()).collect(); - let coll = CollKind::from_vec(SType::SByte, wrapped.clone()).unwrap(); + let coll = CollKind::from_collection(SType::SByte, &wrapped[..]).unwrap(); assert!(matches!( coll, CollKind::NativeColl(NativeColl::CollByte(_)) @@ -674,7 +761,7 @@ mod tests { fn wrapped_from_vec_roundtrip() { let longs = vec![1i64, 2i64, 3i64]; let wrapped: Vec = longs.into_iter().map(|b| b.into()).collect(); - let coll = CollKind::from_vec(SType::SLong, wrapped.clone()).unwrap(); + let coll = CollKind::from_collection(SType::SLong, &wrapped[..]).unwrap(); assert!(matches!( coll, CollKind::WrappedColl { diff --git a/ergotree-ir/src/mir/xor.rs b/ergotree-ir/src/mir/xor.rs index ac58ede59..3e257256c 100644 --- a/ergotree-ir/src/mir/xor.rs +++ b/ergotree-ir/src/mir/xor.rs @@ -8,6 +8,7 @@ use crate::serialization::SigmaParsingError; use crate::serialization::SigmaSerializable; use crate::serialization::SigmaSerializeResult; use crate::types::stype::SType; +use std::sync::Arc; /// Byte-wise XOR op on byte arrays #[derive(PartialEq, Eq, Debug, Clone)] @@ -25,7 +26,7 @@ impl Xor { let right_type: SType = right.post_eval_tpe(); match (left_type, right_type) { - (SType::SColl(l), SType::SColl(r)) => match (*l, *r) { + (SType::SColl(l), SType::SColl(r)) => match (&*l, &*r) { (SType::SByte, SType::SByte) => Ok(Xor { left: left.into(), right: right.into(), @@ -44,7 +45,7 @@ impl Xor { /// Type pub fn tpe(&self) -> SType { - SType::SColl(Box::new(SType::SByte)) + SType::SColl(Arc::new(SType::SByte)) } } @@ -80,11 +81,11 @@ mod arbitrary { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { ( any_with::(ArbExprParams { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), depth: 0, }), any_with::(ArbExprParams { - tpe: SType::SColl(Box::new(SType::SByte)), + tpe: SType::SColl(Arc::new(SType::SByte)), depth: 0, }), ) diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index ca1f996bd..6e64d5cbc 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -448,7 +448,7 @@ impl Print for ExtractRegisterAs { expr: ExtractRegisterAs::new( input, self.register_id, - SType::SOption(self.elem_tpe.clone().into()), + SType::SOption(self.elem_tpe.clone()), ) .unwrap(), } diff --git a/ergotree-ir/src/reference.rs b/ergotree-ir/src/reference.rs new file mode 100644 index 000000000..d306586c0 --- /dev/null +++ b/ergotree-ir/src/reference.rs @@ -0,0 +1,76 @@ +use std::{ops::Deref, sync::Arc}; + +#[derive(Clone, Debug, Eq)] +/// A wrapper type that provides immutable access to [`T`]. Ref can either be [`Ref::Borrowed`], holding a reference to some data in the [`Context`], or [`Ref::Arc`] +pub enum Ref<'ctx, T> { + /// Data is borrowed from Context + Borrowed(&'ctx T), + /// Data is "owned" + Arc(Arc), +} + +impl std::cmp::PartialEq for Ref<'_, T> +where + T: std::cmp::PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.deref() == other.deref() + } +} +impl<'ctx, T: Clone> Ref<'ctx, T> { + /// Convert borrowed data to 'static lifetime + pub fn to_static(&'ctx self) -> Ref<'static, T> { + Ref::Arc(self.to_arc()) + } + /// Convert [`Self`] to Arc + pub fn to_arc(&'ctx self) -> Arc { + match self { + Ref::Arc(r) => r.clone(), + Ref::Borrowed(b) => Arc::new((*b).clone()), + } + } +} + +impl<'ctx, T> From<&'ctx T> for Ref<'ctx, T> { + fn from(val: &'ctx T) -> Self { + Ref::Borrowed(val) + } +} + +impl<'ctx, T> From> for Ref<'ctx, T> { + fn from(val: Arc) -> Self { + Ref::Arc(val) + } +} + +impl<'ctx, T> From for Ref<'ctx, T> { + fn from(val: T) -> Self { + Ref::Arc(Arc::new(val)) + } +} + +impl<'ctx, T> std::ops::Deref for Ref<'ctx, T> { + type Target = T; + fn deref(&self) -> &T { + match self { + Ref::Borrowed(b) => b, + Ref::Arc(rc) => rc, + } + } +} + +#[cfg(test)] +mod test { + use crate::reference::Ref; + use proptest::prelude::*; + + proptest! { + // Test that PartialEq for Ref correctly passes through to PartialEq for T + #[test] + fn test_ref_partialeq(val in any::()) { + let borrowed = Ref::from(&val); + let owned = Ref::from(val); + assert_eq!(borrowed, owned); + } + } +} diff --git a/ergotree-ir/src/serialization/constant.rs b/ergotree-ir/src/serialization/constant.rs index e25d7f403..04eee7572 100644 --- a/ergotree-ir/src/serialization/constant.rs +++ b/ergotree-ir/src/serialization/constant.rs @@ -40,6 +40,7 @@ mod tests { use crate::mir::constant::arbitrary::ArbConstantParams; use crate::serialization::sigma_serialize_roundtrip; use proptest::prelude::*; + use std::sync::Arc; proptest! { @@ -66,7 +67,7 @@ mod tests { println!("Failed to parse constant: {}", e); } assert!(c_res.is_ok()); - assert_eq!(c_res.unwrap().tpe, SType::SColl(Box::new(SType::SBox))); + assert_eq!(c_res.unwrap().tpe, SType::SColl(Arc::new(SType::SBox))); } #[test] diff --git a/ergotree-ir/src/serialization/data.rs b/ergotree-ir/src/serialization/data.rs index c63ec1bcc..190658b5e 100644 --- a/ergotree-ir/src/serialization/data.rs +++ b/ergotree-ir/src/serialization/data.rs @@ -55,7 +55,8 @@ impl DataSerializer { w.put_usize_as_u16_unwrapped(v.len())?; let maybe_bools: Result, TryExtractFromError> = v .clone() - .into_iter() + .iter() + .cloned() .map(|i| i.try_extract_into::()) .collect(); w.put_bits(maybe_bools?.as_slice())? @@ -110,7 +111,7 @@ impl DataSerializer { } } SUnit => Literal::Unit, - SGroupElement => Literal::GroupElement(Box::new(EcPoint::sigma_parse(r)?)), + SGroupElement => Literal::GroupElement(Arc::new(EcPoint::sigma_parse(r)?)), SSigmaProp => { Literal::SigmaProp(Box::new(SigmaProp::new(SigmaBoolean::sigma_parse(r)?))) } @@ -126,18 +127,17 @@ impl DataSerializer { let len = r.get_u16()? as usize; let bools = r.get_bits(len)?; Literal::Coll(CollKind::WrappedColl { - elem_tpe: *elem_type.clone(), + elem_tpe: (**elem_type).clone(), items: bools.into_iter().map(|b| b.into()).collect(), }) } SColl(elem_type) => { let len = r.get_u16()? as usize; - let mut elems = Vec::with_capacity(len); - for _ in 0..len { - elems.push(DataSerializer::sigma_parse(elem_type, r)?); - } + let elems = (0..len) + .map(|_| DataSerializer::sigma_parse(elem_type, r)) + .collect::, SigmaParsingError>>()?; Literal::Coll(CollKind::WrappedColl { - elem_tpe: *elem_type.clone(), + elem_tpe: (**elem_type).clone(), items: elems, }) } @@ -151,7 +151,7 @@ impl DataSerializer { // is correct Literal::Tup(items.try_into()?) } - SBox => Literal::CBox(Arc::new(ErgoBox::sigma_parse(r)?)), + SBox => Literal::CBox(Arc::new(ErgoBox::sigma_parse(r)?).into()), SAvlTree => Literal::AvlTree(Box::new(AvlTreeData::sigma_parse(r)?)), STypeVar(_) => return Err(SigmaParsingError::NotSupported("TypeVar data")), SAny => return Err(SigmaParsingError::NotSupported("SAny data")), diff --git a/ergotree-ir/src/types/savltree.rs b/ergotree-ir/src/types/savltree.rs index e307fc871..017d0833a 100644 --- a/ergotree-ir/src/types/savltree.rs +++ b/ergotree-ir/src/types/savltree.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::serialization::types::TypeCode; use super::sfunc::SFunc; @@ -73,7 +75,7 @@ lazy_static! { name: "digest", tpe: SFunc { t_dom: vec![ SType::SAvlTree], - t_range: SType::SColl(Box::new(SType::SByte)).into(), + t_range: SType::SColl(Arc::new(SType::SByte)).into(), tpe_params: vec![], }, }; @@ -118,7 +120,7 @@ lazy_static! { name: "valueLengthOpt", tpe: SFunc { t_dom: vec![ SType::SAvlTree], - t_range: SType::SOption(Box::new(SType::SInt)).into(), + t_range: SType::SOption(Arc::new(SType::SInt)).into(), tpe_params: vec![], }, }; @@ -232,18 +234,18 @@ lazy_static! { tpe: SFunc { t_dom: vec![ SType::SAvlTree, SType::SColl( - Box::new( + Arc::new( SType::STuple( STuple::pair( - SType::SColl(Box::new(SType::SByte)), - SType::SColl(Box::new(SType::SByte)) + SType::SColl(Arc::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)) ) ) ) ), - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), ], - t_range: SType::SOption(Box::new(SType::SAvlTree)).into(), + t_range: SType::SOption(Arc::new(SType::SAvlTree)).into(), tpe_params: vec![], }, }; @@ -259,13 +261,13 @@ lazy_static! { tpe: SFunc { t_dom: vec![ SType::SAvlTree, SType::SColl( - Box::new( - SType::SColl(Box::new(SType::SByte)) + Arc::new( + SType::SColl(Arc::new(SType::SByte)) ) ), - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), ], - t_range: SType::SOption(Box::new(SType::SAvlTree)).into(), + t_range: SType::SOption(Arc::new(SType::SAvlTree)).into(), tpe_params: vec![], }, }; @@ -281,8 +283,8 @@ lazy_static! { tpe: SFunc { t_dom: vec![ SType::SAvlTree, - SType::SColl(Box::new(SType::SByte)), - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), ], t_range: SType::SBoolean.into(), tpe_params: vec![], @@ -300,18 +302,18 @@ lazy_static! { tpe: SFunc { t_dom: vec![ SType::SAvlTree, SType::SColl( - Box::new( + Arc::new( SType::STuple( STuple::pair( - SType::SColl(Box::new(SType::SByte)), - SType::SColl(Box::new(SType::SByte)) + SType::SColl(Arc::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)) ) ) ) ), - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), ], - t_range: SType::SOption(Box::new(SType::SAvlTree)).into(), + t_range: SType::SOption(Arc::new(SType::SAvlTree)).into(), tpe_params: vec![], }, }; @@ -325,7 +327,7 @@ lazy_static! { method_id: UPDATE_DIGEST_METHOD_ID, name: "updateDigest", tpe: SFunc { - t_dom: vec![ SType::SAvlTree, SType::SColl(Box::new(SType::SByte))], + t_dom: vec![ SType::SAvlTree, SType::SColl(Arc::new(SType::SByte))], t_range: SType::SAvlTree.into(), tpe_params: vec![], }, diff --git a/ergotree-ir/src/types/sbox.rs b/ergotree-ir/src/types/sbox.rs index 57c02fa7a..07f007108 100644 --- a/ergotree-ir/src/types/sbox.rs +++ b/ergotree-ir/src/types/sbox.rs @@ -1,4 +1,5 @@ use crate::serialization::types::TypeCode; +use std::sync::Arc; use super::sfunc::SFunc; use super::smethod::MethodId; @@ -52,7 +53,7 @@ lazy_static! { name: "getReg", tpe: SFunc { t_dom: vec![SType::SBox, SType::SByte], - t_range: SType::SOption(Box::new(STypeVar::t().into())).into(), + t_range: SType::SOption(Arc::new(STypeVar::t().into())).into(), tpe_params: vec![], }, }; @@ -67,7 +68,7 @@ lazy_static! { name: "tokens", tpe: SFunc { t_dom: vec![SType::SBox], - t_range: SType::SColl(Box::new( + t_range: SType::SColl(Arc::new( STuple::pair( SType::SColl(SType::SByte.into()), SType::SLong diff --git a/ergotree-ir/src/types/scoll.rs b/ergotree-ir/src/types/scoll.rs index 240a7c5a0..513b15dd3 100644 --- a/ergotree-ir/src/types/scoll.rs +++ b/ergotree-ir/src/types/scoll.rs @@ -1,6 +1,7 @@ use crate::serialization::types::TypeCode; use crate::types::stuple::STuple; use crate::types::stype_companion::STypeCompanion; +use std::sync::Arc; use super::sfunc::SFunc; use super::smethod::MethodId; @@ -70,7 +71,7 @@ lazy_static! { SType::SColl(SType::STypeVar(STypeVar::iv()).into()), SFunc::new( vec![STypeVar::iv().into()], - SType::SColl(Box::new(STypeVar::ov().into())), + SType::SColl(Arc::new(STypeVar::ov().into())), ).into() ], SType::SColl(SType::STypeVar(STypeVar::ov()).into()), diff --git a/ergotree-ir/src/types/sfunc.rs b/ergotree-ir/src/types/sfunc.rs index 1add72303..b00e0e5e4 100644 --- a/ergotree-ir/src/types/sfunc.rs +++ b/ergotree-ir/src/types/sfunc.rs @@ -39,11 +39,12 @@ impl SFunc { } } - pub(crate) fn with_subst(self, subst: &HashMap) -> Self { + pub(crate) fn with_subst(&self, subst: &HashMap) -> Self { let remaining_vars = self .tpe_params - .into_iter() + .iter() .filter(|v| !subst.contains_key(&v.ident)) + .cloned() .collect(); SFunc { t_dom: self diff --git a/ergotree-ir/src/types/sgroup_elem.rs b/ergotree-ir/src/types/sgroup_elem.rs index f6f76a007..15c8d3b16 100644 --- a/ergotree-ir/src/types/sgroup_elem.rs +++ b/ergotree-ir/src/types/sgroup_elem.rs @@ -1,5 +1,6 @@ use crate::serialization::types::TypeCode; use crate::types::stype_companion::STypeCompanion; +use std::sync::Arc; use super::sfunc::SFunc; use super::smethod::MethodId; @@ -33,7 +34,7 @@ lazy_static! { name: "getEncoded", tpe: SFunc::new( vec![SType::SGroupElement], - SType::SColl(Box::new(SType::SByte)), + SType::SColl(Arc::new(SType::SByte)), ) }; /// GroupElement.geEncoded diff --git a/ergotree-ir/src/types/stuple.rs b/ergotree-ir/src/types/stuple.rs index 51f992d14..71596f3d7 100644 --- a/ergotree-ir/src/types/stuple.rs +++ b/ergotree-ir/src/types/stuple.rs @@ -71,9 +71,9 @@ impl STuple { } } - pub(crate) fn with_subst(self, subst: &HashMap) -> Self { + pub(crate) fn with_subst(&self, subst: &HashMap) -> Self { STuple { - items: self.items.mapped(|a| a.with_subst(subst)), + items: self.items.clone().mapped(|a| a.with_subst(subst)), } } } diff --git a/ergotree-ir/src/types/stype.rs b/ergotree-ir/src/types/stype.rs index bc926bdfa..703509c62 100644 --- a/ergotree-ir/src/types/stype.rs +++ b/ergotree-ir/src/types/stype.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::convert::TryInto; use std::fmt::Debug; +use std::sync::Arc; use impl_trait_for_tuples::impl_for_tuples; @@ -49,9 +50,9 @@ pub enum SType { /// AVL tree value SAvlTree, /// Optional value - SOption(Box), + SOption(Arc), /// Collection of elements of the same type - SColl(Box), + SColl(Arc), /// Tuple (elements can have different types) STuple(STuple), /// Function (signature) @@ -97,14 +98,14 @@ impl SType { ) } - pub(crate) fn with_subst(self, subst: &HashMap) -> Self { + pub(crate) fn with_subst(&self, subst: &HashMap) -> Self { match self { - SType::STypeVar(ref tpe_var) => subst.get(tpe_var).cloned().unwrap_or(self), + SType::STypeVar(ref tpe_var) => subst.get(tpe_var).cloned().unwrap_or((*self).clone()), SType::SOption(tpe) => SType::SOption(tpe.with_subst(subst).into()), SType::SColl(tpe) => SType::SColl(tpe.with_subst(subst).into()), - SType::STuple(stup) => SType::STuple(stup.with_subst(subst)), - SType::SFunc(sfunc) => SType::SFunc(sfunc.with_subst(subst)), - _ => self, + SType::STuple(ref stup) => SType::STuple(stup.with_subst(subst)), + SType::SFunc(ref sfunc) => SType::SFunc(sfunc.with_subst(subst)), + _ => (*self).clone(), } } } @@ -163,7 +164,7 @@ pub trait LiftIntoSType { impl LiftIntoSType for Vec { fn stype() -> SType { - SType::SColl(Box::new(T::stype())) + SType::SColl(Arc::new(T::stype())) } } @@ -259,7 +260,7 @@ impl LiftIntoSType for AvlTreeData { impl LiftIntoSType for Option { fn stype() -> SType { - SType::SOption(Box::new(T::stype())) + SType::SOption(Arc::new(T::stype())) } } @@ -313,8 +314,8 @@ pub(crate) mod tests { prop_oneof![ prop::collection::vec(elem.clone(), 2..=5) .prop_map(|elems| SType::STuple(elems.try_into().unwrap())), - elem.clone().prop_map(|tpe| SType::SColl(Box::new(tpe))), - elem.prop_map(|tpe| SType::SOption(Box::new(tpe))), + elem.clone().prop_map(|tpe| SType::SColl(Arc::new(tpe))), + elem.prop_map(|tpe| SType::SOption(Arc::new(tpe))), ] }, ) diff --git a/ergotree-ir/src/types/type_unify.rs b/ergotree-ir/src/types/type_unify.rs index 4f58813e1..e1ce3f950 100644 --- a/ergotree-ir/src/types/type_unify.rs +++ b/ergotree-ir/src/types/type_unify.rs @@ -79,6 +79,8 @@ pub fn unify_one(t1: &SType, t2: &SType) -> Result, Typ #[cfg(test)] #[allow(clippy::panic)] mod tests { + use std::sync::Arc; + use super::super::stype::tests::primitive_type; use super::*; use crate::types::sfunc::SFunc; @@ -185,20 +187,20 @@ mod tests { (STypeVar::t(), SColl(SInt.into())), ); check_subst( - SColl(Box::new(STypeVar::t().into())), + SColl(Arc::new(STypeVar::t().into())), SColl(SInt.into()), (STypeVar::t(), SInt), ); check_subst( - SColl(Box::new(STypeVar::t().into())), - SColl(Box::new(STuple::pair(SInt, SBoolean).into())), + SColl(Arc::new(STypeVar::t().into())), + SColl(Arc::new(STuple::pair(SInt, SBoolean).into())), (STypeVar::t(), STuple::pair(SInt, SBoolean).into()), ); check_subst( - SColl(Box::new( + SColl(Arc::new( STuple::pair(STypeVar::t().into(), SBoolean).into(), )), - SColl(Box::new(STuple::pair(SInt, SBoolean).into())), + SColl(Arc::new(STuple::pair(SInt, SBoolean).into())), (STypeVar::t(), SInt), ); @@ -209,20 +211,20 @@ mod tests { (STypeVar::t(), SOption(SInt.into())), ); check_subst( - SOption(Box::new(STypeVar::t().into())), + SOption(Arc::new(STypeVar::t().into())), SOption(SInt.into()), (STypeVar::t(), SInt), ); check_subst( - SOption(Box::new(STypeVar::t().into())), - SOption(Box::new(STuple::pair(SInt, SBoolean).into())), + SOption(Arc::new(STypeVar::t().into())), + SOption(Arc::new(STuple::pair(SInt, SBoolean).into())), (STypeVar::t(), STuple::pair(SInt, SBoolean).into()), ); check_subst( - SOption(Box::new( + SOption(Arc::new( STuple::pair(STypeVar::t().into(), SBoolean).into(), )), - SOption(Box::new(STuple::pair(SInt, SBoolean).into())), + SOption(Arc::new(STuple::pair(SInt, SBoolean).into())), (STypeVar::t(), SInt), ); @@ -292,8 +294,8 @@ mod tests { // Coll check_error(SColl(SColl(SInt.into()).into()), SColl(SInt.into())); check_error( - SColl(Box::new(STypeVar::t().into())), - SColl(Box::new(STypeVar::iv().into())), + SColl(Arc::new(STypeVar::t().into())), + SColl(Arc::new(STypeVar::iv().into())), ); // Option diff --git a/ergotree-ir/src/util.rs b/ergotree-ir/src/util.rs index 21102c911..11e79af8d 100644 --- a/ergotree-ir/src/util.rs +++ b/ergotree-ir/src/util.rs @@ -1,19 +1,19 @@ //! Utilities -use elliptic_curve::subtle::CtOption; +// use elliptic_curve::subtle::CtOption; -/// Convert to Option -pub(crate) trait IntoOption { - /// Get Option - fn into_option(self) -> Option; -} +// /// Convert to Option +// pub(crate) trait IntoOption { +// /// Get Option +// fn into_option(self) -> Option; +// } -impl IntoOption for CtOption { - fn into_option(self) -> Option { - if self.is_some().into() { - Some(self.unwrap()) - } else { - None - } - } -} +// impl IntoOption for CtOption { +// fn into_option(self) -> Option { +// if self.is_some().into() { +// Some(self.unwrap()) +// } else { +// None +// } +// } +// } diff --git a/gf2_192/src/gf2_192.rs b/gf2_192/src/gf2_192.rs index b7ac57c68..b77dcec85 100644 --- a/gf2_192/src/gf2_192.rs +++ b/gf2_192/src/gf2_192.rs @@ -125,7 +125,6 @@ impl Gf2_192 { a1muls[8 | i] = a1muls[8] ^ a1muls[i]; a2muls[8 | i] = a2muls[8] ^ a2muls[i]; } - let mut w0 = 0; let mut w1 = 0; let mut w2 = 0; diff --git a/sigma-util/src/vec_ext.rs b/sigma-util/src/vec_ext.rs index 912ce6862..07cd53225 100644 --- a/sigma-util/src/vec_ext.rs +++ b/sigma-util/src/vec_ext.rs @@ -1,5 +1,7 @@ //! Vec extensions +use std::sync::Arc; + /// Vec to Vec conversion pub trait FromVecI8 { /// Convert Vec to Vec @@ -11,6 +13,11 @@ impl FromVecI8 for Vec { bs.iter().map(|b| *b as u8).collect() } } +impl FromVecI8 for Arc<[u8]> { + fn from_vec_i8(bs: Vec) -> Self { + bs.iter().map(|b| *b as u8).collect() + } +} /// Convert Vec to Vec pub trait AsVecU8 { @@ -24,6 +31,12 @@ impl AsVecU8 for Vec { } } +// TODO remove +impl AsVecU8 for Arc<[i8]> { + fn as_vec_u8(&self) -> Vec { + Vec::::from_vec_i8(self.iter().copied().collect()) + } +} /// Convert Vec to Vec pub trait AsVecI8 { /// Returns Vec @@ -35,3 +48,9 @@ impl AsVecI8 for Vec { self.iter().map(|b| *b as i8).collect() } } + +impl AsVecI8 for Arc<[u8]> { + fn as_vec_i8(&self) -> Vec { + self.iter().map(|b| *b as i8).collect() + } +} From 1b632998875b2ef06365ba840d243e549333ea63 Mon Sep 17 00:00:00 2001 From: Kamal Ahmad Date: Mon, 3 Jun 2024 10:55:24 +0500 Subject: [PATCH 2/6] Optimize context creation further --- ergo-lib/src/chain/transaction.rs | 2 -- .../src/chain/transaction/ergo_transaction.rs | 17 +++++------ ergo-lib/src/wallet.rs | 4 +-- ergo-lib/src/wallet/signing.rs | 28 +++++++++++-------- ergo-lib/src/wallet/tx_context.rs | 16 +++++------ 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/ergo-lib/src/chain/transaction.rs b/ergo-lib/src/chain/transaction.rs index adbb9ac16..931df3401 100644 --- a/ergo-lib/src/chain/transaction.rs +++ b/ergo-lib/src/chain/transaction.rs @@ -38,7 +38,6 @@ use ergotree_ir::serialization::SigmaSerializationError; use ergotree_ir::serialization::SigmaSerializeResult; pub use input::*; -use crate::wallet::signing::make_context; use crate::wallet::signing::update_context; use crate::wallet::signing::TransactionContext; use crate::wallet::tx_context::TransactionContextError; @@ -52,7 +51,6 @@ use indexmap::IndexSet; use std::convert::TryFrom; use std::convert::TryInto; use std::iter::FromIterator; -use std::rc::Rc; use super::ergo_state_context::ErgoStateContext; diff --git a/ergo-lib/src/chain/transaction/ergo_transaction.rs b/ergo-lib/src/chain/transaction/ergo_transaction.rs index 50de2682e..e0fb20cde 100644 --- a/ergo-lib/src/chain/transaction/ergo_transaction.rs +++ b/ergo-lib/src/chain/transaction/ergo_transaction.rs @@ -87,7 +87,7 @@ pub enum TxValidationError { /// Exposes common properties for signed and unsigned transactions pub trait ErgoTransaction { /// input boxes ids - fn inputs_ids(&self) -> TxIoVec; + fn inputs_ids(&self) -> impl Iterator + ExactSizeIterator; //TxIoVec; /// data input boxes fn data_inputs(&self) -> Option<&[DataInput]>; /// output boxes @@ -108,17 +108,18 @@ pub trait ErgoTransaction { .ok_or(TxValidationError::OutputSumOverflow)?; // Check if there are no double-spends in input (one BoxId being spent more than once) - let unique_count = inputs.iter().unique().count(); - if unique_count != inputs.len() { - return Err(TxValidationError::DoubleSpend(unique_count, inputs.len())); + let len = inputs.len(); + let unique_count = inputs.unique().count(); + if unique_count != len { + return Err(TxValidationError::DoubleSpend(unique_count, len)); } Ok(()) } } impl ErgoTransaction for UnsignedTransaction { - fn inputs_ids(&self) -> TxIoVec { - self.inputs.clone().mapped(|input| input.box_id) + fn inputs_ids(&self) -> impl Iterator + ExactSizeIterator { + self.inputs.iter().map(|input| input.box_id) } fn data_inputs(&self) -> Option<&[DataInput]> { @@ -137,8 +138,8 @@ impl ErgoTransaction for UnsignedTransaction { } impl ErgoTransaction for Transaction { - fn inputs_ids(&self) -> TxIoVec { - self.inputs.clone().mapped(|input| input.box_id) + fn inputs_ids(&self) -> impl Iterator + ExactSizeIterator { + self.inputs.iter().map(|input| input.box_id) } fn data_inputs(&self) -> Option<&[DataInput]> { diff --git a/ergo-lib/src/wallet.rs b/ergo-lib/src/wallet.rs index 197e64dc7..34d865ccf 100644 --- a/ergo-lib/src/wallet.rs +++ b/ergo-lib/src/wallet.rs @@ -167,12 +167,12 @@ impl Wallet { let message_to_sign = tx.bytes_to_sign().map_err(TxSigningError::from)?; // TODO: re-use, disable unwrap #[allow(clippy::unwrap_used)] - let context = make_context(state_context, &tx_context, input_idx).unwrap(); + let mut context = make_context(state_context, &tx_context, input_idx).unwrap(); Ok(sign_tx_input( self.prover.as_ref(), &tx_context, state_context, - &context, + &mut context, tx_hints, input_idx, message_to_sign.as_slice(), diff --git a/ergo-lib/src/wallet/signing.rs b/ergo-lib/src/wallet/signing.rs index c1d36f45e..ad613d808 100644 --- a/ergo-lib/src/wallet/signing.rs +++ b/ergo-lib/src/wallet/signing.rs @@ -52,10 +52,10 @@ pub fn make_context<'ctx, T: ErgoTransaction>( // Find self_box by matching BoxIDs let self_box = tx_ctx .get_input_box( - tx_ctx + &tx_ctx .spending_tx .inputs_ids() - .get(self_index) + .nth(self_index) .ok_or(TransactionError::InputNofFound(self_index))?, ) .ok_or(TransactionContextError::InputBoxNotFound(self_index))?; @@ -86,11 +86,16 @@ pub fn make_context<'ctx, T: ErgoTransaction>( let inputs_ir = tx_ctx .spending_tx .inputs_ids() - .enumerated() - .try_mapped(|(idx, u)| { + .enumerate() + .map(|(idx, u)| { tx_ctx .get_input_box(&u) .ok_or(TransactionContextError::InputBoxNotFound(idx)) + }) + .collect::, _>>()? + .try_into() + .map_err(|_| { + TransactionContextError::TooManyInputBoxes(tx_ctx.spending_tx.inputs_ids().len()) })?; let extension = tx_ctx .spending_tx @@ -116,10 +121,10 @@ pub(crate) fn update_context<'ctx, T: ErgoTransaction>( // Find self_box by matching BoxIDs let self_box = tx_ctx .get_input_box( - tx_ctx + &tx_ctx .spending_tx .inputs_ids() - .get(self_index) + .nth(self_index) .ok_or(TransactionError::InputNofFound(self_index))?, ) .ok_or(TransactionContextError::InputBoxNotFound(self_index))?; @@ -141,13 +146,13 @@ pub fn sign_transaction( ) -> Result { let tx = tx_context.spending_tx.clone(); let message_to_sign = tx.bytes_to_sign()?; - let ctx = make_context(state_context, &tx_context, 0)?; + let mut ctx = make_context(state_context, &tx_context, 0)?; let signed_inputs = tx.inputs.enumerated().try_mapped(|(idx, _)| { sign_tx_input( prover, &tx_context, state_context, - &ctx, // TODO: use with_self_box_index + &mut ctx, // TODO: use with_self_box_index tx_hints, idx, message_to_sign.as_slice(), @@ -211,15 +216,16 @@ pub fn sign_message( } /// Sign a transaction input -pub fn sign_tx_input( +pub fn sign_tx_input<'ctx>( prover: &dyn Prover, - tx_context: &TransactionContext, + tx_context: &'ctx TransactionContext, state_context: &ErgoStateContext, - context: &Context, + context: &mut Context<'ctx>, tx_hints: Option<&TransactionHintsBag>, input_idx: usize, message_to_sign: &[u8], ) -> Result { + update_context(context, tx_context, input_idx)?; let unsigned_input = tx_context .spending_tx .inputs diff --git a/ergo-lib/src/wallet/tx_context.rs b/ergo-lib/src/wallet/tx_context.rs index 9d0fde6fc..30c561956 100644 --- a/ergo-lib/src/wallet/tx_context.rs +++ b/ergo-lib/src/wallet/tx_context.rs @@ -60,8 +60,8 @@ impl TransactionContext { .enumerate() .map(|(i, b)| (b.box_id(), i as u16)) .collect(); - for (i, unsigned_input) in spending_tx.inputs_ids().iter().enumerate() { - if !box_index.contains_key(unsigned_input) { + for (i, unsigned_input) in spending_tx.inputs_ids().enumerate() { + if !box_index.contains_key(&unsigned_input) { return Err(TransactionContextError::InputBoxNotFound(i)); } } @@ -143,11 +143,7 @@ impl TransactionContext { let in_assets = extract_assets(self.boxes_to_spend.iter().map(|b| &b.tokens))?; let out_assets = extract_assets(self.spending_tx.outputs.iter().map(|b| &b.tokens))?; - verify_assets( - self.spending_tx.inputs_ids().as_slice(), - in_assets, - out_assets, - )?; + verify_assets(self.spending_tx.inputs_ids(), in_assets, out_assets)?; // Verify input proofs. This is usually the most expensive check so it's done last let bytes_to_sign = self.spending_tx.bytes_to_sign()?; let mut context = make_context(state_context, self, 0)?; @@ -232,12 +228,14 @@ fn extract_assets<'a, I: Iterator>>( } fn verify_assets( - inputs: &[BoxId], + mut inputs: impl Iterator, in_assets: HashMap, out_assets: HashMap, ) -> Result<(), TxValidationError> { // If this transaction mints a new token, it's token ID must be the ID of the first box being spent - let new_token_id: TokenId = inputs[0].into(); + #[allow(clippy::unwrap_used)] + // Inputs size is already validated so it must be of size atleast 1 + let new_token_id: TokenId = inputs.nth(0).unwrap().into(); for (&out_token_id, &out_amount) in &out_assets { if let Some(&in_amount) = in_assets.get(&out_token_id) { // Check that Transaction is not creating tokens out of thin air From 16fcc0539e2d42854a417092a1c13273c13b3a21 Mon Sep 17 00:00:00 2001 From: Kamal Ahmad Date: Tue, 4 Jun 2024 07:48:58 +0500 Subject: [PATCH 3/6] Re-use context in multi-sig/reducedtransaction/signing --- bindings/ergo-lib-wasm/src/transaction.rs | 3 +++ ergo-lib/src/chain/transaction.rs | 4 ++-- .../src/chain/transaction/ergo_transaction.rs | 15 ++++++--------- ergo-lib/src/chain/transaction/reduced.rs | 5 +++-- ergo-lib/src/lib.rs | 2 +- ergo-lib/src/wallet.rs | 5 ++--- ergo-lib/src/wallet/multi_sig.rs | 13 ++++++++----- ergo-lib/src/wallet/signing.rs | 5 ++--- ergo-lib/src/wallet/tx_context.rs | 4 ++-- ergotree-interpreter/src/eval.rs | 2 +- ergotree-interpreter/src/eval/context.rs | 1 + ergotree-interpreter/src/eval/savltree.rs | 1 - ergotree-interpreter/src/eval/subst_const.rs | 2 +- ergotree-interpreter/src/lib.rs | 2 +- ergotree-ir/src/lib.rs | 1 - ergotree-ir/src/mir.rs | 2 -- ergotree-ir/src/mir/value.rs | 2 +- ergotree-ir/src/reference.rs | 1 + ergotree-ir/src/types/stype.rs | 4 ++-- 19 files changed, 37 insertions(+), 37 deletions(-) diff --git a/bindings/ergo-lib-wasm/src/transaction.rs b/bindings/ergo-lib-wasm/src/transaction.rs index da11cb50f..62f44ae72 100644 --- a/bindings/ergo-lib-wasm/src/transaction.rs +++ b/bindings/ergo-lib-wasm/src/transaction.rs @@ -13,6 +13,7 @@ use crate::json::UnsignedTransactionJsonEip12; use ergo_lib::chain; use ergo_lib::chain::transaction::{distinct_token_ids, TxIoVec}; use ergo_lib::ergotree_ir::serialization::SigmaSerializable; +use ergo_lib::wallet::signing::make_context; use gloo_utils::format::JsValueSerdeExt; use js_sys::Uint8Array; use std::convert::{TryFrom, TryInto}; @@ -425,8 +426,10 @@ pub fn verify_tx_input_proof( ) .map_err(to_js)?; let state_context_inner = state_context.clone().into(); + let mut context = make_context(&state_context_inner, &tx_context, input_idx).map_err(to_js)?; Ok(ergo_lib::chain::transaction::verify_tx_input_proof( &tx_context, + &mut context, &state_context_inner, input_idx, &tx_context.spending_tx.bytes_to_sign().map_err(to_js)?, diff --git a/ergo-lib/src/chain/transaction.rs b/ergo-lib/src/chain/transaction.rs index 931df3401..0beb6fe9a 100644 --- a/ergo-lib/src/chain/transaction.rs +++ b/ergo-lib/src/chain/transaction.rs @@ -349,6 +349,7 @@ pub fn verify_tx_input_proof<'ctx>( input_idx: usize, bytes_to_sign: &[u8], ) -> Result { + update_context(ctx, tx_context, input_idx)?; let input = tx_context .spending_tx .inputs @@ -357,7 +358,6 @@ pub fn verify_tx_input_proof<'ctx>( let input_box = tx_context .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(input_idx))?; - update_context(ctx, 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, input_box, state_context, ctx) { @@ -372,7 +372,7 @@ pub fn verify_tx_input_proof<'ctx>( None => verifier .verify( &input_box.ergo_tree, - &ctx, + ctx, input.spending_proof.proof.clone(), bytes_to_sign, ) diff --git a/ergo-lib/src/chain/transaction/ergo_transaction.rs b/ergo-lib/src/chain/transaction/ergo_transaction.rs index e0fb20cde..fca824028 100644 --- a/ergo-lib/src/chain/transaction/ergo_transaction.rs +++ b/ergo-lib/src/chain/transaction/ergo_transaction.rs @@ -1,10 +1,7 @@ //! Exposes common properties for signed and unsigned transactions -use ergotree_interpreter::{ - eval::context::TxIoVec, - sigma_protocol::{ - prover::ContextExtension, - verifier::{VerificationResult, VerifierError}, - }, +use ergotree_interpreter::sigma_protocol::{ + prover::ContextExtension, + verifier::{VerificationResult, VerifierError}, }; use ergotree_ir::{ chain::{ @@ -87,7 +84,7 @@ pub enum TxValidationError { /// Exposes common properties for signed and unsigned transactions pub trait ErgoTransaction { /// input boxes ids - fn inputs_ids(&self) -> impl Iterator + ExactSizeIterator; //TxIoVec; + fn inputs_ids(&self) -> impl ExactSizeIterator; /// data input boxes fn data_inputs(&self) -> Option<&[DataInput]>; /// output boxes @@ -118,7 +115,7 @@ pub trait ErgoTransaction { } impl ErgoTransaction for UnsignedTransaction { - fn inputs_ids(&self) -> impl Iterator + ExactSizeIterator { + fn inputs_ids(&self) -> impl ExactSizeIterator { self.inputs.iter().map(|input| input.box_id) } @@ -138,7 +135,7 @@ impl ErgoTransaction for UnsignedTransaction { } impl ErgoTransaction for Transaction { - fn inputs_ids(&self) -> impl Iterator + ExactSizeIterator { + fn inputs_ids(&self) -> impl ExactSizeIterator { self.inputs.iter().map(|input| input.box_id) } diff --git a/ergo-lib/src/chain/transaction/reduced.rs b/ergo-lib/src/chain/transaction/reduced.rs index a145fe44b..b9d4e0d83 100644 --- a/ergo-lib/src/chain/transaction/reduced.rs +++ b/ergo-lib/src/chain/transaction/reduced.rs @@ -15,6 +15,7 @@ use crate::chain::ergo_state_context::ErgoStateContext; use crate::chain::transaction::Transaction; use crate::chain::transaction::UnsignedInput; use crate::wallet::signing::make_context; +use crate::wallet::signing::update_context; use crate::wallet::signing::TransactionContext; use crate::wallet::signing::TxSigningError; use crate::wallet::tx_context::TransactionContextError; @@ -67,13 +68,13 @@ pub fn reduce_tx( state_context: &ErgoStateContext, ) -> Result { let tx = &tx_context.spending_tx; - let ctx = make_context(state_context, &tx_context, 0)?; + let mut ctx = make_context(state_context, &tx_context, 0)?; let reduced_inputs = tx .inputs .clone() .enumerated() .try_mapped::<_, _, TxSigningError>(|(idx, input)| { - // TODO: use Context::with_self_box_index + update_context(&mut ctx, &tx_context, idx)?; let input_box = tx_context .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(idx))?; diff --git a/ergo-lib/src/lib.rs b/ergo-lib/src/lib.rs index 68f3a4c96..a629bc845 100644 --- a/ergo-lib/src/lib.rs +++ b/ergo-lib/src/lib.rs @@ -7,7 +7,7 @@ #![deny(non_snake_case)] #![deny(unused_mut)] #![deny(dead_code)] -//#![deny(unused_imports)] +#![deny(unused_imports)] #![deny(missing_docs)] // Clippy exclusions #![allow(clippy::unit_arg)] diff --git a/ergo-lib/src/wallet.rs b/ergo-lib/src/wallet.rs index 34d865ccf..abe2ac038 100644 --- a/ergo-lib/src/wallet.rs +++ b/ergo-lib/src/wallet.rs @@ -165,9 +165,8 @@ impl Wallet { ) -> Result { let tx = tx_context.spending_tx.clone(); let message_to_sign = tx.bytes_to_sign().map_err(TxSigningError::from)?; - // TODO: re-use, disable unwrap - #[allow(clippy::unwrap_used)] - let mut context = make_context(state_context, &tx_context, input_idx).unwrap(); + let mut context = + make_context(state_context, &tx_context, input_idx).map_err(TxSigningError::from)?; Ok(sign_tx_input( self.prover.as_ref(), &tx_context, diff --git a/ergo-lib/src/wallet/multi_sig.rs b/ergo-lib/src/wallet/multi_sig.rs index 536f1e555..ef464fd51 100644 --- a/ergo-lib/src/wallet/multi_sig.rs +++ b/ergo-lib/src/wallet/multi_sig.rs @@ -24,6 +24,7 @@ use ergotree_interpreter::sigma_protocol::unchecked_tree::UncheckedTree; use ergotree_interpreter::sigma_protocol::verifier::compute_commitments; use std::collections::HashMap; +use super::signing::update_context; use super::tx_context::TransactionContextError; /// TransactionHintsBag @@ -244,11 +245,12 @@ pub fn generate_commitments( ) -> Result { let tx = tx_context.spending_tx.clone(); let mut hints_bag = TransactionHintsBag::empty(); + let mut ctx = make_context(state_context, &tx_context, 0)?; for (i, input) in tx.inputs.iter().enumerate() { + update_context(&mut ctx, &tx_context, i)?; let input_box = tx_context .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(i))?; - let ctx = make_context(state_context, &tx_context, i)?; // TODO: Remove Rc, use Context::with_self_box_index let tree = input_box.ergo_tree.clone(); let exp = tree .proposition() @@ -266,17 +268,18 @@ pub fn generate_commitments( /// Extracting hints from a transaction and outputs it's corresponding TransactionHintsBag pub fn extract_hints( - tx_ctx: &TransactionContext, + tx_context: &TransactionContext, state_context: &ErgoStateContext, real_secrets_to_extract: Vec, simulated_secrets_to_extract: Vec, ) -> Result { let mut hints_bag = TransactionHintsBag::empty(); - for (i, input) in tx_ctx.spending_tx.inputs.iter().enumerate() { - let input_box = tx_ctx + let mut ctx = make_context(state_context, tx_context, 0)?; + for (i, input) in tx_context.spending_tx.inputs.iter().enumerate() { + update_context(&mut ctx, tx_context, i)?; + let input_box = tx_context .get_input_box(&input.box_id) .ok_or(TransactionContextError::InputBoxNotFound(i))?; - let ctx = make_context(state_context, tx_ctx, i)?; // TODO: remove Rc, use with_self_box let tree = input_box.ergo_tree.clone(); let exp = tree .proposition() diff --git a/ergo-lib/src/wallet/signing.rs b/ergo-lib/src/wallet/signing.rs index ad613d808..a08663edc 100644 --- a/ergo-lib/src/wallet/signing.rs +++ b/ergo-lib/src/wallet/signing.rs @@ -63,7 +63,6 @@ pub fn make_context<'ctx, T: ErgoTransaction>( let outputs = tx_ctx.spending_tx.outputs(); let data_inputs_ir = if let Some(data_inputs) = tx_ctx.spending_tx.data_inputs() { Some( - #[allow(clippy::unwrap_used)] data_inputs .iter() .enumerate() @@ -78,7 +77,7 @@ pub fn make_context<'ctx, T: ErgoTransaction>( }) .collect::, _>>()? .try_into() - .unwrap(), + .map_err(|_| TransactionContextError::TooManyDataInputBoxes(data_inputs.len()))?, ) } else { None @@ -152,7 +151,7 @@ pub fn sign_transaction( prover, &tx_context, state_context, - &mut ctx, // TODO: use with_self_box_index + &mut ctx, tx_hints, idx, message_to_sign.as_slice(), diff --git a/ergo-lib/src/wallet/tx_context.rs b/ergo-lib/src/wallet/tx_context.rs index 30c561956..382d473cb 100644 --- a/ergo-lib/src/wallet/tx_context.rs +++ b/ergo-lib/src/wallet/tx_context.rs @@ -234,8 +234,8 @@ fn verify_assets( ) -> Result<(), TxValidationError> { // If this transaction mints a new token, it's token ID must be the ID of the first box being spent #[allow(clippy::unwrap_used)] - // Inputs size is already validated so it must be of size atleast 1 - let new_token_id: TokenId = inputs.nth(0).unwrap().into(); + // Inputs size is already validated so it must be of atleast size 1 + let new_token_id: TokenId = inputs.next().unwrap().into(); for (&out_token_id, &out_amount) in &out_assets { if let Some(&in_amount) = in_assets.get(&out_token_id) { // Check that Transaction is not creating tokens out of thin air diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index 2a4ab05d4..3bc851326 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -192,7 +192,7 @@ pub(crate) trait Evaluable { &self, env: &mut Env<'ctx>, ctx: &Context<'ctx>, - // TODO cost_accum: &mut CostAccumulator, + // TODO for JIT costing: cost_accum: &mut CostAccumulator, ) -> Result, EvalError>; } diff --git a/ergotree-interpreter/src/eval/context.rs b/ergotree-interpreter/src/eval/context.rs index 779af629d..6b86e5052 100644 --- a/ergotree-interpreter/src/eval/context.rs +++ b/ergotree-interpreter/src/eval/context.rs @@ -69,6 +69,7 @@ mod arbitrary { extension, headers, )| { + // Leak variables. Since this is only used for testing this is acceptable and avoids introducing a new type (ContextOwned) Self { height, self_box: Box::leak(Box::new(self_box)), diff --git a/ergotree-interpreter/src/eval/savltree.rs b/ergotree-interpreter/src/eval/savltree.rs index ab7076f64..01fc11d3b 100644 --- a/ergotree-interpreter/src/eval/savltree.rs +++ b/ergotree-interpreter/src/eval/savltree.rs @@ -23,7 +23,6 @@ use ergotree_ir::types::stype::SType; pub(crate) static DIGEST_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| { let avl_tree_data = obj.try_extract_into::()?; Ok(Value::Coll(CollKind::NativeColl(NativeColl::CollByte( - // TODO: From for Rc<[i8]> avl_tree_data.digest.0.iter().map(|&b| b as i8).collect(), )))) }; diff --git a/ergotree-interpreter/src/eval/subst_const.rs b/ergotree-interpreter/src/eval/subst_const.rs index 36a3c745b..725063c1d 100644 --- a/ergotree-interpreter/src/eval/subst_const.rs +++ b/ergotree-interpreter/src/eval/subst_const.rs @@ -71,7 +71,7 @@ impl Evaluable for SubstConstants { } } Ok(Value::Coll(CollKind::NativeColl(NativeColl::CollByte( - ergo_tree.sigma_serialize_bytes()?.as_vec_i8().into(), // TODO: optimize + ergo_tree.sigma_serialize_bytes()?.as_vec_i8().into(), )))) } else { Err(EvalError::Misc(format!( diff --git a/ergotree-interpreter/src/lib.rs b/ergotree-interpreter/src/lib.rs index 57cfd2cee..05932db52 100644 --- a/ergotree-interpreter/src/lib.rs +++ b/ergotree-interpreter/src/lib.rs @@ -2,7 +2,7 @@ // Coding conventions #![forbid(unsafe_code)] -#![allow(clippy::needless_lifetimes)] // Leads to better code clarity +#![allow(clippy::needless_lifetimes)] #![deny(non_upper_case_globals)] #![deny(non_camel_case_types)] #![deny(non_snake_case)] diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs index 657baf961..e08717371 100644 --- a/ergotree-ir/src/lib.rs +++ b/ergotree-ir/src/lib.rs @@ -27,7 +27,6 @@ pub mod chain; pub mod ergo_tree; pub mod mir; pub mod pretty_printer; -/// TODO pub mod reference; pub mod serialization; pub mod sigma_protocol; diff --git a/ergotree-ir/src/mir.rs b/ergotree-ir/src/mir.rs index 6903d3df0..1113dad3f 100644 --- a/ergotree-ir/src/mir.rs +++ b/ergotree-ir/src/mir.rs @@ -28,8 +28,6 @@ pub mod coll_filter; pub mod coll_fold; /// Tests whether a predicate holds for all elements of this collection pub mod coll_forall; -/// Operations over Coll -pub mod coll_iter; /// Collection.map pub mod coll_map; /// Collection.size diff --git a/ergotree-ir/src/mir/value.rs b/ergotree-ir/src/mir/value.rs index 193887616..3b3b33b75 100644 --- a/ergotree-ir/src/mir/value.rs +++ b/ergotree-ir/src/mir/value.rs @@ -608,7 +608,7 @@ impl TryExtractFrom> for Vec { fn try_extract_from(v: Value) -> Result { match v { Value::Coll(v) => match v { - CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), // TODO + CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), _ => Err(TryExtractFromError(format!( "expected {:?}, found {:?}", std::any::type_name::(), diff --git a/ergotree-ir/src/reference.rs b/ergotree-ir/src/reference.rs index d306586c0..540b050a2 100644 --- a/ergotree-ir/src/reference.rs +++ b/ergotree-ir/src/reference.rs @@ -1,3 +1,4 @@ +//! Reference type used extensively throughout interpreter. a Ref<'ctx, T> can either borrow from Context or be Arc use std::{ops::Deref, sync::Arc}; #[derive(Clone, Debug, Eq)] diff --git a/ergotree-ir/src/types/stype.rs b/ergotree-ir/src/types/stype.rs index 703509c62..41efd553d 100644 --- a/ergotree-ir/src/types/stype.rs +++ b/ergotree-ir/src/types/stype.rs @@ -100,12 +100,12 @@ impl SType { pub(crate) fn with_subst(&self, subst: &HashMap) -> Self { match self { - SType::STypeVar(ref tpe_var) => subst.get(tpe_var).cloned().unwrap_or((*self).clone()), + SType::STypeVar(ref tpe_var) => subst.get(tpe_var).cloned().unwrap_or(self.clone()), SType::SOption(tpe) => SType::SOption(tpe.with_subst(subst).into()), SType::SColl(tpe) => SType::SColl(tpe.with_subst(subst).into()), SType::STuple(ref stup) => SType::STuple(stup.with_subst(subst)), SType::SFunc(ref sfunc) => SType::SFunc(sfunc.with_subst(subst)), - _ => (*self).clone(), + _ => self.clone(), } } } From d1eebacbfe4a34b98c344bded74afba5b189e09a Mon Sep 17 00:00:00 2001 From: Kamal Ahmad Date: Sat, 8 Jun 2024 16:22:20 +0500 Subject: [PATCH 4/6] Remove dead code --- ergotree-interpreter/src/eval/func_value.rs | 6 +----- ergotree-interpreter/src/eval/method_call.rs | 2 +- ergotree-ir/src/lib.rs | 1 - ergotree-ir/src/util.rs | 19 ------------------- 4 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 ergotree-ir/src/util.rs diff --git a/ergotree-interpreter/src/eval/func_value.rs b/ergotree-interpreter/src/eval/func_value.rs index bb459ed58..f539db222 100644 --- a/ergotree-interpreter/src/eval/func_value.rs +++ b/ergotree-interpreter/src/eval/func_value.rs @@ -8,11 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for FuncValue { - fn eval<'ctx>( - &self, - _env: &mut Env, - _ctx: &Context<'ctx>, - ) -> Result, EvalError> { + fn eval<'ctx>(&self, _env: &mut Env, _ctx: &Context<'ctx>) -> Result, EvalError> { Ok(Value::Lambda(Lambda { args: self.args().to_vec(), body: self.body().clone().into(), diff --git a/ergotree-interpreter/src/eval/method_call.rs b/ergotree-interpreter/src/eval/method_call.rs index 1c1af8a42..c1b4ec5cc 100644 --- a/ergotree-interpreter/src/eval/method_call.rs +++ b/ergotree-interpreter/src/eval/method_call.rs @@ -2,8 +2,8 @@ use ergotree_ir::mir::method_call::MethodCall; use ergotree_ir::mir::value::Value; use super::smethod_eval_fn; -use super::Env; use super::Context; +use super::Env; use super::EvalError; use super::Evaluable; diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs index e08717371..711a9a2d0 100644 --- a/ergotree-ir/src/lib.rs +++ b/ergotree-ir/src/lib.rs @@ -33,4 +33,3 @@ pub mod sigma_protocol; pub mod source_span; pub mod type_check; pub mod types; -pub mod util; diff --git a/ergotree-ir/src/util.rs b/ergotree-ir/src/util.rs deleted file mode 100644 index 11e79af8d..000000000 --- a/ergotree-ir/src/util.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Utilities - -// use elliptic_curve::subtle::CtOption; - -// /// Convert to Option -// pub(crate) trait IntoOption { -// /// Get Option -// fn into_option(self) -> Option; -// } - -// impl IntoOption for CtOption { -// fn into_option(self) -> Option { -// if self.is_some().into() { -// Some(self.unwrap()) -// } else { -// None -// } -// } -// } From 60cef6b942ade2781c27a88a3cdaea3eb0744fb1 Mon Sep 17 00:00:00 2001 From: Kamal Ahmad Date: Sun, 16 Jun 2024 01:28:49 +0500 Subject: [PATCH 5/6] Fix doc comments --- ergotree-ir/src/reference.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ergotree-ir/src/reference.rs b/ergotree-ir/src/reference.rs index 540b050a2..9dfd0ad68 100644 --- a/ergotree-ir/src/reference.rs +++ b/ergotree-ir/src/reference.rs @@ -1,8 +1,8 @@ -//! Reference type used extensively throughout interpreter. a Ref<'ctx, T> can either borrow from Context or be Arc +//! Reference type used extensively throughout interpreter. a Ref<'ctx, T> can either borrow from Context or be `Arc` use std::{ops::Deref, sync::Arc}; #[derive(Clone, Debug, Eq)] -/// A wrapper type that provides immutable access to [`T`]. Ref can either be [`Ref::Borrowed`], holding a reference to some data in the [`Context`], or [`Ref::Arc`] +/// A wrapper type that provides immutable access to T. Ref can either be [`Ref::Borrowed`], holding a reference to some data in Context, or [`Ref::Arc`] pub enum Ref<'ctx, T> { /// Data is borrowed from Context Borrowed(&'ctx T), @@ -23,7 +23,7 @@ impl<'ctx, T: Clone> Ref<'ctx, T> { pub fn to_static(&'ctx self) -> Ref<'static, T> { Ref::Arc(self.to_arc()) } - /// Convert [`Self`] to Arc + /// Convert [`Self`] to `Arc` pub fn to_arc(&'ctx self) -> Arc { match self { Ref::Arc(r) => r.clone(), From c7fa9f38069b8383e079fdf0b2aa25c22dba5d7e Mon Sep 17 00:00:00 2001 From: Kamal Ahmad Date: Sun, 16 Jun 2024 03:11:35 +0500 Subject: [PATCH 6/6] Update Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 92e65e270..ab9677fe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ tokio = { version = "1.15.0", features = ["full"] } tokio-stream = { version = "0.1.8", features = ["sync", "time"] } tokio-util = { version = "0.6.9", features = ["codec"] } bounded-integer = { version = "^0.5", features = ["types"] } -url = "2.2" +url = "~2.2" getrandom = { version = "0.2.7" } itertools = "0.10.3" miette = { version = "5", features = ["fancy"] }