Skip to content

Commit

Permalink
Merge cbce839 into c07514a
Browse files Browse the repository at this point in the history
  • Loading branch information
greenhat committed Oct 13, 2020
2 parents c07514a + cbce839 commit d0e1e3e
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 42 deletions.
12 changes: 12 additions & 0 deletions bindings/ergo-lib-wasm/src/ast.rs
Expand Up @@ -68,3 +68,15 @@ impl Constant {
.map_err(|e| JsValue::from_str(&format! {"{:?}", e}))
}
}

impl From<ergo_lib::ast::Constant> for Constant {
fn from(c: ergo_lib::ast::Constant) -> Self {
Constant(c)
}
}

impl From<Constant> for ergo_lib::ast::Constant {
fn from(c: Constant) -> Self {
c.0
}
}
70 changes: 69 additions & 1 deletion bindings/ergo-lib-wasm/src/ergo_box.rs
Expand Up @@ -22,6 +22,7 @@ use chain::ergo_box::register::NonMandatoryRegisters;
use ergo_lib::chain;
use wasm_bindgen::prelude::*;

use crate::ast::Constant;
use crate::{contract::Contract, transaction::TxId};

pub mod box_builder;
Expand All @@ -32,7 +33,16 @@ pub mod box_builder;
pub struct ErgoBoxCandidate(chain::ergo_box::ErgoBoxCandidate);

#[wasm_bindgen]
impl ErgoBoxCandidate {}
impl ErgoBoxCandidate {
/// Returns value (ErgoTree constant) stored in the register or None if the register is empty
pub fn register_value(&self, register_id: NonMandatoryRegisterId) -> Option<Constant> {
self.0
.additional_registers
.get(register_id.into())
.cloned()
.map(Constant::from)
}
}

impl Into<chain::ergo_box::ErgoBoxCandidate> for ErgoBoxCandidate {
fn into(self) -> chain::ergo_box::ErgoBoxCandidate {
Expand Down Expand Up @@ -76,6 +86,15 @@ impl ErgoBox {
ErgoBox(b)
}

/// Returns value (ErgoTree constant) stored in the register or None if the register is empty
pub fn register_value(&self, register_id: NonMandatoryRegisterId) -> Option<Constant> {
self.0
.additional_registers
.get(register_id.into())
.cloned()
.map(Constant::from)
}

// JSON representation
// pub fn to_json(&self) -> Result<JsValue, JsValue> {
// JsValue::from_serde(&self.0).map_err(|e| JsValue::from_str(&format!("{}", e)))
Expand Down Expand Up @@ -122,3 +141,52 @@ impl From<chain::ergo_box::box_value::BoxValue> for BoxValue {
BoxValue(v)
}
}

/// newtype for box registers R4 - R9
#[wasm_bindgen]
#[repr(u8)]
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum NonMandatoryRegisterId {
/// id for R4 register
R4 = 4,
/// id for R5 register
R5 = 5,
/// id for R6 register
R6 = 6,
/// id for R7 register
R7 = 7,
/// id for R8 register
R8 = 8,
/// id for R9 register
R9 = 9,
}

impl NonMandatoryRegisterId {}

impl From<NonMandatoryRegisterId> for chain::ergo_box::register::NonMandatoryRegisterId {
fn from(v: NonMandatoryRegisterId) -> Self {
use chain::ergo_box::register::NonMandatoryRegisterId::*;
match v {
NonMandatoryRegisterId::R4 => R4,
NonMandatoryRegisterId::R5 => R5,
NonMandatoryRegisterId::R6 => R6,
NonMandatoryRegisterId::R7 => R7,
NonMandatoryRegisterId::R8 => R8,
NonMandatoryRegisterId::R9 => R9,
}
}
}

impl From<chain::ergo_box::register::NonMandatoryRegisterId> for NonMandatoryRegisterId {
fn from(v: chain::ergo_box::register::NonMandatoryRegisterId) -> Self {
use NonMandatoryRegisterId::*;
match v {
chain::ergo_box::register::NonMandatoryRegisterId::R4 => R4,
chain::ergo_box::register::NonMandatoryRegisterId::R5 => R5,
chain::ergo_box::register::NonMandatoryRegisterId::R6 => R6,
chain::ergo_box::register::NonMandatoryRegisterId::R7 => R7,
chain::ergo_box::register::NonMandatoryRegisterId::R8 => R8,
chain::ergo_box::register::NonMandatoryRegisterId::R9 => R9,
}
}
}
33 changes: 29 additions & 4 deletions bindings/ergo-lib-wasm/src/ergo_box/box_builder.rs
Expand Up @@ -2,10 +2,12 @@
use ergo_lib::chain;
use wasm_bindgen::prelude::*;

use crate::ast::Constant;
use crate::contract::Contract;

use super::BoxValue;
use super::ErgoBoxCandidate;
use super::NonMandatoryRegisterId;

/// ErgoBoxCandidate builder
#[wasm_bindgen]
Expand Down Expand Up @@ -49,13 +51,36 @@ impl ErgoBoxCandidateBuilder {
}

/// Calculate serialized box size(in bytes)
pub fn calc_box_size_bytes(&self) -> usize {
self.0.calc_box_size_bytes()
pub fn calc_box_size_bytes(&self) -> Result<usize, JsValue> {
self.0
.calc_box_size_bytes()
.map_err(|e| JsValue::from_str(&format!("{}", e)))
}

/// Calculate minimal box value for the current box serialized size(in bytes)
pub fn calc_min_box_value(&self) -> BoxValue {
self.0.calc_min_box_value().into()
pub fn calc_min_box_value(&self) -> Result<BoxValue, JsValue> {
self.0
.calc_min_box_value()
.map(BoxValue::from)
.map_err(|e| JsValue::from_str(&format!("{}", e)))
}

/// Set register with a given id (R4-R9) to the given value
pub fn set_register_value(self, register_id: NonMandatoryRegisterId, value: Constant) -> Self {
ErgoBoxCandidateBuilder(self.0.set_register_value(register_id.into(), value.into()))
}

/// Returns register value for the given register id (R4-R9), or None if the register is empty
pub fn register_value(&self, register_id: NonMandatoryRegisterId) -> Option<Constant> {
self.0
.register_value(&register_id.into())
.cloned()
.map(Constant::from)
}

/// Delete register value(make register empty) for the given register id (R4-R9)
pub fn delete_register_value(self, register_id: NonMandatoryRegisterId) -> Self {
ErgoBoxCandidateBuilder(self.0.delete_register_value(&register_id.into()))
}

/// Build the box candidate
Expand Down
1 change: 1 addition & 0 deletions ergo-lib/src/chain/ergo_box.rs
Expand Up @@ -12,6 +12,7 @@ use super::{
token::{TokenAmount, TokenId},
transaction::TxId,
};

use crate::{
ergo_tree::ErgoTree,
serialization::{
Expand Down
88 changes: 77 additions & 11 deletions ergo-lib/src/chain/ergo_box/box_builder.rs
@@ -1,14 +1,18 @@
//! ErgoBoxCandidate builder

use std::collections::HashMap;
use std::convert::TryFrom;
use std::convert::TryInto;

use crate::ast::Constant;
use crate::chain::token::TokenAmount;
use crate::serialization::SigmaSerializable;
use crate::ErgoTree;

use super::box_value::BoxValue;
use super::register::NonMandatoryRegisterId;
use super::register::NonMandatoryRegisters;
use super::register::NonMandatoryRegistersError;
use super::ErgoBoxCandidate;
use thiserror::Error;

Expand All @@ -23,6 +27,10 @@ pub enum ErgoBoxCandidateBuilderError {
/// box size in bytes
box_size_bytes: usize,
},

/// NonMandatoryRegisters error
#[error("NonMandatoryRegisters error: {0}")]
NonMandatoryRegistersError(#[from] NonMandatoryRegistersError),
}

/// ErgoBoxCandidate builder
Expand All @@ -31,11 +39,17 @@ pub struct ErgoBoxCandidateBuilder {
value: BoxValue,
ergo_tree: ErgoTree,
tokens: Vec<TokenAmount>,
additional_registers: NonMandatoryRegisters,
additional_registers: HashMap<NonMandatoryRegisterId, Constant>,
creation_height: u32,
}

impl ErgoBoxCandidateBuilder {
fn build_registers(&self) -> Result<NonMandatoryRegisters, ErgoBoxCandidateBuilderError> {
Ok(NonMandatoryRegisters::new(
self.additional_registers.clone(),
)?)
}

/// Create builder with required box parameters:
/// `value` - box value in nanoErgs,
/// `ergo_tree` - ErgoTree to guard this box,
Expand All @@ -46,7 +60,7 @@ impl ErgoBoxCandidateBuilder {
value,
ergo_tree,
tokens: vec![],
additional_registers: NonMandatoryRegisters::empty(),
additional_registers: HashMap::new(),
creation_height,
}
}
Expand Down Expand Up @@ -74,30 +88,56 @@ impl ErgoBoxCandidateBuilder {
}

/// Calculate serialized box size(in bytes)
pub fn calc_box_size_bytes(&self) -> usize {
pub fn calc_box_size_bytes(&self) -> Result<usize, ErgoBoxCandidateBuilderError> {
let regs = self.build_registers()?;
let b = ErgoBoxCandidate {
value: self.value,
ergo_tree: self.ergo_tree.clone(),
tokens: self.tokens.clone(),
additional_registers: self.additional_registers.clone(),
additional_registers: regs,
creation_height: self.creation_height,
};
b.sigma_serialise_bytes().len()
Ok(b.sigma_serialise_bytes().len())
}

/// Calculate minimal box value for the current box serialized size(in bytes)
pub fn calc_min_box_value(&self) -> BoxValue {
let box_size_bytes = self.calc_box_size_bytes();
BoxValue::try_from(box_size_bytes as i64 * BoxValue::MIN_VALUE_PER_BOX_BYTE as i64).unwrap()
pub fn calc_min_box_value(&self) -> Result<BoxValue, ErgoBoxCandidateBuilderError> {
let box_size_bytes = self.calc_box_size_bytes()?;
Ok(
BoxValue::try_from(box_size_bytes as i64 * BoxValue::MIN_VALUE_PER_BOX_BYTE as i64)
.unwrap(),
)
}

/// Set register with a given id (R4-R9) to the given value
pub fn set_register_value(
mut self,
register_id: NonMandatoryRegisterId,
value: Constant,
) -> Self {
self.additional_registers.insert(register_id, value);
self
}

/// Returns register value for the given register id (R4-R9), or None if the register is empty
pub fn register_value(&self, register_id: &NonMandatoryRegisterId) -> Option<&Constant> {
self.additional_registers.get(register_id)
}

/// Delete register value(make register empty) for the given register id (R4-R9)
pub fn delete_register_value(mut self, register_id: &NonMandatoryRegisterId) -> Self {
self.additional_registers.remove(register_id);
self
}

/// Build the box candidate
pub fn build(self) -> Result<ErgoBoxCandidate, ErgoBoxCandidateBuilderError> {
let regs = self.build_registers()?;
let b = ErgoBoxCandidate {
value: self.value,
ergo_tree: self.ergo_tree,
tokens: self.tokens,
additional_registers: self.additional_registers,
additional_registers: regs,
creation_height: self.creation_height,
};
let box_size_bytes = b.sigma_serialise_bytes().len();
Expand All @@ -118,6 +158,8 @@ impl ErgoBoxCandidateBuilder {
#[cfg(test)]
mod tests {

use NonMandatoryRegisterId::*;

use crate::test_util::force_any_val;

use super::*;
Expand Down Expand Up @@ -159,7 +201,7 @@ mod tests {
fn test_box_size_estimation() {
let builder =
ErgoBoxCandidateBuilder::new(BoxValue::SAFE_USER_MIN, force_any_val::<ErgoTree>(), 1);
let estimated_box_size = builder.calc_box_size_bytes();
let estimated_box_size = builder.calc_box_size_bytes().unwrap();
let b = builder.build().unwrap();
assert_eq!(b.sigma_serialise_bytes().len(), estimated_box_size);
}
Expand All @@ -168,12 +210,36 @@ mod tests {
fn test_calc_min_box_value() {
let builder =
ErgoBoxCandidateBuilder::new(BoxValue::SAFE_USER_MIN, force_any_val::<ErgoTree>(), 1);
assert!(builder.calc_min_box_value() > BoxValue::MIN);
assert!(builder.calc_min_box_value().unwrap() > BoxValue::MIN);
}

#[test]
fn test_build_fail_box_value_too_low() {
let builder = ErgoBoxCandidateBuilder::new(BoxValue::MIN, force_any_val::<ErgoTree>(), 1);
assert!(builder.build().is_err());
}

#[test]
fn test_set_get_register_value() {
let reg_value: Constant = 1i32.into();
let builder =
ErgoBoxCandidateBuilder::new(BoxValue::SAFE_USER_MIN, force_any_val::<ErgoTree>(), 1);
assert!(builder.register_value(&R4).is_none());
let builder2 = builder.set_register_value(R4, reg_value.clone());
assert_eq!(builder2.register_value(&R4).unwrap(), &reg_value);
let b = builder2.build().unwrap();
assert_eq!(b.additional_registers.get(R4).unwrap(), &reg_value);
}

#[test]
fn test_delete_register_value() {
let reg_value: Constant = 1i32.into();
let builder =
ErgoBoxCandidateBuilder::new(BoxValue::SAFE_USER_MIN, force_any_val::<ErgoTree>(), 1)
.set_register_value(R4, reg_value);
let builder2 = builder.delete_register_value(&R4);
assert!(builder2.register_value(&R4).is_none());
let b = builder2.build().unwrap();
assert!(b.additional_registers.get(R4).is_none());
}
}

0 comments on commit d0e1e3e

Please sign in to comment.