Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Updates for 15-rc3 #546

Merged
merged 7 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ members = [
]

[workspace.package]
rust-version = "1.80.0"
rust-version = "1.81.0"
version = "0.14.5"
authors = ["Kaspa developers"]
license = "ISC"
Expand Down
2 changes: 1 addition & 1 deletion consensus/client/src/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ impl UtxoEntryReference {
let outpoint = TransactionOutpoint::simulated();
let script_public_key = kaspa_txscript::pay_to_address_script(address);
let block_daa_score = 0;
let is_coinbase = true;
let is_coinbase = false;

let utxo_entry =
UtxoEntry { address: Some(address.clone()), outpoint, amount, script_public_key, block_daa_score, is_coinbase };
Expand Down
2 changes: 1 addition & 1 deletion rpc/core/src/wasm/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ cfg_if::cfg_if! {
subnetwork_id: inner.subnetwork_id.clone(),
gas: inner.gas,
payload: inner.payload.clone(),
mass: tx.get_mass(),
mass: inner.mass,
verbose_data: None,
}
}
Expand Down
4 changes: 2 additions & 2 deletions rpc/core/src/wasm/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1454,8 +1454,8 @@ try_from! ( args: ISubmitTransactionRequest, SubmitTransactionRequest, {
} else {
let tx = Transaction::try_cast_from(&transaction)?;
SubmitTransactionRequest {
transaction : tx.as_ref().into(),
allow_orphan,
transaction : tx.as_ref().into(),
allow_orphan,
}
};
Ok(request)
Expand Down
1 change: 0 additions & 1 deletion wallet/core/src/tx/generator/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,6 @@ impl Generator {
Ok((DataKind::NoOp, data))
} else if stage.number_of_transactions > 0 {
data.aggregate_mass += self.inner.standard_change_output_compute_mass;
data.change_output_value = Some(data.aggregate_input_value - data.transaction_fees);
Ok((DataKind::Edge, data))
} else if data.aggregate_input_value < data.transaction_fees {
Err(Error::InsufficientFunds { additional_needed: data.transaction_fees - data.aggregate_input_value, origin: "relay" })
Expand Down
59 changes: 54 additions & 5 deletions wallet/core/src/tx/generator/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use workflow_log::style;

use super::*;

const DISPLAY_LOGS: bool = true;
const DISPLAY_LOGS: bool = false;
const DISPLAY_EXPECTED: bool = true;

#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -173,7 +173,7 @@ fn validate(pt: &PendingTransaction) {
let compute_mass = calc.calc_compute_mass_for_unsigned_consensus_transaction(&tx, pt.minimum_signatures());

let utxo_entries = pt.utxo_entries().values().cloned().collect::<Vec<_>>();
let storage_mass = calc.calc_storage_mass_for_transaction_parts(&utxo_entries, &tx.outputs).unwrap_or_default();
let storage_mass = calc.calc_storage_mass_for_transaction_parts(&utxo_entries, &tx.outputs).unwrap_or(u64::MAX);
let calculated_mass = calc.combine_mass(compute_mass, storage_mass) + additional_mass;

assert_eq!(pt.inner.mass, calculated_mass, "pending transaction mass does not match calculated mass");
Expand Down Expand Up @@ -203,7 +203,7 @@ where
let compute_mass = calc.calc_compute_mass_for_unsigned_consensus_transaction(&tx, pt.minimum_signatures());

let utxo_entries = pt.utxo_entries().values().cloned().collect::<Vec<_>>();
let storage_mass = calc.calc_storage_mass_for_transaction_parts(&utxo_entries, &tx.outputs).unwrap_or_default();
let storage_mass = calc.calc_storage_mass_for_transaction_parts(&utxo_entries, &tx.outputs).unwrap_or(u64::MAX);
if DISPLAY_LOGS && storage_mass != 0 {
println!("calculated storage mass: {} calculated_compute_mass: {}", storage_mass, compute_mass,);
}
Expand Down Expand Up @@ -323,6 +323,21 @@ impl Harness {
self.clone()
}

pub fn accumulate(self: &Rc<Self>, count: usize) -> Rc<Self> {
for _n in 0..count {
if DISPLAY_LOGS {
println!(
"{}",
style(format!("accumulate gathering transaction: {} ({})", _n, self.accumulator.borrow().list.len())).magenta()
);
}
let ptx = self.generator.generate_transaction().unwrap().unwrap();
ptx.accumulate(&mut self.accumulator.borrow_mut());
}
// println!("accumulated `{}` transactions", self.accumulator.borrow().list.len());
self.clone()
}

pub fn validate(self: &Rc<Self>) -> Rc<Self> {
while let Some(pt) = self.generator.generate_transaction().unwrap() {
pt.accumulate(&mut self.accumulator.borrow_mut()).validate();
Expand All @@ -332,7 +347,16 @@ impl Harness {

pub fn finalize(self: Rc<Self>) {
let pt = self.generator.generate_transaction().unwrap();
assert!(pt.is_none(), "expected no more transactions");
if pt.is_some() {
let mut pending = self.generator.generate_transaction().unwrap();
let mut count = 1;
while pending.is_some() {
count += 1;
pending = self.generator.generate_transaction().unwrap();
}

panic!("received extra `{}` unexpected transactions", count);
}
let summary = self.generator.summary();
if DISPLAY_LOGS {
println!("{:#?}", summary);
Expand Down Expand Up @@ -644,7 +668,7 @@ fn test_generator_inputs_100_outputs_1_fees_exclude_insufficient_funds() -> Resu
}

#[test]
fn test_generator_inputs_903_outputs_2_fees_exclude() -> Result<()> {
fn test_generator_inputs_1k_outputs_2_fees_exclude() -> Result<()> {
generator(test_network_id(), &[10.0; 1_000], &[], Fees::sender(Kaspa(5.0)), [(output_address, Kaspa(9_000.0))].as_slice())
.unwrap()
.harness()
Expand Down Expand Up @@ -676,3 +700,28 @@ fn test_generator_inputs_903_outputs_2_fees_exclude() -> Result<()> {

Ok(())
}

#[test]
fn test_generator_inputs_32k_outputs_2_fees_exclude() -> Result<()> {
let f = 130.0;
generator(
test_network_id(),
&[f; 32_747],
&[],
Fees::sender(Kaspa(10_000.0)),
[(output_address, Kaspa(f * 32_747.0 - 10_001.0))].as_slice(),
)
.unwrap()
.harness()
.accumulate(379)
.finalize();
Ok(())
}

#[test]
fn test_generator_inputs_250k_outputs_2_sweep() -> Result<()> {
let f = 130.0;
let generator = make_generator(test_network_id(), &[f; 250_000], &[], Fees::None, change_address, PaymentDestination::Change);
generator.unwrap().harness().accumulate(2875).finalize();
Ok(())
}
58 changes: 47 additions & 11 deletions wallet/core/src/wasm/tx/mass.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
use crate::imports::NetworkParams;
use crate::result::Result;
use crate::tx::mass;
use crate::tx::{mass, MAXIMUM_STANDARD_TRANSACTION_MASS};
use kaspa_consensus_client::*;
use kaspa_consensus_core::config::params::Params;
use kaspa_consensus_core::network::{NetworkId, NetworkIdT};
use wasm_bindgen::prelude::*;
use workflow_wasm::convert::*;

/// `maximumStandardTransactionMass()` returns the maximum transaction
/// size allowed by the network.
///
/// @category Wallet SDK
/// @see {@link calculateTransactionMass}
/// @see {@link updateTransactionMass}
/// @see {@link calculateTransactionFee}
#[wasm_bindgen(js_name = maximumStandardTransactionMass)]
pub fn maximum_standard_transaction_mass() -> u64 {
MAXIMUM_STANDARD_TRANSACTION_MASS
}

/// `calculateTransactionMass()` returns the mass of the passed transaction.
/// If the transaction is invalid, or the mass can not be calculated
/// the function throws an error.
///
/// The mass value must not exceed the maximum standard transaction mass
/// that can be obtained using `maximumStandardTransactionMass()`.
///
/// @category Wallet SDK
/// @see {@link maximumStandardTransactionMass}
///
#[wasm_bindgen(js_name = calculateTransactionMass)]
pub fn calculate_unsigned_transaction_mass(network_id: NetworkIdT, tx: &TransactionT, minimum_signatures: Option<u16>) -> Result<u64> {
Expand All @@ -24,39 +40,59 @@ pub fn calculate_unsigned_transaction_mass(network_id: NetworkIdT, tx: &Transact
}

/// `updateTransactionMass()` updates the mass property of the passed transaction.
/// If the transaction is invalid, or the mass is larger than transaction mass allowed
/// by the network, the function throws an error.
/// If the transaction is invalid, the function throws an error.
///
/// The function returns `true` if the mass is within the maximum standard transaction mass and
/// the transaction mass is updated. Otherwise, the function returns `false`.
///
/// This is the same as `calculateTransactionMass()` but modifies the supplied
/// This is similar to `calculateTransactionMass()` but modifies the supplied
/// `Transaction` object.
///
/// @category Wallet SDK
/// @see {@link maximumStandardTransactionMass}
/// @see {@link calculateTransactionMass}
/// @see {@link calculateTransactionFee}
///
#[wasm_bindgen(js_name = updateTransactionMass)]
pub fn update_unsigned_transaction_mass(network_id: NetworkIdT, tx: &Transaction, minimum_signatures: Option<u16>) -> Result<()> {
pub fn update_unsigned_transaction_mass(network_id: NetworkIdT, tx: &Transaction, minimum_signatures: Option<u16>) -> Result<bool> {
let network_id = NetworkId::try_owned_from(network_id)?;
let consensus_params = Params::from(network_id);
let network_params = NetworkParams::from(network_id);
let mc = mass::MassCalculator::new(&consensus_params, network_params);
let mass = mc.calc_overall_mass_for_unsigned_client_transaction(tx, minimum_signatures.unwrap_or(1))?;
tx.set_mass(mass);
Ok(())
if mass > MAXIMUM_STANDARD_TRANSACTION_MASS {
Ok(false)
} else {
tx.set_mass(mass);
Ok(true)
}
}

/// `calculateTransactionFee()` returns minimum fees needed for the transaction to be
/// accepted by the network. If the transaction is invalid or the mass can not be calculated,
/// the function throws an error.
/// the function throws an error. If the mass exceeds the maximum standard transaction mass,
/// the function returns `undefined`.
///
/// @category Wallet SDK
/// @see {@link maximumStandardTransactionMass}
/// @see {@link calculateTransactionMass}
/// @see {@link updateTransactionMass}
///
#[wasm_bindgen(js_name = calculateTransactionFee)]
pub fn calculate_unsigned_transaction_fee(network_id: NetworkIdT, tx: &TransactionT, minimum_signatures: Option<u16>) -> Result<u64> {
pub fn calculate_unsigned_transaction_fee(
network_id: NetworkIdT,
tx: &TransactionT,
minimum_signatures: Option<u16>,
) -> Result<Option<u64>> {
let tx = Transaction::try_cast_from(tx)?;
let network_id = NetworkId::try_owned_from(network_id)?;
let consensus_params = Params::from(network_id);
let network_params = NetworkParams::from(network_id);
let mc = mass::MassCalculator::new(&consensus_params, network_params);
let mass = mc.calc_overall_mass_for_unsigned_client_transaction(tx.as_ref(), minimum_signatures.unwrap_or(1))?;
let fee = mc.calc_fee_for_mass(mass);
Ok(fee)
if mass > MAXIMUM_STANDARD_TRANSACTION_MASS {
Ok(None)
} else {
Ok(Some(mc.calc_fee_for_mass(mass)))
}
}
17 changes: 15 additions & 2 deletions wallet/keys/src/publickey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
//! ```
//!

use kaspa_consensus_core::network::NetworkType;

use crate::imports::*;

use kaspa_consensus_core::network::NetworkType;
use ripemd::{Digest, Ripemd160};
use sha2::Sha256;

/// Data structure that envelopes a PublicKey.
/// Only supports Schnorr-based addresses.
/// @category Wallet SDK
Expand Down Expand Up @@ -69,6 +71,17 @@ impl PublicKey {
pub fn to_x_only_public_key(&self) -> XOnlyPublicKey {
self.xonly_public_key.into()
}

/// Compute a 4-byte key fingerprint for this public key as a hex string.
/// Default implementation uses `RIPEMD160(SHA256(public_key))`.
pub fn fingerprint(&self) -> Option<HexString> {
if let Some(public_key) = self.public_key.as_ref() {
let digest = Ripemd160::digest(Sha256::digest(public_key.serialize().as_slice()));
Some(digest[..4].as_ref().to_hex().into())
} else {
None
}
}
}

impl PublicKey {
Expand Down