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

Massive Spend Refactor #1989

Merged
merged 28 commits into from
Aug 28, 2024
Merged

Massive Spend Refactor #1989

merged 28 commits into from
Aug 28, 2024

Conversation

grumbach
Copy link
Member

@grumbach grumbach commented Jul 19, 2024

BREAKING CHANGE

Continuing off @maqi's redesign of Spends in refactor PR #1930
Redesigns the whole transacting flow from CashNotes all the way to Spend with a simpler design:

Removing:

  • OfflineTransfer: all you need to make a transaction, signed
  • TransferInputs : amassed data to make a transaction's inputs
  • CashNotesAndSecretKey : this for inputs too
  • TransactionBuilder: this makes a transaction from inputs
  • CashNoteBuilder: this makes cashnotes from transactions
  • UnsignedTransfer: this is a special case when we don't have a key to sign the transaction
  • Transaction, Input, Output: this was in Spends
  • the middle spend patch
  • lots of unused error variants
  • duplicate code
  • layers and layers of obfuscation abstraction
  • more than 500 lines of code
  • ...

Replaced by:

  • UnsignedTransaction: all you need to make a transaction, not signed
  • SignedTransaction: all you need to make a transaction, signed

What's next

  • adapt spend_simulation tests that were using the Transactions in Spends @RolandSherwin
  • implement UnsignedTransaction::verify
  • unit test UnsignedTransaction::new, UnsignedTransaction::sign
  • unit test hex serialization for both new types

@joshuef
Copy link
Contributor

joshuef commented Jul 22, 2024

What's the impact here for OMNI disbursement if any?

@grumbach grumbach force-pushed the without_middle_spend branch from 12b7c4d to 9374151 Compare July 22, 2024 14:42
sn_client/src/audit/tests/mod.rs Fixed Show fixed Hide fixed
sn_transfers/benches/reissue.rs Fixed Show fixed Hide fixed
sn_transfers/src/transfers/unsigned_transaction.rs Fixed Show resolved Hide resolved
// info!("{id} verifying status of spend number({num:?}): {spend:?} : {status:?}");
// match status {
// SpendStatus::Utxo => {
// // TODO: with the new spend struct requiring `middle payment`

Check notice

Code scanning / devskim

A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note test

Suspicious comment
@grumbach
Copy link
Member Author

What's the impact here for OMNI disbursement if any?

This reworks the structure of the Spend and refactors the transaction flow, it shouldn't affect OMNI disbursement

@grumbach grumbach force-pushed the without_middle_spend branch from e4203ee to c104e4b Compare July 23, 2024 17:15
Comment on lines 139 to 144
pub fn is_genesis_spend(spend: &SignedSpend) -> bool {
let bytes = spend.spend.to_bytes_for_signing();
spend.spend.unique_pubkey == *GENESIS_SPEND_UNIQUE_KEY
&& GENESIS_SPEND_UNIQUE_KEY.verify(&spend.derived_key_sig, bytes)
&& is_genesis_parent_tx(&spend.spend.parent_tx)
&& spend.spend.amount == NanoTokens::from(GENESIS_CASHNOTE_AMOUNT)
&& spend.spend.amount() == NanoTokens::from(GENESIS_CASHNOTE_AMOUNT)
}
Copy link
Member Author

@grumbach grumbach Jul 23, 2024

Choose a reason for hiding this comment

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

If we know the content of the Genesis Spend, maybe also add those values in this test to make sure it's the one and unique genesis? Do we know those values?

&& spend.spend.reason == GENESIS_REASON
&& spend.spend.ancestors == GENESIS_ANCESTORS
&& spend.spend.descendants == GENESIS_DESCENDANTS

Assuming GENESIS_SK is destroyed at Network Genesis, this scenario should not happen, but are we ever too safe?

Copy link
Member

Choose a reason for hiding this comment

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

Do we know those values?

Yeah, we do can know these values.

Assuming GENESIS_SK is destroyed at Network Genesis

shall be OK, as GENESIS_SK is actually not used (and shall not be used) after GENESIS_SPEND generated.

@grumbach grumbach force-pushed the without_middle_spend branch from 6c2a077 to dd16544 Compare July 23, 2024 18:14
@grumbach grumbach force-pushed the without_middle_spend branch from 7fc6a99 to 850b28f Compare July 23, 2024 20:03
@grumbach grumbach marked this pull request as ready for review July 23, 2024 20:44
@grumbach grumbach enabled auto-merge July 23, 2024 20:55
@grumbach grumbach requested review from maqi and RolandSherwin July 24, 2024 09:45
sn_transfers/src/cashnotes/cashnote.rs Show resolved Hide resolved
sn_transfers/src/cashnotes/cashnote.rs Show resolved Hide resolved
{
/// - verifies that the parent_spends contains self as an output
/// - verifies the sum of total inputs equals to the sum of outputs
pub fn verify_parent_spends(&self, parent_spends: &BTreeSet<SignedSpend>) -> Result<()> {
Copy link
Member

Choose a reason for hiding this comment

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

I am wondering without the middle pay, how the above conditions got all satisfied for the scenario of multiple_inputs to multiple_outputs ?

Copy link
Member

Choose a reason for hiding this comment

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

looks like it now trying to use return multiple cash_note, each cn per recipient, i.e. get inputs distributed to outpus explicitly to resolve this.
So, here, both of the criterias can still be satisfied at the same time.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes all this is covered by the distribution algo in UnsignedTransaction

// check for double spend parents
if spends.len() > 1 {
error!("While verifying parents of {unique_key}, found a double spend parent: {spends:?}");
return Err(TransferError::DoubleSpentParent);
Copy link
Member

Choose a reason for hiding this comment

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

This actually means the spend itself having duplicated ancestors ?
which is different to the scenario that an ancestor got spent already?
maybe it shall give a different name to differiate these two scenarios?

Copy link
Member Author

@grumbach grumbach Jul 25, 2024

Choose a reason for hiding this comment

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

This actually means the spend itself having duplicated ancestors ?

This means one of the spend's parents has multiple entries and is burnt.

Comment on lines 139 to 144
pub fn is_genesis_spend(spend: &SignedSpend) -> bool {
let bytes = spend.spend.to_bytes_for_signing();
spend.spend.unique_pubkey == *GENESIS_SPEND_UNIQUE_KEY
&& GENESIS_SPEND_UNIQUE_KEY.verify(&spend.derived_key_sig, bytes)
&& is_genesis_parent_tx(&spend.spend.parent_tx)
&& spend.spend.amount == NanoTokens::from(GENESIS_CASHNOTE_AMOUNT)
&& spend.spend.amount() == NanoTokens::from(GENESIS_CASHNOTE_AMOUNT)
}
Copy link
Member

Choose a reason for hiding this comment

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

Do we know those values?

Yeah, we do can know these values.

Assuming GENESIS_SK is destroyed at Network Genesis

shall be OK, as GENESIS_SK is actually not used (and shall not be used) after GENESIS_SPEND generated.

sn_transfers/src/transfers/unsigned_transaction.rs Fixed Show resolved Hide resolved
sn_transfers/src/transfers/unsigned_transaction.rs Outdated Show resolved Hide resolved
@maqi maqi mentioned this pull request Jul 25, 2024
@grumbach grumbach force-pushed the without_middle_spend branch 2 times, most recently from c8a9195 to 935becf Compare July 25, 2024 14:37
@@ -93,11 +111,21 @@ impl UnsignedTransaction {
})
.collect();

// order inputs by value, re const after sorting
let mut cashnotes_big_to_small = available_cash_notes;
Copy link
Member

Choose a reason for hiding this comment

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

we shall try to use the small ones first ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ideally we'd like to minimize the amount of Spends created, using big ones first has that effect for now, but it's not optimal over the long run.

In the future I imagine we should create a better algorithm that would optimize that and choose the best options with the closest values as to minimize the amount of spends and avoid using huge Cashnotes for small Txs.

Also, since CashNotes don't have a determined value anymore, we could return the change value to an existing unspent CashNote that would accumulate wealth until it is spent.

All these nice optimizations will not change the API in this PR so that's also nice!

@grumbach grumbach force-pushed the without_middle_spend branch from 935becf to e0d8aeb Compare July 29, 2024 13:25
@grumbach grumbach force-pushed the without_middle_spend branch from ab59db4 to 9fe6f44 Compare July 29, 2024 15:25
@grumbach grumbach force-pushed the without_middle_spend branch from 41193e0 to 8bcab6d Compare July 29, 2024 15:47
@grumbach grumbach added this pull request to the merge queue Aug 28, 2024
Merged via the queue into maidsafe:main with commit e15aae3 Aug 28, 2024
117 of 120 checks passed
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.

4 participants