From fca8c2f3462cf0a65daf8d6b4a8096b4b72b0ea5 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 10 Nov 2020 17:49:33 +0200 Subject: [PATCH 1/5] introduce Context, TransactionContext; --- bindings/ergo-lib-wasm/src/wallet.rs | 22 ++++++++++-------- ergo-lib/src/eval.rs | 23 ++++++++++++++---- ergo-lib/src/eval/context.rs | 28 ++++++++++++++++++++++ ergo-lib/src/sigma_protocol/prover.rs | 20 ++++++++++++---- ergo-lib/src/sigma_protocol/verifier.rs | 9 ++++--- ergo-lib/src/wallet.rs | 31 ++++++++----------------- ergo-lib/src/wallet/signing.rs | 31 ++++++++++++++++++------- 7 files changed, 113 insertions(+), 51 deletions(-) create mode 100644 ergo-lib/src/eval/context.rs diff --git a/bindings/ergo-lib-wasm/src/wallet.rs b/bindings/ergo-lib-wasm/src/wallet.rs index 5d122bfce..37d31ba85 100644 --- a/bindings/ergo-lib-wasm/src/wallet.rs +++ b/bindings/ergo-lib-wasm/src/wallet.rs @@ -1,5 +1,5 @@ //! Wallet-like features -use ergo_lib::chain::ergo_box::ErgoBox; +use ergo_lib::chain; use wasm_bindgen::prelude::*; use crate::{ @@ -28,7 +28,9 @@ impl Wallet { } /// Sign a transaction: - /// `boxes_to_spend` - unspent boxes [`ErgoBoxCandidate`] used as inputs in the transaction + /// `tx` - transaction to sign + /// `boxes_to_spend` - boxes corresponding to [`UnsignedTransaction::inputs`] + /// `data_boxes` - boxes corresponding to [`UnsignedTransaction::data_inputs`] #[wasm_bindgen] pub fn sign_transaction( &self, @@ -37,15 +39,15 @@ impl Wallet { boxes_to_spend: &ErgoBoxes, data_boxes: &ErgoBoxes, ) -> Result { - let boxes_to_spend: Vec = boxes_to_spend.clone().into(); - let data_boxes: Vec = data_boxes.clone().into(); + let boxes_to_spend: Vec = boxes_to_spend.clone().into(); + let data_boxes: Vec = data_boxes.clone().into(); + let tx_context = ergo_lib::wallet::signing::TransactionContext { + spending_tx: tx.clone().into(), + boxes_to_spend, + data_boxes, + }; self.0 - .sign_transaction( - tx.clone().into(), - boxes_to_spend.as_slice(), - data_boxes.as_slice(), - &_state_context.clone().into(), - ) + .sign_transaction(tx_context, &_state_context.clone().into()) .map_err(|e| JsValue::from_str(&format!("{}", e))) .map(Transaction::from) } diff --git a/ergo-lib/src/eval.rs b/ergo-lib/src/eval.rs index 69dc8fafe..c9acf1401 100644 --- a/ergo-lib/src/eval.rs +++ b/ergo-lib/src/eval.rs @@ -9,6 +9,9 @@ use cost_accum::CostAccumulator; use thiserror::Error; use value::Value; +use self::context::Context; + +pub(crate) mod context; mod cost_accum; mod costs; mod value; @@ -46,9 +49,14 @@ pub struct ReductionResult { /// Interpreter pub trait Evaluator { /// This method is used in both prover and verifier to compute SigmaBoolean value. - fn reduce_to_crypto(&self, expr: &Expr, env: &Env) -> Result { + fn reduce_to_crypto( + &self, + expr: &Expr, + env: &Env, + ctx: &Context, + ) -> Result { let mut ca = CostAccumulator::new(0, None); - eval(expr, env, &mut ca).and_then(|v| match v { + eval(expr, env, &mut ca, ctx).and_then(|v| match v { Value::Boolean(b) => Ok(ReductionResult { sigma_prop: SigmaBoolean::TrivialProp(b), cost: 0, @@ -63,7 +71,12 @@ pub trait Evaluator { } #[allow(unconditional_recursion)] -fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result { +fn eval( + expr: &Expr, + env: &Env, + ca: &mut CostAccumulator, + ctx: &Context, +) -> Result { match expr { Expr::Const(Constant { tpe: SType::SBoolean, @@ -81,8 +94,8 @@ fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result todo!(), Expr::MethodCall { .. } => todo!(), Expr::BinOp(bin_op, l, r) => { - let v_l = eval(l, env, ca)?; - let v_r = eval(r, env, ca)?; + let v_l = eval(l, env, ca, ctx)?; + let v_r = eval(r, env, ca, ctx)?; ca.add_cost_of(expr); Ok(match bin_op { BinOp::Num(op) => match op { diff --git a/ergo-lib/src/eval/context.rs b/ergo-lib/src/eval/context.rs new file mode 100644 index 000000000..f4d79ec69 --- /dev/null +++ b/ergo-lib/src/eval/context.rs @@ -0,0 +1,28 @@ +use crate::ast::Constant; +use crate::chain::ergo_state_context::ErgoStateContext; +use crate::wallet::signing::TransactionContext; + +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct Context { + pub height: Constant, +} + +impl Context { + #[cfg(test)] + pub fn dummy() -> Self { + Context { + height: 0i32.into(), + } + } + + pub fn new( + _state_ctx: &ErgoStateContext, + _tx_ctx: &TransactionContext, + _self_index: usize, + ) -> Self { + // TODO: implement + Context { + height: 0i32.into(), + } + } +} diff --git a/ergo-lib/src/sigma_protocol/prover.rs b/ergo-lib/src/sigma_protocol/prover.rs index 1817447de..57a0e1ed1 100644 --- a/ergo-lib/src/sigma_protocol/prover.rs +++ b/ergo-lib/src/sigma_protocol/prover.rs @@ -16,6 +16,7 @@ use super::{ UncheckedTree, UnprovenLeaf, UnprovenSchnorr, UnprovenTree, }; use crate::ergo_tree::{ErgoTree, ErgoTreeParsingError}; +use crate::eval::context::Context; use crate::eval::{Env, EvalError, Evaluator}; use thiserror::Error; @@ -67,11 +68,12 @@ pub trait Prover: Evaluator { &self, tree: &ErgoTree, env: &Env, + ctx: &Context, message: &[u8], ) -> Result { let expr = tree.proposition()?; let proof = self - .reduce_to_crypto(expr.as_ref(), env) + .reduce_to_crypto(expr.as_ref(), env, ctx) .map_err(ProverError::EvalError) .and_then(|v| match v.sigma_prop { SigmaBoolean::TrivialProp(true) => Ok(UncheckedTree::NoProof), @@ -314,7 +316,12 @@ mod tests { let message = vec![0u8; 100]; let prover = TestProver { secrets: vec![] }; - let res = prover.prove(&bool_true_tree, &Env::empty(), message.as_slice()); + let res = prover.prove( + &bool_true_tree, + &Env::empty(), + &Context::dummy(), + message.as_slice(), + ); assert!(res.is_ok()); assert_eq!(res.unwrap().proof, ProofBytes::Empty); } @@ -328,7 +335,12 @@ mod tests { let message = vec![0u8; 100]; let prover = TestProver { secrets: vec![] }; - let res = prover.prove(&bool_false_tree, &Env::empty(), message.as_slice()); + let res = prover.prove( + &bool_false_tree, + &Env::empty(), + &Context::dummy(), + message.as_slice(), + ); assert!(res.is_err()); assert_eq!(res.err().unwrap(), ProverError::ReducedToFalse); } @@ -346,7 +358,7 @@ mod tests { let prover = TestProver { secrets: vec![PrivateInput::DlogProverInput(secret)], }; - let res = prover.prove(&tree, &Env::empty(), message.as_slice()); + let res = prover.prove(&tree, &Env::empty(), &Context::dummy(), message.as_slice()); assert!(res.is_ok()); assert_ne!(res.unwrap().proof, ProofBytes::Empty); } diff --git a/ergo-lib/src/sigma_protocol/verifier.rs b/ergo-lib/src/sigma_protocol/verifier.rs index 9bacf4829..7da2186af 100644 --- a/ergo-lib/src/sigma_protocol/verifier.rs +++ b/ergo-lib/src/sigma_protocol/verifier.rs @@ -9,6 +9,7 @@ use super::{ SigmaBoolean, UncheckedSigmaTree, UncheckedTree, }; use crate::ergo_tree::{ErgoTree, ErgoTreeParsingError}; +use crate::eval::context::Context; use crate::eval::{Env, EvalError, Evaluator}; use dlog_protocol::FirstDlogProverMessage; @@ -51,11 +52,12 @@ pub trait Verifier: Evaluator { &self, tree: &ErgoTree, env: &Env, + ctx: &Context, proof: &ProofBytes, message: &[u8], ) -> Result { let expr = tree.proposition()?; - let cprop = self.reduce_to_crypto(expr.as_ref(), env)?.sigma_prop; + let cprop = self.reduce_to_crypto(expr.as_ref(), env, ctx)?.sigma_prop; let res: bool = match cprop { SigmaBoolean::TrivialProp(b) => b, sb => { @@ -144,11 +146,11 @@ mod tests { let prover = TestProver { secrets: vec![PrivateInput::DlogProverInput(secret)], }; - let res = prover.prove(&tree, &Env::empty(), message.as_slice()); + let res = prover.prove(&tree, &Env::empty(), &Context::dummy(), message.as_slice()); let proof = res.unwrap().proof; let verifier = TestVerifier; - let ver_res = verifier.verify(&tree, &Env::empty(), &proof, message.as_slice()); + let ver_res = verifier.verify(&tree, &Env::empty(), &Context::dummy(), &proof, message.as_slice()); prop_assert_eq!(ver_res.unwrap().result, true); } } @@ -247,6 +249,7 @@ mod tests { let ver_res = verifier.verify( &ergo_tree, &Env::empty(), + &Context::dummy(), &tx.inputs.get(1).unwrap().spending_proof.proof, message.as_slice(), ); diff --git a/ergo-lib/src/wallet.rs b/ergo-lib/src/wallet.rs index 482f5566b..439a5d51f 100644 --- a/ergo-lib/src/wallet.rs +++ b/ergo-lib/src/wallet.rs @@ -9,17 +9,15 @@ use secret_key::SecretKey; use signing::{sign_transaction, TxSigningError}; use thiserror::Error; -use crate::{ - chain::{ - ergo_box::ErgoBox, ergo_state_context::ErgoStateContext, - transaction::unsigned::UnsignedTransaction, transaction::Transaction, - }, - sigma_protocol::{ - private_input::PrivateInput, - prover::{Prover, TestProver}, - }, +use crate::chain::ergo_state_context::ErgoStateContext; +use crate::chain::transaction::Transaction; +use crate::sigma_protocol::{ + private_input::PrivateInput, + prover::{Prover, TestProver}, }; +use self::signing::TransactionContext; + /// Wallet pub struct Wallet { prover: Box, @@ -53,18 +51,9 @@ impl Wallet { /// Signs a transaction pub fn sign_transaction( &self, - tx: UnsignedTransaction, - boxes_to_spend: &[ErgoBox], - _data_boxes: &[ErgoBox], - _state_context: &ErgoStateContext, + tx_context: TransactionContext, + state_context: &ErgoStateContext, ) -> Result { - sign_transaction( - self.prover.as_ref(), - tx, - boxes_to_spend, - _data_boxes, - _state_context, - ) - .map_err(WalletError::from) + sign_transaction(self.prover.as_ref(), tx_context, state_context).map_err(WalletError::from) } } diff --git a/ergo-lib/src/wallet/signing.rs b/ergo-lib/src/wallet/signing.rs index 741ade0b7..5a1812f26 100644 --- a/ergo-lib/src/wallet/signing.rs +++ b/ergo-lib/src/wallet/signing.rs @@ -1,6 +1,7 @@ //! Transaction signing use crate::chain::transaction::Input; +use crate::eval::context::Context; use crate::{ chain::{ ergo_box::ErgoBox, @@ -24,25 +25,38 @@ pub enum TxSigningError { InputBoxNotFound(usize), } +/// Transaction and an additional info required for signing +#[derive(PartialEq, Debug, Clone)] +pub struct TransactionContext { + /// Unsigned transaction to sign + pub spending_tx: UnsignedTransaction, + /// Boxes corresponding to [`UnsignedTransaction::inputs`] + pub boxes_to_spend: Vec, + /// Boxes corresponding to [`UnsignedTransaction::data_inputs`] + pub data_boxes: Vec, +} + /// Signs a transaction (generating proofs for inputs) pub fn sign_transaction( prover: &dyn Prover, - tx: UnsignedTransaction, - boxes_to_spend: &[ErgoBox], - _data_boxes: &[ErgoBox], - _state_context: &ErgoStateContext, + tx_context: TransactionContext, + state_context: &ErgoStateContext, ) -> Result { + let tx = tx_context.spending_tx.clone(); let message_to_sign = tx.bytes_to_sign(); let mut signed_inputs: Vec = vec![]; - boxes_to_spend + tx_context + .boxes_to_spend .iter() .enumerate() .try_for_each(|(idx, input_box)| { if let Some(unsigned_input) = tx.inputs.get(idx) { + let ctx = Context::new(state_context, &tx_context, idx); prover .prove( &input_box.ergo_tree, &Env::empty(), + &ctx, message_to_sign.as_slice(), ) .map(|proof| { @@ -99,6 +113,7 @@ mod tests { let res = verifier.verify( &b.ergo_tree, &Env::empty(), + &Context::dummy(), &input.spending_proof.proof, &message, )?; @@ -138,9 +153,9 @@ mod tests { .build().unwrap(); let output_candidates = vec![candidate]; let tx = UnsignedTransaction::new(inputs, vec![], output_candidates); - - let res = sign_transaction(Box::new(prover).as_ref(), tx, boxes_to_spend.as_slice(), vec![].as_slice(), - &ErgoStateContext::dummy()); + let tx_context = TransactionContext { spending_tx: tx, + boxes_to_spend: boxes_to_spend.clone(), data_boxes: vec![] }; + let res = sign_transaction(Box::new(prover).as_ref(), tx_context, &ErgoStateContext::dummy()); let signed_tx = res.unwrap(); prop_assert!(verify_tx_proofs(&signed_tx, &boxes_to_spend).unwrap()); } From d9762b8ba5cb5af438fc56a05ef4fdf211a8db32 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 10 Nov 2020 18:48:50 +0200 Subject: [PATCH 2/5] remove Value and use Constant instead; --- ergo-lib/src/eval.rs | 60 +++++++++++++++++++------------------- ergo-lib/src/eval/value.rs | 35 ---------------------- 2 files changed, 30 insertions(+), 65 deletions(-) delete mode 100644 ergo-lib/src/eval/value.rs diff --git a/ergo-lib/src/eval.rs b/ergo-lib/src/eval.rs index c9acf1401..2bffc284c 100644 --- a/ergo-lib/src/eval.rs +++ b/ergo-lib/src/eval.rs @@ -1,20 +1,18 @@ //! Interpreter use crate::{ - ast::{ops::BinOp, ops::NumOp, Constant, ConstantVal, Expr}, + ast::{Constant, ConstantVal, Expr}, sigma_protocol::sigma_boolean::SigmaBoolean, types::SType, }; use cost_accum::CostAccumulator; use thiserror::Error; -use value::Value; use self::context::Context; pub(crate) mod context; mod cost_accum; mod costs; -mod value; /// Environment vars for script interpreter pub struct Env(); @@ -56,16 +54,24 @@ pub trait Evaluator { ctx: &Context, ) -> Result { let mut ca = CostAccumulator::new(0, None); - eval(expr, env, &mut ca, ctx).and_then(|v| match v { - Value::Boolean(b) => Ok(ReductionResult { - sigma_prop: SigmaBoolean::TrivialProp(b), - cost: 0, - }), - Value::SigmaProp(sb) => Ok(ReductionResult { - sigma_prop: *sb, - cost: 0, - }), - _ => Err(EvalError::InvalidResultType), + eval(expr, env, &mut ca, ctx).and_then(|v| -> Result { + match v { + Constant { + tpe: SType::SBoolean, + v: ConstantVal::Boolean(b), + } => Ok(ReductionResult { + sigma_prop: SigmaBoolean::TrivialProp(b), + cost: 0, + }), + Constant { + tpe: SType::SSigmaProp, + v: ConstantVal::SigmaProp(sp), + } => Ok(ReductionResult { + sigma_prop: sp.value().clone(), + cost: 0, + }), + _ => Err(EvalError::InvalidResultType), + } }) } } @@ -76,16 +82,9 @@ fn eval( env: &Env, ca: &mut CostAccumulator, ctx: &Context, -) -> Result { +) -> Result { match expr { - Expr::Const(Constant { - tpe: SType::SBoolean, - v: ConstantVal::Boolean(b), - }) => Ok(Value::Boolean(*b)), - Expr::Const(Constant { - tpe: SType::SSigmaProp, - v: ConstantVal::SigmaProp(sp), - }) => Ok(Value::SigmaProp(Box::new((*sp.value()).clone()))), + Expr::Const(c) => Ok(c.clone()), Expr::Coll { .. } => todo!(), Expr::Tup { .. } => todo!(), Expr::PredefFunc(_) => todo!(), @@ -93,15 +92,16 @@ fn eval( Expr::BoxM(_) => todo!(), Expr::CtxM(_) => todo!(), Expr::MethodCall { .. } => todo!(), - Expr::BinOp(bin_op, l, r) => { - let v_l = eval(l, env, ca, ctx)?; - let v_r = eval(r, env, ca, ctx)?; + Expr::BinOp(_bin_op, l, r) => { + let _v_l = eval(l, env, ca, ctx)?; + let _v_r = eval(r, env, ca, ctx)?; ca.add_cost_of(expr); - Ok(match bin_op { - BinOp::Num(op) => match op { - NumOp::Add => v_l + v_r, - }, - }) + todo!() + // Ok(match bin_op { + // BinOp::Num(op) => match op { + // NumOp::Add => v_l + v_r, + // }, + // }) } _ => Err(EvalError::UnexpectedExpr), } diff --git a/ergo-lib/src/eval/value.rs b/ergo-lib/src/eval/value.rs deleted file mode 100644 index b89f660e6..000000000 --- a/ergo-lib/src/eval/value.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::{chain::ergo_box::ErgoBox, sigma_protocol::sigma_boolean::SigmaBoolean}; -use std::ops::Add; - -#[allow(dead_code)] -pub enum Value { - Boolean(bool), - Byte(i8), - Short(i16), - Int(i32), - Long(i64), - BigInt, - GroupElement, - SigmaProp(Box), - Box(Box), - AvlTree, - Coll(Vec), - Tup(Vec), -} - -impl Value { - #[inline] - pub fn byte(value: i8) -> Self { - Value::Byte(value) - } -} - -impl Add for Value { - type Output = Self; - fn add(self, other: Self) -> Self { - match (self, other) { - (Value::Byte(s), Value::Byte(o)) => Self::byte(s + o), - _ => todo!(), - } - } -} From d9fb10eec3a3e6d8ceedbc408cdda9335a8864b4 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 10 Nov 2020 19:14:37 +0200 Subject: [PATCH 3/5] introduce Evaluable; implement Evaluable for Height; --- ergo-lib/src/ast.rs | 19 +++++++++++++++++++ ergo-lib/src/eval.rs | 31 +++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/ergo-lib/src/ast.rs b/ergo-lib/src/ast.rs index e39109e1f..178b02347 100644 --- a/ergo-lib/src/ast.rs +++ b/ergo-lib/src/ast.rs @@ -1,4 +1,7 @@ //! AST for ErgoTree +use crate::eval::cost_accum::CostAccumulator; +use crate::eval::EvalError; +use crate::eval::Evaluable; use crate::{serialization::op_code::OpCode, types::*}; use core::fmt; use Expr::*; @@ -121,6 +124,22 @@ pub enum ContextMethods { Inputs, /// Tx outputs Outputs, + /// Current blockchain height + Height, +} + +impl Evaluable for ContextMethods { + fn eval( + &self, + _env: &crate::eval::Env, + _ca: &mut CostAccumulator, + ctx: &crate::eval::context::Context, + ) -> Result { + match self { + ContextMethods::Height => Ok(ctx.height.clone()), + _ => Err(EvalError::UnexpectedExpr), + } + } } #[derive(PartialEq, Eq, Debug, Clone)] diff --git a/ergo-lib/src/eval.rs b/ergo-lib/src/eval.rs index 2bffc284c..1adff533a 100644 --- a/ergo-lib/src/eval.rs +++ b/ergo-lib/src/eval.rs @@ -11,7 +11,7 @@ use thiserror::Error; use self::context::Context; pub(crate) mod context; -mod cost_accum; +pub(crate) mod cost_accum; mod costs; /// Environment vars for script interpreter @@ -76,6 +76,17 @@ pub trait Evaluator { } } +/// Implemented by every node that can be evaluated +pub trait Evaluable { + /// Evaluation routine to be implement by each node + fn eval( + &self, + env: &Env, + ca: &mut CostAccumulator, + ctx: &Context, + ) -> Result; +} + #[allow(unconditional_recursion)] fn eval( expr: &Expr, @@ -90,7 +101,7 @@ fn eval( Expr::PredefFunc(_) => todo!(), Expr::CollM(_) => todo!(), Expr::BoxM(_) => todo!(), - Expr::CtxM(_) => todo!(), + Expr::CtxM(v) => v.eval(env, ca, ctx), Expr::MethodCall { .. } => todo!(), Expr::BinOp(_bin_op, l, r) => { let _v_l = eval(l, env, ca, ctx)?; @@ -106,3 +117,19 @@ fn eval( _ => Err(EvalError::UnexpectedExpr), } } + +#[cfg(test)] +mod tests { + use crate::ast::ContextMethods; + use crate::ast::TryExtractFrom; + + use super::*; + + #[test] + fn height() { + let expr = Expr::CtxM(ContextMethods::Height); + let mut ca = CostAccumulator::new(0, None); + let res = eval(&expr, &Env::empty(), &mut ca, &Context::dummy()).unwrap(); + assert_eq!(i32::try_extract_from(res).unwrap(), 0); + } +} From 2033bad09340e04256d1db80482440cd7b74be67 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 11 Nov 2020 08:43:57 +0200 Subject: [PATCH 4/5] add doc comments; --- ergo-lib/src/eval.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ergo-lib/src/eval.rs b/ergo-lib/src/eval.rs index 1adff533a..4f9d6381b 100644 --- a/ergo-lib/src/eval.rs +++ b/ergo-lib/src/eval.rs @@ -14,7 +14,7 @@ pub(crate) mod context; pub(crate) mod cost_accum; mod costs; -/// Environment vars for script interpreter +/// Environment for the interpreter pub struct Env(); impl Env { @@ -36,17 +36,17 @@ pub enum EvalError { UnexpectedExpr, } -/// Result of ErgoTree reduction procedure (see `reduce_to_crypto`). +/// Result of expression reduction procedure (see `reduce_to_crypto`). pub struct ReductionResult { /// value of SigmaProp type which represents a statement verifiable via sigma protocol. pub sigma_prop: SigmaBoolean, - /// estimated cost of contract execution + /// estimated cost of expression evaluation pub cost: u64, } /// Interpreter pub trait Evaluator { - /// This method is used in both prover and verifier to compute SigmaBoolean value. + /// Evaluate the given expression by reducing it to SigmaBoolean value. fn reduce_to_crypto( &self, expr: &Expr, @@ -76,7 +76,8 @@ pub trait Evaluator { } } -/// Implemented by every node that can be evaluated +/// Expression evaluation. +/// Should be implemented by every node that can be evaluated. pub trait Evaluable { /// Evaluation routine to be implement by each node fn eval( From ba794256c922523b255db265ad9f43a88485c742 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 11 Nov 2020 09:26:42 +0200 Subject: [PATCH 5/5] update changelog; --- ergo-lib/CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ergo-lib/CHANGELOG.md b/ergo-lib/CHANGELOG.md index 5cd0794d6..165796375 100644 --- a/ergo-lib/CHANGELOG.md +++ b/ergo-lib/CHANGELOG.md @@ -16,7 +16,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed -- moved and change visibility of various modules(input, data_input, prover_result, etc.) [#135](https://github.com/ergoplatform/sigma-rust/pull/135) +- Moved and changed visibility of various modules(input, data_input, prover_result, etc.) [#135](https://github.com/ergoplatform/sigma-rust/pull/135) +- Added Context parameter to Prover::prove, Verifier::verify [#139](https://github.com/ergoplatform/sigma-rust/pull/139) +- Moved all transaction-related parameters into TransactionContext parameter in Wallet::sign_transaction [#139](https://github.com/ergoplatform/sigma-rust/pull/139) ## [0.3.0] - 2020-11-04