[Multisend] Improve multisend and UTXO split handling#1096
Closed
CryptoDev-Project wants to merge 1 commit into
Closed
[Multisend] Improve multisend and UTXO split handling#1096CryptoDev-Project wants to merge 1 commit into
CryptoDev-Project wants to merge 1 commit into
Conversation
611444f to
91de889
Compare
|
Multisend has been definitely removed in #2293. Closing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1️⃣ "MultiSendStake Activated" and "MultiSendMasternode Not Activated" and we win masternode reward
My testing shows that we send the masternode reward in the above scenario. We need to set sendMSOnStake only when !outpoint.IsMasternodeReward(out.tx)
2️⃣ "MultiSendStake Activated" and "MultiSendMasternode Not Activated" and we win both masternode and staking reward in same wallet
In this outlier case scenario, we'll go through the loop beginning wallet.cpp#L3485 twice - once for the stake reward and once for mn reward. Both times, sendMSOnStake will hold true. In each case, nAmount is calculated as (out.tx->GetCredit(ISMINE_SPENDABLE) - out.tx->GetDebit(ISMINE_SPENDABLE). As we own spendable coins equating to the entire block value, the first time through the loop will result in us sending the entire block reward using the stake output as an input. The second time will involve us attempting to send the entire block value a second time using the masternode reward as input. This transaction will fail as masternode reward input is insufficient when attempting to send (masternode reward + staking reward).
The fix for 1️⃣ removes the second run through the loop, but we still send the entire block value as we earned both masternode and staking reward, both now considered ISMINE_SPENDABLE from the relevant TX. During testing, even with the second loop removed, I also obeserved failed multisend transaction commits where (stake input + stake reward) < block value. We need to remove the stake reward or masternode reward values for wallets that haven't activated those.
The fix implemented for 2️⃣, which factored in the requirements for both reward categories, results in only the staking reward being sent via multisend when only MultiSendStake is activated. I then switched to having only MultiSendMasternode activated and, as required, the staking reward is deducted from the value sent. We're now accounting for when either, but not both, options are selected.
3️⃣ "MultiSendStake Activated" and "MultiSendMasternode Activated"
Having implemented the above fixes, I now activate multisend for masternodes and staking. Once again, behavior deviates from expectations. This is because we are looping through the code twice where one wins both masternode and staking reward. The masternode reward output, like the stake output before it, attempts to send the entire block reward via multisend and fails. Therefore, when we 'set which MultiSend triggered', we must set both as having being triggered if we won, and sent via multisend, the entire block reward.
4️⃣ Excessively low user setting for stake split threshold
Even after the above changes, we still face issues where (stake input + stake reward) < block value and we win both masternode and staking reward. However, this is such an outside case that I feel it's okay to let the multisend transaction fail. The code would need a rewrite to add additional inputs to the transaction and is simply not worth it in my opinion given that it's an issue that's likely to never happen, but with extremely minor consequences if it does, i.e. a multisend transaction failure.
However, even if we don't win both masternode and staking reward, we will encounter issues where stakesplitthreshold is set so low that one of the UTXO's fails to cover the amount to be sent via multisend. To resolve this issue, I have added code to override the users stakesplitthreshold with the block value if they happen to choose anything below that value.
5️⃣ Stake split decision including masternode reward in error
During testing, I also observed that wallet.cpp#L2699 uses nCredit solely to determine whether we actually need a split. However, nCredit includes the masternode reward in error. Therefore, I've deducted it from nReward for the purposes of the call to CreateTxOuts.
6️⃣ Multisend after stake resulting in UTXO split
When a stake reward results in a UTXO split, the resulting multisend transaction is attempted multiple times, once for each UTXO from the stake split. This was the original fix I provided, and must remain.