Skip to content

Commit

Permalink
Merge ba79425 into 18fad86
Browse files Browse the repository at this point in the history
  • Loading branch information
greenhat committed Nov 11, 2020
2 parents 18fad86 + ba79425 commit cf1587d
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 119 deletions.
22 changes: 12 additions & 10 deletions 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::{
Expand Down Expand Up @@ -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,
Expand All @@ -37,15 +39,15 @@ impl Wallet {
boxes_to_spend: &ErgoBoxes,
data_boxes: &ErgoBoxes,
) -> Result<Transaction, JsValue> {
let boxes_to_spend: Vec<ErgoBox> = boxes_to_spend.clone().into();
let data_boxes: Vec<ErgoBox> = data_boxes.clone().into();
let boxes_to_spend: Vec<chain::ergo_box::ErgoBox> = boxes_to_spend.clone().into();
let data_boxes: Vec<chain::ergo_box::ErgoBox> = 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)
}
Expand Down
4 changes: 3 additions & 1 deletion ergo-lib/CHANGELOG.md
Expand Up @@ -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

Expand Down
19 changes: 19 additions & 0 deletions 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::*;
Expand Down Expand Up @@ -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<Constant, EvalError> {
match self {
ContextMethods::Height => Ok(ctx.height.clone()),
_ => Err(EvalError::UnexpectedExpr),
}
}
}

#[derive(PartialEq, Eq, Debug, Clone)]
Expand Down
115 changes: 78 additions & 37 deletions ergo-lib/src/eval.rs
@@ -1,19 +1,20 @@
//! 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;

mod cost_accum;
use self::context::Context;

pub(crate) mod context;
pub(crate) mod cost_accum;
mod costs;
mod value;

/// Environment vars for script interpreter
/// Environment for the interpreter
pub struct Env();

impl Env {
Expand All @@ -35,61 +36,101 @@ 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.
fn reduce_to_crypto(&self, expr: &Expr, env: &Env) -> Result<ReductionResult, EvalError> {
/// Evaluate the given expression by reducing it to SigmaBoolean value.
fn reduce_to_crypto(
&self,
expr: &Expr,
env: &Env,
ctx: &Context,
) -> Result<ReductionResult, EvalError> {
let mut ca = CostAccumulator::new(0, None);
eval(expr, env, &mut ca).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<ReductionResult, EvalError> {
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),
}
})
}
}

/// 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(
&self,
env: &Env,
ca: &mut CostAccumulator,
ctx: &Context,
) -> Result<Constant, EvalError>;
}

#[allow(unconditional_recursion)]
fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result<Value, EvalError> {
fn eval(
expr: &Expr,
env: &Env,
ca: &mut CostAccumulator,
ctx: &Context,
) -> Result<Constant, EvalError> {
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!(),
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)?;
let v_r = eval(r, env, ca)?;
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),
}
}

#[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);
}
}
28 changes: 28 additions & 0 deletions 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(),
}
}
}
35 changes: 0 additions & 35 deletions ergo-lib/src/eval/value.rs

This file was deleted.

20 changes: 16 additions & 4 deletions ergo-lib/src/sigma_protocol/prover.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -67,11 +68,12 @@ pub trait Prover: Evaluator {
&self,
tree: &ErgoTree,
env: &Env,
ctx: &Context,
message: &[u8],
) -> Result<ProverResult, ProverError> {
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),
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down

0 comments on commit cf1587d

Please sign in to comment.