Skip to content

Commit

Permalink
Merge pull request #2357 from dusk-network/wallet-core-deployments
Browse files Browse the repository at this point in the history
wallet-core: add deployment transactions
  • Loading branch information
ureeves authored Sep 12, 2024
2 parents b700b42 + d9ca75f commit 60c81f9
Show file tree
Hide file tree
Showing 5 changed files with 420 additions and 6 deletions.
2 changes: 1 addition & 1 deletion execution-core/src/transfer/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ impl ContractCall {
#[archive_attr(derive(CheckBytes))]
/// Holds bytes of bytecode and its hash.
pub struct ContractBytecode {
/// Hash of the bytecode bytes.
/// Blake3 hash of the bytecode bytes.
pub hash: [u8; 32],
/// Bytecode bytes.
pub bytes: Vec<u8>,
Expand Down
206 changes: 206 additions & 0 deletions rusk/tests/services/multi_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const BLOCK_GAS_LIMIT: u64 = 24_000_000;
const GAS_LIMIT: u64 = 12_000_000; // Lowest value for a transfer
const INITIAL_BALANCE: u64 = 10_000_000_000;

const BOB_BYTECODE: &[u8] = include_bytes!(
"../../../target/dusk/wasm32-unknown-unknown/release/bob.wasm"
);

// Creates the Rusk initial state for the tests below
fn initial_state<P: AsRef<Path>>(dir: P) -> Result<Rusk> {
let snapshot =
Expand Down Expand Up @@ -175,6 +179,167 @@ fn wallet_transfer(
);
}

/// Executes three different transactions in the same block, expecting only two
/// to be included due to exceeding the block gas limit. The last of the
/// transactions is a contract deployment, and is expected to deploy that
/// contract, but then be reverted.
fn wallet_transfer_deploy(
rusk: &Rusk,
wallet: &wallet::Wallet<TestStore, TestStateClient>,
amount: u64,
) {
// Generate a receiver pk
let receiver = wallet
.phoenix_public_key(3)
.expect("Failed to get public key");

let mut rng = StdRng::seed_from_u64(0xdead);

let initial_balance_0 = wallet
.get_balance(0)
.expect("Failed to get the balance")
.value;
let initial_balance_1 = wallet
.get_balance(1)
.expect("Failed to get the balance")
.value;
let initial_balance_2 = wallet
.get_balance(2)
.expect("Failed to get the balance")
.value;

// Check the senders initial balance is correct
assert_eq!(
initial_balance_0, INITIAL_BALANCE,
"Wrong initial balance for the sender"
);
assert_eq!(
initial_balance_1, INITIAL_BALANCE,
"Wrong initial balance for the sender"
);
assert_eq!(
initial_balance_2, INITIAL_BALANCE,
"Wrong initial balance for the sender"
);

// Check the receiver initial balance is zero
assert_eq!(
wallet
.get_balance(3)
.expect("Failed to get the balance")
.value,
0,
"Wrong initial balance for the receiver"
);

let mut txs = Vec::with_capacity(3);

for i in 0..2 {
let tx = wallet
.phoenix_transfer(&mut rng, i, &receiver, amount, GAS_LIMIT, 1)
.expect("Failed to transfer");
txs.push(tx);
}

let init_args = Vec::new();
let owner = wallet
.account_public_key(0)
.expect("Gettitng public key should work");

let tx = wallet
.phoenix_deployment(
&mut rng,
2,
BOB_BYTECODE,
&owner,
init_args,
0,
GAS_LIMIT,
1,
)
.expect("Failed to deploy");
txs.push(tx);

let expected = ExecuteResult {
discarded: 0,
executed: 2,
};

generator_procedure(
rusk,
&txs[..],
BLOCK_HEIGHT,
BLOCK_GAS_LIMIT,
vec![],
Some(expected),
)
.expect("generator procedure to succeed");

// Check the receiver's balance is changed accordingly
assert_eq!(
wallet
.get_balance(3)
.expect("Failed to get the balance")
.value,
2 * amount,
"Wrong resulting balance for the receiver"
);

let final_balance_0 = wallet
.get_balance(0)
.expect("Failed to get the balance")
.value;
let gas_limit_0 = txs[0].gas_limit();
let gas_price_0 = txs[0].gas_price();
let fee_0 = gas_limit_0 * gas_price_0;

let final_balance_1 = wallet
.get_balance(1)
.expect("Failed to get the balance")
.value;
let gas_limit_1 = txs[1].gas_limit();
let gas_price_1 = txs[1].gas_price();
let fee_1 = gas_limit_1 * gas_price_1;

assert!(
initial_balance_0 - amount - fee_0 <= final_balance_0,
"Final sender balance {} should be greater or equal than {}",
final_balance_0,
initial_balance_0 - amount - fee_0
);

assert!(
initial_balance_0 - amount >= final_balance_0,
"Final sender balance {} should be lesser or equal than {}",
final_balance_0,
initial_balance_0 - amount
);

assert!(
initial_balance_1 - amount - fee_1 <= final_balance_1,
"Final sender balance {} should be greater or equal than {}",
final_balance_1,
initial_balance_1 - amount - fee_1
);

assert!(
initial_balance_1 - amount >= final_balance_1,
"Final sender balance {} should be lesser or equal than {}",
final_balance_1,
initial_balance_1 - amount
);

// Check the discarded transaction didn't change the balance
assert_eq!(
wallet
.get_balance(2)
.expect("Failed to get the balance")
.value,
initial_balance_2,
"Wrong resulting balance for discarded TX sender"
);
}

#[tokio::test(flavor = "multi_thread")]
pub async fn multi_transfer() -> Result<()> {
// Setup the logger
Expand Down Expand Up @@ -215,3 +380,44 @@ pub async fn multi_transfer() -> Result<()> {

Ok(())
}

#[tokio::test(flavor = "multi_thread")]
pub async fn multi_transfer_deploy() -> Result<()> {
// Setup the logger
logger();

let tmp = tempdir().expect("Should be able to create temporary directory");
let rusk = initial_state(&tmp)?;

let cache = Arc::new(RwLock::new(HashMap::new()));

// Create a wallet
let wallet = wallet::Wallet::new(
TestStore,
TestStateClient {
rusk: rusk.clone(),
cache,
},
);

let original_root = rusk.state_root();

info!("Original Root: {:?}", hex::encode(original_root));

wallet_transfer_deploy(&rusk, &wallet, 1_000);

// Check the state's root is changed from the original one
let new_root = rusk.state_root();
info!(
"New root after the 1st transfer: {:?}",
hex::encode(new_root)
);
assert_ne!(original_root, new_root, "Root should have changed");

// let recv = kadcast_recv.try_recv();
// let (_, _, h) = recv.expect("Transaction has not been locally
// propagated"); assert_eq!(h, 0, "Transaction locally propagated with
// wrong height");

Ok(())
}
91 changes: 89 additions & 2 deletions test-wallet/src/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ use wallet_core::{
keys::{derive_bls_sk, derive_phoenix_sk},
phoenix_balance,
transaction::{
moonlight_stake, moonlight_stake_reward, moonlight_to_phoenix,
moonlight_unstake, phoenix as phoenix_transaction, phoenix_stake,
moonlight_deployment, moonlight_stake, moonlight_stake_reward,
moonlight_to_phoenix, moonlight_unstake,
phoenix as phoenix_transaction, phoenix_deployment, phoenix_stake,
phoenix_stake_reward, phoenix_to_moonlight, phoenix_unstake,
},
BalanceInfo,
Expand Down Expand Up @@ -647,6 +648,50 @@ where
Ok(tx)
}

/// Deploy a contract using Phoenix to pay for gas.
pub fn phoenix_deployment<Rng: RngCore + CryptoRng>(
&self,
rng: &mut Rng,
sender_index: u8,
bytecode: impl Into<Vec<u8>>,
owner: &BlsPublicKey,
init_args: Vec<u8>,
nonce: u64,
gas_limit: u64,
gas_price: u64,
) -> Result<Transaction, Error<S, SC>> {
let mut phoenix_sender_sk = self.phoenix_secret_key(sender_index)?;

let inputs = self.input_notes_openings_nullifiers(
&phoenix_sender_sk,
gas_limit * gas_price,
)?;

let root = self.state.fetch_root().map_err(Error::from_state_err)?;

let chain_id =
self.state.fetch_chain_id().map_err(Error::from_state_err)?;

let tx = phoenix_deployment(
rng,
&phoenix_sender_sk,
inputs,
root,
bytecode,
owner,
init_args,
nonce,
gas_limit,
gas_price,
chain_id,
&LocalProver,
)?;

phoenix_sender_sk.zeroize();

Ok(tx)
}

/// Transfer Dusk from one account to another using moonlight.
pub fn moonlight_transfer(
&self,
Expand Down Expand Up @@ -898,6 +943,48 @@ where
Ok(tx)
}

/// Deploy a contract using Moonlight to pay for gas.
pub fn moonlight_deployment(
&self,
sender_index: u8,
bytecode: impl Into<Vec<u8>>,
owner: &BlsPublicKey,
init_args: Vec<u8>,
gas_limit: u64,
gas_price: u64,
deploy_nonce: u64,
) -> Result<Transaction, Error<S, SC>> {
let mut sender_sk = self.account_secret_key(sender_index)?;
let sender_pk = self.account_public_key(sender_index)?;

let chain_id =
self.state.fetch_chain_id().map_err(Error::from_state_err)?;

let moonlight_current_nonce = self
.state
.fetch_account(&sender_pk)
.map_err(Error::from_state_err)?
.nonce;

let moonlight_nonce = moonlight_current_nonce + 1;

let tx = moonlight_deployment(
&sender_sk,
bytecode,
owner,
init_args,
gas_limit,
gas_price,
moonlight_nonce,
deploy_nonce,
chain_id,
)?;

sender_sk.zeroize();

Ok(tx)
}

/// Gets the balance of a key.
pub fn get_balance(
&self,
Expand Down
1 change: 1 addition & 0 deletions wallet-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dusk-bytes = "0.1"
bytecheck = { version = "0.6", default-features = false }
zeroize = { version = "1", default-features = false, features = ["derive"] }
rand_chacha = { version = "0.3", default-features = false }
blake3 = { version = "1", default-features = false }
sha2 = { version = "0.10", default-features = false }
rand = { version = "0.8", default-features = false }
ff = { version = "0.13", default-features = false }
Expand Down
Loading

0 comments on commit 60c81f9

Please sign in to comment.