Skip to content

Commit

Permalink
Merge pull request #85 from dusk-network/fee_crossover_rng_fix
Browse files Browse the repository at this point in the history
Pass fee and crossover in execute to fix wrong transaction hash
  • Loading branch information
Daksh14 authored Nov 8, 2023
2 parents 541d4ec + dbaa79f commit 74417ab
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 64 deletions.
Binary file modified assets/dusk_wallet_core.wasm
Binary file not shown.
60 changes: 50 additions & 10 deletions assets/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,45 @@
}
}
},
"CrossoverType": {
"description": "The value of the Crossover and the blinder",
"type": "object",
"required": [
"crossover",
"blinder",
"value"
],
"properties": {
"crossover": {
"description": "The rkyv serialized bytes of the crossover struct",
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0
}
},
"blinder": {
"description": "The rkyv serialized blinder of the crossover",
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0
}
},
"value": {
"description": "The value of the crossover",
"type": "integer",
"format": "uint64"
}
}
},
"ExecuteArgs": {
"description": "The arguments of the execute function",
"type": "object",
"required": [
"fee",
"gas_limit",
"gas_price",
"inputs",
Expand All @@ -157,22 +192,27 @@
"$ref": "#/definitions/ExecuteCall"
},
"crossover": {
"description": "The [phoenix_core::Crossover] value",
"type": "integer",
"format": "uint64",
"minimum": 0
"description": "The crossover value",
"$ref": "#/definitions/CrossoverType"
},
"fee": {
"description": "A rkyv serialized Fee",
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0
}
},
"gas_limit": {
"description": "The gas limit of the transaction",
"type": "integer",
"format": "uint64",
"minimum": 0
"format": "uint64"
},
"gas_price": {
"description": "The gas price per unit for the transaction",
"type": "integer",
"format": "uint64",
"minimum": 0
"format": "uint64"
},
"inputs": {
"description": "A rkyv serialized [Vec<phoenix_core::Note>] to be used as inputs",
Expand Down Expand Up @@ -208,8 +248,8 @@
"format": "uint8",
"minimum": 0
},
"maxItems": 64,
"minItems": 64
"maxItems": 32,
"minItems": 32
},
"seed": {
"description": "Seed used to derive the keys of the wallet",
Expand Down
28 changes: 17 additions & 11 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use alloc::{vec, vec::Vec};
use core::mem;

use dusk_bytes::Serializable;
use phoenix_core::Note;
use phoenix_core::{Fee, Note};
use sha2::{Digest, Sha512};

use crate::{key, tx, types, utils, MAX_KEY, MAX_LEN};
Expand Down Expand Up @@ -132,11 +132,12 @@ pub fn execute(args: i32, len: i32) -> i64 {
let types::ExecuteArgs {
call,
crossover,
gas_limit,
gas_price,
fee,
inputs,
openings,
output,
gas_limit,
gas_price,
refund,
rng_seed,
seed,
Expand All @@ -150,6 +151,11 @@ pub fn execute(args: i32, len: i32) -> i64 {
Err(_) => return utils::fail(),
};

let fee: Fee = match rkyv::from_bytes(&fee) {
Ok(n) => n,
Err(_) => return utils::fail(),
};

let openings: Vec<tx::Opening> = match rkyv::from_bytes(&openings) {
Ok(n) => n,
Err(_) => return utils::fail(),
Expand All @@ -160,7 +166,7 @@ pub fn execute(args: i32, len: i32) -> i64 {
None => return utils::fail(),
};

let rng_seed = match utils::sanitize_seed(rng_seed) {
let rng_seed: [u8; 32] = match rng_seed.try_into().ok() {
Some(s) => s,
None => return utils::fail(),
};
Expand All @@ -169,7 +175,7 @@ pub fn execute(args: i32, len: i32) -> i64 {
let total_output = gas_limit
.saturating_mul(gas_price)
.saturating_add(value)
.saturating_add(crossover.unwrap_or_default());
.saturating_add(crossover.clone().map(|c| c.value).unwrap_or_default());

let mut keys = unsafe { [mem::zeroed(); MAX_KEY + 1] };
let mut keys_ssk = unsafe { [mem::zeroed(); MAX_KEY + 1] };
Expand Down Expand Up @@ -221,9 +227,6 @@ pub fn execute(args: i32, len: i32) -> i64 {
let total_refund = total_input.saturating_sub(total_output);

let mut outputs = Vec::with_capacity(2);
if let Some(o) = output {
outputs.push(o);
}
if total_refund > 0 {
outputs.push(types::ExecuteOutput {
note_type: types::OutputType::Obfuscated,
Expand All @@ -232,10 +235,13 @@ pub fn execute(args: i32, len: i32) -> i64 {
value: total_refund,
});
}
if let Some(o) = output {
outputs.push(o);
}

let rng = &mut utils::rng(&rng_seed);
let rng = &mut utils::rng(rng_seed);
let tx = tx::UnprovenTransaction::new(
rng, inputs, outputs, refund, gas_limit, gas_price, crossover, call,
rng, inputs, outputs, fee, crossover, call,
);
let tx = match tx {
Some(t) => t,
Expand Down Expand Up @@ -307,7 +313,7 @@ pub fn filter_notes(args: i32, len: i32) -> i64 {

let notes: Vec<_> = notes
.into_iter()
.zip(flags.into_iter())
.zip(flags)
.filter_map(|(n, f)| (!f).then_some(n))
.collect();

Expand Down
46 changes: 24 additions & 22 deletions src/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use rkyv::{Archive, Deserialize, Serialize};
use rusk_abi::hash::Hasher;
use rusk_abi::{ContractId, POSEIDON_TREE_DEPTH};

use crate::{types, utils};
use crate::{types, types::CrossoverType, utils};

/// Chosen arity for the Notes tree implementation.
pub const POSEIDON_TREE_ARITY: usize = 4;
Expand Down Expand Up @@ -94,7 +94,7 @@ pub struct Output {
/// A crossover to a transaction that is yet to be proven.
#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
#[archive_attr(derive(CheckBytes))]
pub struct Crossover {
pub struct WasmCrossover {
/// Crossover value to be used in inter-contract calls.
pub crossover: PhoenixCrossover,
/// Value of the crossover.
Expand Down Expand Up @@ -128,7 +128,7 @@ pub struct UnprovenTransaction {
/// Fee setup for the transaction.
pub fee: Fee,
/// Crossover value for inter-contract calls.
pub crossover: Option<Crossover>,
pub crossover: Option<WasmCrossover>,
/// Call data payload for contract calls.
pub call: Option<CallData>,
}
Expand All @@ -143,10 +143,8 @@ impl UnprovenTransaction {
rng: &mut Rng,
inputs: I,
outputs: O,
refund: String,
gas_limit: u64,
gas_price: u64,
crossover: Option<u64>,
fee: Fee,
crossover: Option<CrossoverType>,
call: Option<types::ExecuteCall>,
) -> Option<Self>
where
Expand All @@ -163,7 +161,6 @@ impl UnprovenTransaction {
.unzip();

let anchor = inputs.first().map(|i| i.opening.root().hash)?;
let refund = utils::bs58_to_psk(&refund)?;

let mut output_notes = Vec::with_capacity(4);
let mut outputs_values = Vec::with_capacity(4);
Expand Down Expand Up @@ -222,20 +219,25 @@ impl UnprovenTransaction {
(c.contract.to_bytes(), c.method.clone(), c.payload.clone())
});

let fee = Fee::new(rng, gas_limit, gas_price, &refund);

let crossover = crossover.map(|crossover| {
let blinder = JubJubScalar::random(rng);
let (_, crossover_note) =
Note::obfuscated(rng, &refund, crossover, blinder)
.try_into()
.expect("Obfuscated notes should always yield crossovers");
Crossover {
crossover: crossover_note,
value: crossover,
blinder,
}
});
let crossover = crossover.and_then(
|CrossoverType {
blinder,
crossover,
value,
}| {
Some({
WasmCrossover {
crossover: rkyv::from_bytes::<PhoenixCrossover>(
&crossover,
)
.ok()?,
value,
blinder: rkyv::from_bytes::<JubJubScalar>(&blinder)
.ok()?,
}
})
},
);

let tx_hash = Transaction::hash_input_bytes_from_components(
&nullifiers,
Expand Down
16 changes: 14 additions & 2 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,27 @@ pub struct BalanceResponse {
#[doc = " Total computed balance"]
pub value: u64,
}
#[doc = " The value of the Crossover and the blinder"]
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct CrossoverType {
#[doc = " The rkyv serialized blinder of the crossover"]
pub blinder: Vec<u8>,
#[doc = " The rkyv serialized bytes of the crossover struct"]
pub crossover: Vec<u8>,
#[doc = " The value of the crossover"]
pub value: u64,
}
#[doc = " The arguments of the execute function"]
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct ExecuteArgs {
#[doc = " A call to a contract method"]
#[serde(skip_serializing_if = "Option::is_none")]
pub call: Option<ExecuteCall>,
#[doc = " The [phoenix_core::Crossover] value"]
#[doc = " The crossover value"]
#[serde(skip_serializing_if = "Option::is_none")]
pub crossover: Option<u64>,
pub crossover: Option<CrossoverType>,
#[doc = " A rkyv serialized Fee"]
pub fee: Vec<u8>,
#[doc = " The gas limit of the transaction"]
pub gas_limit: u64,
#[doc = " The gas price per unit for the transaction"]
Expand Down
12 changes: 3 additions & 9 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,9 @@ where
compose(true, ptr, len)
}

/// Creates a secure RNG from a seed.
pub fn rng(seed: &[u8; RNG_SEED]) -> ChaCha12Rng {
let mut hash = Sha256::new();

hash.update(seed);
hash.update(b"RNG");

let hash = hash.finalize().into();
ChaCha12Rng::from_seed(hash)
/// Creates a secure RNG directly a seed.
pub fn rng(seed: [u8; 32]) -> ChaCha12Rng {
ChaCha12Rng::from_seed(seed)
}

/// Creates a secure RNG from a seed with embedded index.
Expand Down
Loading

0 comments on commit 74417ab

Please sign in to comment.