mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-22 09:38:33 +02:00
[CONTRACTS] Contracts branch update for 1.80 (#718)
* Simple contracts restructured v3 (#675) * Add prototype contract implementation Lacks: - Payment proofs (add early payment proofs) - Tests - Better structure * Separate contract utilities * Simplify the main setup/sign code flow * Remove commented initial_sec_key assignment * Simplify sign::compute function * Add logic for "removal" of secret keys from the context * Further simplify a bit sign and setup * No need for mutable context when adding outputs * Refactor the commented code (lol) * Refactor a bit * tmp --------- Co-authored-by: oryhp <gtrphyro@gmail.com> * contract test fixes (#676) * [Contracts] Experimental Slate v5 (#677) * beginning to add and modify slate version 5 * completion of conversions from V5 to V4 Slate * timestamp and memo fields * upgrade/downgrade serialization of v5 slates * add v5 binary slate versions + start of tests * add bin slate ser/deser to tests * ensure serialization of timestamp always excludes milliseconds * start to update v5 tests, update v5 documentation * add fn to generate populated internal slate for conversion testing * add basic tests to convert all slate versions * update * commit cargo.lock * [WIP] [Contracts] Early payment proofs (#681) * add types and beginnings of signature utils * add proof serialization * serialisation of proof data + signature operation * add serialization type for invoice proof + separate bin wrapper version * add witness data + serializion to invoice payment proof, insert verfication functions in place in order to begin verification testing * tests and infrastructure in place for validation * verification of promise sig * added verification of promise signature, infrastructure up to the point where a signature must be subtracted * attempting to figure out differences between recipient nonce that's getting stored and calculated recipient nonce * implementation of witness verification function, retrieve relevant values and re-validate derived recipient partial signature * move stored portion of invoice proof into core types for storage, need to rename invoice proof * define/refine the stored portion of payment proofs type 2? * Folding all proof data into tx log entry storage * back to importing master * remove cargo files from diffs * remove a lot of extra debug output * return proof witness as part of proof retrieval, define json serialization of invoice proof + witness fields * finish adding verification steps to foreign API * remove redundant promise sig field * move lcation of sign/verify calls * Replace Azure Pipelines with Github Actions (#688) * Update CI Badge on README.MD (#690) * Trigger CI on push and pull request (#693) * Update versioning to 5.2.0-beta.1 against grin 5.2.0-beta.3 (#691) * update versioning to 5.2.0-beta.1 against grin 5.2.0-beta.3 * tweak for CI trigger --------- Co-authored-by: Quentin Le Sceller <q.lesceller@gmail.com> --------- Co-authored-by: Quentin Le Sceller <q.lesceller@gmail.com> * fix Cargo.lock * Contracts - Test fixes + warning cleanups (#694) * clean up warnings in libwallet crate * clean up warnings in controller crate * update all contract tests with awareness of new proof structure * added explicit payment proof tests for both rsr and srs (#695) * Basic mwmixnet send (#696) * integrating onion library * updates and changes to support newly included mwmixnet types * add (incorrect) owner api function * turn off test for now * switch working grin branch to master * fix doctests for build * update cargo lock in attempt to fix croaring build on CI server * update cargo lock with upstream thiserror crate * update test dependency for croaring * [Contracts] Add self spend transaction state (#697) * Add self spend transaction state * subtle errors with output states and tx lookups - fixes * [Contracts] Slatepack v5 Deserialization fix (#698) * add V5 deserialization test + fixes * clarify comment * upwrap fix during v4 deserialization * further unwrap removal * update cargo lock, use latest grin packages * addition of self-spend cancel + tests (#699) * add tests + legacy self send cancel (#702) * [Contracts] Cancel self-spend TX Pt. 2 (#703) * add tests + legacy self send cancel * add missing file * Update grin to latest master, change versioning label to include contracts (#712) * Add owner_api_listen_interface as hidden configuration field (#714) * updates for rust 1.80 * updates for rust 1.80 --------- Co-authored-by: oryhp <gtrphyro@gmail.com> Co-authored-by: Quentin Le Sceller <q.lesceller@gmail.com>
This commit is contained in:
co-authored by
oryhp
Quentin Le Sceller
parent
765f11b168
commit
cdd63fb565
@@ -15,7 +15,11 @@
|
||||
//! Generic implementation of owner API functions
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::api_impl::owner::contract_new as owner_contract_new;
|
||||
use crate::api_impl::owner::contract_sign as owner_contract_sign;
|
||||
use crate::api_impl::owner::{check_ttl, post_tx};
|
||||
use crate::contract::proofs::InvoiceProof;
|
||||
use crate::contract::types::{ContractNewArgsAPI, ContractSetupArgsAPI};
|
||||
use crate::grin_core::core::FeeFields;
|
||||
use crate::grin_keychain::Keychain;
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
@@ -25,6 +29,7 @@ use crate::{
|
||||
address, BlockFees, CbData, Error, NodeClient, Slate, SlateState, TxLogEntryType, VersionInfo,
|
||||
WalletBackend,
|
||||
};
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
|
||||
use super::owner::tx_lock_outputs;
|
||||
|
||||
@@ -114,14 +119,16 @@ where
|
||||
let excess = ret_slate.calc_excess(keychain.secp())?;
|
||||
|
||||
if let Some(ref mut p) = ret_slate.payment_proof {
|
||||
let sig = tx::create_payment_proof_signature(
|
||||
ret_slate.amount,
|
||||
&excess,
|
||||
p.sender_address,
|
||||
address::address_from_derivation_path(&keychain, &parent_key_id, 0)?,
|
||||
)?;
|
||||
if let Some(saddr) = p.sender_address {
|
||||
let sig = tx::create_payment_proof_signature(
|
||||
ret_slate.amount,
|
||||
&excess,
|
||||
saddr,
|
||||
address::address_from_derivation_path(&keychain, &parent_key_id, 0)?,
|
||||
)?;
|
||||
|
||||
p.receiver_signature = Some(sig);
|
||||
p.promise_signature = Some(sig);
|
||||
}
|
||||
}
|
||||
|
||||
ret_slate.amount = 0;
|
||||
@@ -231,3 +238,94 @@ where
|
||||
}
|
||||
Ok(sl)
|
||||
}
|
||||
|
||||
/// Initialize a receive transaction contract
|
||||
pub fn contract_new<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: &ContractNewArgsAPI,
|
||||
// use_test_rng: bool,
|
||||
) -> Result<Slate, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let net_change = args.setup_args.net_change.unwrap();
|
||||
if net_change <= 0 {
|
||||
return Err(Error::GenericError(
|
||||
"Can't create a non-receiving contract from a foreign API.".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
owner_contract_new(&mut *w, keychain_mask, args)
|
||||
}
|
||||
|
||||
/// Sign a receive transaction contract
|
||||
pub fn contract_sign<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: &ContractSetupArgsAPI,
|
||||
slate: &Slate,
|
||||
// use_test_rng: bool,
|
||||
) -> Result<Slate, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let net_change = args.net_change.unwrap();
|
||||
if net_change <= 0 {
|
||||
return Err(Error::GenericError(
|
||||
"Can't sign a non-receiving contract from a foreign API.".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
owner_contract_sign(&mut *w, keychain_mask, args, slate)
|
||||
}
|
||||
|
||||
/// Verify an invoice payment proof
|
||||
pub fn verify_payment_proof_invoice<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
recipient_address: &DalekPublicKey,
|
||||
proof: &InvoiceProof,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let mut client = w.w2n_client().clone();
|
||||
|
||||
let wd = match proof.witness_data.clone() {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
return Err(Error::PaymentProof(format!(
|
||||
"Cannot verify invoice proof with no witness data",
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let (retrieved_kernel, _) = match client.get_kernel(&wd.kernel_commitment, None, None) {
|
||||
Err(e) => {
|
||||
return Err(Error::PaymentProof(format!(
|
||||
"Error retrieving kernel from chain: {}",
|
||||
e
|
||||
)));
|
||||
}
|
||||
Ok(None) => {
|
||||
return Err(Error::PaymentProof(format!(
|
||||
"Transaction kernel with excess {:?} not found on chain",
|
||||
wd.kernel_commitment
|
||||
)));
|
||||
}
|
||||
Ok(Some((k, _, index))) => (k, index),
|
||||
};
|
||||
|
||||
// Now verify with retrieved data
|
||||
proof.verify_witness(
|
||||
recipient_address,
|
||||
&retrieved_kernel.excess_sig,
|
||||
&retrieved_kernel.msg_to_sign()?,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,27 +17,35 @@
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::api_impl::foreign::finalize_tx as foreign_finalize;
|
||||
use crate::contract::proofs::{InvoiceProof, ProofWitness};
|
||||
use crate::grin_core::core::hash::Hashed;
|
||||
use crate::grin_core::core::{Output, OutputFeatures, Transaction};
|
||||
use crate::grin_core::libtx::proof;
|
||||
use crate::grin_keychain::ViewKey;
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::grin_util::Mutex;
|
||||
use crate::grin_util::ToHex;
|
||||
use crate::grin_util::secp::pedersen;
|
||||
use crate::grin_util::{static_secp_instance, Mutex, ToHex};
|
||||
use crate::util::{OnionV3Address, OnionV3AddressError};
|
||||
|
||||
use crate::api_impl::owner_updater::StatusMessage;
|
||||
use crate::contract::types::{ContractNewArgsAPI, ContractRevokeArgsAPI, ContractSetupArgsAPI};
|
||||
use crate::grin_keychain::{BlindingFactor, Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::mwmixnet::onion::create_onion;
|
||||
use crate::mwmixnet::types::{
|
||||
add_excess, new_hop, random_secret, ComSignature, Hop, MixnetReqCreationParams, SwapReq,
|
||||
};
|
||||
|
||||
use crate::internal::{keys, scan, selection, tx, updater};
|
||||
use crate::slate::{PaymentInfo, Slate, SlateState};
|
||||
use crate::types::{AcctPathMapping, NodeClient, TxLogEntry, WalletBackend, WalletInfo};
|
||||
use crate::Error;
|
||||
use crate::{
|
||||
address, wallet_lock, BuiltOutput, InitTxArgs, IssueInvoiceTxArgs, NodeHeightResult,
|
||||
address, contract, wallet_lock, BuiltOutput, InitTxArgs, IssueInvoiceTxArgs, NodeHeightResult,
|
||||
OutputCommitMapping, PaymentProof, RetrieveTxQueryArgs, ScannedBlockInfo, Slatepack,
|
||||
SlatepackAddress, Slatepacker, SlatepackerArgs, TxLogEntryType, ViewWallet, WalletInitStatus,
|
||||
WalletInst, WalletLCProvider,
|
||||
};
|
||||
use chrono::prelude::{DateTime, NaiveDateTime, Utc};
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
use ed25519_dalek::SecretKey as DalekSecretKey;
|
||||
use ed25519_dalek::Verifier;
|
||||
@@ -473,6 +481,145 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieve invoice payment proof
|
||||
/// TODO: Need to unify with legacy above
|
||||
pub fn retrieve_payment_proof_invoice<'a, L, C, K>(
|
||||
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
status_send_channel: &Option<Sender<StatusMessage>>,
|
||||
refresh_from_node: bool,
|
||||
tx_id: Option<u32>,
|
||||
tx_slate_id: Option<Uuid>,
|
||||
) -> Result<InvoiceProof, Error>
|
||||
where
|
||||
L: WalletLCProvider<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
if tx_id.is_none() && tx_slate_id.is_none() {
|
||||
return Err(Error::PaymentProofRetrieval(
|
||||
"Transaction ID or Slate UUID must be specified".to_owned(),
|
||||
));
|
||||
}
|
||||
if refresh_from_node {
|
||||
update_wallet_state(
|
||||
wallet_inst.clone(),
|
||||
keychain_mask,
|
||||
status_send_channel,
|
||||
false,
|
||||
)?
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let txs = retrieve_txs(
|
||||
wallet_inst.clone(),
|
||||
keychain_mask,
|
||||
status_send_channel,
|
||||
refresh_from_node,
|
||||
tx_id,
|
||||
tx_slate_id,
|
||||
None,
|
||||
)?;
|
||||
if txs.1.len() != 1 {
|
||||
return Err(Error::PaymentProofRetrieval(
|
||||
"Transaction doesn't exist".to_owned(),
|
||||
));
|
||||
}
|
||||
// Pull out all needed fields, returning an error if they're not present
|
||||
let tx = txs.1[0].clone();
|
||||
let amount = if tx.amount_credited >= tx.amount_debited {
|
||||
tx.amount_credited - tx.amount_debited
|
||||
} else {
|
||||
// TODO: Invoice proof not expecting fee included here
|
||||
tx.amount_debited - tx.amount_credited
|
||||
};
|
||||
|
||||
let (mut proof, sender_part_sig) = match tx.payment_proof {
|
||||
Some(p) => {
|
||||
if p.receiver_public_nonce.is_none() {
|
||||
return Err(Error::PaymentProofRetrieval(
|
||||
"Invoice Proof requires stored receiver public nonce".into(),
|
||||
));
|
||||
};
|
||||
if p.receiver_public_excess.is_none() {
|
||||
return Err(Error::PaymentProofRetrieval(
|
||||
"Invoice Proof requires stored receiver public excess".into(),
|
||||
));
|
||||
};
|
||||
if p.timestamp.is_none() {
|
||||
return Err(Error::PaymentProofRetrieval(
|
||||
"Invoice Proof requires stored timestamp".into(),
|
||||
));
|
||||
};
|
||||
if p.sender_part_sig.is_none() {
|
||||
return Err(Error::PaymentProofRetrieval(
|
||||
"Invoice Proof requires stored sender partial signature".into(),
|
||||
));
|
||||
};
|
||||
|
||||
(
|
||||
InvoiceProof {
|
||||
proof_type: if let Some(t) = p.proof_type { t } else { 1u8 },
|
||||
amount,
|
||||
receiver_public_nonce: p.receiver_public_nonce.unwrap(),
|
||||
receiver_public_excess: p.receiver_public_excess.unwrap(),
|
||||
sender_address: p.sender_address,
|
||||
timestamp: p.timestamp.unwrap().timestamp(),
|
||||
memo: p.memo,
|
||||
promise_signature: p.promise_signature,
|
||||
witness_data: None,
|
||||
},
|
||||
p.sender_part_sig.unwrap(),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
return Err(Error::PaymentProofRetrieval(
|
||||
"Transaction does not contain a payment proof".to_owned(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Now to kernel lookup, to fill in the witness data
|
||||
// Check kernel exists
|
||||
let mut client = {
|
||||
wallet_lock!(wallet_inst, w);
|
||||
w.w2n_client().clone()
|
||||
};
|
||||
|
||||
let kernel_excess = match tx.kernel_excess {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
return Err(Error::PaymentProofRetrieval(format!(
|
||||
"Invoice proof transaction kernel excess missing",
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let (retrieved_kernel, index) = match client.get_kernel(&kernel_excess, None, None) {
|
||||
Err(e) => {
|
||||
return Err(Error::PaymentProof(format!(
|
||||
"Error retrieving kernel from chain: {}",
|
||||
e
|
||||
)));
|
||||
}
|
||||
Ok(None) => {
|
||||
return Err(Error::PaymentProof(format!(
|
||||
"Transaction kernel with excess {:?} not found on chain",
|
||||
kernel_excess
|
||||
)));
|
||||
}
|
||||
Ok(Some((k, _, index))) => (k, index),
|
||||
};
|
||||
|
||||
proof.witness_data = Some(ProofWitness {
|
||||
kernel_index: index,
|
||||
kernel_commitment: retrieved_kernel.excess,
|
||||
sender_partial_sig: sender_part_sig,
|
||||
});
|
||||
|
||||
Ok(proof)
|
||||
}
|
||||
|
||||
/// Initiate tx as sender
|
||||
pub fn init_send_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
@@ -568,9 +715,14 @@ where
|
||||
let sender_address = OnionV3Address::from_private(&sec_addr_key.0)?;
|
||||
|
||||
slate.payment_proof = Some(PaymentInfo {
|
||||
sender_address: sender_address.to_ed25519()?,
|
||||
sender_address: Some(sender_address.to_ed25519()?),
|
||||
receiver_address: a.pub_key,
|
||||
receiver_signature: None,
|
||||
promise_signature: None,
|
||||
timestamp: DateTime::<Utc>::from_utc(
|
||||
NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
|
||||
Utc,
|
||||
),
|
||||
memo: None,
|
||||
});
|
||||
|
||||
context.payment_proof_derivation_index = Some(deriv_path);
|
||||
@@ -1369,3 +1521,143 @@ where
|
||||
output: output,
|
||||
})
|
||||
}
|
||||
|
||||
// Contract implementation
|
||||
|
||||
/// Initialize transaction contract
|
||||
pub fn contract_new<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: &ContractNewArgsAPI,
|
||||
// use_test_rng: bool,
|
||||
) -> Result<Slate, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
contract::new(&mut *w, keychain_mask, &args.setup_args)
|
||||
}
|
||||
|
||||
// /// Setup transaction contract
|
||||
// pub fn contract_setup<'a, T: ?Sized, C, K>(
|
||||
// w: &mut T,
|
||||
// keychain_mask: Option<&SecretKey>,
|
||||
// args: &ContractSetupArgsAPI,
|
||||
// slate: &Slate,
|
||||
// // use_test_rng: bool,
|
||||
// ) -> Result<Slate, Error>
|
||||
// where
|
||||
// T: WalletBackend<'a, C, K>,
|
||||
// C: NodeClient + 'a,
|
||||
// K: Keychain + 'a,
|
||||
// {
|
||||
// contract::setup(&mut *w, keychain_mask, slate, &args)
|
||||
// }
|
||||
|
||||
/// Sign transaction contract
|
||||
pub fn contract_sign<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: &ContractSetupArgsAPI,
|
||||
slate: &Slate,
|
||||
// use_test_rng: bool,
|
||||
) -> Result<Slate, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
contract::sign(&mut *w, keychain_mask, slate, &args)
|
||||
}
|
||||
|
||||
/// Revoke transaction contract
|
||||
pub fn contract_revoke<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: &ContractRevokeArgsAPI,
|
||||
// use_test_rng: bool,
|
||||
) -> Result<Option<Slate>, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
contract::revoke(&mut *w, keychain_mask, &args)
|
||||
}
|
||||
|
||||
/// Revoke transaction contract
|
||||
pub fn get_slate_index_matching_my_context<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
// use_test_rng: bool,
|
||||
) -> Result<usize, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let keychain = w.keychain(keychain_mask)?;
|
||||
let context = w.get_private_context(keychain_mask, slate.id.as_bytes())?;
|
||||
slate.find_index_matching_context(&keychain, &context)
|
||||
}
|
||||
|
||||
/// Create MXMixnet request
|
||||
pub fn create_mwmixnet_req<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
params: &MixnetReqCreationParams,
|
||||
slate: &Slate,
|
||||
// use_test_rng: bool,
|
||||
) -> Result<SwapReq, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let context = w.get_private_context(keychain_mask, slate.id.as_bytes())?;
|
||||
|
||||
let my_keys = context.get_private_keys();
|
||||
let kernel = slate.tx_or_err()?.kernels()[0];
|
||||
|
||||
let msg = kernel.msg_to_sign()?;
|
||||
|
||||
let comsig = ComSignature::sign(slate.amount, &my_keys.0, &msg.to_hex().as_bytes().to_vec())?;
|
||||
|
||||
let mut hops: Vec<Hop> = Vec::new();
|
||||
let mut final_commit = kernel.excess.clone();
|
||||
let mut final_blind = my_keys.0.clone();
|
||||
|
||||
for i in 0..params.server_keys.len() {
|
||||
let excess = params.server_keys[i].clone();
|
||||
|
||||
let secp = secp256k1zkp::Secp256k1::with_caps(secp256k1zkp::ContextFlag::Commit);
|
||||
final_blind.add_assign(&secp, &excess).unwrap();
|
||||
final_commit = add_excess(&final_commit, &excess).unwrap();
|
||||
let proof = if i == params.server_keys.len() - 1 {
|
||||
let n1 = random_secret();
|
||||
let rp = secp.bullet_proof(
|
||||
slate.amount - (params.fee_per_hop * params.server_keys.len() as u32) as u64,
|
||||
final_blind.clone(),
|
||||
n1.clone(),
|
||||
n1.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
assert!(secp.verify_bullet_proof(final_commit, rp, None).is_ok());
|
||||
Some(rp)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let hop = new_hop(¶ms.server_keys[i], &excess, params.fee_per_hop, proof);
|
||||
hops.push(hop);
|
||||
}
|
||||
|
||||
let onion = create_onion(&kernel.excess, &hops)?;
|
||||
|
||||
Ok(SwapReq { comsig, onion })
|
||||
|
||||
//slate.find_index_matching_context(&keychain, &context)
|
||||
}
|
||||
|
||||
@@ -200,6 +200,8 @@ pub struct RetrieveTxQueryArgs {
|
||||
pub include_received_only: Option<bool>,
|
||||
/// whether to only consider coinbase transactions
|
||||
pub include_coinbase_only: Option<bool>,
|
||||
/// whether to only consider self spend transactions
|
||||
pub include_self_spend_only: Option<bool>,
|
||||
/// whether to only consider reverted transactions
|
||||
pub include_reverted_only: Option<bool>,
|
||||
/// lower bound on the total amount (amount_credited - amount_debited), inclusive
|
||||
@@ -237,6 +239,7 @@ impl Default for RetrieveTxQueryArgs {
|
||||
include_sent_only: Some(false),
|
||||
include_received_only: Some(false),
|
||||
include_coinbase_only: Some(false),
|
||||
include_self_spend_only: Some(false),
|
||||
include_reverted_only: Some(false),
|
||||
min_amount: None,
|
||||
max_amount: None,
|
||||
|
||||
Reference in New Issue
Block a user