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

make create_transaction() read only. attempt 3. #162

Merged

Conversation

dan-da
Copy link
Collaborator

@dan-da dan-da commented Jul 9, 2024

Addresses #122. Obsoletes #159.

This is my 3rd attempt to refactor create_transaction(). Perhaps 3rd try is the charm.

For original background motivation and discussion, see previous attempts: #136 and #159.

Some goals of this attempt are:

  • address Alan's comments in 159.
  • make the code simpler and cleaner to read, understand, maintain.
  • make UtxoNotification variants symmetric.
  • keep create_transaction() simple for caller to use, but also flexible.
  • lay some groundwork for onchain symmetric key notification
  • abstract over key/address type in public APIs.
  • prepare for using derived key indexes in a future commit.

Changes since #159:

highlights / key changes:

  • input utxos are now automatically matched to the appropriate spending key. previously that was a TODO.
  • abstract SpendingKey and ReceivingAddr in create_transaction() and all RPC APIs. This should make it possible to add new address types without major refactors post-launch.
  • add create_raw_transaction() for fine-grained control over inputs and outputs, including change. (Same api exists in bitcoin.)
  • all create_transaction() related code is now simpler and cleaner, at least to my eye, with significant functionality moved into TxInput, TxInputList, TxOutput, TxOutputList.
  • create_transaction() return type is now just a Transaction, not a tuple.
  • change spending key is now a param to create_transaction() in order to keep it &self. (see discussion below).

rpc_server:

  • own_receiving_address --> next_receiving_address
  • SpendingKey -> SpendingKeyType in rpc APIs
  • ReceivingAddress -> ReceivingAddressType in rpc APIs
  • adapt send_to_many() to create_transaction() changes. (simpler now)

global_state:

  • simplify TransactionDetails, and is now private struct.
  • eliminated several private helper fn
  • simplified create_transaction family of fns with TxInputList, TxOutputList
  • added doc comments
  • add generate_tx_outputs() public helper method
  • create_transaction() args changed:
    • receiver_data --> tx_outputs
    • tx_outputs is now &mut, and may have change output appended for caller's use.
    • add change_spending_key
  • create_transaction() return type is now just a Transaction, not a tuple.
  • caller must pass a change spending key into create_transaction() because
    next_unused_generation_spending_key() takes &mut self.
  • added create_raw_transaction() for fine grained control over inputs and outputs
  • simplify create_transaction() helper fns.

wallet:

  • add abstract SpendingKeyType and ReceivingKeyType
  • add wallet_state::find_spending_key_for_utxo()
  • wallet_state::allocate_sufficient_input_funds_from_lock() now returns
    matching SpendingKeyType with each input. (fixes prev TODO)

transaction:

  • add TxInput, TxInputList, TxOutput, TxOutputList
  • add UtxoNotifyMethod, UtxoNotification

other:

  • UtxoReceiver -> TxOutput

Explanations of things that may not be obvious:

  1. preparing for derived keys. Presently some functions call WalletSecret::nth_generation_spending_key(&self, counter: u16), passing 0. I've now added ::next_unused_generation_spending_key(&mut self), which presently always uses index 0 but in the future will increment a stateful counter. The difficulty is that it must take &mut self, so it cannot be called from within GlobalState methods that take &self, such as create_transaction(). So create_transaction() now requires the caller to provide the next unused spending key.

  2. let me know if there's something else. I put a lot of code comments, but let me know if anything is unclear.

dan-da added 16 commits July 8, 2024 15:59
Previously a write-lock was held across `create_transaction()` which
includes a lengthy (potentially minutes) call to `prove`.  This would be
unacceptably bad for concurrency.

This commit makes create_transaction() take &self instead of &mut self.

Only a single mutation was being performed inside add_change() and this
is now moved into `send()` RPC after `create_transaction()` completes.
The write-lock acquisition is like-wise moved, so it should only be
held very briefly while adding a record to wallet's `expected_utxos`.
Refactors create_transaction() to enable the caller to specify which
output utxo shold use onchain global-announcement vs offchain
expected-utxo.  A method is provided to automatically determine this
based on if it appears the utxo is destined for our own wallet or not.

Also, create_transaction() now returns (unblinded) TransactionData
which includes a list of all ExpectedUtxo.  It is caller's
responsibility to inform the wallet, which mutates state.

It can be said that we now:
 * support off-chain notifications for the general case of all utxo
   going to our wallet instead of only the sub-case of change address.
 * support specifying if each utxo will use on or off-chain notification
   except for the change address, which is always off-chain.

Changes:

wallet_state:
 * add get_known_spending_keys().  placeholder to centralize logic
 * add is_wallet_utxo()

models/state/mod.rs:
 * add struct TransactionData
 * move UtxoReceiverData into utxo_receiver.rs
 * use ExpectedUtxo in place of ChangeUtxoData
 * create_transaction() returns (Transaction, TransactionData)
 * add doc-comment, example for create_transaction()
 * receiver_data param to create_transaction can now specify if each
   utxo uses Onchain or Offchain notification
 * add add_expected_utxos_to_wallet()
 * remove redundant create_transaction_with_timestamp()

rpc_server.rs:
 * add send_to_many() endpoint, which is called by send()
 * use UtxoReceiverData::auto() to determine if recipient(s) should
   be notified Onchain or Offchain
 * remove pause/resume of miner.  doesn't seem necessary.
 * simplify wallet notificaiton
Addresses Neptune-Crypto#122

Enables caller of create_transaction() to choose whether the Change
UTXO will use OnChain or OffChain notification.

Note that caller could already do this since the last commit by
manually creating the Change UTXO so that sum(inputs) == sum(outputs).
Therefore, this change only makes it a bit easier, and is more
consistent in that the caller can easily control the notification
behavior of all outputs.

The default behavior is still OffChain notification and doc-comments
and example usage recommend this for normal usage.

Also, this fine level of control is not available in the RPC send and
send_to_many endpoints.  Only in the rust API.

Changes:
 * add change_notify_method arg to create_transaction()
 * update tests to use extra arg.
 * rename UtxoReceiverData --> UtxoReceiver
 * rename TransactionData --> TransactionDetails
 * fix: backwards logic in UtxoRecipient::auto()
 * improve doc-comment for create_transaction()
 * add ChangeNotifyMethod enum
 * add some missing doc-comments
adds:
 * test_utxoreceiver_auto_off_chain()
 * test_utxoreceiver_auto_on_chain
UtxoReceiver::receiver_preimage -> receiver_privacy_digest
Changes:
 * remove redundant receive_privacy_digest param from
   UtxoReceiver::auto()
 * RpcServer::send_to_many(): flush DBs before notifying main
 * RpcServer::send_to_many(): log error if noiifying main fails
 * test_rpc_server(): spawn a dummy main to listen to RpcServer
   notifications
 * add test: send_to_many_test()
Usage: neptune-cli send-to-many <OUTPUTS>... <FEE>

Arguments:
  <OUTPUTS>...  format: address:amount address:amount ...
  <FEE>

----

Also simplifies the success output of Send comand to just
"Send completed" instead of verbosely including the many-line address
and amount.
Changes enums UtxoNotifyMethod and ChangeNotifyMethod in anticipation
of the day that we implement Symmetric Key notifications for UTXO
that can be claimed by our own wallet, such as Change outputs.

pub enum UtxoNotifyMethod {
    OnChain(PublicAnnouncement),
    OffChain,
}

becomes:

pub enum UtxoNotifyMethod {
    OnChainPubKey(PublicAnnouncement),
    OnChainSymmetricKey,
    OffChain,
}
@dan-da dan-da requested a review from aszepieniec July 9, 2024 04:12
Copy link
Contributor

@aszepieniec aszepieniec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent data structures. Updated function interfaces follow logically from them. Very little room for controversy. Minor suggestions inline.

src/bin/neptune-cli.rs Outdated Show resolved Hide resolved
src/models/blockchain/transaction/transaction_output.rs Outdated Show resolved Hide resolved
src/models/blockchain/transaction/mod.rs Outdated Show resolved Hide resolved
src/models/state/wallet/wallet_state.rs Outdated Show resolved Hide resolved
@dan-da dan-da requested a review from Sword-Smith July 11, 2024 19:46
@dan-da dan-da merged commit a70adbc into Neptune-Crypto:master Jul 12, 2024
3 checks passed
@dan-da
Copy link
Collaborator Author

dan-da commented Jul 12, 2024

I went ahead and merged this. @Sword-Smith if you have any concerns, pls let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants