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

MTX.fund - Fixes #666

Closed
wants to merge 4 commits into from
Closed

MTX.fund - Fixes #666

wants to merge 4 commits into from

Conversation

nodech
Copy link
Contributor

@nodech nodech commented Dec 3, 2021

This is alternative implementation of #639 that solves issue in the CoinSelector.

Separate existing and preferred inputs:

  • existing are the inputs that are present in the mtx.
  • preferred now refers to inputs passed by options.inputs.
  • Use CoinView to resolve coins.

Closes #639
Closes #901

@nodech
Copy link
Contributor Author

nodech commented Dec 3, 2021

Test is just repeat of the matrix, it can be rewritten and shortened as a function..

@nodech nodech changed the title MTX - use coinview to resolve preferred inputs MTX.fund - Fixes Dec 3, 2021
@coveralls
Copy link

coveralls commented Dec 3, 2021

Coverage Status

coverage: 69.875% (+0.07%) from 69.802%
when pulling c9cc309 on nodech:mtx-fund
into 9ddb69e on handshake-org:master.

@nodech nodech added enhancement general - improving existing feature primitives part of the codebase tests part of the codebase patch Release version bug general - Something isn't working labels Dec 3, 2021
Copy link
Member

@pinheadmz pinheadmz left a comment

Choose a reason for hiding this comment

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

Questions and comments below. One other thing I think we should test is some signatures / witness stacks. There's no mtx.check() in these tests and one of the important reasons for this patch is to enable the wallet to fund a MTX that already has a signed input. Use cases are coinjoins, atomic swaps, wallet plugins that handle fancy non standard scripts, etc. We already kinda have that in the atomic-swap test but I think it'd be prudent to include at least one external signature check in mtx-test.js as well.

@@ -1413,6 +1413,27 @@ class MTX extends TX {
/**
* Coin Selector
* @alias module:primitives.CoinSelector
Copy link
Member

Choose a reason for hiding this comment

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

Nice job on the jsdocs properties -- do we actually need this alias?

http://hsd-dev.org/hsd/module-primitives.CoinSelector.html

I'm not sure why it needs to be listed as a primitive since the code is not in the primitves/ directory...

http://hsd-dev.org/hsd/module-primitives.html

Copy link
Member

Choose a reason for hiding this comment

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

Also we're not describing the options here but I see that is missing from many classes in hsd, so that should be a future project...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hm.. CoinSelector is part of the primitives/mtx - so I guess that's the reason?

Will also add options. It's almost exact as properties but still.

lib/primitives/mtx.js Outdated Show resolved Hide resolved
const coin = dummyCoin(wallet1.getAddress(), 1000000);

mtx.addOutput(wallet2.getAddress(), 1500000);
mtx.view.addCoin(coin);
Copy link
Member

Choose a reason for hiding this comment

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

Could also be mtx.addCoin(coin) right? I tried this and test passed -- is there any significant difference?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above. We want to make sure view is processed properly.


// Ensure we have coins for the existing inputs.
const view = this.tx.view;
Copy link
Member

Choose a reason for hiding this comment

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

This is confusing me a little bit because the constructor already assigns this.tx = tx.clone(); and this.view = tx.view; Except for the last for loop (line 1782) you use this.view which is what I'd expect ...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because mtx.clone does not clone coinview, this.tx has fresh view.

So this method ensures we have all necessary coins in the original CoinView and copies to the new one.

lib/primitives/mtx.js Outdated Show resolved Hide resolved
lib/primitives/mtx.js Outdated Show resolved Hide resolved
@pinheadmz
Copy link
Member

Another thing I noticed is that in the worst case scenario, we will loop through this.coins twice and then iterate through a third time to fill the remaining inputs -- do you think it makes any sense to merge the existing & preferred loops? This will also get a lot better when we refactor txdb and not pull ALL COINS out for every tx...

Comment on lines +1781 to +1770
for (const coin of coins) {
view.addCoin(coin);
this.viewCoins.push(coin);
Copy link
Member

Choose a reason for hiding this comment

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

Why is this ending different than resolvePreferred()? Do we already have these coins in chosen?

    for (const coin of coins) {
      this.tx.addCoin(coin);
      this.chosen.push(coin);
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this.tx.addCoin will also create inputs in the tx. We don't want to do that here, because those inputs already exist in the this.tx. We are just updating view (Comment above)

return;

while (this.index < this.coins.length) {
const coin = this.coins[this.index++];
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible that a coin would be added twice? If, for example, this.coins[1] was actually spent by one of the preferred or existing inputs, could that coin be mistakenly added a second time to fund the rest of the transaction? I actually am not even sure mtx.check() would catch a double-spend like this, we might need an explicit test

@pinheadmz
Copy link
Member

The anyone can renew test can also be updated:

// Have to add this last because wallet fund clears existing input data
const witness = new Stack();
witness.pushData(script.encode());
mtx.inputs[0].witness.fromStack(witness);

@handshake-org handshake-org deleted a comment from Gksvxc7up Jan 31, 2022
@pinheadmz
Copy link
Member

@nodech checking in on this?

@nodech
Copy link
Contributor Author

nodech commented Mar 9, 2022

One thing that users will have to consider with these changes is that, coinview should always be supplied with coin information when using preferred inputs and existing inputs. If you don't add coins to the coinview, the code will try to fill them in from the coin list it gets, but if the coin list is big that will hit the performance. - That feature is there to help users just in case.

As for double spend question: It's not job of the CoinSelector to resolve double spents that happen because of the existing and preferred inputs. The coinselector itself wont double spend the coins if they are correctly applied to the coinview.

nodech and others added 3 commits August 22, 2024 14:43
Previous version of interactive-name-swap used a ugly hack to get around limitations
on wallet funding, since wallet.fund() no longer wipes previous inputs, the previous
implementation is not longer the recommended way.
@nodech nodech added breaking-major Backwards incompatible - Release version and removed patch Release version labels Aug 27, 2024
@nodech nodech closed this in #901 Aug 27, 2024
@nodech nodech deleted the mtx-fund branch August 27, 2024 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-major Backwards incompatible - Release version bug general - Something isn't working enhancement general - improving existing feature primitives part of the codebase tests part of the codebase
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants