SDK: move all WASM runtime fns into wasm/ submod

This commit is contained in:
zero
2024-04-03 10:43:11 +02:00
parent 83549ccbf0
commit b9cc42cdf4
26 changed files with 277 additions and 253 deletions

View File

@@ -19,11 +19,10 @@
use darkfi_sdk::{
crypto::{pasta_prelude::*, ContractId, PublicKey},
dark_tree::DarkLeaf,
db::{db_del, db_get, db_lookup},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -115,8 +114,8 @@ pub(crate) fn dao_exec_process_instruction(
///////////////////////////////////////////////////
// Get the ProposalVote from DAO state
let proposal_db = db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let Some(data) = db_get(proposal_db, &serialize(&params.proposal_bulla))? else {
let proposal_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let Some(data) = wasm::db::db_get(proposal_db, &serialize(&params.proposal_bulla))? else {
msg!("[Dao::Exec] Error: Proposal {:?} not found", params.proposal_bulla);
return Err(DaoError::ProposalNonexistent.into())
};
@@ -140,8 +139,8 @@ pub(crate) fn dao_exec_process_instruction(
/// `process_update` function for `Dao::Exec`
pub(crate) fn dao_exec_process_update(cid: ContractId, update: DaoExecUpdate) -> ContractResult {
// Remove proposal from db
let proposal_vote_db = db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
db_del(proposal_vote_db, &serialize(&update.proposal_bulla))?;
let proposal_vote_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
wasm::db::db_del(proposal_vote_db, &serialize(&update.proposal_bulla))?;
Ok(())
}

View File

@@ -19,12 +19,10 @@
use darkfi_sdk::{
crypto::{ContractId, MerkleNode, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle::merkle_add,
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -76,8 +74,8 @@ pub(crate) fn dao_mint_process_instruction(
let params: DaoMintParams = deserialize(&self_.data[1..])?;
// Check the DAO bulla doesn't already exist
let bulla_db = db_lookup(cid, DAO_CONTRACT_DB_DAO_BULLAS)?;
if db_contains_key(bulla_db, &serialize(&params.dao_bulla.inner()))? {
let bulla_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_DAO_BULLAS)?;
if wasm::db::db_contains_key(bulla_db, &serialize(&params.dao_bulla.inner()))? {
msg!("[DAO::Mint] Error: DAO already exists {}", params.dao_bulla);
return Err(DaoError::DaoAlreadyExists.into())
}
@@ -94,14 +92,14 @@ pub(crate) fn dao_mint_process_instruction(
/// `process_update` function for `Dao::Mint`
pub(crate) fn dao_mint_process_update(cid: ContractId, update: DaoMintUpdate) -> ContractResult {
// Grab all db handles we want to work on
let info_db = db_lookup(cid, DAO_CONTRACT_DB_INFO_TREE)?;
let bulla_db = db_lookup(cid, DAO_CONTRACT_DB_DAO_BULLAS)?;
let roots_db = db_lookup(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS)?;
let info_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_INFO_TREE)?;
let bulla_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_DAO_BULLAS)?;
let roots_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS)?;
db_set(bulla_db, &serialize(&update.dao_bulla), &[])?;
wasm::db::db_set(bulla_db, &serialize(&update.dao_bulla), &[])?;
let dao = vec![MerkleNode::from(update.dao_bulla.inner())];
merkle_add(
wasm::merkle::merkle_add(
info_db,
roots_db,
DAO_CONTRACT_KEY_LATEST_DAO_ROOT,

View File

@@ -21,10 +21,8 @@ use std::io::Cursor;
use darkfi_sdk::{
crypto::{ContractId, MerkleTree},
dark_tree::DarkLeaf,
db::{db_get, db_init, db_lookup, db_set, zkas_db_set},
error::ContractResult,
util::{get_call_index, set_return_data},
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Decodable, Encodable, WriteExt};
@@ -70,22 +68,22 @@ darkfi_sdk::define_contract!(
fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
// The zkas circuits can simply be embedded in the wasm and set up by
// the initialization.
zkas_db_set(&include_bytes!("../../proof/mint.zk.bin")[..])?;
zkas_db_set(&include_bytes!("../../proof/propose-input.zk.bin")[..])?;
zkas_db_set(&include_bytes!("../../proof/propose-main.zk.bin")[..])?;
zkas_db_set(&include_bytes!("../../proof/vote-input.zk.bin")[..])?;
zkas_db_set(&include_bytes!("../../proof/vote-main.zk.bin")[..])?;
zkas_db_set(&include_bytes!("../../proof/exec.zk.bin")[..])?;
zkas_db_set(&include_bytes!("../../proof/auth-money-transfer.zk.bin")[..])?;
wasm::db::zkas_db_set(&include_bytes!("../../proof/mint.zk.bin")[..])?;
wasm::db::zkas_db_set(&include_bytes!("../../proof/propose-input.zk.bin")[..])?;
wasm::db::zkas_db_set(&include_bytes!("../../proof/propose-main.zk.bin")[..])?;
wasm::db::zkas_db_set(&include_bytes!("../../proof/vote-input.zk.bin")[..])?;
wasm::db::zkas_db_set(&include_bytes!("../../proof/vote-main.zk.bin")[..])?;
wasm::db::zkas_db_set(&include_bytes!("../../proof/exec.zk.bin")[..])?;
wasm::db::zkas_db_set(&include_bytes!("../../proof/auth-money-transfer.zk.bin")[..])?;
// Set up db for general info
let dao_info_db = match db_lookup(cid, DAO_CONTRACT_DB_INFO_TREE) {
let dao_info_db = match wasm::db::db_lookup(cid, DAO_CONTRACT_DB_INFO_TREE) {
Ok(v) => v,
Err(_) => db_init(cid, DAO_CONTRACT_DB_INFO_TREE)?,
Err(_) => wasm::db::db_init(cid, DAO_CONTRACT_DB_INFO_TREE)?,
};
// Set up the entries in the header table
match db_get(dao_info_db, DAO_CONTRACT_KEY_DAO_MERKLE_TREE)? {
match wasm::db::db_get(dao_info_db, DAO_CONTRACT_KEY_DAO_MERKLE_TREE)? {
Some(bytes) => {
// We found some bytes, try to deserialize into a tree.
// For now, if this doesn't work, we bail.
@@ -101,38 +99,42 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
tree_data.write_u32(0)?;
tree.encode(&mut tree_data)?;
db_set(dao_info_db, DAO_CONTRACT_KEY_DAO_MERKLE_TREE, &tree_data)?;
wasm::db::db_set(dao_info_db, DAO_CONTRACT_KEY_DAO_MERKLE_TREE, &tree_data)?;
}
}
// Set up db to avoid double creating DAOs
let _ = match db_lookup(cid, DAO_CONTRACT_DB_DAO_BULLAS) {
let _ = match wasm::db::db_lookup(cid, DAO_CONTRACT_DB_DAO_BULLAS) {
Ok(v) => v,
Err(_) => db_init(cid, DAO_CONTRACT_DB_DAO_BULLAS)?,
Err(_) => wasm::db::db_init(cid, DAO_CONTRACT_DB_DAO_BULLAS)?,
};
// Set up db for DAO bulla Merkle roots
let _ = match db_lookup(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS) {
let _ = match wasm::db::db_lookup(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS) {
Ok(v) => v,
Err(_) => db_init(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS)?,
Err(_) => wasm::db::db_init(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS)?,
};
// Set up db for proposal votes
// k: ProposalBulla
// v: (BlindAggregateVote, bool) (the bool marks if the proposal is finished)
let _ = match db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS) {
let _ = match wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS) {
Ok(v) => v,
Err(_) => db_init(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?,
Err(_) => wasm::db::db_init(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?,
};
// TODO: These nullifiers should exist per-proposal
let _ = match db_lookup(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS) {
let _ = match wasm::db::db_lookup(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS) {
Ok(v) => v,
Err(_) => db_init(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS)?,
Err(_) => wasm::db::db_init(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS)?,
};
// Update db version
db_set(dao_info_db, DAO_CONTRACT_KEY_DB_VERSION, &serialize(&env!("CARGO_PKG_VERSION")))?;
wasm::db::db_set(
dao_info_db,
DAO_CONTRACT_KEY_DB_VERSION,
&serialize(&env!("CARGO_PKG_VERSION")),
)?;
Ok(())
}
@@ -141,7 +143,7 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
/// for verifying signatures and ZK proofs. The payload given here are all the
/// contract calls in the transaction.
fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
let call_idx = get_call_index();
let call_idx = wasm::util::get_call_index();
let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
let self_ = &calls[call_idx as usize].data;
let func = DaoFunction::try_from(self_.data[0])?;
@@ -154,13 +156,13 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
DaoFunction::AuthMoneyTransfer => dao_authxfer_get_metadata(cid, call_idx, calls)?,
};
set_return_data(&metadata)
wasm::util::set_return_data(&metadata)
}
/// This function verifies a state transition and produces a state update
/// if everything is successful.
fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
let call_idx = get_call_index();
let call_idx = wasm::util::get_call_index();
let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
let self_ = &calls[call_idx as usize].data;
let func = DaoFunction::try_from(self_.data[0])?;
@@ -173,7 +175,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
DaoFunction::AuthMoneyTransfer => dao_authxfer_process_instruction(cid, call_idx, calls)?,
};
set_return_data(&update_data)
wasm::util::set_return_data(&update_data)
}
/// This function attempts to write a given state update provided the previous

View File

@@ -23,13 +23,11 @@ use darkfi_money_contract::{
use darkfi_sdk::{
crypto::{contract_id::MONEY_CONTRACT_ID, pasta_prelude::*, ContractId, MerkleNode, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_get, db_lookup, db_set},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
tx::TransactionHash,
util::{get_tx_location, get_verifying_block_height},
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -87,7 +85,7 @@ pub(crate) fn dao_propose_get_metadata(
}
// ANCHOR: dao-blockwindow-example-usage
let current_day = blockwindow(get_verifying_block_height());
let current_day = blockwindow(wasm::util::get_verifying_block_height());
// ANCHOR_END: dao-blockwindow-example-usage
let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
@@ -120,12 +118,14 @@ pub(crate) fn dao_propose_process_instruction(
let self_ = &calls[call_idx as usize].data;
let params: DaoProposeParams = deserialize(&self_.data[1..])?;
let coin_roots_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let null_roots_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let null_roots_db =
wasm::db::db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
for input in &params.inputs {
// Check the Merkle roots for the input coins are valid
let Some(coin_root_data) = db_get(coin_roots_db, &serialize(&input.merkle_coin_root))?
let Some(coin_root_data) =
wasm::db::db_get(coin_roots_db, &serialize(&input.merkle_coin_root))?
else {
msg!(
"[Dao::Propose] Error: Invalid input Merkle root: {:?}",
@@ -135,7 +135,9 @@ pub(crate) fn dao_propose_process_instruction(
};
// Check the SMT roots for the input nullifiers are valid
let Some(null_root_data) = db_get(null_roots_db, &serialize(&input.smt_null_root))? else {
let Some(null_root_data) =
wasm::db::db_get(null_roots_db, &serialize(&input.smt_null_root))?
else {
msg!("[Dao::Propose] Error: Invalid input SMT root: {:?}", input.smt_null_root);
return Err(DaoError::InvalidInputMerkleRoot.into())
};
@@ -151,8 +153,8 @@ pub(crate) fn dao_propose_process_instruction(
let tx_hash_data: [u8; 32] = coin_root_data[0..32].try_into().unwrap();
let tx_hash = TransactionHash(tx_hash_data);
// Get block_height where tx_hash was confirmed
let (tx_height, _) = get_tx_location(&tx_hash)?;
let current_height = get_verifying_block_height();
let (tx_height, _) = wasm::util::get_tx_location(&tx_hash)?;
let current_height = wasm::util::get_verifying_block_height();
if current_height - tx_height > PROPOSAL_SNAPSHOT_CUTOFF_LIMIT {
msg!("[Dao::Propose] Error: Snapshot is too old. Current height: {}, snapshot height: {}",
current_height, tx_height);
@@ -161,28 +163,28 @@ pub(crate) fn dao_propose_process_instruction(
}
// Is the DAO bulla generated in the ZK proof valid
let dao_roots_db = db_lookup(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS)?;
if !db_contains_key(dao_roots_db, &serialize(&params.dao_merkle_root))? {
let dao_roots_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS)?;
if !wasm::db::db_contains_key(dao_roots_db, &serialize(&params.dao_merkle_root))? {
msg!("[Dao::Propose] Error: Invalid DAO Merkle root: {}", params.dao_merkle_root);
return Err(DaoError::InvalidDaoMerkleRoot.into())
}
// Make sure the proposal doesn't already exist
let proposal_db = db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
if db_contains_key(proposal_db, &serialize(&params.proposal_bulla))? {
let proposal_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
if wasm::db::db_contains_key(proposal_db, &serialize(&params.proposal_bulla))? {
msg!("[Dao::Propose] Error: Proposal already exists: {:?}", params.proposal_bulla);
return Err(DaoError::ProposalAlreadyExists.into())
}
// Snapshot the latest Money merkle tree
let money_info_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_INFO_TREE)?;
let Some(data) = db_get(money_info_db, MONEY_CONTRACT_LATEST_COIN_ROOT)? else {
let money_info_db = wasm::db::db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_INFO_TREE)?;
let Some(data) = wasm::db::db_get(money_info_db, MONEY_CONTRACT_LATEST_COIN_ROOT)? else {
msg!("[Dao::Propose] Error: Failed to fetch latest Money Merkle root");
return Err(ContractError::Internal)
};
let snapshot_coins: MerkleNode = deserialize(&data)?;
let Some(data) = db_get(money_info_db, MONEY_CONTRACT_LATEST_NULLIFIER_ROOT)? else {
let Some(data) = wasm::db::db_get(money_info_db, MONEY_CONTRACT_LATEST_NULLIFIER_ROOT)? else {
msg!("[Dao::Propose] Error: Failed to fetch latest Money SMT root");
return Err(ContractError::Internal)
};
@@ -209,7 +211,7 @@ pub(crate) fn dao_propose_process_update(
update: DaoProposeUpdate,
) -> ContractResult {
// Grab all db handles we want to work on
let proposal_vote_db = db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let proposal_vote_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
// Build the proposal metadata
let proposal_metadata = DaoProposalMetadata {
@@ -219,7 +221,11 @@ pub(crate) fn dao_propose_process_update(
};
// Set the new proposal in the db
db_set(proposal_vote_db, &serialize(&update.proposal_bulla), &serialize(&proposal_metadata))?;
wasm::db::db_set(
proposal_vote_db,
&serialize(&update.proposal_bulla),
&serialize(&proposal_metadata),
)?;
Ok(())
}

View File

@@ -19,12 +19,10 @@
use darkfi_sdk::{
crypto::{pasta_prelude::*, ContractId, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_get, db_lookup, db_set},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
util::get_verifying_block_height,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -58,8 +56,9 @@ pub(crate) fn dao_vote_get_metadata(
// Commitment calculation for all votes
let mut all_vote_commit = pallas::Point::identity();
let proposal_votes_db = db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let Some(data) = db_get(proposal_votes_db, &serialize(&params.proposal_bulla))? else {
let proposal_votes_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let Some(data) = wasm::db::db_get(proposal_votes_db, &serialize(&params.proposal_bulla))?
else {
msg!("[Dao::Vote] Error: Proposal doesn't exist: {:?}", params.proposal_bulla);
return Err(DaoError::ProposalNonexistent.into())
};
@@ -90,7 +89,7 @@ pub(crate) fn dao_vote_get_metadata(
));
}
let current_day = blockwindow(get_verifying_block_height());
let current_day = blockwindow(wasm::util::get_verifying_block_height());
let yes_vote_commit_coords = params.yes_vote_commit.to_affine().coordinates().unwrap();
let all_vote_commit_coords = all_vote_commit.to_affine().coordinates().unwrap();
@@ -133,8 +132,9 @@ pub(crate) fn dao_vote_process_instruction(
let params: DaoVoteParams = deserialize(&self_.data[1..])?;
// Check proposal bulla exists
let proposal_votes_db = db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let Some(data) = db_get(proposal_votes_db, &serialize(&params.proposal_bulla))? else {
let proposal_votes_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let Some(data) = wasm::db::db_get(proposal_votes_db, &serialize(&params.proposal_bulla))?
else {
msg!("[Dao::Vote] Error: Proposal doesn't exist: {:?}", params.proposal_bulla);
return Err(DaoError::ProposalNonexistent.into())
};
@@ -143,7 +143,7 @@ pub(crate) fn dao_vote_process_instruction(
let mut proposal_metadata: DaoProposalMetadata = deserialize(&data)?;
// Check the Merkle root and nullifiers for the input coins are valid
let dao_vote_nullifier_db = db_lookup(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS)?;
let dao_vote_nullifier_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS)?;
let mut vote_nullifiers = vec![];
for input in &params.inputs {
@@ -152,7 +152,7 @@ pub(crate) fn dao_vote_process_instruction(
let null_key = serialize(&(params.proposal_bulla, input.vote_nullifier));
if vote_nullifiers.contains(&input.vote_nullifier) ||
db_contains_key(dao_vote_nullifier_db, &null_key)?
wasm::db::db_contains_key(dao_vote_nullifier_db, &null_key)?
{
msg!("[Dao::Vote] Error: Attempted double vote");
return Err(DaoError::DoubleVote.into())
@@ -177,24 +177,24 @@ pub(crate) fn dao_vote_process_instruction(
/// `process_update` function for `Dao::Vote`
pub(crate) fn dao_vote_process_update(cid: ContractId, update: DaoVoteUpdate) -> ContractResult {
// Grab all db handles we want to work on
let proposal_vote_db = db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
let proposal_vote_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_PROPOSAL_BULLAS)?;
// Perform this code:
// total_yes_vote_commit += update.yes_vote_commit
// total_all_vote_commit += update.all_vote_commit
db_set(
wasm::db::db_set(
proposal_vote_db,
&serialize(&update.proposal_bulla),
&serialize(&update.proposal_metadata),
)?;
// We are essentially doing: vote_nulls.append(update_nulls)
let dao_vote_nulls_db = db_lookup(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS)?;
let dao_vote_nulls_db = wasm::db::db_lookup(cid, DAO_CONTRACT_DB_VOTE_NULLIFIERS)?;
for nullifier in update.vote_nullifiers {
// Uniqueness is enforced for (proposal_bulla, nullifier)
let key = serialize(&(update.proposal_bulla, nullifier));
db_set(dao_vote_nulls_db, &key, &[])?;
wasm::db::db_set(dao_vote_nulls_db, &key, &[])?;
}
Ok(())

View File

@@ -19,11 +19,9 @@
use darkfi_sdk::{
crypto::{pasta_prelude::Field, smt::EMPTY_NODES_FP, ContractId, MerkleNode, MerkleTree},
dark_tree::DarkLeaf,
db::{db_init, db_lookup, db_set, zkas_db_set},
error::ContractResult,
pasta::pallas,
util::{get_call_index, set_return_data},
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -118,12 +116,12 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
let token_mint_v1_bincode = include_bytes!("../proof/token_mint_v1.zk.bin");
let token_frz_v1_bincode = include_bytes!("../proof/token_freeze_v1.zk.bin");
// For that, we use `zkas_db_set` and pass in the bincode.
zkas_db_set(&fee_v1_bincode[..])?;
zkas_db_set(&mint_v1_bincode[..])?;
zkas_db_set(&burn_v1_bincode[..])?;
zkas_db_set(&token_mint_v1_bincode[..])?;
zkas_db_set(&token_frz_v1_bincode[..])?;
// For that, we use `wasm::db::zkas_wasm::db::db_set` and pass in the bincode.
wasm::db::zkas_db_set(&fee_v1_bincode[..])?;
wasm::db::zkas_db_set(&mint_v1_bincode[..])?;
wasm::db::zkas_db_set(&burn_v1_bincode[..])?;
wasm::db::zkas_db_set(&token_mint_v1_bincode[..])?;
wasm::db::zkas_db_set(&token_frz_v1_bincode[..])?;
// FIXME: Get tx hash from env
let tx_hash = [0u8; 32];
@@ -138,41 +136,41 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
// Set up a database tree to hold Merkle roots of all coin trees
// k=root_hash:32, v=(tx_hash:32, call_idx: 2)
if db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE).is_err() {
let db_coin_roots = db_init(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
db_set(db_coin_roots, &serialize(&EMPTY_COINS_TREE_ROOT), &roots_value_data)?;
if wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE).is_err() {
let db_coin_roots = wasm::db::db_init(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
wasm::db::db_set(db_coin_roots, &serialize(&EMPTY_COINS_TREE_ROOT), &roots_value_data)?;
}
// Set up a database tree to hold Merkle roots of all nullifier trees
// k=root_hash:32, v=(tx_hash:32, call_idx: 2)
if db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE).is_err() {
let db_null_roots = db_init(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
db_set(db_null_roots, &serialize(&EMPTY_NODES_FP[0]), &roots_value_data)?;
if wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE).is_err() {
let db_null_roots = wasm::db::db_init(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
wasm::db::db_set(db_null_roots, &serialize(&EMPTY_NODES_FP[0]), &roots_value_data)?;
}
// Set up a database tree to hold all coins ever seen
// k=Coin, v=[]
if db_lookup(cid, MONEY_CONTRACT_COINS_TREE).is_err() {
db_init(cid, MONEY_CONTRACT_COINS_TREE)?;
if wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE).is_err() {
wasm::db::db_init(cid, MONEY_CONTRACT_COINS_TREE)?;
}
// Set up a database tree to hold nullifiers of all spent coins
// k=Nullifier, v=[]
if db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE).is_err() {
db_init(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
if wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE).is_err() {
wasm::db::db_init(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
}
// Set up a database tree to hold the set of frozen token mints
// k=TokenId, v=[]
if db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE).is_err() {
db_init(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
if wasm::db::db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE).is_err() {
wasm::db::db_init(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
}
// Set up a database tree for arbitrary data
let info_db = match db_lookup(cid, MONEY_CONTRACT_INFO_TREE) {
let info_db = match wasm::db::db_lookup(cid, MONEY_CONTRACT_INFO_TREE) {
Ok(v) => v,
Err(_) => {
let info_db = db_init(cid, MONEY_CONTRACT_INFO_TREE)?;
let info_db = wasm::db::db_init(cid, MONEY_CONTRACT_INFO_TREE)?;
// Create the incrementalmerkletree for seen coins and initialize
// it with a "fake" coin that can be used for dummy inputs.
@@ -181,23 +179,31 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
let mut coin_tree_data = vec![];
coin_tree_data.write_u32(0)?;
coin_tree.encode(&mut coin_tree_data)?;
db_set(info_db, MONEY_CONTRACT_COIN_MERKLE_TREE, &coin_tree_data)?;
wasm::db::db_set(info_db, MONEY_CONTRACT_COIN_MERKLE_TREE, &coin_tree_data)?;
// Initialize the paid fees accumulator
db_set(info_db, MONEY_CONTRACT_TOTAL_FEES_PAID, &serialize(&0_u64))?;
wasm::db::db_set(info_db, MONEY_CONTRACT_TOTAL_FEES_PAID, &serialize(&0_u64))?;
// Initialize coins and nulls latest root field
// This will result in exhausted gas so we use a precalculated value:
//let root = coin_tree.root(0).unwrap();
db_set(info_db, MONEY_CONTRACT_LATEST_COIN_ROOT, &serialize(&EMPTY_COINS_TREE_ROOT))?;
db_set(info_db, MONEY_CONTRACT_LATEST_NULLIFIER_ROOT, &serialize(&EMPTY_NODES_FP[0]))?;
wasm::db::db_set(
info_db,
MONEY_CONTRACT_LATEST_COIN_ROOT,
&serialize(&EMPTY_COINS_TREE_ROOT),
)?;
wasm::db::db_set(
info_db,
MONEY_CONTRACT_LATEST_NULLIFIER_ROOT,
&serialize(&EMPTY_NODES_FP[0]),
)?;
info_db
}
};
// Update db version
db_set(info_db, MONEY_CONTRACT_DB_VERSION, &serialize(&env!("CARGO_PKG_VERSION")))?;
wasm::db::db_set(info_db, MONEY_CONTRACT_DB_VERSION, &serialize(&env!("CARGO_PKG_VERSION")))?;
Ok(())
}
@@ -206,7 +212,7 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
/// for verifying signatures and zk proofs. The payload given here are all the
/// contract calls in the transaction.
fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
let call_idx = get_call_index();
let call_idx = wasm::util::get_call_index();
let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
let self_ = &calls[call_idx as usize].data;
let func = MoneyFunction::try_from(self_.data[0])?;
@@ -216,7 +222,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
MoneyFunction::TransferV1 => {
// We pass everything into the correct function, and it will return
// the metadata for us, which we can then copy into the host with
// the `set_return_data` function. On the host, this metadata will
// the `wasm::util::set_return_data` function. On the host, this metadata will
// be used to do external verification (zk proofs, and signatures).
money_transfer_get_metadata_v1(cid, call_idx, calls)?
}
@@ -230,14 +236,14 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
}
};
set_return_data(&metadata)
wasm::util::set_return_data(&metadata)
}
/// This function verifies a state transition and produces a state update
/// if everything is successful. This step should happen **after** the host
/// has successfully verified the metadata from `get_metadata()`.
fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
let call_idx = get_call_index();
let call_idx = wasm::util::get_call_index();
let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
let self_ = &calls[call_idx as usize].data;
let func = MoneyFunction::try_from(self_.data[0])?;
@@ -247,7 +253,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
MoneyFunction::TransferV1 => {
// Again, we pass everything into the correct function.
// If it executes successfully, we'll get a state update
// which we can copy into the host using `set_return_data`.
// which we can copy into the host using `wasm::util::set_return_data`.
// This update can then be written with `process_update()`
// if everything is in order.
money_transfer_process_instruction_v1(cid, call_idx, calls)?
@@ -270,7 +276,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
}
};
set_return_data(&update_data)
wasm::util::set_return_data(&update_data)
}
/// This function attempts to write a given state update provided the previous steps

View File

@@ -19,11 +19,10 @@
use darkfi_sdk::{
crypto::{pasta_prelude::*, ContractId, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -85,10 +84,10 @@ pub(crate) fn money_auth_token_mint_process_instruction_v1(
let params: MoneyAuthTokenMintParamsV1 = deserialize(&self_.data[1..])?;
// We have to check if the token mint is frozen.
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
let token_freeze_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
// Check that the mint is not frozen
if db_contains_key(token_freeze_db, &serialize(&params.token_id))? {
if wasm::db::db_contains_key(token_freeze_db, &serialize(&params.token_id))? {
msg!("[MintV1] Error: Token mint for {} is frozen", params.token_id);
return Err(MoneyError::TokenMintFrozen.into())
}

View File

@@ -27,12 +27,10 @@ use darkfi_sdk::{
ContractId, MerkleNode, PublicKey,
},
dark_tree::DarkLeaf,
db::{db_contains_key, db_get, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle::{merkle_add, sparse_merkle_insert_batch},
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -110,10 +108,10 @@ pub(crate) fn money_fee_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let info_db = db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let info_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
// Fees can only be paid using the native token, so we'll compare
// the token commitments with this one:
@@ -135,7 +133,7 @@ pub(crate) fn money_fee_process_instruction_v1(
// The Merkle root is used to know whether this is a coin that
// existed in a previous state.
if !db_contains_key(coin_roots_db, &serialize(&params.input.merkle_root))? {
if !wasm::db::db_contains_key(coin_roots_db, &serialize(&params.input.merkle_root))? {
msg!("[FeeV1] Error: Input Merkle root not found in previous state");
return Err(MoneyError::CoinMerkleRootNotFound.into())
}
@@ -152,7 +150,7 @@ pub(crate) fn money_fee_process_instruction_v1(
}
// The new coin should not exist
if db_contains_key(coins_db, &serialize(&params.output.coin))? {
if wasm::db::db_contains_key(coins_db, &serialize(&params.output.coin))? {
msg!("[FeeV1] Error: Duplicate coin found");
return Err(MoneyError::DuplicateCoin.into())
}
@@ -181,7 +179,7 @@ pub(crate) fn money_fee_process_instruction_v1(
// Accumulate the paid fee
let mut paid_fee: u64 =
deserialize(&db_get(info_db, MONEY_CONTRACT_TOTAL_FEES_PAID)?.unwrap())?;
deserialize(&wasm::db::db_get(info_db, MONEY_CONTRACT_TOTAL_FEES_PAID)?.unwrap())?;
paid_fee += fee;
// At this point the state transition has passed, so we create a state update.
@@ -203,15 +201,15 @@ pub(crate) fn money_fee_process_update_v1(
update: MoneyFeeUpdateV1,
) -> ContractResult {
// Grab all necessary db handles for where we want to write
let info_db = db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
let info_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
db_set(info_db, MONEY_CONTRACT_TOTAL_FEES_PAID, &serialize(&update.fee))?;
wasm::db::db_set(info_db, MONEY_CONTRACT_TOTAL_FEES_PAID, &serialize(&update.fee))?;
sparse_merkle_insert_batch(
wasm::merkle::sparse_merkle_insert_batch(
info_db,
nullifiers_db,
nullifier_roots_db,
@@ -219,9 +217,9 @@ pub(crate) fn money_fee_process_update_v1(
&[update.nullifier.inner()],
)?;
db_set(coins_db, &serialize(&update.coin), &[])?;
wasm::db::db_set(coins_db, &serialize(&update.coin), &[])?;
merkle_add(
wasm::merkle::merkle_add(
info_db,
coin_roots_db,
MONEY_CONTRACT_LATEST_COIN_ROOT,

View File

@@ -19,13 +19,10 @@
use darkfi_sdk::{
crypto::{pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, ContractId, MerkleNode},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle::{merkle_add, sparse_merkle_insert_batch},
msg,
pasta::pallas,
util::get_verifying_block_height,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -83,7 +80,7 @@ pub(crate) fn money_genesis_mint_process_instruction_v1(
let params: MoneyGenesisMintParamsV1 = deserialize(&self_.data[1..])?;
// Verify this contract call is verified against genesis block(0).
let verifying_block_height = get_verifying_block_height();
let verifying_block_height = wasm::util::get_verifying_block_height();
if verifying_block_height != 0 {
msg!(
"[GenesisMintV1] Error: Call is executed for block {}, not genesis",
@@ -100,10 +97,10 @@ pub(crate) fn money_genesis_mint_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
// Check that the coin from the output hasn't existed before.
if db_contains_key(coins_db, &serialize(&params.output.coin))? {
if wasm::db::db_contains_key(coins_db, &serialize(&params.output.coin))? {
msg!("[GenesisMintV1] Error: Duplicate coin in output");
return Err(MoneyError::DuplicateCoin.into())
}
@@ -140,15 +137,15 @@ pub(crate) fn money_genesis_mint_process_update_v1(
update: MoneyGenesisMintUpdateV1,
) -> ContractResult {
// Grab all db handles we want to work on
let info_db = db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
let info_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
// This will just make a snapshot to match the coins one
msg!("[GenesisMintV1] Updating nullifiers snapshot");
sparse_merkle_insert_batch(
wasm::merkle::sparse_merkle_insert_batch(
info_db,
nullifiers_db,
nullifier_roots_db,
@@ -157,11 +154,11 @@ pub(crate) fn money_genesis_mint_process_update_v1(
)?;
msg!("[GenesisMintV1] Adding new coin to the set");
db_set(coins_db, &serialize(&update.coin), &[])?;
wasm::db::db_set(coins_db, &serialize(&update.coin), &[])?;
msg!("[GenesisMintV1] Adding new coin to the Merkle tree");
let coins = vec![MerkleNode::from(update.coin.inner())];
merkle_add(
wasm::merkle::merkle_add(
info_db,
coin_roots_db,
MONEY_CONTRACT_LATEST_COIN_ROOT,

View File

@@ -20,13 +20,10 @@ use darkfi_sdk::{
blockchain::expected_reward,
crypto::{pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, ContractId, MerkleNode},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle::{merkle_add, sparse_merkle_insert_batch},
msg,
pasta::pallas,
util::{get_last_block_height, get_verifying_block_height},
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -84,14 +81,14 @@ pub(crate) fn money_pow_reward_process_instruction_v1(
let params: MoneyPoWRewardParamsV1 = deserialize(&self_.data[1..])?;
// Verify this contract call is not verified against genesis block
let verifying_block_height = get_verifying_block_height();
let verifying_block_height = wasm::util::get_verifying_block_height();
if verifying_block_height == 0 {
msg!("[PoWRewardV1] Error: Call is executed for genesis block");
return Err(MoneyError::PoWRewardCallOnGenesisBlock.into())
}
// Verify this contract call is verified against next block height
let Some(last_block_height) = get_last_block_height()? else {
let Some(last_block_height) = wasm::util::get_last_block_height()? else {
msg!("[PoWRewardV1] Error: Could not receive last block height from db");
return Err(MoneyError::PoWRewardRetrieveLastBlockHeightError.into())
};
@@ -125,10 +122,10 @@ pub(crate) fn money_pow_reward_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
// Check that the coin from the output hasn't existed before.
if db_contains_key(coins_db, &serialize(&params.output.coin))? {
if wasm::db::db_contains_key(coins_db, &serialize(&params.output.coin))? {
msg!("[PoWRewardV1] Error: Duplicate coin in output");
return Err(MoneyError::DuplicateCoin.into())
}
@@ -165,15 +162,15 @@ pub(crate) fn money_pow_reward_process_update_v1(
update: MoneyPoWRewardUpdateV1,
) -> ContractResult {
// Grab all db handles we want to work on
let info_db = db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
let info_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
// This will just make a snapshot to match the coins one
msg!("[PowRewardV1] Updating nullifiers snapshot");
sparse_merkle_insert_batch(
wasm::merkle::sparse_merkle_insert_batch(
info_db,
nullifiers_db,
nullifier_roots_db,
@@ -182,11 +179,11 @@ pub(crate) fn money_pow_reward_process_update_v1(
)?;
msg!("[PoWRewardV1] Adding new coin to the set");
db_set(coins_db, &serialize(&update.coin), &[])?;
wasm::db::db_set(coins_db, &serialize(&update.coin), &[])?;
msg!("[PoWRewardV1] Adding new coin to the Merkle tree");
let coins = vec![MerkleNode::from(update.coin.inner())];
merkle_add(
wasm::merkle::merkle_add(
info_db,
coin_roots_db,
MONEY_CONTRACT_LATEST_COIN_ROOT,

View File

@@ -26,11 +26,10 @@ use darkfi_sdk::{
ContractId,
},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -78,9 +77,9 @@ pub(crate) fn money_otcswap_process_instruction_v1(
}
// Grab the db handles we'll be using here
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
// We expect two new nullifiers and two new coins
let mut new_nullifiers = Vec::with_capacity(2);
@@ -126,7 +125,7 @@ pub(crate) fn money_otcswap_process_instruction_v1(
// The Merkle root is used to know whether this coin
// has existed in a previous state.
if !db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
if !wasm::db::db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
msg!("[OtcSwapV1] Error: Merkle root not found in previous state (input {})", i);
return Err(MoneyError::SwapMerkleRootNotFound.into())
}
@@ -144,7 +143,8 @@ pub(crate) fn money_otcswap_process_instruction_v1(
// Newly created coins for this call are in the outputs
for (i, output) in params.outputs.iter().enumerate() {
if new_coins.contains(&output.coin) || db_contains_key(coins_db, &serialize(&output.coin))?
if new_coins.contains(&output.coin) ||
wasm::db::db_contains_key(coins_db, &serialize(&output.coin))?
{
msg!("[OtcSwapV1] Error: Duplicate coin found in output {}", i);
return Err(MoneyError::DuplicateCoin.into())

View File

@@ -19,11 +19,10 @@
use darkfi_sdk::{
crypto::{ContractId, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -74,10 +73,10 @@ pub(crate) fn money_token_freeze_process_instruction_v1(
let params: MoneyTokenFreezeParamsV1 = deserialize(&self_.data[1..])?;
// We just check if the mint was already frozen beforehand
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
let token_freeze_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
// Check that the mint is not frozen
if db_contains_key(token_freeze_db, &serialize(&params.token_id))? {
if wasm::db::db_contains_key(token_freeze_db, &serialize(&params.token_id))? {
msg!("[MintV1] Error: Token mint for {} is frozen", params.token_id);
return Err(MoneyError::TokenMintFrozen.into())
}
@@ -96,9 +95,9 @@ pub(crate) fn money_token_freeze_process_update_v1(
cid: ContractId,
update: MoneyTokenFreezeUpdateV1,
) -> ContractResult {
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
let token_freeze_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
msg!("[MintV1] Freezing mint for token {}", update.token_id);
db_set(token_freeze_db, &serialize(&update.token_id), &[])?;
wasm::db::db_set(token_freeze_db, &serialize(&update.token_id), &[])?;
Ok(())
}

View File

@@ -19,12 +19,10 @@
use darkfi_sdk::{
crypto::{ContractId, FuncRef, MerkleNode, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle::{merkle_add, sparse_merkle_insert_batch},
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -83,10 +81,10 @@ pub(crate) fn money_token_mint_process_instruction_v1(
// We have to check if the token mint is frozen, and if by some chance
// the minted coin has existed already.
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
// Check that the coin from the output hasn't existed before
if db_contains_key(coins_db, &serialize(&params.coin))? {
if wasm::db::db_contains_key(coins_db, &serialize(&params.coin))? {
msg!("[MintV1] Error: Duplicate coin in output");
return Err(MoneyError::DuplicateCoin.into())
}
@@ -106,15 +104,15 @@ pub(crate) fn money_token_mint_process_update_v1(
update: MoneyTokenMintUpdateV1,
) -> ContractResult {
// Grab all db handles we want to work on
let info_db = db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
let info_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
// This will just make a snapshot to match the coins one
msg!("[MintV1] Updating nullifiers snapshot");
sparse_merkle_insert_batch(
wasm::merkle::sparse_merkle_insert_batch(
info_db,
nullifiers_db,
nullifier_roots_db,
@@ -123,11 +121,11 @@ pub(crate) fn money_token_mint_process_update_v1(
)?;
msg!("[MintV1] Adding new coin to the set");
db_set(coins_db, &serialize(&update.coin), &[])?;
wasm::db::db_set(coins_db, &serialize(&update.coin), &[])?;
msg!("[MintV1] Adding new coin to the Merkle tree");
let coins = vec![MerkleNode::from(update.coin.inner())];
merkle_add(
wasm::merkle::merkle_add(
info_db,
coin_roots_db,
MONEY_CONTRACT_LATEST_COIN_ROOT,

View File

@@ -26,12 +26,10 @@ use darkfi_sdk::{
ContractId, FuncId, FuncRef, MerkleNode, PublicKey,
},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle::{merkle_add, sparse_merkle_insert_batch},
msg,
pasta::pallas,
ContractCall,
wasm, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
@@ -137,9 +135,9 @@ pub(crate) fn money_transfer_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
// Accumulator for the value commitments. We add inputs to it, and subtract
// outputs from it. For the commitments to be valid, the accumulator must
@@ -162,7 +160,7 @@ pub(crate) fn money_transfer_process_instruction_v1(
for (i, input) in params.inputs.iter().enumerate() {
// The Merkle root is used to know whether this is a coin that
// existed in a previous state.
if !db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
if !wasm::db::db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
msg!("[TransferV1] Error: Merkle root not found in previous state (input {})", i);
return Err(MoneyError::TransferMerkleRootNotFound.into())
}
@@ -185,7 +183,8 @@ pub(crate) fn money_transfer_process_instruction_v1(
let mut new_coins = Vec::with_capacity(params.outputs.len());
msg!("[TransferV1] Iterating over anonymous outputs");
for (i, output) in params.outputs.iter().enumerate() {
if new_coins.contains(&output.coin) || db_contains_key(coins_db, &serialize(&output.coin))?
if new_coins.contains(&output.coin) ||
wasm::db::db_contains_key(coins_db, &serialize(&output.coin))?
{
msg!("[TransferV1] Error: Duplicate coin found in output {}", i);
return Err(MoneyError::DuplicateCoin.into())
@@ -232,14 +231,14 @@ pub(crate) fn money_transfer_process_update_v1(
update: MoneyTransferUpdateV1,
) -> ContractResult {
// Grab all necessary db handles for where we want to write
let info_db = db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
let info_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
let nullifier_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE)?;
msg!("[TransferV1] Adding new nullifiers to the set");
sparse_merkle_insert_batch(
wasm::merkle::sparse_merkle_insert_batch(
info_db,
nullifiers_db,
nullifier_roots_db,
@@ -249,12 +248,12 @@ pub(crate) fn money_transfer_process_update_v1(
msg!("[TransferV1] Adding new coins to the set");
for coin in &update.coins {
db_set(coins_db, &serialize(coin), &[])?;
wasm::db::db_set(coins_db, &serialize(coin), &[])?;
}
msg!("[TransferV1] Adding new coins to the Merkle tree");
let coins: Vec<_> = update.coins.iter().map(|x| MerkleNode::from(x.inner())).collect();
merkle_add(
wasm::merkle::merkle_add(
info_db,
coin_roots_db,
MONEY_CONTRACT_LATEST_COIN_ROOT,

View File

@@ -18,7 +18,7 @@
use std::io::Cursor;
use darkfi_sdk::crypto::ContractId;
use darkfi_sdk::{crypto::ContractId, wasm};
use darkfi_serial::{deserialize, serialize, Decodable};
use log::{debug, error, info};
use wasmer::{FunctionEnvMut, WasmPtr};
@@ -448,7 +448,7 @@ pub(crate) fn db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u3
return darkfi_sdk::error::DB_SET_FAILED
}
darkfi_sdk::entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}
/// Remove a key from the database.
@@ -558,7 +558,7 @@ pub(crate) fn db_del(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u3
return darkfi_sdk::error::DB_DEL_FAILED
}
darkfi_sdk::entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}
/// Reads a value by key from the key-value store.
@@ -910,7 +910,7 @@ pub(crate) fn zkas_db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_le
"[WASM] [{}] zkas_db_set(): Existing zkas bincode is the same. Skipping.",
cid,
);
return darkfi_sdk::entrypoint::SUCCESS
return wasm::entrypoint::SUCCESS
}
}
}
@@ -977,5 +977,5 @@ pub(crate) fn zkas_db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_le
// Subtract used gas. Here we count the bytes written into the db.
env.subtract_gas(&mut store, (key.len() + value.len()) as u64);
darkfi_sdk::entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}

View File

@@ -20,7 +20,8 @@ use std::io::Cursor;
use darkfi_sdk::{
crypto::{MerkleNode, MerkleTree},
AsHex,
hex::AsHex,
wasm,
};
use darkfi_serial::{serialize, Decodable, Encodable, WriteExt};
use log::{debug, error};
@@ -312,5 +313,5 @@ pub(crate) fn merkle_add(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u3
let spent_gas = return_data.len() + tree_data.len() + (new_roots.len() * 32);
env.subtract_gas(&mut store, spent_gas as u64);
darkfi_sdk::entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}

View File

@@ -18,9 +18,12 @@
use std::io::Cursor;
use darkfi_sdk::crypto::{
pasta_prelude::*,
smt::{PoseidonFp, SparseMerkleTree, StorageAdapter, EMPTY_NODES_FP, SMT_FP_DEPTH},
use darkfi_sdk::{
crypto::{
pasta_prelude::*,
smt::{PoseidonFp, SparseMerkleTree, StorageAdapter, EMPTY_NODES_FP, SMT_FP_DEPTH},
},
wasm,
};
use darkfi_serial::{serialize, Decodable, Encodable};
use halo2_proofs::pasta::pallas;
@@ -281,5 +284,5 @@ pub(crate) fn sparse_merkle_insert_batch(
let spent_gas = leaves_len * 32;
env.subtract_gas(&mut store, spent_gas as u64);
darkfi_sdk::entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}

View File

@@ -18,6 +18,7 @@
use std::io::Cursor;
use darkfi_sdk::wasm;
use darkfi_serial::Decodable;
use log::{debug, error};
use wasmer::{FunctionEnvMut, WasmPtr};
@@ -80,7 +81,7 @@ pub(crate) fn set_return_data(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, le
}
env.contract_return_data.set(Some(return_data));
darkfi_sdk::entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}
/// Appends a new object to the [`Env`] objects store.
@@ -183,7 +184,7 @@ pub(crate) fn get_object_bytes(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, i
return darkfi_sdk::error::INTERNAL_ERROR
};
darkfi_sdk::entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}
/// Returns the size (number of bytes) of an object in the object store

View File

@@ -21,7 +21,7 @@ use std::{
sync::Arc,
};
use darkfi_sdk::{crypto::ContractId, entrypoint, tx::TransactionHash, AsHex};
use darkfi_sdk::{crypto::ContractId, tx::TransactionHash, wasm, AsHex};
use darkfi_serial::serialize;
use log::{debug, error, info};
use wasmer::{
@@ -405,7 +405,7 @@ impl Runtime {
// Return a success value if there is no return value from
// the contract.
debug!(target: "runtime::vm_runtime", "Contract has no return value (expected)");
entrypoint::SUCCESS
wasm::entrypoint::SUCCESS
}
_ => {
match ret[0] {
@@ -424,7 +424,7 @@ impl Runtime {
// corresponds to a successful contract call; in this case, we return the contract's
// result data. Otherwise, map the integer return value to a [`ContractError`].
match retval {
entrypoint::SUCCESS => Ok(retdata),
wasm::entrypoint::SUCCESS => Ok(retdata),
_ => {
let err = darkfi_sdk::error::ContractError::from(retval);
error!(target: "runtime::vm_runtime", "[WASM] Contract returned: {:?}", err);

View File

@@ -21,9 +21,9 @@ use num_bigint::BigUint;
use super::{PoseidonFp, SparseMerkleTree, StorageAdapter, SMT_FP_DEPTH};
use crate::{
crypto::pasta_prelude::*,
db::{db_get, db_set, DbHandle},
msg,
pasta::pallas,
wasm::db::{db_get, db_set, DbHandle},
};
pub type SmtWasmFp = SparseMerkleTree<

View File

@@ -24,15 +24,12 @@ pub use pasta_curves as pasta;
/// Blockchain structures
pub mod blockchain;
/// Database functions
pub mod db;
/// DarkTree structures
pub mod dark_tree;
/// Contract deployment utilities
pub mod deploy;
/// Entrypoint used for the wasm binaries
pub mod entrypoint;
/// Error handling
pub mod error;
pub use error::{ContractError, GenericResult};
@@ -47,15 +44,10 @@ pub mod log;
/// Crypto-related definitions
pub mod crypto;
/// Merkle
pub mod merkle;
/// Transaction structure
pub mod tx;
pub use tx::ContractCall;
/// Utility functions
pub mod util;
/// DarkTree structures
pub mod dark_tree;
#[macro_use]
/// WASM API functions
pub mod wasm;

View File

@@ -18,10 +18,10 @@
use darkfi_serial::Encodable;
use super::{
use crate::{
crypto::ContractId,
error::{ContractError, GenericResult},
util::parse_ret,
wasm,
};
pub type DbHandle = u32;
@@ -78,7 +78,7 @@ pub fn db_get(db_handle: DbHandle, key: &[u8]) -> GenericResult<Option<Vec<u8>>>
len += key.to_vec().encode(&mut buf)?;
let ret = unsafe { db_get_(buf.as_ptr(), len as u32) };
parse_ret(ret)
wasm::util::parse_ret(ret)
}
/// Everyone can call this. Checks if a key is contained in the key-value store.
@@ -123,7 +123,7 @@ pub fn db_set(db_handle: DbHandle, key: &[u8], value: &[u8]) -> GenericResult<()
let ret = db_set_(buf.as_ptr(), len as u32);
if ret != crate::entrypoint::SUCCESS {
if ret != wasm::entrypoint::SUCCESS {
return Err(ContractError::from(ret))
}
@@ -146,7 +146,7 @@ pub fn db_del(db_handle: DbHandle, key: &[u8]) -> GenericResult<()> {
let ret = db_del_(buf.as_ptr(), len as u32);
if ret != crate::entrypoint::SUCCESS {
if ret != wasm::entrypoint::SUCCESS {
return Err(ContractError::from(ret))
}
@@ -163,7 +163,7 @@ pub fn zkas_db_set(bincode: &[u8]) -> GenericResult<()> {
let ret = zkas_db_set_(buf.as_ptr(), len as u32);
if ret != crate::entrypoint::SUCCESS {
if ret != wasm::entrypoint::SUCCESS {
return Err(ContractError::from(ret))
}

View File

@@ -34,37 +34,37 @@ macro_rules! define_contract {
/// # Safety
#[no_mangle]
pub unsafe extern "C" fn __initialize(input: *mut u8) -> i64 {
let (contract_id, instruction_data) = $crate::entrypoint::deserialize(input);
let (contract_id, instruction_data) = $crate::wasm::entrypoint::deserialize(input);
match $init_func(contract_id, &instruction_data) {
Ok(()) => $crate::entrypoint::SUCCESS,
Ok(()) => $crate::wasm::entrypoint::SUCCESS,
Err(e) => e.into(),
}
}
#[no_mangle]
pub unsafe extern "C" fn __entrypoint(input: *mut u8) -> i64 {
let (contract_id, instruction_data) = $crate::entrypoint::deserialize(input);
let (contract_id, instruction_data) = $crate::wasm::entrypoint::deserialize(input);
match $exec_func(contract_id, &instruction_data) {
Ok(()) => $crate::entrypoint::SUCCESS,
Ok(()) => $crate::wasm::entrypoint::SUCCESS,
Err(e) => e.into(),
}
}
#[no_mangle]
pub unsafe extern "C" fn __update(input: *mut u8) -> i64 {
let (contract_id, update_data) = $crate::entrypoint::deserialize(input);
let (contract_id, update_data) = $crate::wasm::entrypoint::deserialize(input);
match $apply_func(contract_id, &update_data) {
Ok(()) => $crate::entrypoint::SUCCESS,
Ok(()) => $crate::wasm::entrypoint::SUCCESS,
Err(e) => e.into(),
}
}
#[no_mangle]
pub unsafe extern "C" fn __metadata(input: *mut u8) -> i64 {
let (contract_id, instruction_data) = $crate::entrypoint::deserialize(input);
let (contract_id, instruction_data) = $crate::wasm::entrypoint::deserialize(input);
match $metadata_func(contract_id, &instruction_data) {
Ok(()) => $crate::entrypoint::SUCCESS,
Ok(()) => $crate::wasm::entrypoint::SUCCESS,
Err(e) => e.into(),
}
}

View File

@@ -18,11 +18,11 @@
use darkfi_serial::Encodable;
use super::{
use crate::{
crypto::MerkleNode,
db::DbHandle,
error::{ContractError, GenericResult},
pasta::pallas,
wasm::db::DbHandle,
};
/// Add given elements into a Merkle tree.

29
src/sdk/src/wasm/mod.rs Normal file
View File

@@ -0,0 +1,29 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2024 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/// Database functions
pub mod db;
/// Entrypoint used for the wasm binaries
pub mod entrypoint;
/// Merkle
pub mod merkle;
/// Utility functions
pub mod util;

View File

@@ -19,7 +19,7 @@
use darkfi_serial::{Decodable, Encodable};
use std::io::Cursor;
use super::{
use crate::{
error::{ContractError, GenericResult},
tx::TransactionHash,
};