Skip to content

Commit

Permalink
rusk-wallet: Seperate http query and tx contract call
Browse files Browse the repository at this point in the history
Signed-off-by: Daksh <[email protected]>
  • Loading branch information
Daksh14 committed Dec 30, 2024
1 parent 4d125ed commit e41a8bd
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 59 deletions.
94 changes: 57 additions & 37 deletions rusk-wallet/src/bin/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use rusk_wallet::{
};
use wallet_core::BalanceInfo;

use crate::io::prompt;
use crate::io::prompt::{self};
use crate::settings::Settings;
use crate::{WalletFile, WalletPath};

Expand Down Expand Up @@ -229,6 +229,12 @@ pub(crate) enum Command {
#[arg(short = 'f', long)]
fn_args: Vec<u8>,

/// If query is true then HTTP contract call is done to obtain return
/// value of function if query is false then a transaction is
/// sent for mutation of the state of the contract
#[arg(short, long)]
query: bool,

/// Max amount of gas for this transaction
#[arg(short = 'l', long, default_value_t = DEFAULT_LIMIT_CALL)]
gas_limit: u64,
Expand Down Expand Up @@ -559,6 +565,7 @@ impl Command {
fn_args,
gas_limit,
gas_price,
query,
} => {
let gas = Gas::new(gas_limit).with_price(gas_price);

Expand All @@ -569,42 +576,52 @@ impl Command {
.try_into()
.map_err(|_| Error::InvalidContractId)?;

let call =
ContractCall::new(contract_id, fn_name.clone(), &fn_args)
.map_err(|_| Error::Rkyv)?;
match query {
true => {
let contract_id = hex::encode(contract_id);

let tx = match address {
Address::Shielded(_) => {
wallet.sync().await?;
wallet
.phoenix_execute(
addr_idx,
Dusk::from(0),
gas,
call.into(),
)
.await
}
Address::Public(_) => {
wallet
.moonlight_execute(
addr_idx,
Dusk::from(0),
Dusk::from(0),
gas,
call.into(),
)
.await
}
}?;
let http_call = wallet
.http_contract_call(contract_id, &fn_name, fn_args)
.await?;

let contract_id = hex::encode(contract_id);
Ok(RunResult::ContractCallQuery(http_call))
}
false => {
let call = ContractCall::new(
contract_id,
fn_name.clone(),
&fn_args,
)
.map_err(|_| Error::Rkyv)?;

let http_call = wallet
.http_contract_call(contract_id, &fn_name, fn_args)
.await?;
let tx = match address {
Address::Shielded(_) => {
wallet.sync().await?;
wallet
.phoenix_execute(
addr_idx,
Dusk::from(0),
gas,
call.into(),
)
.await
}
Address::Public(_) => {
wallet
.moonlight_execute(
addr_idx,
Dusk::from(0),
Dusk::from(0),
gas,
call.into(),
)
.await
}
}?;

Ok(RunResult::ContractCall(tx.hash(), http_call))
Ok(RunResult::ContractCallTx(tx.hash()))
}
}
}

Self::ContractDeploy {
Expand Down Expand Up @@ -695,7 +712,8 @@ pub enum RunResult<'a> {
Profile((u8, &'a Profile)),
Profiles(&'a Vec<Profile>),
ContractId([u8; CONTRACT_ID_BYTES]),
ContractCall(BlsScalar, Vec<u8>),
ContractCallTx(BlsScalar),
ContractCallQuery(Vec<u8>),
ExportedKeys(PathBuf, PathBuf),
Create(),
Restore(),
Expand Down Expand Up @@ -773,11 +791,13 @@ impl fmt::Display for RunResult<'_> {
ContractId(bytes) => {
write!(f, "> Contract ID: {}", hex::encode(bytes))
}
ContractCall(scalar, bytes) => {
ContractCallTx(scalar) => {
let hash = hex::encode(scalar.to_bytes());
writeln!(f, "> Contract call transaction hash: {hash}",)?;

writeln!(f, "> Http contract query: {:?}", bytes)
writeln!(f, "> Contract call transaction hash: {hash}",)
}
ContractCallQuery(bytes) => {
writeln!(f, "> Http contract query: {:?}", hex::encode(bytes))
}
ExportedKeys(pk, kp) => {
let pk = pk.display();
Expand Down
28 changes: 27 additions & 1 deletion rusk-wallet/src/bin/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub(crate) async fn run_loop(
println!("\r{}", res);
match res {
RunResult::Tx(hash)
| RunResult::ContractCall(hash, _) => {
| RunResult::ContractCallTx(hash) => {
let tx_id = hex::encode(hash.to_bytes());

// Wait for transaction confirmation
Expand Down Expand Up @@ -468,6 +468,32 @@ fn confirm(cmd: &Command, wallet: &Wallet<WalletFile>) -> anyhow::Result<bool> {
}
prompt::ask_confirm()
}
Command::ContractCall {
address,
contract_id,
fn_name,
fn_args,
query,
gas_limit,
gas_price,
} => {
println!(" > Function name {}", fn_name);
println!(" > Function arguments {}", hex::encode(fn_args));
println!(" > Contract ID {}", hex::encode(contract_id));
println!(" > Is HTTP query? {}", query);

if !query {
let max_fee = gas_limit * gas_price;

println!(" > Max fee = {} DUSK", Dusk::from(max_fee));

if let Some(Address::Public(_)) = address {
println!(" > ALERT: THIS IS A PUBLIC TRANSACTION");
}
}

prompt::ask_confirm()
}
_ => Ok(true),
}
}
Expand Down
48 changes: 30 additions & 18 deletions rusk-wallet/src/bin/interactive/command_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rusk_wallet::{
Address, Error, Wallet, MAX_CONTRACT_INIT_ARG_SIZE, MAX_FUNCTION_NAME_SIZE,
};

use super::prompt::request_contract_call_method;
use super::ProfileOp;
use crate::settings::Settings;
use crate::{prompt, Command, WalletFile};
Expand Down Expand Up @@ -296,27 +297,37 @@ pub(crate) async fn online(
}))
}
MenuItem::ContractCall => {
let (addr, balance) = pick_transaction_model(
wallet,
profile_idx,
phoenix_spendable,
moonlight_balance,
)?;

if check_min_gas_balance(
balance,
DEFAULT_LIMIT_CALL,
"a contract call",
)
.is_err()
{
return Ok(ProfileOp::Stay);
}

let mempool_gas_prices = wallet.get_mempool_gas_prices().await?;
let mut address = None;

let query = match request_contract_call_method()? {
prompt::ContractCall::Query => true,
prompt::ContractCall::Transaction => {
let (addr, balance) = pick_transaction_model(
wallet,
profile_idx,
phoenix_spendable,
moonlight_balance,
)?;

address = Some(addr);

if check_min_gas_balance(
balance,
DEFAULT_LIMIT_CALL,
"a contract call",
)
.is_err()
{
return Ok(ProfileOp::Stay);
}

false
}
};

ProfileOp::Run(Box::new(Command::ContractCall {
address: Some(addr),
address,
contract_id: prompt::request_bytes("contract id")?,
fn_name: prompt::request_str(
"function name to call",
Expand All @@ -330,6 +341,7 @@ pub(crate) async fn online(
DEFAULT_PRICE,
mempool_gas_prices,
)?,
query,
}))
}
MenuItem::History => {
Expand Down
29 changes: 28 additions & 1 deletion rusk-wallet/src/bin/io/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,32 @@ pub(crate) fn request_transaction_model() -> anyhow::Result<TransactionModel> {
)
}

pub enum ContractCall {
/// Call by http query (return values)
Query,
/// Call by a transaction (mutating state)
Transaction,
}

impl Display for ContractCall {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ContractCall::Query => write!(f, "By HTTP Query"),
ContractCall::Transaction => write!(f, "By Transaction"),
}
}
}

/// Request transaction model to use
pub(crate) fn request_contract_call_method() -> anyhow::Result<ContractCall> {
let choices = vec![ContractCall::Query, ContractCall::Transaction];

Ok(
Select::new("Please specify the contract call method to use", choices)
.prompt()?,
)
}

/// Request transaction model to use
pub(crate) fn request_address(
current_idx: u8,
Expand All @@ -371,7 +397,8 @@ pub(crate) fn request_address(
pub(crate) fn request_contract_code() -> anyhow::Result<PathBuf> {
let validator = |path_str: &str| {
let path = PathBuf::from(path_str);
if path.extension().map_or(false, |ext| ext == "wasm") {
if path.extension().map_or(false, |ext| ext == "wasm") && path.exists()
{
Ok(Validation::Valid)
} else {
Ok(Validation::Invalid("Not a valid directory".into()))
Expand Down
7 changes: 5 additions & 2 deletions rusk-wallet/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ async fn exec() -> anyhow::Result<()> {
RunResult::ContractId(id) => {
println!("Contract ID: {:?}", id);
}
RunResult::ContractCall(scalar, result) => {
RunResult::ContractCallTx(scalar) => {
let tx_id = hex::encode(scalar.to_bytes());

// Wait for transaction confirmation from network
Expand All @@ -410,7 +410,10 @@ async fn exec() -> anyhow::Result<()> {

println!("{tx_id}");

println!("HTTP call result: {:?}", result);

}
RunResult::ContractCallQuery(bytes) => {
println!("HTTP call result: {:?}", bytes);
}
RunResult::Settings() => {}
RunResult::Create() | RunResult::Restore() => {}
Expand Down

0 comments on commit e41a8bd

Please sign in to comment.