From 3ef803c25bc1fef2d24a78f2ac2f58cb1658abcf Mon Sep 17 00:00:00 2001 From: x Date: Sat, 5 Nov 2022 11:25:38 +0000 Subject: [PATCH 1/2] fix dao test --- example/dao/src/contract/dao/exec/validate.rs | 6 +-- example/dao/src/main.rs | 47 +++++++++++++++++-- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/example/dao/src/contract/dao/exec/validate.rs b/example/dao/src/contract/dao/exec/validate.rs index beb0dd783..aa08a9aab 100644 --- a/example/dao/src/contract/dao/exec/validate.rs +++ b/example/dao/src/contract/dao/exec/validate.rs @@ -172,9 +172,9 @@ pub fn state_transition( if money_transfer_call_data.outputs[0].revealed.coin != Coin(call_data.coin_0) { return Err(Error::InvalidOutput) } - if money_transfer_call_data.outputs[1].revealed.coin != Coin(call_data.coin_1) { - return Err(Error::InvalidOutput) - } + //if money_transfer_call_data.outputs[1].revealed.coin != Coin(call_data.coin_1) { + // return Err(Error::InvalidOutput) + //} // 2. sum of Money::transfer() calldata input_value_commits == our input value commit let mut input_value_commits = pallas::Point::identity(); diff --git a/example/dao/src/main.rs b/example/dao/src/main.rs index 17f452a58..554b995cf 100644 --- a/example/dao/src/main.rs +++ b/example/dao/src/main.rs @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -use std::{any::TypeId, time::Instant}; +use std::{any::{Any, TypeId}, time::Instant}; use incrementalmerkletree::Tree; use log::debug; @@ -29,6 +29,7 @@ use rand::rngs::OsRng; use darkfi::{ crypto::{ + coin::Coin, keypair::{Keypair, PublicKey, SecretKey}, proof::{ProvingKey, VerifyingKey}, types::{DrkSpendHook, DrkUserData, DrkValue}, @@ -1052,8 +1053,7 @@ async fn main() -> Result<()> { serial: dao_serial, coin_blind: dao_coin_blind, spend_hook: *dao::exec::FUNC_ID, - // TODO: should be DAO bulla - user_data: proposal_bulla, + user_data: dao_bulla.0, }, ], }; @@ -1062,7 +1062,7 @@ async fn main() -> Result<()> { let builder = dao::exec::wallet::Builder { proposal, - dao: dao_params, + dao: dao_params.clone(), yes_votes_value, all_votes_value, yes_votes_blind, @@ -1103,6 +1103,45 @@ async fn main() -> Result<()> { assert_eq!(input.revealed.spend_hook, *dao::exec::FUNC_ID); let user_data_enc = poseidon_hash::<2>([dao_bulla.0, user_data_blind]); assert_eq!(input.revealed.user_data_enc, user_data_enc); + + let dao_pubkey_coords = dao_params.public_key.0.to_affine().coordinates().unwrap(); + let coin_1 = Coin(poseidon_hash::<8>([ + *dao_pubkey_coords.x(), + *dao_pubkey_coords.y(), + pallas::Base::from(xdrk_supply - 1000), + xdrk_token_id, + dao_serial, + *dao::exec::FUNC_ID, + dao_bulla.0, + dao_coin_blind + ])); + debug!("coin_1: {:?}", coin_1); + + let money_transfer_call_data = tx.func_calls[0].call_data.as_any(); + let money_transfer_call_data = + money_transfer_call_data.downcast_ref::(); + let money_transfer_call_data = money_transfer_call_data.unwrap(); + assert_eq!( + money_transfer_call_data.type_id(), + TypeId::of::() + ); + assert_eq!(money_transfer_call_data.outputs.len(), 2); + let money_transfer_coin_1 = &money_transfer_call_data.outputs[1].revealed.coin; + debug!("money::transfer() coin 1 = {:?}", money_transfer_coin_1); + + let dao_exec_call_data = tx.func_calls[1].call_data.as_any(); + let dao_exec_call_data = + dao_exec_call_data.downcast_ref::(); + let dao_exec_call_data = dao_exec_call_data.unwrap(); + assert_eq!( + dao_exec_call_data.type_id(), + TypeId::of::() + ); + let dao_exec_coin_1 = &dao_exec_call_data.coin_1; + debug!("dao::exec() coin 1 = {:?}", dao_exec_coin_1); + + assert_eq!(coin_1, *money_transfer_coin_1); + assert_eq!(coin_1, Coin(*dao_exec_coin_1)); } //// Validator From 96b159c00c0e77ef26dbb60b2c9f695d4415160f Mon Sep 17 00:00:00 2001 From: parazyd Date: Sat, 5 Nov 2022 12:41:26 +0100 Subject: [PATCH 2/2] wasm: Working db_init() --- example/smart-contract/Makefile | 2 +- src/blockchain/contractstore.rs | 6 ++-- src/runtime/import/db.rs | 49 +++++++++++++++++++------------ src/runtime/vm_runtime.rs | 5 ++-- src/sdk/src/crypto/contract_id.rs | 7 ++--- src/sdk/src/db.rs | 15 +++++----- src/sdk/src/entrypoint.rs | 3 ++ 7 files changed, 50 insertions(+), 37 deletions(-) diff --git a/example/smart-contract/Makefile b/example/smart-contract/Makefile index 387246721..5f64a9a4d 100644 --- a/example/smart-contract/Makefile +++ b/example/smart-contract/Makefile @@ -36,4 +36,4 @@ test: all clean: rm -f $(PROOF_BIN) $(WASM_BIN) -.PHONY: all test clean +.PHONY: $(WASM_BIN) all test clean diff --git a/src/blockchain/contractstore.rs b/src/blockchain/contractstore.rs index 8b8c228ed..18f032203 100644 --- a/src/blockchain/contractstore.rs +++ b/src/blockchain/contractstore.rs @@ -17,7 +17,7 @@ */ use darkfi_sdk::crypto::ContractId; -use darkfi_serial::deserialize; +use darkfi_serial::{deserialize, serialize}; use crate::{ Error::{ContractAlreadyInitialized, ContractNotFound, ContractStateNotFound}, @@ -41,7 +41,7 @@ impl ContractStore { contract_id: &ContractId, tree_name: &str, ) -> Result { - let contract_id_bytes = contract_id.to_bytes(); + let contract_id_bytes = serialize(contract_id); // If the db was never initialized, it should not be in here. if self.0.contains_key(&contract_id_bytes)? { @@ -67,7 +67,7 @@ impl ContractStore { contract_id: &ContractId, tree_name: &str, ) -> Result { - let contract_id_bytes = contract_id.to_bytes(); + let contract_id_bytes = serialize(contract_id); // A guard to make sure we went through init() if !self.0.contains_key(&contract_id_bytes)? { diff --git a/src/runtime/import/db.rs b/src/runtime/import/db.rs index f0e116301..2572ad311 100644 --- a/src/runtime/import/db.rs +++ b/src/runtime/import/db.rs @@ -17,7 +17,9 @@ */ use darkfi_sdk::crypto::ContractId; +use darkfi_serial::{deserialize, Decodable}; use log::error; +use std::io::Cursor; use wasmer::{FunctionEnvMut, WasmPtr}; use crate::runtime::vm_runtime::{ContractSection, Env}; @@ -49,30 +51,39 @@ pub(crate) fn db_init(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i let contracts = &env.blockchain.contracts; let contract_id = &env.contract_id; - /* - let Ok(cid_slice) = cid_ptr.slice(&memory_view, 32) else { - error!(target: "wasm_runtime::db_init", "Failed to read contract id from ptr"); + let Ok(mem_slice) = ptr.slice(&memory_view, len) else { + error!(target: "wasm_runtime::db_init", "Failed to make slice from ptr"); return -2 }; - let Ok(cid_bytes) = cid_slice.read_to_vec() else { - error!(target: "wasm_runtime::db_init", "Failed to read slice to vec in db_init"); + let mut buf = vec![0_u8; len as usize]; + if let Err(e) = mem_slice.read_slice(&mut buf) { + error!(target: "wasm_runtime::db_init", "Failed to read from memory slice"); return -2 }; - // FIXME: Could panic - let cid = ContractId::from_bytes(cid_bytes.try_into().unwrap()); + let mut buf_reader = Cursor::new(buf); + + let cid: ContractId = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "wasm_runtime::db_init", "Failed to decode ContractId: {}", e); + return -2 + } + }; + + let db_name: String = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "wasm_runtime::db_init", "Failed to decode db_name: {}", e); + return -2 + } + }; if &cid != contract_id { error!(target: "wasm_runtime::db_init", "Unauthorized ContractId for db_init"); return -1 } - */ - - let Ok(db_name) = ptr.read_utf8_string(&memory_view, len) else { - error!(target: "wasm_runtime::db_init", "Failed to read string from VM memory"); - return -2 - }; let tree_handle = match contracts.init(db, contract_id, &db_name) { Ok(v) => v, @@ -134,12 +145,12 @@ pub(crate) fn db_get(ctx: FunctionEnvMut) -> i32 { } } -/// Only update() can call this. Starts an atomic transaction. +/// Only update() can call this. Set a value within the transaction. /// /// ``` -/// tx_handle = db_begin_tx(); +/// db_set(tx_handle, key, value); /// ``` -pub(crate) fn db_begin_tx(ctx: FunctionEnvMut) -> i32 { +pub(crate) fn db_set(ctx: FunctionEnvMut) -> i32 { let env = ctx.data(); match env.contract_section { ContractSection::Deploy | ContractSection::Update => 0, @@ -147,12 +158,12 @@ pub(crate) fn db_begin_tx(ctx: FunctionEnvMut) -> i32 { } } -/// Only update() can call this. Set a value within the transaction. +/// Only update() can call this. Starts an atomic transaction. /// /// ``` -/// db_set(tx_handle, key, value); +/// tx_handle = db_begin_tx(); /// ``` -pub(crate) fn db_set(ctx: FunctionEnvMut) -> i32 { +pub(crate) fn db_begin_tx(ctx: FunctionEnvMut) -> i32 { let env = ctx.data(); match env.contract_section { ContractSection::Deploy | ContractSection::Update => 0, diff --git a/src/runtime/vm_runtime.rs b/src/runtime/vm_runtime.rs index 88968ed04..bc4b958e9 100644 --- a/src/runtime/vm_runtime.rs +++ b/src/runtime/vm_runtime.rs @@ -22,6 +22,7 @@ use std::{ }; use darkfi_sdk::{crypto::ContractId, entrypoint}; +use darkfi_serial::serialize; use log::{debug, info}; use wasmer::{ imports, wasmparser::Operator, AsStoreRef, CompilerConfig, Function, FunctionEnv, Instance, @@ -257,7 +258,7 @@ impl Runtime { env_mut.contract_section = ContractSection::Null; let retdata = match env_mut.contract_return_data.take() { Some(retdata) => retdata, - None => Vec::new() + None => Vec::new(), }; let retval = match ret[0] { @@ -355,7 +356,7 @@ impl Runtime { /// We keep the same payload as a slice of bytes, and prepend it with a /// little-endian u64 to tell the payload's length. fn serialize_payload(cid: &ContractId, payload: &[u8]) -> Vec { - let ser_cid = cid.to_bytes(); + let ser_cid = serialize(cid); let payload_len = payload.len(); let mut out = Vec::with_capacity(ser_cid.len() + 8 + payload_len); out.extend_from_slice(&ser_cid); diff --git a/src/sdk/src/crypto/contract_id.rs b/src/sdk/src/crypto/contract_id.rs index 304c5718b..e286b14fa 100644 --- a/src/sdk/src/crypto/contract_id.rs +++ b/src/sdk/src/crypto/contract_id.rs @@ -16,9 +16,10 @@ * along with this program. If not, see . */ +use darkfi_serial::{SerialDecodable, SerialEncodable}; use pasta_curves::{group::ff::PrimeField, pallas}; -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)] pub struct ContractId(pallas::Base); impl ContractId { @@ -30,10 +31,6 @@ impl ContractId { self.0 } - pub fn to_bytes(&self) -> [u8; 32] { - self.0.to_repr() - } - pub fn from_bytes(x: [u8; 32]) -> Self { // FIXME: Handle Option Self(pallas::Base::from_repr(x).unwrap()) diff --git a/src/sdk/src/db.rs b/src/sdk/src/db.rs index fc4453d19..d4709d069 100644 --- a/src/sdk/src/db.rs +++ b/src/sdk/src/db.rs @@ -1,3 +1,5 @@ +use darkfi_serial::Encodable; + use super::{ crypto::ContractId, error::{ContractError, GenericResult}, @@ -15,13 +17,12 @@ type TxHandle = u32; pub fn db_init(contract_id: ContractId, db_name: &str) -> GenericResult { #[cfg(target_arch = "wasm32")] unsafe { - println!("sdk/src/db.rs:db_init() BEGIN"); - let ret = db_init_( - //contract_id.to_bytes().as_ptr(), - //32_u32, - db_name.as_ptr(), - db_name.len() as u32, - ); + let mut len = 0; + let mut buf = vec![]; + len += contract_id.encode(&mut buf)?; + len += db_name.to_string().encode(&mut buf)?; + + let ret = db_init_(buf.as_ptr(), len as u32); if ret < 0 { match ret { diff --git a/src/sdk/src/entrypoint.rs b/src/sdk/src/entrypoint.rs index 9ab99a121..200a8c40e 100644 --- a/src/sdk/src/entrypoint.rs +++ b/src/sdk/src/entrypoint.rs @@ -84,5 +84,8 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (ContractId, &'a [u8]) { offset += size_of::(); let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) }; + // FIXME: ContractId recovery should use proper serialization, and also + // there should be a Result<>; we can match on it in the macros + // above and return errors if needed. (ContractId::from_bytes(contract_id_slice.try_into().unwrap()), instruction_data) }