contract/money: Faucet cleanup

This removes clear inputs from Money::Transfer, and removes all faucet
references in the code.

Additionally, in src/validator/ we use the ValidatorConfig struct
directly, rather than using the ValidatorConfig::new() function.
This commit is contained in:
parazyd
2024-02-08 11:59:33 +01:00
parent 0957973ff6
commit 00aefdded5
16 changed files with 57 additions and 182 deletions

View File

@@ -223,14 +223,13 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
None
};
let config = ValidatorConfig::new(
blockchain_config.threshold,
blockchain_config.pow_target,
let config = ValidatorConfig {
finalization_threshold: blockchain_config.threshold,
pow_target: blockchain_config.pow_target,
pow_fixed_difficulty,
genesis_block,
vec![],
false, // TODO: Make configurable
);
verify_fees: false, // TODO: Make configurable
};
// Initialize validator
let validator = Validator::new(&sled_db, config).await?;

View File

@@ -85,14 +85,13 @@ impl Harness {
// Generate validators configuration
// NOTE: we are not using consensus constants here so we
// don't get circular dependencies.
let validator_config = ValidatorConfig::new(
3,
config.pow_target,
config.pow_fixed_difficulty.clone(),
let validator_config = ValidatorConfig {
finalization_threshold: 3,
pow_target: config.pow_target,
pow_fixed_difficulty: config.pow_fixed_difficulty.clone(),
genesis_block,
vec![],
verify_fees,
);
};
// Generate validators using pregenerated vks
let (_, vks) = vks::read_or_gen_vks_and_pks()?;
@@ -141,18 +140,11 @@ impl Harness {
let bob = &self.bob.validator;
alice
.validate_blockchain(
vec![],
self.config.pow_target,
self.config.pow_fixed_difficulty.clone(),
)
.validate_blockchain(self.config.pow_target, self.config.pow_fixed_difficulty.clone())
.await?;
bob.validate_blockchain(self.config.pow_target, self.config.pow_fixed_difficulty.clone())
.await?;
bob.validate_blockchain(
vec![],
self.config.pow_target,
self.config.pow_fixed_difficulty.clone(),
)
.await?;
let alice_blockchain_len = alice.blockchain.len();
assert_eq!(alice_blockchain_len, bob.blockchain.len());

View File

@@ -73,7 +73,7 @@ async fn sync_blocks_real(ex: Arc<Executor<'static>>) -> Result<()> {
// Verify node synced
let alice = &th.alice.validator;
let charlie = &charlie.validator;
charlie.validate_blockchain(vec![], pow_target, pow_fixed_difficulty).await?;
charlie.validate_blockchain(pow_target, pow_fixed_difficulty).await?;
assert_eq!(alice.blockchain.len(), charlie.blockchain.len());
// Thanks for reading

View File

@@ -245,7 +245,6 @@ impl Drk {
let debris = builder.build()?;
let full_params = MoneyTransferParamsV1 {
clear_inputs: vec![],
inputs: vec![partial.params.inputs[0].clone(), debris.params.inputs[0].clone()],
outputs: vec![partial.params.outputs[0].clone(), debris.params.outputs[0].clone()],
};

View File

@@ -129,8 +129,7 @@ impl SwapCallBuilder {
};
// Now we fill this with necessary stuff
let mut params =
MoneyTransferParamsV1 { clear_inputs: vec![], inputs: vec![], outputs: vec![] };
let mut params = MoneyTransferParamsV1 { inputs: vec![], outputs: vec![] };
// Create a new ephemeral secret key
let signature_secret = SecretKey::random(&mut OsRng);

View File

@@ -23,8 +23,7 @@ use darkfi::{
use darkfi_sdk::{
bridgetree,
crypto::{
note::AeadEncryptedNote, pasta_prelude::*, BaseBlind, Blind, MerkleNode, PublicKey,
ScalarBlind, SecretKey,
note::AeadEncryptedNote, pasta_prelude::*, MerkleNode, Nullifier, SecretKey, TokenId,
},
pasta::pallas,
};
@@ -34,7 +33,7 @@ use rand::rngs::OsRng;
use super::proof::{create_transfer_burn_proof, create_transfer_mint_proof};
use crate::{
client::{compute_remainder_blind, MoneyNote, OwnCoin},
model::{ClearInput, CoinAttributes, Input, MoneyTransferParamsV1, Nullifier, Output, TokenId},
model::{CoinAttributes, Input, MoneyTransferParamsV1, Output},
};
/// Struct holding necessary information to build a `Money::TransferV1` contract call.
@@ -78,27 +77,11 @@ impl TransferCallBuilder {
debug!("Building Money::TransferV1 contract call");
assert!(self.clear_inputs.len() + self.inputs.len() > 0);
let mut params =
MoneyTransferParamsV1 { clear_inputs: vec![], inputs: vec![], outputs: vec![] };
let mut params = MoneyTransferParamsV1 { inputs: vec![], outputs: vec![] };
let mut signature_secrets = vec![];
let mut proofs = vec![];
let token_blind = Blind::random(&mut OsRng);
debug!("Building clear inputs");
for input in self.clear_inputs {
signature_secrets.push(input.signature_secret);
let signature_public = PublicKey::from_secret(input.signature_secret);
let value_blind = Blind::random(&mut OsRng);
params.clear_inputs.push(ClearInput {
value: input.value,
token_id: input.token_id,
value_blind,
token_blind,
signature_public,
});
}
let token_blind = pallas::Base::random(&mut OsRng);
let mut input_blinds = vec![];
let mut output_blinds = vec![];
@@ -139,7 +122,7 @@ impl TransferCallBuilder {
for (i, output) in self.outputs.iter().enumerate() {
let value_blind = if i == self.outputs.len() - 1 {
compute_remainder_blind(&params.clear_inputs, &input_blinds, &output_blinds)
compute_remainder_blind(&[], &input_blinds, &output_blinds)
} else {
Blind::random(&mut OsRng)
};

View File

@@ -17,7 +17,7 @@
*/
use darkfi_sdk::{
crypto::{pasta_prelude::Field, ContractId, MerkleNode, MerkleTree, PublicKey},
crypto::{pasta_prelude::Field, ContractId, MerkleNode, MerkleTree},
dark_tree::DarkLeaf,
db::{db_init, db_lookup, db_set, zkas_db_set},
error::ContractResult,
@@ -34,8 +34,8 @@ use crate::{
MoneyTransferUpdateV1,
},
MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_DB_VERSION, MONEY_CONTRACT_FAUCET_PUBKEYS,
MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_TOKEN_FREEZE_TREE,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_DB_VERSION, MONEY_CONTRACT_INFO_TREE,
MONEY_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_TOKEN_FREEZE_TREE,
MONEY_CONTRACT_TOTAL_FEES_PAID,
};
@@ -105,11 +105,7 @@ darkfi_sdk::define_contract!(
/// We use this function to initialize all the necessary databases and prepare them
/// with initial data if necessary. This is also the place where we bundle the zkas
/// circuits that are to be used with functions provided by the contract.
fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
// The payload for now contains a vector of `PublicKey` used to
// whitelist faucets that can create clear inputs.
let faucet_pubkeys: Vec<PublicKey> = deserialize(ix)?;
fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
// zkas circuits can simply be embedded in the wasm and set up by using
// respective db functions. The special `zkas db` operations exist in
// order to be able to verify the circuits being bundled and enforcing
@@ -173,9 +169,6 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
}
};
// Whitelisted faucets
db_set(info_db, MONEY_CONTRACT_FAUCET_PUBKEYS, &serialize(&faucet_pubkeys))?;
// Update db version
db_set(info_db, MONEY_CONTRACT_DB_VERSION, &serialize(&env!("CARGO_PKG_VERSION")))?;

View File

@@ -58,12 +58,6 @@ pub(crate) fn money_otcswap_process_instruction_v1(
// every atomic swap looks the same on the network, therefore there is
// no special anonymity leak for different swaps that are being done,
// at least in the scope of this contract call.
if !params.clear_inputs.is_empty() {
msg!("[OtcSwapV1] Error: Clear inputs are not empty");
return Err(MoneyError::InvalidNumberOfInputs.into())
}
if params.inputs.len() != 2 {
msg!("[OtcSwapV1] Error: Expected 2 inputs");
return Err(MoneyError::InvalidNumberOfInputs.into())

View File

@@ -17,12 +17,9 @@
*/
use darkfi_sdk::{
crypto::{
pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, ContractId, FuncId, FuncRef,
MerkleNode, PublicKey,
},
crypto::{pasta_prelude::*, ContractId, FuncId, FuncRef, MerkleNode, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_get, db_lookup, db_set},
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle_add, msg,
pasta::pallas,
@@ -34,9 +31,8 @@ use crate::{
error::MoneyError,
model::{MoneyTransferParamsV1, MoneyTransferUpdateV1, DARK_TOKEN_ID},
MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_FAUCET_PUBKEYS, MONEY_CONTRACT_INFO_TREE,
MONEY_CONTRACT_LATEST_COIN_ROOT, MONEY_CONTRACT_NULLIFIERS_TREE,
MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
MONEY_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
};
/// `get_metadata` function for `Money::TransferV1`
@@ -53,11 +49,6 @@ pub(crate) fn money_transfer_get_metadata_v1(
// Public keys for the transaction signatures we have to verify
let mut signature_pubkeys: Vec<PublicKey> = vec![];
// Take all the pubkeys from any clear inputs
for input in &params.clear_inputs {
signature_pubkeys.push(input.signature_public);
}
// Calculate the spend hook
let spend_hook = match calls[call_idx as usize].parent_index {
Some(parent_idx) => {
@@ -124,7 +115,7 @@ pub(crate) fn money_transfer_process_instruction_v1(
let self_ = &calls[call_idx as usize];
let params: MoneyTransferParamsV1 = deserialize(&self_.data.data[1..])?;
if params.clear_inputs.len() + params.inputs.len() < 1 {
if params.inputs.is_empty() {
msg!("[TransferV1] Error: No inputs in the call");
return Err(MoneyError::TransferMissingInputs.into())
}
@@ -136,20 +127,10 @@ pub(crate) fn money_transfer_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)?;
// FIXME: Remove faucet references
// Grab faucet pubkeys. They're allowed to create clear inputs.
// Currently we use them for airdrops in the testnet.
let Some(faucet_pubkeys) = db_get(info_db, MONEY_CONTRACT_FAUCET_PUBKEYS)? else {
msg!("[TransferV1] Error: Missing faucet pubkeys from info db");
return Err(MoneyError::TransferMissingFaucetKeys.into())
};
let faucet_pubkeys: Vec<PublicKey> = deserialize(&faucet_pubkeys)?;
// Accumulator for the value commitments. We add inputs to it, and subtract
// outputs from it. For the commitments to be valid, the accumulator must
// be in its initial state after performing the arithmetics.
@@ -159,26 +140,6 @@ pub(crate) fn money_transfer_process_instruction_v1(
// Perform the actual state transition
// ===================================
// For clear inputs, we only allow the whitelisted faucet(s) to create them.
// Additionally, only DARK_TOKEN_ID is able to be here. For any arbitrary
// tokens, there is another functionality in this contract called `Mint` which
// allows users to mint their own tokens.
msg!("[TransferV1] Iterating over clear inputs");
for (i, input) in params.clear_inputs.iter().enumerate() {
if input.token_id != *DARK_TOKEN_ID {
msg!("[TransferV1] Error: Clear input {} used non-native token", i);
return Err(MoneyError::TransferClearInputNonNativeToken.into())
}
if !faucet_pubkeys.contains(&input.signature_public) {
msg!("[TransferV1] Error: Clear input {} used unauthorised pubkey", i);
return Err(MoneyError::TransferClearInputUnauthorised.into())
}
// Add this input to the value commitment accumulator
valcom_total += pedersen_commitment_u64(input.value, input.value_blind);
}
// For anonymous inputs, we must also gather all the new nullifiers
// that are introduced.
let mut new_nullifiers = Vec::with_capacity(params.inputs.len());
@@ -207,6 +168,7 @@ pub(crate) fn money_transfer_process_instruction_v1(
// Newly created coins for this call are in the outputs. Here we gather them,
// and we also check that they haven't existed before.
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))?
{
@@ -231,13 +193,9 @@ pub(crate) fn money_transfer_process_instruction_v1(
// transferred. For exchanging we use another functionality of this
// contract called `OtcSwap`.
let tokcom = params.outputs[0].token_commit;
let mut failed_tokcom = params.inputs.iter().any(|x| x.token_commit != tokcom);
failed_tokcom = failed_tokcom || params.outputs.iter().any(|x| x.token_commit != tokcom);
failed_tokcom = failed_tokcom ||
params
.clear_inputs
.iter()
.any(|x| poseidon_hash([x.token_id.inner(), x.token_blind.inner()]) != tokcom);
let failed_tokcom = params.inputs.iter().any(|x| x.token_commit != tokcom) ||
params.outputs.iter().any(|x| x.token_commit != tokcom);
if failed_tokcom {
msg!("[TransferV1] Error: Token commitments do not match");

View File

@@ -28,9 +28,6 @@ pub enum MoneyError {
#[error("Missing outputs in transfer call")]
TransferMissingOutputs,
#[error("Missing faucet pubkeys from info db")]
TransferMissingFaucetKeys,
#[error("Clear input used non-native token")]
TransferClearInputNonNativeToken,
@@ -116,7 +113,7 @@ impl From<MoneyError> for ContractError {
match e {
MoneyError::TransferMissingInputs => Self::Custom(1),
MoneyError::TransferMissingOutputs => Self::Custom(2),
MoneyError::TransferMissingFaucetKeys => Self::Custom(3),
// 3 was removed
MoneyError::TransferClearInputNonNativeToken => Self::Custom(4),
MoneyError::TransferClearInputUnauthorised => Self::Custom(5),
MoneyError::TransferMerkleRootNotFound => Self::Custom(6),

View File

@@ -79,7 +79,6 @@ pub const MONEY_CONTRACT_TOKEN_FREEZE_TREE: &str = "token_freezes";
pub const MONEY_CONTRACT_DB_VERSION: &[u8] = b"db_version";
pub const MONEY_CONTRACT_COIN_MERKLE_TREE: &[u8] = b"coin_tree";
pub const MONEY_CONTRACT_LATEST_COIN_ROOT: &[u8] = b"last_root";
pub const MONEY_CONTRACT_FAUCET_PUBKEYS: &[u8] = b"faucet_pubkeys";
pub const MONEY_CONTRACT_TOTAL_FEES_PAID: &[u8] = b"total_fees_paid";
/// zkas fee circuit namespace

View File

@@ -210,8 +210,6 @@ pub struct MoneyFeeUpdateV1 {
// ANCHOR: money-params
/// Parameters for `Money::Transfer` and `Money::OtcSwap`
pub struct MoneyTransferParamsV1 {
/// Clear inputs
pub clear_inputs: Vec<ClearInput>,
/// Anonymous inputs
pub inputs: Vec<Input>,
/// Anonymous outputs

View File

@@ -35,8 +35,8 @@ use darkfi_money_contract::{
use darkfi_sdk::{
bridgetree,
crypto::{
note::AeadEncryptedNote, pasta_prelude::Field, poseidon_hash, BaseBlind, Blind, ContractId,
Keypair, MerkleNode, MerkleTree, PublicKey, SecretKey,
note::AeadEncryptedNote, pasta_prelude::Field, poseidon_hash, ContractId, Keypair,
MerkleNode, MerkleTree, Nullifier, SecretKey,
},
pasta::pallas,
};
@@ -129,7 +129,6 @@ impl Wallet {
pub async fn new(
keypair: Keypair,
genesis_block: &BlockInfo,
faucet_pubkeys: &[PublicKey],
vks: &Vks,
verify_fees: bool,
) -> Result<Self> {
@@ -141,14 +140,13 @@ impl Wallet {
// Generate validator
// NOTE: we are not using consensus constants here so we
// don't get circular dependencies.
let config = ValidatorConfig::new(
3,
90,
Some(BigUint::from(1_u8)),
genesis_block.clone(),
faucet_pubkeys.to_vec(),
let config = ValidatorConfig {
finalization_threshold: 3,
pow_target: 90,
pow_fixed_difficulty: Some(BigUint::from(1_u8)),
genesis_block: genesis_block.clone(),
verify_fees,
);
};
let validator = Validator::new(&sled_db, config).await?;
// Create necessary Merkle trees for tracking
@@ -213,32 +211,27 @@ impl TestHarness {
}
let faucet_kp = Keypair::random(&mut rng);
let faucet_pubkeys = vec![faucet_kp.public];
let faucet =
Wallet::new(faucet_kp, &genesis_block, &faucet_pubkeys, &vks, verify_fees).await?;
let faucet = Wallet::new(faucet_kp, &genesis_block, &vks, verify_fees).await?;
holders.insert(Holder::Faucet, faucet);
let alice_kp = Keypair::random(&mut rng);
let alice =
Wallet::new(alice_kp, &genesis_block, &faucet_pubkeys, &vks, verify_fees).await?;
let alice = Wallet::new(alice_kp, &genesis_block, &vks, verify_fees).await?;
holders.insert(Holder::Alice, alice);
let bob_kp = Keypair::random(&mut rng);
let bob = Wallet::new(bob_kp, &genesis_block, &faucet_pubkeys, &vks, verify_fees).await?;
let bob = Wallet::new(bob_kp, &genesis_block, &vks, verify_fees).await?;
holders.insert(Holder::Bob, bob);
let charlie_kp = Keypair::random(&mut rng);
let charlie =
Wallet::new(charlie_kp, &genesis_block, &faucet_pubkeys, &vks, verify_fees).await?;
let charlie = Wallet::new(charlie_kp, &genesis_block, &vks, verify_fees).await?;
holders.insert(Holder::Charlie, charlie);
let rachel_kp = Keypair::random(&mut rng);
let rachel =
Wallet::new(rachel_kp, &genesis_block, &faucet_pubkeys, &vks, verify_fees).await?;
let rachel = Wallet::new(rachel_kp, &genesis_block, &vks, verify_fees).await?;
holders.insert(Holder::Rachel, rachel);
let dao_kp = Keypair::random(&mut rng);
let dao = Wallet::new(dao_kp, &genesis_block, &faucet_pubkeys, &vks, verify_fees).await?;
let dao = Wallet::new(dao_kp, &genesis_block, &vks, verify_fees).await?;
holders.insert(Holder::Dao, dao);
// Build benchmarks map

View File

@@ -123,7 +123,6 @@ impl TestHarness {
// Then second holder combines the halves
let swap_full_params = MoneyTransferParamsV1 {
clear_inputs: vec![],
inputs: vec![debris0.params.inputs[0].clone(), debris1.params.inputs[0].clone()],
outputs: vec![debris0.params.outputs[0].clone(), debris1.params.outputs[0].clone()],
};

View File

@@ -18,7 +18,6 @@
use std::sync::Arc;
use darkfi_sdk::crypto::{MerkleTree, PublicKey};
use darkfi_serial::serialize_async;
use log::{debug, error, info, warn};
use num_bigint::BigUint;
@@ -67,32 +66,10 @@ pub struct ValidatorConfig {
pub pow_fixed_difficulty: Option<BigUint>,
/// Genesis block
pub genesis_block: BlockInfo,
/// Whitelisted faucet pubkeys (testnet stuff)
pub faucet_pubkeys: Vec<PublicKey>,
/// Flag to enable tx fee verification
pub verify_fees: bool,
}
impl ValidatorConfig {
pub fn new(
finalization_threshold: usize,
pow_target: usize,
pow_fixed_difficulty: Option<BigUint>,
genesis_block: BlockInfo,
faucet_pubkeys: Vec<PublicKey>,
verify_fees: bool,
) -> Self {
Self {
finalization_threshold,
pow_target,
pow_fixed_difficulty,
genesis_block,
faucet_pubkeys,
verify_fees,
}
}
}
/// Atomic pointer to validator.
pub type ValidatorPtr = Arc<Validator>;
@@ -119,7 +96,7 @@ impl Validator {
let overlay = BlockchainOverlay::new(&blockchain)?;
// Deploy native wasm contracts
deploy_native_contracts(&overlay, &config.faucet_pubkeys).await?;
deploy_native_contracts(&overlay).await?;
// Add genesis block if blockchain is empty
if blockchain.genesis().is_err() {
@@ -536,7 +513,6 @@ impl Validator {
/// Be careful as this will try to load everything in memory.
pub async fn validate_blockchain(
&self,
faucet_pubkeys: Vec<PublicKey>,
pow_target: usize,
pow_fixed_difficulty: Option<BigUint>,
) -> Result<()> {
@@ -559,7 +535,7 @@ impl Validator {
let mut module = PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty)?;
// Deploy native wasm contracts
deploy_native_contracts(&overlay, &faucet_pubkeys).await?;
deploy_native_contracts(&overlay).await?;
// Validate genesis block
verify_genesis_block(&overlay, previous).await?;

View File

@@ -18,12 +18,12 @@
use darkfi_sdk::{
crypto::{
ecvrf::VrfProof, pasta_prelude::PrimeField, PublicKey, DAO_CONTRACT_ID,
DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID,
ecvrf::VrfProof, pasta_prelude::PrimeField, DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID,
MONEY_CONTRACT_ID,
},
pasta::{group::ff::FromUniformBytes, pallas},
};
use darkfi_serial::{serialize_async, AsyncDecodable};
use darkfi_serial::AsyncDecodable;
use log::info;
use smol::io::Cursor;
@@ -44,15 +44,11 @@ use crate::{
/// touch anything, or just potentially update the db schemas or whatever
/// is necessary. This logic should be handled in the init function of
/// the actual contract, so make sure the native contracts handle this well.
pub async fn deploy_native_contracts(
overlay: &BlockchainOverlayPtr,
faucet_pubkeys: &Vec<PublicKey>,
) -> Result<()> {
pub async fn deploy_native_contracts(overlay: &BlockchainOverlayPtr) -> Result<()> {
info!(target: "validator::utils::deploy_native_contracts", "Deploying native WASM contracts");
// The faucet pubkeys are pubkeys which are allowed to create clear inputs
// in the Money contract.
let money_contract_deploy_payload = serialize_async(faucet_pubkeys).await;
// The Money contract uses an empty payload to deploy itself.
let money_contract_deploy_payload = vec![];
// The DAO contract uses an empty payload to deploy itself.
let dao_contract_deploy_payload = vec![];