From ed8999a3a00f2989a5fd071d980ad98d1ac1311e Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 21 Dec 2020 14:42:51 -0300 Subject: [PATCH 01/22] [GUI] send screen, hide shield all coins btn for now. Github-Pull: #2094 Rebased-From: 575349b7fbe0021d63ecddf70fd38826b4b6f622 --- src/qt/pivx/send.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/pivx/send.cpp b/src/qt/pivx/send.cpp index 826d1d1ff8880..3339767d616bd 100644 --- a/src/qt/pivx/send.cpp +++ b/src/qt/pivx/send.cpp @@ -77,6 +77,7 @@ SendWidget::SendWidget(PIVXGUI* parent) : // Shield coins ui->btnShieldCoins->setTitleClassAndText("btn-title-grey", tr("Shield Coins")); ui->btnShieldCoins->setSubTitleClassAndText("text-subtitle", tr("Convert all transparent coins into shielded coins")); + ui->btnShieldCoins->setVisible(false); connect(ui->pushButtonFee, &QPushButton::clicked, this, &SendWidget::onChangeCustomFeeClicked); connect(ui->btnCoinControl, &OptionButton::clicked, this, &SendWidget::onCoinControlClicked); From 227161bc88eba74f683b3523128db045594da977 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Mon, 21 Dec 2020 17:27:17 +0100 Subject: [PATCH 02/22] [Trivial][RPC] Drop 'ed' suffix from Shielded in TxSaplingToJSON Github-Pull: #2093 Rebased-From: 8fd6af03e124fff00dbf6d7fc403900ad06c29d2 --- src/sapling/sapling_core_write.cpp | 4 ++-- test/functional/sapling_mempool.py | 2 +- test/functional/sapling_wallet.py | 8 ++++---- test/functional/sapling_wallet_listreceived.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sapling/sapling_core_write.cpp b/src/sapling/sapling_core_write.cpp index 7f59a6828a2a8..f7eaa573c969f 100644 --- a/src/sapling/sapling_core_write.cpp +++ b/src/sapling/sapling_core_write.cpp @@ -46,9 +46,9 @@ void TxSaplingToJSON(const CTransaction& tx, UniValue& entry) { entry.pushKV("valueBalance", FormatMoney(tx.sapData->valueBalance)); entry.pushKV("valueBalanceSat", tx.sapData->valueBalance); UniValue vspenddesc = TxShieldedSpendsToJSON(tx); - entry.pushKV("vShieldedSpend", vspenddesc); + entry.pushKV("vShieldSpend", vspenddesc); UniValue voutputdesc = TxShieldedOutputsToJSON(tx); - entry.pushKV("vShieldedOutput", voutputdesc); + entry.pushKV("vShieldOutput", voutputdesc); if (tx.sapData->hasBindingSig()) { entry.pushKV("bindingSig", HexStr(tx.sapData->bindingSig.begin(), tx.sapData->bindingSig.end())); } diff --git a/test/functional/sapling_mempool.py b/test/functional/sapling_mempool.py index febc33a629d19..93589a6edaea0 100755 --- a/test/functional/sapling_mempool.py +++ b/test/functional/sapling_mempool.py @@ -94,7 +94,7 @@ def run_test(self): # Now disconnect the block with the note's anchor, # and check that the tx is removed from the mempool self.log.info("Disconnect the last block to change the sapling anchor") - anchor = txC_json['vShieldedSpend'][0]['anchor'] + anchor = txC_json['vShieldSpend'][0]['anchor'] assert_equal(anchor, miner.getbestsaplinganchor()) miner.invalidateblock(miner.getbestblockhash()) assert (anchor != miner.getbestsaplinganchor()) diff --git a/test/functional/sapling_wallet.py b/test/functional/sapling_wallet.py index b8b02a4b891da..5b71dfb3985f6 100755 --- a/test/functional/sapling_wallet.py +++ b/test/functional/sapling_wallet.py @@ -238,17 +238,17 @@ def run_test(self): # Verify existence of Sapling related JSON fields resp = self.nodes[0].getrawtransaction(mytxid7, 1) assert_equal(Decimal(resp['valueBalance']), Decimal('11.00')) # 20 shield input - 8 shield spend - 1 change - assert_equal(len(resp['vShieldedSpend']), 3) - assert_equal(len(resp['vShieldedOutput']), 2) + assert_equal(len(resp['vShieldSpend']), 3) + assert_equal(len(resp['vShieldOutput']), 2) assert('bindingSig' in resp) - shieldedSpend = resp['vShieldedSpend'][0] + shieldedSpend = resp['vShieldSpend'][0] assert('cv' in shieldedSpend) assert('anchor' in shieldedSpend) assert('nullifier' in shieldedSpend) assert('rk' in shieldedSpend) assert('proof' in shieldedSpend) assert('spendAuthSig' in shieldedSpend) - shieldedOutput = resp['vShieldedOutput'][0] + shieldedOutput = resp['vShieldOutput'][0] assert('cv' in shieldedOutput) assert('cmu' in shieldedOutput) assert('ephemeralKey' in shieldedOutput) diff --git a/test/functional/sapling_wallet_listreceived.py b/test/functional/sapling_wallet_listreceived.py index 7c9a20acfe609..2b19e9a42c591 100755 --- a/test/functional/sapling_wallet_listreceived.py +++ b/test/functional/sapling_wallet_listreceived.py @@ -136,7 +136,7 @@ def run_test(self): # Verify the spent nullifier tx_json = self.nodes[1].getrawtransaction(txid, True) - assert_equal(nullifier, tx_json["vShieldedSpend"][0]["nullifier"]) + assert_equal(nullifier, tx_json["vShieldSpend"][0]["nullifier"]) # Decrypted transaction details should be correct pt = self.nodes[1].viewshieldtransaction(txid) From 7fd9e62d94a8d5e6775e4a94406b387dbb39e3c7 Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 21 Dec 2020 18:18:00 -0300 Subject: [PATCH 03/22] [DOC] Readme, migrated staled travis badge for github actions status badge. Github-Pull: #2095 Rebased-From: 8972187975bc3da4588a320b1c41314d0ffff79b --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a5c81dfec2391..6f19d29fdaab0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ PIVX Core integration/staging repository ===================================== -[![Build Status](https://travis-ci.org/PIVX-Project/PIVX.svg?branch=master)](https://travis-ci.org/PIVX-Project/PIVX) [![GitHub version](https://badge.fury.io/gh/PIVX-Project%2FPIVX.svg)](https://badge.fury.io/gh/PIVX-Project%2FPIVX) +[![master Actions Status](https://github.com/PIVX-Project/PIVX/workflows/CI%20Actions%20for%20PIVX/badge.svg)](https://github.com/PIVX-Project/PIVX/actions) [![GitHub version](https://badge.fury.io/gh/PIVX-Project%2FPIVX.svg)](https://badge.fury.io/gh/PIVX-Project%2FPIVX) +[GitHub version](#github-version) PIVX is an open source cryptocurrency focused on fast, private transactions using the Zerocoin protocol, with low transaction fees & environmental footprint. It utilizes the first ever anonymous proof of stake protocol, called zPoS, combined with regular PoS and masternodes for securing its network. zPoS incentivizes using the privacy features available in PIVX by granting a higher block reward for zPoS over regular PoS and masternodes. In practice, PIVX has between 4 to 10 times higher use of its privacy features in comparison to other coins that combine public and private transactions. This is thanks to innovations like zPoS and integrating the Zerocoin protocol into light/mobile wallets, allowing for a complete and lightweight privacy protocol that can be used on the go. This also includes security improvements like [deterministic generation of zPIV for easy backups.](https://www.reddit.com/r/pivx/comments/8gbjf7/how_to_use_deterministic_zerocoin_generation/) The goal of PIVX is to achieve a decentralized, sustainable cryptocurrency with near instant full-time private transactions, fair governance and community intelligence. From afcba756ce52babb0995f30dcc436a73149d290e Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 21 Dec 2020 19:07:18 -0300 Subject: [PATCH 04/22] [DOC] main readme, re-written to current project state. Github-Pull: #2095 Rebased-From: aafbd8ea8a054b19a4be42345611142169060a05 --- README.md | 105 +++++++++++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 6f19d29fdaab0..a6fcacfd9764a 100644 --- a/README.md +++ b/README.md @@ -2,59 +2,52 @@ PIVX Core integration/staging repository ===================================== [![master Actions Status](https://github.com/PIVX-Project/PIVX/workflows/CI%20Actions%20for%20PIVX/badge.svg)](https://github.com/PIVX-Project/PIVX/actions) [![GitHub version](https://badge.fury.io/gh/PIVX-Project%2FPIVX.svg)](https://badge.fury.io/gh/PIVX-Project%2FPIVX) -[GitHub version](#github-version) - -PIVX is an open source cryptocurrency focused on fast, private transactions using the Zerocoin protocol, with low transaction fees & environmental footprint. It utilizes the first ever anonymous proof of stake protocol, called zPoS, combined with regular PoS and masternodes for securing its network. zPoS incentivizes using the privacy features available in PIVX by granting a higher block reward for zPoS over regular PoS and masternodes. In practice, PIVX has between 4 to 10 times higher use of its privacy features in comparison to other coins that combine public and private transactions. This is thanks to innovations like zPoS and integrating the Zerocoin protocol into light/mobile wallets, allowing for a complete and lightweight privacy protocol that can be used on the go. This also includes security improvements like [deterministic generation of zPIV for easy backups.](https://www.reddit.com/r/pivx/comments/8gbjf7/how_to_use_deterministic_zerocoin_generation/) -The goal of PIVX is to achieve a decentralized, sustainable cryptocurrency with near instant full-time private transactions, fair governance and community intelligence. -- Anonymized transactions & consensus using the [_Zerocoin Protocol_](http://www.pivx.org/zpiv) and [zPoS](https://pivx.org/zpos/). -- light/mobile wallet privacy using the [Zerocoin Light Node Protocol](https://pivx.org/wp-content/uploads/2018/11/Zerocoin_Light_Node_Protocol.pdf) -- Fast transactions featuring guaranteed zero confirmation transactions, we call it _SwiftX_. -- Decentralized blockchain voting utilizing Masternode technology to form a DAO. The blockchain will distribute monthly treasury funds based on successful proposals submitted by the community and voted on by the DAO. - -More information at [pivx.org](http://www.pivx.org) Visit our ANN thread at [BitcoinTalk](http://www.bitcointalk.org/index.php?topic=1262920). Join the community at [PIVX Discord](https://discordapp.com/invite/jzqVsJd). - -### Coin Specs - - - - - - - -
AlgoQuark
Block Time60 Seconds
Difficulty RetargetingEvery Block
Max Coin Supply (PoW Phase)43,199,500 PIV
Max Coin Supply (PoS Phase)Infinite
Premine60,000 PIV*
- -*60,000 PIV Premine was burned in block [279917](http://www.presstab.pw/phpexplorer/PIVX/block.php?blockhash=206d9cfe859798a0b0898ab00d7300be94de0f5469bb446cecb41c3e173a57e0) - -### Reward Distribution - - - - - -
Genesis Block
Block HeightReward AmountNotes
160,000 PIVInitial Pre-mine, burnt in block 279917
- -### PoW Rewards Breakdown - - - - - - -
Block HeightMasternodesMinerBudget
2-4320020% (50 PIV)80% (200 PIV)N/A
43201-15120020% (50 PIV)70% (200 PIV)10% (25 PIV)
151201-25920045% (22.5 PIV)45% (22.5 PIV)10% (5 PIV)
- -### PoS Rewards Breakdown - - - - - - - - - - - - - - -
PhaseBlock HeightRewardMasternodes & StakersBudget
Phase 0259201-30239950 PIV90% (45 PIV)10% (5 PIV)
Phase 1302400-34559945 PIV90% (40.5 PIV)10% (4.5 PIV)
Phase 2345600-38879940 PIV90% (36 PIV)10% (4 PIV)
Phase 3388800-43199935 PIV90% (31.5 PIV)10% (3.5 PIV)
Phase 4432000-47519930 PIV90% (27 PIV)10% (3 PIV)
Phase 5475200-51839925 PIV90% (22.5 PIV)10% (2.5 PIV)
Phase 6518400-56159920 PIV90% (18 PIV)10% (2 PIV)
Phase 7561600-60479915 PIV90% (13.5 PIV)10% (1.5 PIV)
Phase 8604800-64799910 PIV90% (9 PIV)10% (1 PIV)
Phase 9648000-11542035 PIV90% (4.5 PIV)10% (0.5 PIV)
Phase X1154203-∞6 PIV84% (5 PIV/zPIV)16% (1 PIV)
+ +## What is PIVX? + +PIVX is an open source community-driven cryptocurrency, focused on five main aspects: + +(1) User Data Protection: Through the use of SHIELD, a zk-SNARKs based privacy protocol. + +(2) Low environmental footprint and network participation equality: Through the use of a highly developed Proof of Stake protocol. + +(3) Decentralized Governance System: A DAO built on top of the tier two Masternodes network, enabling a monthly community treasury, proposals submission and decentralized voting. + +(4) Fast Transactions: Through the use of low block times and future instant transactions locking features. + +(5) Easy of Use: PIVX is compromised to offer the best possible graphical interface for a core node/wallet. A full featured graphical product for new and advanced users. + +Lot more information and specs at [PIVX.org](http://www.pivx.org). Join the community at [PIVX Discord](https://discordapp.com/invite/jzqVsJd). + +## License +PIVX Core is released under the terms of the MIT license. See [COPYING](https://github.com/PIVX-Project/PIVX/blob/master/COPYING) for more information or see https://opensource.org/licenses/MIT. + +## Development Process + +The master branch is regularly built (see doc/build-*.md for instructions) and tested, but it is not guaranteed to be completely stable. [Tags](https://github.com/PIVX-Project/PIVX/tags) are created regularly from release branches to indicate new official, stable release versions of PIVX Core. + +The contribution workflow is described in [CONTRIBUTING.md](https://github.com/PIVX-Project/PIVX/blob/master/CONTRIBUTING.md) and useful hints for developers can be found in [doc/developer-notes.md](https://github.com/PIVX-Project/PIVX/blob/master/doc/developer-notes.md). + +## Testing + +Testing and code review is the bottleneck for development; we get more pull requests than we can review and test on short notice. Please be patient and help out by testing other people's pull requests, and remember this is a security-critical project where any mistake might cost people lots of money. + +## Automated Testing + +Developers are strongly encouraged to write [unit tests](https://github.com/PIVX-Project/PIVX/blob/master/src/test/README.md) for new code, and to submit new unit tests for old code. Unit tests can be compiled and run (assuming they weren't disabled in configure) with: make check. Further details on running and extending unit tests can be found in [/src/test/README.md](https://github.com/PIVX-Project/PIVX/blob/master/src/test/README.md). + +There are also regression and integration tests, written in Python. These tests can be run (if the test dependencies are installed) with: test/functional/test_runner.py` + +The CI (Continuous Integration) systems make sure that every pull request is built for Windows, Linux, and macOS, and that unit/sanity tests are run automatically. + +## Manual Quality Assurance (QA) Testing + +Changes should be tested by somebody other than the developer who wrote the code. This is especially important for large or high-risk changes. It is useful to add a test plan to the pull request description if testing the changes is not straightforward. + +## Translations + +Changes to translations as well as new translations can be submitted to PIVX Core's Transifex page. + +Translations are periodically pulled from Transifex and merged into the git repository. See the [translation process](https://github.com/PIVX-Project/PIVX/blob/master/doc/translation_process.md) for details on how this works. + +Important: We do not accept translation changes as GitHub pull requests because the next pull from Transifex would automatically overwrite them again. From 1d95c40312045e05a91832ad67b55e92b79752be Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 21 Dec 2020 20:01:35 -0300 Subject: [PATCH 05/22] [DOC] main readme, added latest release version and release date badges Github-Pull: #2095 Rebased-From: d54fab57f31448f9d6ee9a895110ad3efb4033da --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a6fcacfd9764a..360f32d5a12a2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ PIVX Core integration/staging repository ===================================== -[![master Actions Status](https://github.com/PIVX-Project/PIVX/workflows/CI%20Actions%20for%20PIVX/badge.svg)](https://github.com/PIVX-Project/PIVX/actions) [![GitHub version](https://badge.fury.io/gh/PIVX-Project%2FPIVX.svg)](https://badge.fury.io/gh/PIVX-Project%2FPIVX) +[![master Actions Status](https://github.com/PIVX-Project/PIVX/workflows/CI%20Actions%20for%20PIVX/badge.svg)](https://github.com/PIVX-Project/PIVX/actions) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/PIVX-Project/pivx?color=%235c4b7d&cacheSeconds=3600)](https://github.com/PIVX-Project/PIVX/releases) +[![GitHub Release Date](https://img.shields.io/github/release-date/PIVX-Project/pivx?color=%235c4b7d&cacheSeconds=3600)](https://github.com/PIVX-Project/PIVX/releases) ## What is PIVX? @@ -13,11 +15,11 @@ PIVX is an open source community-driven cryptocurrency, focused on five main asp (3) Decentralized Governance System: A DAO built on top of the tier two Masternodes network, enabling a monthly community treasury, proposals submission and decentralized voting. -(4) Fast Transactions: Through the use of low block times and future instant transactions locking features. +(4) Fast Transactions: Through the use of fast block times and the tier two network, PIVX is committed to continue researching new and better instant transactions mechanisms. -(5) Easy of Use: PIVX is compromised to offer the best possible graphical interface for a core node/wallet. A full featured graphical product for new and advanced users. +(5) Ease of Use: PIVX is determined to offer the best possible graphical interface for a core node/wallet. A full featured graphical product for new and advanced users. -Lot more information and specs at [PIVX.org](http://www.pivx.org). Join the community at [PIVX Discord](https://discordapp.com/invite/jzqVsJd). +A lot more information and specs at [PIVX.org](https://www.pivx.org/). Join the community at [PIVX Discord](https://discordapp.com/invite/jzqVsJd). ## License PIVX Core is released under the terms of the MIT license. See [COPYING](https://github.com/PIVX-Project/PIVX/blob/master/COPYING) for more information or see https://opensource.org/licenses/MIT. @@ -30,7 +32,7 @@ The contribution workflow is described in [CONTRIBUTING.md](https://github.com/P ## Testing -Testing and code review is the bottleneck for development; we get more pull requests than we can review and test on short notice. Please be patient and help out by testing other people's pull requests, and remember this is a security-critical project where any mistake might cost people lots of money. +Testing and code review is the bottleneck for development; we get more pull requests than we can review and test on short notice. Please be patient and help out by testing other people's pull requests, and remember this is a security-critical project where any mistake might cost people a lot of money. ## Automated Testing From f3662f80e63a14043da1c73d30b77d8e9e9d3743 Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 22 Dec 2020 01:37:58 -0300 Subject: [PATCH 06/22] [GUI] Finally, fix duplicate records. Github-Pull: #2096 Rebased-From: f54c20617cc139658273db641fd3e6ae6d219397 --- src/qt/transactionrecord.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index acc6ec0774c08..a9be40d742523 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -343,7 +343,7 @@ bool TransactionRecord::decomposeDebitTransaction(const CWallet* wallet, const C } // Decompose shielded debit - return decomposeShieldedDebitTransaction(wallet, wtx, nTxFee, involvesWatchAddress, parts); + return decomposeShieldedDebitTransaction(wallet, wtx, nTxFee, involvesWatchAddress, parts) || !parts.empty(); } // Check whether all the shielded inputs and outputs are from and send to this wallet @@ -445,10 +445,14 @@ QList TransactionRecord::decomposeTransaction(const CWallet* } } - // if we get to this point, we have a mixed debit transaction, can't break down payees. - TransactionRecord record(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize(), TransactionRecord::Other, "", nNet, 0); - record.involvesWatchAddress = involvesWatchAddress; - parts.append(record); + // Check if wasn't able to decompose the transaction + if (parts.empty()) { + // if we get to this point, we have a mixed debit transaction, can't break down payees. + TransactionRecord record(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize(), TransactionRecord::Other, "", nNet, + 0); + record.involvesWatchAddress = involvesWatchAddress; + parts.append(record); + } return parts; } From f17aabc5e6424a1638b2e8fd247b1695a2360d22 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Dec 2020 11:32:33 +0100 Subject: [PATCH 07/22] [Trivial][GUI] coin control: Fixed column size in list-mode Github-Pull: #2098 Rebased-From: 373dd28cd5908a2c4113aecc403363936530723d --- src/qt/coincontroldialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 1eefd9b2580a4..bab6fd6e39573 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -801,7 +801,7 @@ void CoinControlDialog::updateView() // save COLUMN_CHECKBOX width for tree-mode colCheckBoxWidth_treeMode = std::max(110, ui->treeWidget->columnWidth(COLUMN_CHECKBOX)); // minimize COLUMN_CHECKBOX width in list-mode (need to display only the check box) - ui->treeWidget->resizeColumnToContents(COLUMN_CHECKBOX); + ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 70); } // sort view From d95f0cabb87e4a4b8f2757c230ed2d8b93dc8de8 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Wed, 23 Dec 2020 21:22:00 +0100 Subject: [PATCH 08/22] [BUG][GUI] Don't return StakingOnlyUnlocked from WalletModel::sendCoins Github-Pull: #2104 Rebased-From: f79a00d20666a9af89cc0a975e75158cefdb0ecf --- src/qt/walletmodel.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 70b6f013752f7..8eb94ec08e3cf 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -463,12 +463,6 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction& transaction) { - QByteArray transaction_array; /* store serialized transaction */ - - if (isStakingOnlyUnlocked()) { - return StakingOnlyUnlocked; - } - bool fColdStakingActive = isColdStakingNetworkelyEnabled(); bool fSaplingActive = Params().GetConsensus().NetworkUpgradeActive(cachedNumBlocks, Consensus::UPGRADE_V5_0); @@ -479,6 +473,8 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction& tran return TransactionCheckFailed; } + QByteArray transaction_array; /* store serialized transaction */ + { LOCK2(cs_main, wallet->cs_wallet); QList recipients = transaction.getRecipients(); From a6b3f7712bfd306e6371aff04bc8d64a80c56986 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Dec 2020 23:15:35 +0100 Subject: [PATCH 09/22] [BUG][GUI] Cache unconfirmed_balance only for transparent outs shield balance is already cached in unconfirmed_shielded_balance, which is then added to unconfirmed_balance to get the total. Github-Pull: #2102 Rebased-From: 149524fe05329a862b6c3a7242f5bd43c0aef27c --- src/interface/wallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interface/wallet.cpp b/src/interface/wallet.cpp index ca9abcac0c3df..ff7d0c2e0efe7 100644 --- a/src/interface/wallet.cpp +++ b/src/interface/wallet.cpp @@ -11,7 +11,7 @@ namespace interfaces { WalletBalances Wallet::getBalances() { WalletBalances result; result.balance = m_wallet.GetAvailableBalance(); - result.unconfirmed_balance = m_wallet.GetUnconfirmedBalance(); + result.unconfirmed_balance = m_wallet.GetUnconfirmedBalance(ISMINE_SPENDABLE_TRANSPARENT); result.immature_balance = m_wallet.GetImmatureBalance(); result.have_watch_only = m_wallet.HaveWatchOnly(); if (result.have_watch_only) { @@ -26,4 +26,4 @@ namespace interfaces { return result; } -} // namespace interfaces \ No newline at end of file +} // namespace interfaces From 2c315a355194621b46d1073280dacfab1b556d3b Mon Sep 17 00:00:00 2001 From: Fuzzbawls Date: Mon, 21 Dec 2020 01:53:10 -0800 Subject: [PATCH 10/22] Only Return the transaction hex string in `rawshieldsendmany` Instead of returning the full TX JSON object, just return the hex string for use in functional tests and in real-world use for `sendrawtransaction` Github-Pull: #2097 Rebased-From: 681a16bd57cb7095abcd839258bb6a43a8b5d6f2 --- src/wallet/rpcwallet.cpp | 6 ++---- test/functional/sapling_malleable_sigs.py | 4 ++-- test/functional/sapling_mempool.py | 12 ++++++------ test/functional/sapling_wallet.py | 14 +++++++------- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1150fcd47ce3d..0513c4bca1124 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1742,7 +1742,7 @@ UniValue rawshieldsendmany(const JSONRPCRequest& request) " If not specified, the wallet will try to compute the minimum possible fee for a shield TX,\n" " based on the expected transaction size and the current value of -minRelayTxFee.\n" "\nResult:\n" - "{tx_json} (json object) decoded transaction\n" + "\"transaction\" (string) hex string of the transaction\n" "\nExamples:\n" + HelpExampleCli("rawshieldsendmany", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" '[{\"address\": \"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\" ,\"amount\": 5.0}]'") @@ -1751,9 +1751,7 @@ UniValue rawshieldsendmany(const JSONRPCRequest& request) ); CTransaction tx = CreateShieldedTransaction(request).getFinalTx(); - UniValue tx_json(UniValue::VOBJ); - TxToUniv(tx, UINT256_ZERO, tx_json); - return tx_json; + return EncodeHexTx(tx); } UniValue listaddressgroupings(const JSONRPCRequest& request) diff --git a/test/functional/sapling_malleable_sigs.py b/test/functional/sapling_malleable_sigs.py index e88705e99b2a6..4238de4dd6852 100755 --- a/test/functional/sapling_malleable_sigs.py +++ b/test/functional/sapling_malleable_sigs.py @@ -36,13 +36,13 @@ def run_test(self): # Create rawtx shielding 10 PIV self.log.info("Shielding 10 PIV...") - rawtx = node.rawshieldsendmany("from_transparent", shield_to)["hex"] + rawtx_hex = node.rawshieldsendmany("from_transparent", shield_to) self.log.info("Raw tx created") # Creating malleated tx self.log.info("Removing sapling data...") new_tx = CTransaction() - new_tx.deserialize(BytesIO(hex_str_to_bytes(rawtx))) + new_tx.deserialize(BytesIO(hex_str_to_bytes(rawtx_hex))) new_tx.sapData = b"" new_rawtx = bytes_to_hex_str(new_tx.serialize()) self.log.info("Sending malleated tx...") diff --git a/test/functional/sapling_mempool.py b/test/functional/sapling_mempool.py index 93589a6edaea0..e4cc0e4efcbbb 100755 --- a/test/functional/sapling_mempool.py +++ b/test/functional/sapling_mempool.py @@ -44,7 +44,7 @@ def run_test(self): # Alice creates (but doesn't send) tx_A to transparent address tadd_A self.log.info("Alice creating tx_A...") tadd_A = alice.getnewaddress() - rawTx = alice.rawshieldsendmany(alice_zaddr, [{"address": tadd_A, "amount": Decimal('9.00')}], 1, fee) + rawTx_hex = alice.rawshieldsendmany(alice_zaddr, [{"address": tadd_A, "amount": Decimal('9.00')}], 1, fee) # Alice creates and sends tx_B, unshielding the same note to tadd_B self.log.info("Alice creating and sending tx_B...") @@ -59,7 +59,7 @@ def run_test(self): # Now tx_A would double-spend the sapling note in the memory pool assert_raises_rpc_error(-26, "bad-txns-nullifier-double-spent", - alice.sendrawtransaction, rawTx['hex']) + alice.sendrawtransaction, rawTx_hex) self.log.info("tx_A NOT accepted in the mempool. Good.") # Mine tx_B and try to send tx_A again @@ -70,7 +70,7 @@ def run_test(self): assert("blockhash" in txB_json) self.log.info("trying to relay tx_A again...") assert_raises_rpc_error(-26, "bad-txns-shielded-requirements-not-met", - alice.sendrawtransaction, rawTx['hex']) + alice.sendrawtransaction, rawTx_hex) self.log.info("tx_A NOT accepted in the mempool. Good.") # miner sends another 10 PIV note to Alice @@ -83,8 +83,8 @@ def run_test(self): # Alice creates and sends tx_C, unshielding the note to tadd_C self.log.info("Alice creating and sending tx_C...") tadd_C = alice.getnewaddress() - txC_json = alice.rawshieldsendmany(alice_zaddr, [{"address": tadd_C, "amount": Decimal('9.00')}], 1, fee) - txid_C = alice.sendrawtransaction(txC_json['hex']) + txC_hex = alice.rawshieldsendmany(alice_zaddr, [{"address": tadd_C, "amount": Decimal('9.00')}], 1, fee) + txid_C = alice.sendrawtransaction(txC_hex) # Miner receives tx_C and accepts it in the mempool sync_mempools(self.nodes) @@ -94,7 +94,7 @@ def run_test(self): # Now disconnect the block with the note's anchor, # and check that the tx is removed from the mempool self.log.info("Disconnect the last block to change the sapling anchor") - anchor = txC_json['vShieldSpend'][0]['anchor'] + anchor = alice.decoderawtransaction(txC_hex)['vShieldSpend'][0]['anchor'] assert_equal(anchor, miner.getbestsaplinganchor()) miner.invalidateblock(miner.getbestblockhash()) assert (anchor != miner.getbestsaplinganchor()) diff --git a/test/functional/sapling_wallet.py b/test/functional/sapling_wallet.py index 5b71dfb3985f6..49c789d5c77ad 100755 --- a/test/functional/sapling_wallet.py +++ b/test/functional/sapling_wallet.py @@ -75,11 +75,11 @@ def run_test(self): # Trying to send a rawtx with low fee directly self.log.info("Good. It was not possible. Now try with a raw tx...") self.restart_node(0, extra_args=self.extra_args[0]+['-minrelaytxfee=0.0000001']) - rawtx = self.nodes[0].rawshieldsendmany("from_transparent", recipients, 1)["hex"] + rawtx_hex = self.nodes[0].rawshieldsendmany("from_transparent", recipients, 1) self.restart_node(0, extra_args=self.extra_args[0]) connect_nodes(self.nodes[0], 1) assert_raises_rpc_error(-26, "insufficient fee", - self.nodes[0].sendrawtransaction, rawtx) + self.nodes[0].sendrawtransaction, rawtx_hex) self.log.info("Good. Not accepted in the mempool.") # Fixed fee @@ -103,14 +103,14 @@ def run_test(self): # shield more funds creating and then sending a raw transaction self.log.info("TX 3: shield funds creating and sending raw transaction.") - tx_json = self.nodes[0].rawshieldsendmany("from_transparent", recipients, 1, fee) + tx_hex = self.nodes[0].rawshieldsendmany("from_transparent", recipients, 1, fee) # Check SPORK_20 for sapling maintenance mode SPORK_20 = "SPORK_20_SAPLING_MAINTENANCE" self.activate_spork(0, SPORK_20) self.wait_for_spork(True, SPORK_20) assert_raises_rpc_error(-26, "bad-tx-sapling-maintenance", - self.nodes[0].sendrawtransaction, tx_json["hex"]) + self.nodes[0].sendrawtransaction, tx_hex) self.log.info("Good. Not accepted when SPORK_20 is active.") # Try with RPC... @@ -121,7 +121,7 @@ def run_test(self): sleep(5) self.deactivate_spork(0, SPORK_20) self.wait_for_spork(False, SPORK_20) - mytxid3 = self.nodes[0].sendrawtransaction(tx_json["hex"]) + mytxid3 = self.nodes[0].sendrawtransaction(tx_hex) self.log.info("Good. Accepted when SPORK_20 is not active.") # Verify priority of tx is INF_PRIORITY, defined as 1E+25 (10000000000000000000000000) @@ -181,8 +181,8 @@ def run_test(self): # Send more shield funds (with create + send raw transaction) self.log.info("TX 6: shield raw transaction.") - tx_json = self.nodes[0].rawshieldsendmany("from_shield", recipients5, 1, fee) - mytxid6 = self.nodes[0].sendrawtransaction(tx_json["hex"]) + tx_hex = self.nodes[0].rawshieldsendmany("from_shield", recipients5, 1, fee) + mytxid6 = self.nodes[0].sendrawtransaction(tx_hex) self.check_tx_priority([mytxid6]) self.nodes[2].generate(1) From 85d83b11509c92d7c6f19ea0cd6804be0c98c659 Mon Sep 17 00:00:00 2001 From: Fuzzbawls Date: Mon, 21 Dec 2020 14:39:52 -0800 Subject: [PATCH 11/22] Further RPC help output cleanups - Make sure we're indicating when a command requires the wallet to be unlocked. - Add whitespace lines to improve readability between description, arguments, results, and examples - Remove duplicate/errant Result lines in `getsaplingnotescount` Github-Pull: #2097 Rebased-From: 58e64b16c00c7e746e718f25fad87038dc237af8 --- src/wallet/rpcdump.cpp | 16 ++++++++++++++++ src/wallet/rpcwallet.cpp | 30 +++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 8e355f680c5a9..22387d000f657 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -702,15 +702,19 @@ UniValue importsaplingkey(const JSONRPCRequest& request) throw std::runtime_error( "importsaplingkey \"key\" ( rescan startHeight )\n" "\nAdds a key (as returned by exportsaplingkey) to your wallet.\n" + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" "1. \"key\" (string, required) The zkey (see exportsaplingkey)\n" "2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n" "3. startHeight (numeric, optional, default=0) Block height to start rescan from\n" "\nNote: This call can take minutes to complete if rescan is true.\n" + "\nResult:\n" "{\n" " \"address\" : \"address|DefaultAddress\", (string) The address corresponding to the spending key (the default address).\n" "}\n" + "\nExamples:\n" "\nExport a zkey\n" + HelpExampleCli("exportsaplingkey", "\"myaddress\"") + @@ -790,15 +794,19 @@ UniValue importsaplingviewingkey(const JSONRPCRequest& request) throw std::runtime_error( "importsaplingviewingkey \"vkey\" ( rescan startHeight )\n" "\nAdds a viewing key (as returned by exportsaplingviewingkey) to your wallet.\n" + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" "1. \"vkey\" (string, required) The viewing key (see exportsaplingviewingkey)\n" "2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n" "3. startHeight (numeric, optional, default=0) Block height to start rescan from\n" "\nNote: This call can take minutes to complete if rescan is true.\n" + "\nResult:\n" "{\n" " \"address\" : \"address|DefaultAddress\", (string) The address corresponding to the viewing key (for Sapling, this is the default address).\n" "}\n" + "\nExamples:\n" "\nImport a viewing key\n" + HelpExampleCli("importsaplingviewingkey", "\"vkey\"") + @@ -880,10 +888,14 @@ UniValue exportsaplingviewingkey(const JSONRPCRequest& request) "exportsaplingviewingkey \"shielded_addr\"\n" "\nReveals the viewing key corresponding to 'shielded addr'.\n" "Then the importsaplingviewingkey can be used with this output\n" + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" "1. \"shielded_addr\" (string, required) The shielded addr for the viewing key\n" + "\nResult:\n" "\"vkey\" (string) The viewing key\n" + "\nExamples:\n" + HelpExampleCli("exportsaplingviewingkey", "\"myaddress\"") + HelpExampleRpc("exportsaplingviewingkey", "\"myaddress\"") @@ -915,10 +927,14 @@ UniValue exportsaplingkey(const JSONRPCRequest& request) "exportsaplingkey \"shielded addr\"\n" "\nReveals the key corresponding to the 'shielded addr'.\n" "Then the importsaplingkey can be used with this output\n" + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" "1. \"addr\" (string, required) The shielded addr for the private key\n" + "\nResult:\n" "\"key\" (string) The private key\n" + "\nExamples:\n" + HelpExampleCli("exportsaplingkey", "\"myaddress\"") + HelpExampleRpc("exportsaplingkey", "\"myaddress\"") diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0513c4bca1124..39e45b0a8cd6d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -507,9 +507,11 @@ UniValue getnewshieldaddress(const JSONRPCRequest& request) throw std::runtime_error( "getnewshieldaddress\n" "\nReturns a new shield address for receiving payments.\n" - "\nArguments:\n" + + HelpRequiringPassphrase() + "\n" + "\nResult:\n" "\"address\" (string) The new shield address.\n" + "\nExamples:\n" + HelpExampleCli("getnewshieldaddress", "") + HelpExampleRpc("getnewshieldaddress", "") @@ -532,6 +534,7 @@ UniValue listshieldunspent(const JSONRPCRequest& request) "\nReturns array of unspent shield notes with between minconf and maxconf (inclusive) confirmations.\n" "Optionally filter to only include notes sent to specified addresses.\n" "When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n" + "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" @@ -541,6 +544,7 @@ UniValue listshieldunspent(const JSONRPCRequest& request) " \"address\" (string) shield addr\n" " ,...\n" " ]\n" + "\nResult:\n" "[ (array of json object)\n" " {\n" @@ -808,13 +812,16 @@ UniValue listshieldaddresses(const JSONRPCRequest& request) throw std::runtime_error( "listshieldaddresses ( includeWatchonly )\n" "\nReturns the list of shield addresses belonging to the wallet.\n" + "\nArguments:\n" "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'importviewingkey')\n" + "\nResult:\n" "[ (json array of string)\n" " \"addr\" (string) a shield address belonging to the wallet\n" " ,...\n" "]\n" + "\nExamples:\n" + HelpExampleCli("listshieldaddresses", "") + HelpExampleRpc("listshieldaddresses", "") @@ -1308,12 +1315,15 @@ UniValue getshieldbalance(const JSONRPCRequest& request) "\nCAUTION: If the wallet contains any addresses for which it only has incoming viewing keys," "\nthe returned private balance may be larger than the actual balance, because spends cannot" "\nbe detected with incoming viewing keys.\n" + "\nArguments:\n" "1. \"address\" (string, optional) The selected address. If non empty nor \"*\", it must be a Sapling address\n" "2. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n" "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'importsaplingviewingkey')\n" + "\nResult:\n" "amount (numeric) the total balance of shield funds (in Sapling addresses)\n" + "\nExamples:\n" "\nThe total amount in the wallet\n" + HelpExampleCli("getshieldbalance", "") @@ -1352,7 +1362,7 @@ UniValue viewshieldtransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "viewshieldtransaction \"txid\"\n" - "\nGet detailed shield information about in-wallet transaction \n" + "\nGet detailed shield information about in-wallet transaction \"txid\"\n" + HelpRequiringPassphrase() + "\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" @@ -2170,6 +2180,8 @@ UniValue sendmany(const JSONRPCRequest& request) HelpExampleRpc("sendmany", "\"\", \"{\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\":0.01,\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\":0.02}\", 6, \"testing\"") ); + EnsureWalletIsUnlocked(); + // Read Params if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\""); @@ -2439,9 +2451,11 @@ UniValue listreceivedbyshieldaddress(const JSONRPCRequest& request) throw std::runtime_error( "listreceivedbyshieldaddress \"address\" ( minconf )\n" "\nReturn a list of amounts received by a shield addr belonging to the node's wallet.\n" + "\nArguments:\n" "1. \"address\" (string) The private address.\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" + "\nResult:\n" "{\n" " \"txid\": \"txid\", (string) the transaction id\n" @@ -2454,6 +2468,7 @@ UniValue listreceivedbyshieldaddress(const JSONRPCRequest& request) " \"outindex\" (sapling) : n, (numeric) the output index\n" " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n" "}\n" + "\nExamples:\n" + HelpExampleCli("listreceivedbyshieldaddress", "\"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\"") + HelpExampleRpc("listreceivedbyshieldaddress", "\"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\"") @@ -2904,7 +2919,7 @@ UniValue gettransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( "gettransaction \"txid\" ( includeWatchonly )\n" - "\nGet detailed information about in-wallet transaction \n" + "\nGet detailed information about in-wallet transaction \"txid\"\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" @@ -2980,7 +2995,7 @@ UniValue abandontransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "abandontransaction \"txid\"\n" - "\nMark in-wallet transaction as abandoned\n" + "\nMark in-wallet transaction \"txid\" as abandoned\n" "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n" "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n" "It only works on transactions which are not included in a block and are not currently in the mempool.\n" @@ -4050,12 +4065,13 @@ UniValue getsaplingnotescount(const JSONRPCRequest& request) throw std::runtime_error( "getsaplingnotescount ( minconf )\n" "Returns the number of sapling notes available in the wallet.\n" + "\nArguments:\n" "1. minconf (numeric, optional, default=1) Only include notes in transactions confirmed at least this many times.\n" - "\nResult:\n" + "\nResult:\n" "num (numeric) the number of sapling notes in the wallet\n" - "}\n" + "\nExamples:\n" + HelpExampleCli("getsaplingnotescount", "0") + HelpExampleRpc("getsaplingnotescount", "0") @@ -4063,7 +4079,7 @@ UniValue getsaplingnotescount(const JSONRPCRequest& request) LOCK2(cs_main, pwalletMain->cs_wallet); - int nMinDepth = request.params.size() > 0 ? request.params[0].get_int() : 1; + int nMinDepth = !request.params.empty() ? request.params[0].get_int() : 1; int count = 0; for (const auto& wtx : pwalletMain->mapWallet) { if (wtx.second.GetDepthInMainChain() >= nMinDepth) { From 18e83cf242fe379ec31910963a7b0c3fb97beaeb Mon Sep 17 00:00:00 2001 From: Fuzzbawls Date: Wed, 23 Dec 2020 15:07:01 -0800 Subject: [PATCH 12/22] Only return the tx hex string in rawdelegatestake Github-Pull: #2097 Rebased-From: dab46779ee4fcb01c612681f3cd902d0ed5b65ca --- src/wallet/rpcwallet.cpp | 46 +++------------------------------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 39e45b0a8cd6d..f30dde94c4a26 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1233,45 +1233,7 @@ UniValue rawdelegatestake(const JSONRPCRequest& request) "7. \"fForceNotEnabled\" (boolean, optional, default = false) ONLY FOR TESTING: force the creation even if SPORK 17 is disabled (for tests).\n" "\nResult:\n" - "{\n" - " \"txid\" : \"id\", (string) The transaction id (same as provided)\n" - " \"version\" : n, (numeric) The version\n" - " \"type\" : n, (numeric) The type\n" - " \"size\" : n, (numeric) The serialized transaction size\n" - " \"locktime\" : ttt, (numeric) The lock time\n" - " \"vin\" : [ (array of json objects)\n" - " {\n" - " \"txid\": \"id\", (string) The transaction id\n" - " \"vout\": n, (numeric) \n" - " \"scriptSig\": { (json object) The script\n" - " \"asm\": \"asm\", (string) asm\n" - " \"hex\": \"hex\" (string) hex\n" - " },\n" - " \"sequence\": n (numeric) The script sequence number\n" - " }\n" - " ,...\n" - " ],\n" - " \"vout\" : [ (array of json objects)\n" - " {\n" - " \"value\" : x.xxx, (numeric) The value in PIV\n" - " \"n\" : n, (numeric) index\n" - " \"scriptPubKey\" : { (json object)\n" - " \"asm\" : \"asm\", (string) the asm\n" - " \"hex\" : \"hex\", (string) the hex\n" - " \"reqSigs\" : n, (numeric) The required sigs\n" - " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" - " \"addresses\" : [ (json array of string)\n" - " \"pivxaddress\" (string) pivx address\n" - " ,...\n" - " ]\n" - " }\n" - " }\n" - " ,...\n" - " ],\n" - " \"extraPayloadSize\" : n (numeric) Size of extra payload. Only present if it's a special TX\n" - " \"extraPayload\" : \"hex\" (string) Hex encoded extra payload data. Only present if it's a special TX\n" - " \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n" - "}\n" + "\"transaction\" (string) hex string of the transaction\n" "\nExamples:\n" + HelpExampleCli("rawdelegatestake", "\"S1t2a3kab9c8c71VA78xxxy4MxZg6vgeS6\" 100") + @@ -1284,10 +1246,7 @@ UniValue rawdelegatestake(const JSONRPCRequest& request) CReserveKey reservekey(pwalletMain); CreateColdStakeDelegation(request.params, wtx, reservekey); - UniValue result(UniValue::VOBJ); - TxToUniv(wtx, UINT256_ZERO, result); - - return result; + return EncodeHexTx(wtx); } @@ -1753,6 +1712,7 @@ UniValue rawshieldsendmany(const JSONRPCRequest& request) " based on the expected transaction size and the current value of -minRelayTxFee.\n" "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" + "\nExamples:\n" + HelpExampleCli("rawshieldsendmany", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" '[{\"address\": \"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\" ,\"amount\": 5.0}]'") From 73864a0b7f8086240da45936816577aa0199bacb Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 23 Dec 2020 14:42:05 -0300 Subject: [PATCH 13/22] Startup: move masternode port validation inside `initMasternode`. Do not return an error if a different peer port is used for tor addresses. The peer is behind a hidden service which has the port fixed to the default port. Github-Pull: #2103 Rebased-From: 2cd0670ed5d8d30e707ddaf3da2abd39fe6f111a --- src/activemasternode.cpp | 7 +++++++ src/init.cpp | 5 ----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 2c09db0b8880c..9218f2f927ab1 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -53,6 +53,13 @@ OperationResult initMasternode(const std::string& _strMasterNodePrivKey, const s return errorOut(strprintf(_("Invalid -masternodeaddr address: %s"), strMasterNodeAddr)); } + // Peer port needs to match the masternode public one for IPv4 and IPv6. + // Onion can run in other ports because those are behind a hidden service which has the public port fixed to the default port. + if (nPort != GetListenPort() && !addrTest.IsTor() && !params.IsRegTestNet()) { + return errorOut(strprintf(_("Invalid -masternodeaddr port %d, isn't the same as the peer port %d"), + nPort, GetListenPort())); + } + CKey key; CPubKey pubkey; if (!CMessageSigner::GetKeysFromSecret(_strMasterNodePrivKey, key, pubkey)) { diff --git a/src/init.cpp b/src/init.cpp index fd7a20ea4679c..7604cc1e6f68c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1035,11 +1035,6 @@ bool AppInit2() // Exit early if -masternode=1 and -listen=0 if (gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE) && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) return UIError(_("Error: -listen must be true if -masternode is set.")); - // Exit early if -masternode=1 and -port is not the default port - if (gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE) && (GetListenPort() != Params().GetDefaultPort() && !Params().IsRegTestNet())) - return UIError(strprintf(_("Error: Invalid port %d for running a masternode."), GetListenPort()) + "\n\n" + - strprintf(_("Masternodes are required to run on port %d for %s-net"), Params().GetDefaultPort(), Params().NetworkIDString())); - if (gArgs.GetBoolArg("-benchmark", false)) UIWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); From 6377883cac4ae30ef832b76e89bdb41a307b3da5 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Thu, 24 Dec 2020 15:35:02 +0100 Subject: [PATCH 14/22] [BUG][Tests] Fix remote nodes switched ports in PivxTier2TestFramework Github-Pull: #2103 Rebased-From: b878bff6a86c10a114945c35f7ef918bf4f84164 --- src/activemasternode.cpp | 2 +- test/functional/test_framework/test_framework.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 9218f2f927ab1..a41fc18c25a81 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -55,7 +55,7 @@ OperationResult initMasternode(const std::string& _strMasterNodePrivKey, const s // Peer port needs to match the masternode public one for IPv4 and IPv6. // Onion can run in other ports because those are behind a hidden service which has the public port fixed to the default port. - if (nPort != GetListenPort() && !addrTest.IsTor() && !params.IsRegTestNet()) { + if (nPort != GetListenPort() && !addrTest.IsTor()) { return errorOut(strprintf(_("Invalid -masternodeaddr port %d, isn't the same as the peer port %d"), nPort, GetListenPort())); } diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 27812b6bbfd88..0b921d26b9690 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1208,8 +1208,8 @@ def setup_2_masternodes_network(self): self.stake(1) time.sleep(3) self.advance_mocktime(10) - remoteOnePort = p2p_port(self.remoteTwoPos) - remoteTwoPort = p2p_port(self.remoteOnePos) + remoteOnePort = p2p_port(self.remoteOnePos) + remoteTwoPort = p2p_port(self.remoteTwoPos) self.remoteOne.initmasternode(self.mnOnePrivkey, "127.0.0.1:"+str(remoteOnePort)) self.remoteTwo.initmasternode(self.mnTwoPrivkey, "127.0.0.1:"+str(remoteTwoPort)) From 5fb488a9c92c03b8f33c525ce5095079ac68965c Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Dec 2020 14:59:30 +0100 Subject: [PATCH 15/22] Consensus: enforce proposal max payments (6 main-net / 20 test-net) Github-Pull: #2101 Rebased-From: f5f8bd9df4b54baabeba391c30ef75d929f3b40d --- src/budget/budgetproposal.cpp | 7 +++++++ src/chainparams.cpp | 2 ++ src/consensus/params.h | 1 + src/rpc/budget.cpp | 6 ++++++ 4 files changed, 16 insertions(+) diff --git a/src/budget/budgetproposal.cpp b/src/budget/budgetproposal.cpp index f04e2cc9b45db..9073a6a6bf02e 100644 --- a/src/budget/budgetproposal.cpp +++ b/src/budget/budgetproposal.cpp @@ -100,6 +100,13 @@ bool CBudgetProposal::CheckStartEnd() return false; } + // !TODO: remove (and alwyas use new rules) when all proposals submitted before v5 enforcement are expired. + bool fNewRules = Params().GetConsensus().NetworkUpgradeActive(nBlockStart, Consensus::UPGRADE_V5_0); + if (fNewRules && GetTotalPaymentCount() > Params().GetConsensus().nMaxProposalPayments) { + strInvalid = "Invalid payment count"; + return false; + } + return true; } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3bf95f645e828..ff7cecef0fece 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -147,6 +147,7 @@ class CMainParams : public CChainParams consensus.nTargetTimespanV2 = 30 * 60; consensus.nTargetSpacing = 1 * 60; consensus.nTimeSlotLength = 15; + consensus.nMaxProposalPayments = 6; // spork keys consensus.strSporkPubKey = "0410050aa740d280b134b40b40658781fc1116ba7700764e0ce27af3e1737586b3257d19232e0cb5084947f5107e44bcd577f126c9eb4a30ea2807b271d2145298"; @@ -281,6 +282,7 @@ class CTestNetParams : public CMainParams consensus.nTargetTimespanV2 = 30 * 60; consensus.nTargetSpacing = 1 * 60; consensus.nTimeSlotLength = 15; + consensus.nMaxProposalPayments = 20; // spork keys consensus.strSporkPubKey = "04677c34726c491117265f4b1c83cef085684f36c8df5a97a3a42fc499316d0c4e63959c9eca0dba239d9aaaf72011afffeb3ef9f51b9017811dec686e412eb504"; diff --git a/src/consensus/params.h b/src/consensus/params.h index 9ca97cb809f61..591d91e7416e8 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -105,6 +105,7 @@ struct Params { int64_t nTargetTimespanV2; int64_t nTargetSpacing; int nTimeSlotLength; + int nMaxProposalPayments; // spork keys std::string strSporkPubKey; diff --git a/src/rpc/budget.cpp b/src/rpc/budget.cpp index 9eebc048e5717..66e488d3b576a 100644 --- a/src/rpc/budget.cpp +++ b/src/rpc/budget.cpp @@ -64,6 +64,12 @@ void checkBudgetInputs(const UniValue& params, std::string &strProposalName, std if (nPaymentCount < 1) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid payment count, must be more than zero."); + int nMaxPayments = Params().GetConsensus().nMaxProposalPayments; + if (nPaymentCount > nMaxPayments) { + throw JSONRPCError(RPC_INVALID_PARAMETER, + strprintf("Invalid payment count, must be <= %d", nMaxPayments)); + } + CBlockIndex* pindexPrev = GetChainTip(); if (!pindexPrev) throw JSONRPCError(RPC_IN_WARMUP, "Try again after active chain is loaded"); From 723a41bea9cf4a4a2afa49f3a85eda128ae4af0b Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Dec 2020 15:42:01 +0100 Subject: [PATCH 16/22] Consensus: enforce that proposal BlockStart must be a superblock Github-Pull: #2101 Rebased-From: 2b53142ee20a697b90f2cdf4ad396f1a9a1c1f24 --- src/budget/budgetproposal.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/budget/budgetproposal.cpp b/src/budget/budgetproposal.cpp index 9073a6a6bf02e..0ee4914963a37 100644 --- a/src/budget/budgetproposal.cpp +++ b/src/budget/budgetproposal.cpp @@ -8,6 +8,7 @@ #include "masternodeman.h" CBudgetProposal::CBudgetProposal(): + nAlloted(0), fValid(true), strInvalid(""), strProposalName("unknown"), @@ -27,6 +28,7 @@ CBudgetProposal::CBudgetProposal(const std::string& name, const CAmount& amount, int blockstart, const uint256& nfeetxhash): + nAlloted(0), fValid(true), strInvalid(""), strProposalName(name), @@ -38,14 +40,10 @@ CBudgetProposal::CBudgetProposal(const std::string& name, nTime(0) { const int nBlocksPerCycle = Params().GetConsensus().nBudgetCycleBlocks; + // !todo: remove this when v5 rules are enforced (nBlockStart is always = to nCycleStart) int nCycleStart = nBlockStart - nBlockStart % nBlocksPerCycle; - // Right now single payment proposals have nBlockEnd have a cycle too early! - // switch back if it break something else - // calculate the end of the cycle for this vote, add half a cycle (vote will be deleted after that block) - // nBlockEnd = nCycleStart + GetBudgetPaymentCycleBlocks() * nPaymentCount + GetBudgetPaymentCycleBlocks() / 2; - - // Calculate the end of the cycle for this vote, vote will be deleted after next cycle + // calculate the expiration block nBlockEnd = nCycleStart + (nBlocksPerCycle + 1) * paycount; } @@ -90,8 +88,13 @@ bool CBudgetProposal::IsHeavilyDownvoted(bool fNewRules) bool CBudgetProposal::CheckStartEnd() { - if (nBlockStart < 0) { - strInvalid = "Invalid Proposal"; + // !TODO: remove (and always use new rules) when all proposals submitted before v5 enforcement are expired. + bool fNewRules = Params().GetConsensus().NetworkUpgradeActive(nBlockStart, Consensus::UPGRADE_V5_0); + + if (nBlockStart < 0 || + // block start must be a superblock + (fNewRules && (nBlockStart % Params().GetConsensus().nBudgetCycleBlocks) != 0)) { + strInvalid = "Invalid nBlockStart"; return false; } @@ -100,8 +103,6 @@ bool CBudgetProposal::CheckStartEnd() return false; } - // !TODO: remove (and alwyas use new rules) when all proposals submitted before v5 enforcement are expired. - bool fNewRules = Params().GetConsensus().NetworkUpgradeActive(nBlockStart, Consensus::UPGRADE_V5_0); if (fNewRules && GetTotalPaymentCount() > Params().GetConsensus().nMaxProposalPayments) { strInvalid = "Invalid payment count"; return false; From 495c546abfb09c9e1aa325b460433d25666a73bf Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Dec 2020 16:28:38 +0100 Subject: [PATCH 17/22] Tests: check invalid RPC inputs in rpc_budget test Github-Pull: #2101 Rebased-From: 3aaa51049a28cd691afe85dec09874d161872106 --- test/functional/rpc_budget.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/functional/rpc_budget.py b/test/functional/rpc_budget.py index a430c727832fb..0d88298b00d48 100755 --- a/test/functional/rpc_budget.py +++ b/test/functional/rpc_budget.py @@ -36,6 +36,10 @@ def run_test(self): assert_raises_rpc_error(-8, "Invalid payment count, must be more than zero.", self.nodes[0].preparebudget, name, scheme + url, 0, nextsuperblock, address, cycleamount) + self.log.info("Test with invalid (21) cycles") + assert_raises_rpc_error(-8, "Invalid payment count, must be <= 20", self.nodes[0].preparebudget, + name, scheme + url, 21, nextsuperblock, address, cycleamount) + self.log.info("Test with invalid block start") assert_raises_rpc_error(-8, "Invalid block start", self.nodes[0].preparebudget, name, scheme + url, numcycles, nextsuperblock - 12, address, cycleamount) @@ -47,8 +51,9 @@ def run_test(self): name, scheme + url, numcycles, nextsuperblock, "DBREvBPNQguwuC4YMoCG5FoH1sA2YntvZm", cycleamount) self.log.info("Test with too low amount") - assert_raises_rpc_error(-8, "Invalid amount - Payment of 9.00 is less than minimum 10 PIV allowed", self.nodes[0].preparebudget, - name, scheme + url, numcycles, nextsuperblock, address, 9) + invalid_amt = 9.99999999 + assert_raises_rpc_error(-8, "Invalid amount - Payment of %.8f is less than minimum 10 PIV allowed" % invalid_amt, self.nodes[0].preparebudget, + name, scheme + url, numcycles, nextsuperblock, address, invalid_amt) self.log.info("Test with too high amount") assert_raises_rpc_error(-8, "Invalid amount - Payment of 648001.00 more than max of 648000.00", self.nodes[0].preparebudget, From 107529b55d4ac3d047f9f1c5f85d78bb25f52712 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Thu, 24 Dec 2020 02:47:45 +0100 Subject: [PATCH 18/22] Tests: check getbudgetinfo / getbudgetprojection updated output Github-Pull: #2101 Rebased-From: a005fa71f9a9ae7aafb6bf92562eabc8ad3da230 --- .../tiertwo_governance_sync_basic.py | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/test/functional/tiertwo_governance_sync_basic.py b/test/functional/tiertwo_governance_sync_basic.py index cc52827fbbac8..07982bdc0456e 100755 --- a/test/functional/tiertwo_governance_sync_basic.py +++ b/test/functional/tiertwo_governance_sync_basic.py @@ -7,6 +7,7 @@ from test_framework.util import ( assert_equal, assert_true, + Decimal, ) import time @@ -60,6 +61,39 @@ def check_vote_existence(self, proposalName, mnCollateralHash, voteType): found = True assert_true(found, "Error checking vote existence in node " + str(i)) + def get_proposal_obj(self, Name, URL, Hash, FeeHash, BlockStart, BlockEnd, + TotalPaymentCount, RemainingPaymentCount, PaymentAddress, + Ratio, Yeas, Nays, Abstains, TotalPayment, MonthlyPayment, + IsEstablished, IsValid, Allotted, TotalBudgetAllotted, IsInvalidReason = ""): + obj = {} + obj["Name"] = Name + obj["URL"] = URL + obj["Hash"] = Hash + obj["FeeHash"] = FeeHash + obj["BlockStart"] = BlockStart + obj["BlockEnd"] = BlockEnd + obj["TotalPaymentCount"] = TotalPaymentCount + obj["RemainingPaymentCount"] = RemainingPaymentCount + obj["PaymentAddress"] = PaymentAddress + obj["Ratio"] = Ratio + obj["Yeas"] = Yeas + obj["Nays"] = Nays + obj["Abstains"] = Abstains + obj["TotalPayment"] = TotalPayment + obj["MonthlyPayment"] = MonthlyPayment + obj["IsEstablished"] = IsEstablished + obj["IsValid"] = IsValid + if IsInvalidReason != "": + obj["IsInvalidReason"] = IsInvalidReason + obj["Alloted"] = Allotted + obj["TotalBudgetAlloted"] = TotalBudgetAllotted + return obj + + def check_budgetprojection(self, expected): + for i in range(self.num_nodes): + assert_equal(self.nodes[i].getbudgetprojection(), expected) + self.log.info("Budget projection valid for node %d" % i) + def run_test(self): self.enable_mocktime() self.setup_2_masternodes_network() @@ -106,7 +140,7 @@ def run_test(self): # let's wait a little bit and see if all nodes are sync time.sleep(1) self.check_proposal_existence(firstProposalName, proposalHash) - self.log.info("proposal broadcast succeed!") + self.log.info("proposal broadcast successful!") # Proposal is established after 5 minutes. Mine 7 blocks # Proposal needs to be on the chain > 5 min. @@ -131,6 +165,20 @@ def run_test(self): self.check_vote_existence(firstProposalName, self.mnTwoTxHash, "YES") self.log.info("all good, MN2 vote accepted everywhere!") + # Now check the budget + blockStart = nextSuperBlockHeight + blockEnd = blockStart + firstProposalCycles * 145 + TotalPayment = firstProposalAmountPerCycle * firstProposalCycles + Allotted = firstProposalAmountPerCycle + RemainingPaymentCount = firstProposalCycles + expected_budget = [ + self.get_proposal_obj(firstProposalName, firstProposalLink, proposalHash, proposalFeeTxId, blockStart, + blockEnd, firstProposalCycles, RemainingPaymentCount, firstProposalAddress, 1, + 2, 0, 0, Decimal(str(TotalPayment)), Decimal(str(firstProposalAmountPerCycle)), + True, True, Decimal(str(Allotted)), Decimal(str(Allotted))) + ] + self.check_budgetprojection(expected_budget) + # Quick block count check. assert_equal(self.ownerOne.getblockcount(), 276) @@ -164,6 +212,10 @@ def run_test(self): self.log.info("budget proposal paid!, all good") + # Check that the proposal info returns updated payment count + expected_budget[0]["RemainingPaymentCount"] -= 1 + self.check_budgetprojection(expected_budget) + From 4285bee903518ff10e4fb57c4ae5571f6b74ff45 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Thu, 24 Dec 2020 03:55:58 +0100 Subject: [PATCH 19/22] scripted-diff: Fix "alloted" typo -BEGIN VERIFY SCRIPT- sed -i 's/alloted/allotted/g' src/*/*.h src/*/*.cpp test/functional/*.py ; sed -i 's/Alloted/Allotted/g' src/*/*.h src/*/*.cpp test/functional/*.py ; -END VERIFY SCRIPT- Github-Pull: #2101 Rebased-From: 72abccfc07836b23ec981287a080df4ecc11b3de --- src/budget/budgetproposal.cpp | 4 ++-- src/budget/budgetproposal.h | 6 +++--- src/rpc/budget.cpp | 8 ++++---- test/functional/tiertwo_governance_sync_basic.py | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/budget/budgetproposal.cpp b/src/budget/budgetproposal.cpp index 0ee4914963a37..ab77c665bf03d 100644 --- a/src/budget/budgetproposal.cpp +++ b/src/budget/budgetproposal.cpp @@ -8,7 +8,7 @@ #include "masternodeman.h" CBudgetProposal::CBudgetProposal(): - nAlloted(0), + nAllotted(0), fValid(true), strInvalid(""), strProposalName("unknown"), @@ -28,7 +28,7 @@ CBudgetProposal::CBudgetProposal(const std::string& name, const CAmount& amount, int blockstart, const uint256& nfeetxhash): - nAlloted(0), + nAllotted(0), fValid(true), strInvalid(""), strProposalName(name), diff --git a/src/budget/budgetproposal.h b/src/budget/budgetproposal.h index 2f1824925c31d..1754d3f245a49 100644 --- a/src/budget/budgetproposal.h +++ b/src/budget/budgetproposal.h @@ -22,7 +22,7 @@ static const int64_t BUDGET_VOTE_UPDATE_MIN = 60 * 60; class CBudgetProposal { private: - CAmount nAlloted; + CAmount nAllotted; bool fValid; std::string strInvalid; @@ -87,8 +87,8 @@ class CBudgetProposal int GetNays() const { return GetVoteCount(CBudgetVote::VOTE_NO); } int GetAbstains() const { return GetVoteCount(CBudgetVote::VOTE_ABSTAIN); }; CAmount GetAmount() const { return nAmount; } - void SetAllotted(CAmount nAllotedIn) { nAlloted = nAllotedIn; } - CAmount GetAllotted() const { return nAlloted; } + void SetAllotted(CAmount nAllottedIn) { nAllotted = nAllottedIn; } + CAmount GetAllotted() const { return nAllotted; } void CleanAndRemove(); diff --git a/src/rpc/budget.cpp b/src/rpc/budget.cpp index 66e488d3b576a..9bd8d81f491f3 100644 --- a/src/rpc/budget.cpp +++ b/src/rpc/budget.cpp @@ -45,7 +45,7 @@ void budgetToJSON(const CBudgetProposal* pbudgetProposal, UniValue& bObj, int nC bObj.pushKV("IsValid", fValid); if (!fValid) bObj.pushKV("IsInvalidReason", pbudgetProposal->IsInvalidReason()); - bObj.pushKV("Alloted", ValueFromAmount(pbudgetProposal->GetAllotted())); + bObj.pushKV("Allotted", ValueFromAmount(pbudgetProposal->GetAllotted())); } void checkBudgetInputs(const UniValue& params, std::string &strProposalName, std::string &strURL, @@ -544,8 +544,8 @@ UniValue getbudgetprojection(const JSONRPCRequest& request) " \"IsEstablished\": true|false, (boolean) Established (true) or (false)\n" " \"IsValid\": true|false, (boolean) Valid (true) or Invalid (false)\n" " \"IsInvalidReason\": \"xxxx\", (string) Error message, if any\n" - " \"Alloted\": xxx.xxx, (numeric) Amount alloted in current period\n" - " \"TotalBudgetAlloted\": xxx.xxx (numeric) Total alloted\n" + " \"Allotted\": xxx.xxx, (numeric) Amount allotted in current period\n" + " \"TotalBudgetAllotted\": xxx.xxx (numeric) Total allotted\n" " }\n" " ,...\n" "]\n" @@ -562,7 +562,7 @@ UniValue getbudgetprojection(const JSONRPCRequest& request) UniValue bObj(UniValue::VOBJ); budgetToJSON(&p, bObj, g_budgetman.GetBestHeight()); nTotalAllotted += p.GetAllotted(); - bObj.pushKV("TotalBudgetAlloted", ValueFromAmount(nTotalAllotted)); + bObj.pushKV("TotalBudgetAllotted", ValueFromAmount(nTotalAllotted)); ret.push_back(bObj); } diff --git a/test/functional/tiertwo_governance_sync_basic.py b/test/functional/tiertwo_governance_sync_basic.py index 07982bdc0456e..4adc1eaf03097 100755 --- a/test/functional/tiertwo_governance_sync_basic.py +++ b/test/functional/tiertwo_governance_sync_basic.py @@ -85,8 +85,8 @@ def get_proposal_obj(self, Name, URL, Hash, FeeHash, BlockStart, BlockEnd, obj["IsValid"] = IsValid if IsInvalidReason != "": obj["IsInvalidReason"] = IsInvalidReason - obj["Alloted"] = Allotted - obj["TotalBudgetAlloted"] = TotalBudgetAllotted + obj["Allotted"] = Allotted + obj["TotalBudgetAllotted"] = TotalBudgetAllotted return obj def check_budgetprojection(self, expected): From 4a8e571b8a136a0ada64bb8a9490ce5ef87eeffd Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Dec 2020 17:15:53 +0100 Subject: [PATCH 20/22] [BUG] Fix total budget on testnet the cycle is 144 blocks, not 146. Use the available GetBlockValue/nBudgetCycleBlocks, instead of hardcoding the constants. Note: GetTotalBudget should consider the possibility of changes to the block value, between consecutive superblocks. Since the chain already passed the last reduction, and the block value is fixed at 5, we can leave this as is for now. Github-Pull: #2101 Rebased-From: bdfaaed277981dce9618b7a335edd744780aebaf --- src/budget/budgetmanager.cpp | 44 ++++------------------------------- src/test/budget_tests.cpp | 3 ++- test/functional/rpc_budget.py | 5 ++-- 3 files changed, 9 insertions(+), 43 deletions(-) diff --git a/src/budget/budgetmanager.cpp b/src/budget/budgetmanager.cpp index 87228855a3540..eec014627d5df 100644 --- a/src/budget/budgetmanager.cpp +++ b/src/budget/budgetmanager.cpp @@ -749,47 +749,11 @@ std::string CBudgetManager::GetRequiredPaymentsString(int nBlockHeight) CAmount CBudgetManager::GetTotalBudget(int nHeight) { - if (Params().NetworkID() == CBaseChainParams::TESTNET) { - CAmount nSubsidy = 500 * COIN; - return ((nSubsidy / 100) * 10) * 146; - } - - //get block value and calculate from that - CAmount nSubsidy = 0; - const Consensus::Params& consensus = Params().GetConsensus(); - const bool isPoSActive = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_POS); - if (nHeight >= 151200 && !isPoSActive) { - nSubsidy = 50 * COIN; - } else if (isPoSActive && nHeight <= 302399) { - nSubsidy = 50 * COIN; - } else if (nHeight <= 345599 && nHeight >= 302400) { - nSubsidy = 45 * COIN; - } else if (nHeight <= 388799 && nHeight >= 345600) { - nSubsidy = 40 * COIN; - } else if (nHeight <= 431999 && nHeight >= 388800) { - nSubsidy = 35 * COIN; - } else if (nHeight <= 475199 && nHeight >= 432000) { - nSubsidy = 30 * COIN; - } else if (nHeight <= 518399 && nHeight >= 475200) { - nSubsidy = 25 * COIN; - } else if (nHeight <= 561599 && nHeight >= 518400) { - nSubsidy = 20 * COIN; - } else if (nHeight <= 604799 && nHeight >= 561600) { - nSubsidy = 15 * COIN; - } else if (nHeight <= 647999 && nHeight >= 604800) { - nSubsidy = 10 * COIN; - } else if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_ZC_V2)) { - nSubsidy = 10 * COIN; - } else { - nSubsidy = 5 * COIN; - } + // 20% of the block value + CAmount nSubsidy = GetBlockValue(nHeight) / 5; - // Amount of blocks in a months period of time (using 1 minutes per) = (60*24*30) - if (nHeight <= 172800) { - return 648000 * COIN; - } else { - return ((nSubsidy / 100) * 10) * 1440 * 30; - } + // multiplied by the number of blocks in a cycle (144 on testnet, 30*1440 on mainnet) + return nSubsidy * Params().GetConsensus().nBudgetCycleBlocks; } void CBudgetManager::AddSeenProposalVote(const CBudgetVote& vote) diff --git a/src/test/budget_tests.cpp b/src/test/budget_tests.cpp index b5bfcf3baf856..d62051286f995 100644 --- a/src/test/budget_tests.cpp +++ b/src/test/budget_tests.cpp @@ -23,7 +23,8 @@ BOOST_AUTO_TEST_CASE(budget_value) { SelectParams(CBaseChainParams::TESTNET); int nHeightTest = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_ZC_V2].nActivationHeight + 1; - CheckBudgetValue(nHeightTest, "testnet", 7300*COIN); + CheckBudgetValue(nHeightTest-1, "testnet", 7200*COIN); + CheckBudgetValue(nHeightTest, "testnet", 144*COIN); SelectParams(CBaseChainParams::MAIN); nHeightTest = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_ZC_V2].nActivationHeight + 1; diff --git a/test/functional/rpc_budget.py b/test/functional/rpc_budget.py index 0d88298b00d48..93e87c923eddc 100755 --- a/test/functional/rpc_budget.py +++ b/test/functional/rpc_budget.py @@ -56,8 +56,9 @@ def run_test(self): name, scheme + url, numcycles, nextsuperblock, address, invalid_amt) self.log.info("Test with too high amount") - assert_raises_rpc_error(-8, "Invalid amount - Payment of 648001.00 more than max of 648000.00", self.nodes[0].preparebudget, - name, scheme + url, numcycles, nextsuperblock, address, 648001) + invalid_amt = 50 * 144 + 0.00000001 + assert_raises_rpc_error(-8, "Invalid amount - Payment of %.8f more than max of 7200.00" % invalid_amt, self.nodes[0].preparebudget, + name, scheme + url, numcycles, nextsuperblock, address, invalid_amt) self.log.info("Test without URL scheme") From 3de9861a10c2c6950d82f33454483f3198206745 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Sat, 26 Dec 2020 16:23:12 +0100 Subject: [PATCH 21/22] [Policy] Set DEFAULT_SHIELDEDTXFEE_K to 100 (from 1000) Thus reduce default min fee for shielded txes by 10x Github-Pull: #2108 Rebased-From: 6a33d4faea9d83de529861a29785134adfa6c0c9 --- src/policy/policy.cpp | 2 +- src/test/librust/sapling_wallet_tests.cpp | 8 ++--- .../librust/transaction_builder_tests.cpp | 7 ++-- src/validation.cpp | 2 +- src/validation.h | 2 +- test/functional/sapling_mempool.py | 4 +-- test/functional/sapling_supply.py | 4 +-- test/functional/sapling_wallet.py | 34 +++++++++---------- .../functional/sapling_wallet_listreceived.py | 12 +++---- 9 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 1a69023fd4b0e..9cf47d5374564 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -47,7 +47,7 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee) CAmount GetShieldedDustThreshold(const CFeeRate& dustRelayFee) { - unsigned int K = DEFAULT_SHIELDEDTXFEE_K; // Fixed (1000) for now + unsigned int K = DEFAULT_SHIELDEDTXFEE_K; // Fixed (100) for now return 3 * K * dustRelayFee.GetFee(SPENDDESCRIPTION_SIZE + CTXOUT_REGULAR_SIZE + BINDINGSIG_SIZE); diff --git a/src/test/librust/sapling_wallet_tests.cpp b/src/test/librust/sapling_wallet_tests.cpp index e25392bcad2a0..81291cd517eaa 100644 --- a/src/test/librust/sapling_wallet_tests.cpp +++ b/src/test/librust/sapling_wallet_tests.cpp @@ -565,8 +565,8 @@ BOOST_AUTO_TEST_CASE(SpentSaplingNoteIsFromMe) { BOOST_CHECK_EQUAL(tx2.vin.size(), 0); BOOST_CHECK_EQUAL(tx2.vout.size(), 0); BOOST_CHECK_EQUAL(tx2.sapData->vShieldedSpend.size(), 1); - BOOST_CHECK_EQUAL(tx2.sapData->vShieldedOutput.size(), 1); // 0.025 dust change added to the fee - BOOST_CHECK_EQUAL(tx2.sapData->valueBalance, 12500000); // 0.025 dust change added to the fee + BOOST_CHECK_EQUAL(tx2.sapData->vShieldedOutput.size(), 2); + BOOST_CHECK_EQUAL(tx2.sapData->valueBalance, 10000000); CWalletTx wtx2 {&wallet, tx2}; @@ -1115,8 +1115,8 @@ BOOST_AUTO_TEST_CASE(MarkAffectedSaplingTransactionsDirty) { BOOST_CHECK_EQUAL(tx2.vin.size(), 0); BOOST_CHECK_EQUAL(tx2.vout.size(), 0); BOOST_CHECK_EQUAL(tx2.sapData->vShieldedSpend.size(), 1); - BOOST_CHECK_EQUAL(tx2.sapData->vShieldedOutput.size(), 1); // 0.05 dust change added to the fee - BOOST_CHECK_EQUAL(tx2.sapData->valueBalance, 15000000); // 0.05 dust change added to the fee + BOOST_CHECK_EQUAL(tx2.sapData->vShieldedOutput.size(), 2); + BOOST_CHECK_EQUAL(tx2.sapData->valueBalance, 10000000); CWalletTx wtx2 {&wallet, tx2}; diff --git a/src/test/librust/transaction_builder_tests.cpp b/src/test/librust/transaction_builder_tests.cpp index b4b53e638c31a..17aed96c8058e 100644 --- a/src/test/librust/transaction_builder_tests.cpp +++ b/src/test/librust/transaction_builder_tests.cpp @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(SaplingToSapling) { auto pa = sk.default_address(); // Create a Sapling-only transaction - // --- 0.4 shielded-PIV in, 0.25 shielded-PIV out, 0.1 shielded-PIV fee, 0.05 shielded-PIV change (added to fee) + // --- 0.4 shielded-PIV in, 0.299 shielded-PIV out, 0.1 shielded-PIV fee, 0.001 shielded-PIV change (added to fee) auto testNote = GetTestSaplingNote(pa, 40000000); auto builder = TransactionBuilder(consensusParams, 2); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); @@ -73,16 +73,15 @@ BOOST_AUTO_TEST_CASE(SaplingToSapling) { // TODO: the following check can be split out in to another test BOOST_CHECK_THROW(builder.AddSaplingSpend(expsk, testNote.note, uint256(), testNote.tree.witness()), std::runtime_error); - builder.AddSaplingOutput(fvk.ovk, pa, 25000000, {}); + builder.AddSaplingOutput(fvk.ovk, pa, 29900000, {}); auto tx = builder.Build().GetTxOrThrow(); BOOST_CHECK_EQUAL(tx.vin.size(), 0); BOOST_CHECK_EQUAL(tx.vout.size(), 0); BOOST_CHECK_EQUAL(tx.sapData->vShieldedSpend.size(), 1); - // since the change is below the dust threshold, it is added to the fee BOOST_CHECK_EQUAL(tx.sapData->vShieldedOutput.size(), 1); - BOOST_CHECK_EQUAL(tx.sapData->valueBalance, 15000000); + BOOST_CHECK_EQUAL(tx.sapData->valueBalance, 10100000); CValidationState state; BOOST_CHECK(SaplingValidation::ContextualCheckTransaction(tx, state, Params(), 3, true, false)); diff --git a/src/validation.cpp b/src/validation.cpp index 34e58963b2b98..43f069db3155f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -292,7 +292,7 @@ CAmount GetMinRelayFee(unsigned int nBytes, bool fAllowFree) CAmount GetShieldedTxMinFee(const CTransaction& tx) { assert (tx.IsShieldedTx()); - unsigned int K = DEFAULT_SHIELDEDTXFEE_K; // Fixed (1000) for now + unsigned int K = DEFAULT_SHIELDEDTXFEE_K; // Fixed (100) for now CAmount nMinFee = ::minRelayTxFee.GetFee(tx.GetTotalSize()) * K; if (!Params().GetConsensus().MoneyRange(nMinFee)) nMinFee = Params().GetConsensus().nMaxMoneyOut; diff --git a/src/validation.h b/src/validation.h index 06713a60f3b6e..98965ee455f08 100644 --- a/src/validation.h +++ b/src/validation.h @@ -111,7 +111,7 @@ static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30; * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */ static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5; /** Default multiplier used in the computation for shielded txes min fee */ -static const unsigned int DEFAULT_SHIELDEDTXFEE_K = 1000; +static const unsigned int DEFAULT_SHIELDEDTXFEE_K = 100; /** Enable bloom filter */ static const bool DEFAULT_PEERBLOOMFILTERS = true; diff --git a/test/functional/sapling_mempool.py b/test/functional/sapling_mempool.py index e4cc0e4efcbbb..711c3f97f50dc 100755 --- a/test/functional/sapling_mempool.py +++ b/test/functional/sapling_mempool.py @@ -25,7 +25,7 @@ def run_test(self): alice = self.nodes[1] # Fixed fee - fee = 1 + fee = 0.05 self.log.info("Mining 120 blocks...") miner.generate(120) @@ -49,7 +49,7 @@ def run_test(self): # Alice creates and sends tx_B, unshielding the same note to tadd_B self.log.info("Alice creating and sending tx_B...") tadd_B = alice.getnewaddress() - txid_B = alice.shieldsendmany(alice_zaddr, [{"address": tadd_B, "amount": Decimal('9.00')}], 1, fee) + txid_B = alice.shieldsendmany(alice_zaddr, [{"address": tadd_B, "amount": Decimal('9.95')}], 1, fee) # Miner receives tx_B and accepts it in the mempool assert (txid_B in alice.getrawmempool()) diff --git a/test/functional/sapling_supply.py b/test/functional/sapling_supply.py index 2c43272180bea..ba83934b2be9e 100755 --- a/test/functional/sapling_supply.py +++ b/test/functional/sapling_supply.py @@ -24,11 +24,11 @@ def generate_and_sync(self, count): def check_shield_supply(self, z_supply): self.log.info("Checking supply...") - assert_equal(self.nodes[0].getsupplyinfo()['shieldsupply'], z_supply) + assert_equal(self.nodes[0].getsupplyinfo()['shieldsupply'], Decimal("%.8f" % z_supply)) self.log.info("OK. Shield supply is %.8f" % z_supply) def run_test(self): - fee = 1 + fee = 0.05 # First mine 101 blocks to mature one utxo self.log.info("Generating 101 blocks...") self.generate_and_sync(101) diff --git a/test/functional/sapling_wallet.py b/test/functional/sapling_wallet.py index 49c789d5c77ad..0af64085b9185 100755 --- a/test/functional/sapling_wallet.py +++ b/test/functional/sapling_wallet.py @@ -83,7 +83,7 @@ def run_test(self): self.log.info("Good. Not accepted in the mempool.") # Fixed fee - fee = 1 + fee = 0.05 # Node 0 shields some funds # taddr -> Sapling @@ -209,11 +209,11 @@ def run_test(self): self.sync_all() # Verify balance - assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('3')) # 30 received - (20 sent + 3 fee) - 4 sent - assert_equal(self.nodes[1].getshieldbalance(saplingAddr1), Decimal('20')) # 20 received - assert_equal(self.nodes[0].getshieldbalance(saplingAddr2), Decimal('2')) # 10 received - 10 sent + 2 change + assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('4.9')) # 30 received - (20 sent + 0.15 fee) - 4.95 sent + assert_equal(self.nodes[1].getshieldbalance(saplingAddr1), Decimal('20')) # 20 received + assert_equal(self.nodes[0].getshieldbalance(saplingAddr2), Decimal('3.9')) # 10 received - 10 sent + 3.9 change assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) - assert_equal(self.nodes[0].getshieldbalance(), Decimal('5')) + assert_equal(self.nodes[0].getshieldbalance(), Decimal('8.8')) self.log.info("Balances check out") # Node 1 sends some shield funds to node 0, as well as unshielding @@ -230,14 +230,14 @@ def run_test(self): self.sync_all() # Verify balance - assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('11')) # 3 prev balance + 8 received - assert_equal(self.nodes[1].getshieldbalance(saplingAddr1), Decimal('1')) # 20 prev balance - (18 sent + 1 fee) + assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('12.9')) # 4.9 prev balance + 8 received + assert_equal(self.nodes[1].getshieldbalance(saplingAddr1), Decimal('1.95')) # 20 prev balance - (18 sent + 0.05 fee) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('10')) self.log.info("Balances check out") # Verify existence of Sapling related JSON fields resp = self.nodes[0].getrawtransaction(mytxid7, 1) - assert_equal(Decimal(resp['valueBalance']), Decimal('11.00')) # 20 shield input - 8 shield spend - 1 change + assert_equal(Decimal(resp['valueBalance']), Decimal('10.05')) # 20 shield input - 8 shield spend - 1.95 change assert_equal(len(resp['vShieldSpend']), 3) assert_equal(len(resp['vShieldOutput']), 2) assert('bindingSig' in resp) @@ -262,26 +262,26 @@ def run_test(self): sk0 = self.nodes[0].exportsaplingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[2].importsaplingkey(sk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) - assert_equal(self.nodes[2].getshieldbalance(saplingAddrInfo0["address"]), Decimal('11')) + assert_equal(self.nodes[2].getshieldbalance(saplingAddrInfo0["address"]), Decimal('12.9')) sk1 = self.nodes[1].exportsaplingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[2].importsaplingkey(sk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) - assert_equal(self.nodes[2].getshieldbalance(saplingAddrInfo1["address"]), Decimal('1')) + assert_equal(self.nodes[2].getshieldbalance(saplingAddrInfo1["address"]), Decimal('1.95')) # Verify importing a viewing key will update the nullifiers and witnesses correctly self.log.info("Checking exporting/importing a viewing key...") extfvk0 = self.nodes[0].exportsaplingviewingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[3].importsaplingviewingkey(extfvk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) - assert_equal(Decimal(self.nodes[3].getshieldbalance(saplingAddrInfo0["address"], 1, True)), Decimal('11')) + assert_equal(Decimal(self.nodes[3].getshieldbalance(saplingAddrInfo0["address"], 1, True)), Decimal('12.9')) extfvk1 = self.nodes[1].exportsaplingviewingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[3].importsaplingviewingkey(extfvk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) - assert_equal(self.nodes[3].getshieldbalance(saplingAddrInfo1["address"], 1, True), Decimal('1')) + assert_equal(self.nodes[3].getshieldbalance(saplingAddrInfo1["address"], 1, True), Decimal('1.95')) # no balance in the wallet assert_equal(self.nodes[3].getshieldbalance(), Decimal('0')) # watch only balance - assert_equal(self.nodes[3].getshieldbalance("*", 1, True), Decimal('12.00')) + assert_equal(self.nodes[3].getshieldbalance("*", 1, True), Decimal('14.85')) # Now shield some funds using sendmany self.log.info("TX11: Shielding coins to multiple destinations with sendmany RPC...") @@ -318,9 +318,9 @@ def run_test(self): # Verify balance self.nodes[2].generate(1) self.sync_all() - assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('19')) # 11 prev balance + 8 received - assert_equal(self.nodes[1].getshieldbalance(saplingAddr1), Decimal('2')) # 1 prev balance + 1 received - assert_equal(self.nodes[0].getshieldbalance(saplingAddr2), Decimal('2.5')) # 2 prev balance + 0.5 received + assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('20.9')) # 12.9 prev balance + 8 received + assert_equal(self.nodes[1].getshieldbalance(saplingAddr1), Decimal('2.95')) # 1.95 prev balance + 1 received + assert_equal(self.nodes[0].getshieldbalance(saplingAddr2), Decimal('4.4')) # 3.9 prev balance + 0.5 received # Balance of node 0 is: prev_balance - 1 PIV (+fee) sent externally + 250 PIV matured coinbase assert_equal(self.nodes[0].getbalance(), satoshi_round(prev_balance + Decimal('249') - Decimal(fee))) @@ -345,7 +345,7 @@ def run_test(self): # Verify balance self.nodes[2].generate(1) self.sync_all() - assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('29')) # 19 prev balance + 10 received + assert_equal(self.nodes[0].getshieldbalance(saplingAddr0), Decimal('30.9')) # 20.9 prev balance + 10 received self.log.info("All good.") diff --git a/test/functional/sapling_wallet_listreceived.py b/test/functional/sapling_wallet_listreceived.py index 2b19e9a42c591..5fbfd4c6963bb 100755 --- a/test/functional/sapling_wallet_listreceived.py +++ b/test/functional/sapling_wallet_listreceived.py @@ -48,7 +48,7 @@ def run_test(self): self.nodes[1].shieldsendmany, taddr, [{'address': shield_addr1, 'amount': 2, 'memo': too_big_memo_str}]) # Fixed fee - fee = 0.5 + fee = 0.05 # Send 1 PIV to shield addr1 txid = self.nodes[1].shieldsendmany(taddr, [ # node_1 with 6 PIV sending them all (fee is 0.1 PIV) @@ -128,9 +128,9 @@ def run_test(self): # Generate some change by sending part of shield_addr1 to shield_addr2 txidPrev = txid shield_addr2 = self.nodes[1].getnewshieldaddress() - txid = self.nodes[1].shieldsendmany(shield_addr1, # shield_addr1 has 2 PIV, send 0.6 PIV + 0.5 PIV fee + txid = self.nodes[1].shieldsendmany(shield_addr1, # shield_addr1 has 2 PIV, send 0.6 PIV + 0.05 PIV fee [{'address': shield_addr2, 'amount': 0.6, "memo": non_ascii_memo_str}], - 1, fee) # change 0.9 + 1, fee) # change 1.35 self.sync_all() self.generate_and_sync(height+4) @@ -165,8 +165,8 @@ def run_test(self): assert_equal(out['address'], shield_addr1) assert_equal(out['outgoing'], False) assert_equal(out['memo'], no_memo) - assert_equal(out['value'], Decimal('0.9')) - assert_equal(out['valueSat'], 90000000) + assert_equal(out['value'], Decimal('1.35')) + assert_equal(out['valueSat'], 135000000) found[1] = True assert_equal(found, [True] * 2) @@ -176,7 +176,7 @@ def run_test(self): assert_true(2 == len(r), "shield_addr1 Should have received 2 notes") assert_equal(txid, r[0]['txid']) - assert_equal(Decimal('0.9'), r[0]['amount']) + assert_equal(Decimal('1.35'), r[0]['amount']) assert_true(r[0]['change'], "Note valued at (1.4-fee) should be change") assert_equal(no_memo, r[0]['memo']) From 41abf5aecc3020efbaf5923e32eea9d06a5409a4 Mon Sep 17 00:00:00 2001 From: PeterL73 Date: Tue, 22 Dec 2020 07:39:28 +0000 Subject: [PATCH 22/22] clear StakeableCoins before initializing Github-Pull: #2109 Rebased-From: f12af33ee234edabe19e41f8210508042024f438 --- src/wallet/wallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 01dbb057cf1a7..dd64015159606 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2414,6 +2414,8 @@ bool CWallet::StakeableCoins(std::vector* pCoins) const bool fIncludeColdStaking = !sporkManager.IsSporkActive(SPORK_19_COLDSTAKING_MAINTENANCE) && gArgs.GetBoolArg("-coldstaking", DEFAULT_COLDSTAKING); + if (pCoins) pCoins->clear(); + LOCK2(cs_main, cs_wallet); for (const auto& it : mapWallet) { const uint256& wtxid = it.first;