message:
[Mining] Track a recent mining hashrate.
This grants each mining thread within the wallet a struct to store
the hashrate from its most recent round. `getmininginfo` will
return the sum of these in `hashspeed_recent` as a best approximation.
The threads also individually log their hashrate alongside the full
hashrate.

diff:
#include <algorithm>
#include <queue>
#include <utility>
+#include <vector>
#include <boost/thread.hpp>
#include "veil/zerocoin/accumulators.h"
@@ -845,19 +846,57 @@ double GetHashSpeed() {
return arith_uint256(nHashes/nTimeDuration).getdouble();
}
+class ThreadHashSpeed {
+ public:
+ ThreadHashSpeed() {}
+ ThreadHashSpeed(ThreadHashSpeed&& ths) {
+ LOCK(ths.cs);
+ nHashes = ths.nHashes;
+ nTimeDuration = ths.nTimeDuration;
+ }
+ CCriticalSection cs;
+ arith_uint256 nHashes = 0;
+ int32_t nTimeDuration = 0;
+};
+
+CCriticalSection cs_hashspeeds;
+std::vector<ThreadHashSpeed> vHashSpeeds;
+
void ClearHashSpeed() {
+ {
LOCK(cs_nonce);
nHashes = 0;
nTimeStart = 0;
nTimeDuration = 0;
}
+ {
+ LOCK(cs_hashspeeds);
+ for (auto& ths : vHashSpeeds) {
+ LOCK(ths.cs);
+ ths.nHashes = 0;
+ ths.nTimeDuration = 0;
+ }
+ }
+}
+
+double GetRecentHashSpeed() {
+ LOCK(cs_hashspeeds);
+ double nTotalHashSpeed = 0.0;
+ for (auto& hs : vHashSpeeds) {
+ LOCK(hs.cs);
+ if (hs.nTimeDuration > 0)
+ nTotalHashSpeed += hs.nHashes.getdouble() / hs.nTimeDuration;
+ }
+ return nTotalHashSpeed;
+}
-void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfStake = false, bool fProofOfFullNode = false) {
+void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfStake = false, bool fProofOfFullNode = false, ThreadHashSpeed* pThreadHashSpeed = nullptr) {
LogPrintf("Veil Miner started\n");
unsigned int nExtraNonce = 0;
static const int nInnerLoopCount = 0x010000;
static uint32_t nStakeHashesLast = 0;
+ int32_t nLocalStartTime = 0;
bool enablewallet = false;
#ifdef ENABLE_WALLET
enablewallet = !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
@@ -964,8 +1003,9 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
{
LOCK(cs_nonce);
nExtraNonce = nNonce_base++;
+ nLocalStartTime = GetTime();
if (!nTimeStart)
- nTimeStart = GetTime();
+ nTimeStart = nLocalStartTime;
}
pblock->nNonce = 0;
@@ -1031,8 +1071,19 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
if (!nTimeDuration) nTimeDuration = 1;
nHashSpeed = arith_uint256(nHashes/1000/nTimeDuration).getdouble();
}
-
+ if (pThreadHashSpeed != nullptr) {
+ double nRecentHashSpeed = 0;
+ {
+ LOCK(pThreadHashSpeed->cs);
+ pThreadHashSpeed->nHashes = nTries + (nMidTries * nInnerLoopCount);
+ pThreadHashSpeed->nTimeDuration = std::max<int32_t>(GetTime() - nLocalStartTime, 1);
+ nRecentHashSpeed = pThreadHashSpeed->nHashes.getdouble() / 1000 / pThreadHashSpeed->nTimeDuration;
+ }
+ LogPrint(BCLog::MINING, "%s: PoW Hashspeed %d kh/s (this thread this round: %.03f khs)\n", __func__, nHashSpeed, nRecentHashSpeed);
+ } else {
LogPrint(BCLog::MINING, "%s: PoW Hashspeed %d kh/s\n", __func__, nHashSpeed);
+ }
+
if (!success) {
continue;
}
@@ -1050,11 +1101,12 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
}
}
-void BitcoinRandomXMiner(std::shared_ptr<CReserveScript> coinbaseScript, int vm_index, uint32_t startNonce) {
+void BitcoinRandomXMiner(std::shared_ptr<CReserveScript> coinbaseScript, int vm_index, uint32_t startNonce, ThreadHashSpeed* pThreadHashSpeed) {
LogPrintf("Veil RandomX Miner started\n");
unsigned int nExtraNonce = 0;
static const int nInnerLoopCount = RANDOMX_INNER_LOOP_COUNT;
+ int32_t nLocalStartTime = 0;
bool fBlockFoundAlready = false;
while (GenerateActive())
@@ -1086,8 +1138,9 @@ void BitcoinRandomXMiner(std::shared_ptr<CReserveScript> coinbaseScript, int vm_
{
LOCK(cs_nonce);
nExtraNonce = nNonce_base++;
+ nLocalStartTime = GetTime();
if (!nTimeStart)
- nTimeStart = GetTime();
+ nTimeStart = nLocalStartTime;
}
pblock->nNonce = startNonce;
@@ -1146,8 +1199,19 @@ void BitcoinRandomXMiner(std::shared_ptr<CReserveScript> coinbaseScript, int vm_
nHashSpeed = arith_uint256(nHashes/nTimeDuration).getdouble();
}
}
-
+ if (pThreadHashSpeed != nullptr) {
+ double nRecentHashSpeed = 0;
+ {
+ LOCK(pThreadHashSpeed->cs);
+ pThreadHashSpeed->nHashes = nTries;
+ pThreadHashSpeed->nTimeDuration = std::max<int32_t>(GetTime() - nLocalStartTime, 1);
+ nRecentHashSpeed = pThreadHashSpeed->nHashes.getdouble() / pThreadHashSpeed->nTimeDuration;
+ }
+ LogPrint(BCLog::MINING, "%s: RandomX PoW Hashspeed %d hashes/s (this thread this round: %.03f hashes/s\n", __func__, nHashSpeed, nRecentHashSpeed);
+ } else {
LogPrint(BCLog::MINING, "%s: RandomX PoW Hashspeed %d hashes/s\n", __func__, nHashSpeed);
+ }
+
if (nTries == nInnerLoopCount) {
continue;
}
@@ -1167,12 +1231,12 @@ void BitcoinRandomXMiner(std::shared_ptr<CReserveScript> coinbaseScript, int vm_
}
}
-void static ThreadBitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript)
+void static ThreadBitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, ThreadHashSpeed* pThreadHashSpeed)
{
LogPrintf("%s: starting\n", __func__);
boost::this_thread::interruption_point();
try {
- BitcoinMiner(coinbaseScript);
+ BitcoinMiner(coinbaseScript, false, false, pThreadHashSpeed);
boost::this_thread::interruption_point();
} catch (std::exception& e) {
LogPrintf("%s: exception\n", __func__);
@@ -1188,7 +1252,13 @@ void ThreadRandomXBitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, c
LogPrintf("%s: starting\n", __func__);
boost::this_thread::interruption_point();
try {
- BitcoinRandomXMiner(coinbaseScript, vm_index, startNonce);
+ ThreadHashSpeed* pThreadHashSpeed = nullptr;
+ {
+ LOCK(cs_hashspeeds);
+ if (0 <= vm_index && vm_index < vHashSpeeds.size())
+ pThreadHashSpeed = &vHashSpeeds[vm_index];
+ }
+ BitcoinRandomXMiner(coinbaseScript, vm_index, startNonce, pThreadHashSpeed);
boost::this_thread::interruption_point();
} catch (std::exception& e) {
LogPrintf("%s: exception\n", __func__);
@@ -1268,13 +1338,16 @@ void GenerateBitcoins(bool fGenerate, int nThreads, std::shared_ptr<CReserveScri
if (nThreads == 0 || !fGenerate)
return;
+ LOCK(cs_hashspeeds);
+ vHashSpeeds.resize(nThreads);
+
// XXX - Todo - find a way to clean out the old threads or reuse the threads already created
if (GetMiningAlgorithm() == MINE_RANDOMX && GetTime() >= Params().PowUpdateTimestamp()) {
pthreadGroupRandomX->create_thread(boost::bind(&StartRandomXMining, pthreadGroupPoW,
nThreads, coinbaseScript));
} else {
for (int i = 0; i < nThreads; i++)
- pthreadGroupPoW->create_thread(boost::bind(&ThreadBitcoinMiner, coinbaseScript));
+ pthreadGroupPoW->create_thread(boost::bind(&ThreadBitcoinMiner, coinbaseScript, &vHashSpeeds[i]));
}
}

diff:
@@ -51,6 +51,7 @@ static std::string GetMiningType(int nPoWType, bool fProofOfStake = false, bool
double GetHashSpeed();
void ClearHashSpeed();
+double GetRecentHashSpeed();
int GetMiningAlgorithm();
bool SetMiningAlgorithm(const std::string& algo, bool fSet = true);

diff:
@@ -378,6 +378,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
obj.pushKV("difficulty", (double)nDiff);
obj.pushKV("networkhashps", getnetworkhashps(request));
obj.pushKV("hashspeed", GetHashSpeed());
+ obj.pushKV("hashspeed_recent", GetRecentHashSpeed());
obj.pushKV("pooledtx", (uint64_t)mempool.size());
obj.pushKV("chain", Params().NetworkIDString());
obj.pushKV("warnings", GetWarnings("statusbar"));


message:
Lock cs_main before calling GetBlocksToMaturity
This is similar to another call, just somehow missed this one earlier.

change_type: MODIFY

diff:
@@ -2527,11 +2527,19 @@ static void ExportTransactions(CWallet* const pwallet, const CWalletTx& wtx, con
{
if (wtx.GetDepthInMainChain() < 1)
csvRecord[TRANSACTION_CSV_FIELD_CATEGORY] = "orphan";
- else if (wtx.GetBlocksToMaturity() > 0)
+ else
+ {
+ int nBlocksToMaturity;
+ {
+ LOCK(cs_main);
+ nBlocksToMaturity = wtx.GetBlocksToMaturity();
+ }
+ if (nBlocksToMaturity > 0)
csvRecord[TRANSACTION_CSV_FIELD_CATEGORY] = "immature";
else
csvRecord[TRANSACTION_CSV_FIELD_CATEGORY] = "generate";
}
+ }
else
{
csvRecord[TRANSACTION_CSV_FIELD_CATEGORY] = "receive";

license: MIT License

repo: veil-project/veil


message: Split ZerocoinSpendReceipt into a generic Receipt.

diff:
@@ -207,6 +207,7 @@ BITCOIN_CORE_H = \
veil/ringct/keyutil.h \
veil/ringct/outputrecord.h \
veil/ringct/rctindex.h \
+ veil/ringct/receipt.h \
veil/ringct/rpcanonwallet.h \
veil/ringct/stealth.h \
veil/ringct/temprecipient.h \
@@ -350,11 +351,12 @@ libbitcoin_wallet_a_SOURCES = \
veil/zerocoin/spendreceipt.cpp \
veil/zerocoin/ztracker.cpp \
veil/zerocoin/zwallet.cpp \
- veil/ringct/temprecipient.cpp \
veil/ringct/anonwalletdb.cpp \
veil/ringct/anonwallet.cpp \
veil/ringct/outputrecord.cpp \
+ veil/ringct/receipt.cpp \
veil/ringct/rpcanonwallet.cpp \
+ veil/ringct/temprecipient.cpp \
$(BITCOIN_CORE_H)
if TARGET_ARM64

change_type: ADD

diff:
+// Copyright (c) 2017-2019 The PIVX developers
+// Copyright (c) 2019-2021 The Veil developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <veil/ringct/receipt.h>
+#include <veil/ringct/transactionrecord.h>
+
+
+void CMultiTxReceipt::SetStatus(std::string strStatus, int nStatus)
+{
+ strStatusMessage = strStatus;
+ this->nStatus = nStatus;
+}
+
+CTransactionRecord CMultiTxReceipt::GetTransactionRecord(const int n) const
+{
+ if (!mapRecords.count(n))
+ return CTransactionRecord();
+ return mapRecords.at(n);
+}
+
+void CMultiTxReceipt::AddTransaction(CTransactionRef& txRef, const CTransactionRecord& rtx)
+{
+ auto n = vtx.size();
+ mapRecords.emplace(n, rtx);
+ vtx.emplace_back(txRef);
+}
+
+std::string CMultiTxReceipt::GetStatusMessage()
+{
+ return strStatusMessage;
+}

diff:
+// Copyright (c) 2017-2019 The PIVX developers
+// Copyright (c) 2019-2021 The Veil developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef VEIL_RECEIPT_H
+#define VEIL_RECEIPT_H
+
+#include <veil/ringct/temprecipient.h>
+#include <veil/ringct/transactionrecord.h>
+
+class CMultiTxReceipt
+{
+protected:
+ std::string strStatusMessage;
+ int nStatus;
+ std::map<int, CTransactionRecord> mapRecords; // key:tx's spot in vtx
+ std::vector<CTransactionRef> vtx;
+
+public:
+ void AddTransaction(CTransactionRef& txRef, const CTransactionRecord& rtx);
+ void SetStatus(std::string strStatus, int nStatus);
+ std::string GetStatusMessage();
+ std::vector<CTransactionRef> GetTransactions() const { return vtx; }
+ CTransactionRecord GetTransactionRecord(int n) const;
+};
+
+#endif //VEIL_RECEIPT_H

diff:
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <veil/zerocoin/spendreceipt.h>
+#include <veil/ringct/receipt.h>
#include <veil/ringct/transactionrecord.h>
void CZerocoinSpendReceipt::AddSpend(const CZerocoinSpend& spend)
@@ -31,26 +32,6 @@ std::vector<CZerocoinSpend> CZerocoinSpendReceipt::GetSpends_back()
void CZerocoinSpendReceipt::SetStatus(std::string strStatus, int nStatus, int nNeededSpends)
{
- strStatusMessage = strStatus;
- this->nStatus = nStatus;
+ CMultiTxReceipt::SetStatus(strStatus, nStatus);
this->nNeededSpends = nNeededSpends;
}
-
-CTransactionRecord CZerocoinSpendReceipt::GetTransactionRecord(const int n) const
-{
- if (!mapRecords.count(n))
- return CTransactionRecord();
- return mapRecords.at(n);
-}
-
-void CZerocoinSpendReceipt::AddTransaction(CTransactionRef& txRef, const CTransactionRecord& rtx)
-{
- auto n = vtx.size();
- mapRecords.emplace(n, rtx);
- vtx.emplace_back(txRef);
-}
-
-std::string CZerocoinSpendReceipt::GetStatusMessage()
-{
- return strStatusMessage;
-}

diff:
// Copyright (c) 2017-2019 The PIVX developers
-// Copyright (c) 2019 The Veil developers
+// Copyright (c) 2019-2021 The Veil developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#define VEIL_SPENDRECEIPT_H
#include <primitives/zerocoin.h>
+#include <veil/ringct/receipt.h>
#include <veil/ringct/temprecipient.h>
#include <veil/ringct/transactionrecord.h>
-class CTransactionRecord;
-
-class CZerocoinSpendReceipt
+class CZerocoinSpendReceipt : public CMultiTxReceipt
{
private:
- std::string strStatusMessage;
- int nStatus;
int nNeededSpends;
std::map<int, std::vector<CZerocoinSpend>> mapSpends; // key:tx's spot in vtx
- std::map<int, CTransactionRecord> mapRecords; // key:tx's spot in vtx
- std::vector<CTransactionRef> vtx;
public:
void AddSpend(const CZerocoinSpend& spend);
- void AddTransaction(CTransactionRef& txRef, const CTransactionRecord& rtx);
std::vector<CZerocoinSpend> GetSpends(int n);
std::vector<CZerocoinSpend> GetSpends_back();
void SetStatus(std::string strStatus, int nStatus, int nNeededSpends = 0);
- std::string GetStatusMessage();
- std::vector<CTransactionRef> GetTransactions() const { return vtx; }
- CTransactionRecord GetTransactionRecord(int n) const;
};
#endif //VEIL_SPENDRECEIPT_H


message: [Trivial] Fix a size_t reference for clang 13

diff:
/**
* A valid mnemonic dictionary has exactly this many words.
*/
-static constexpr size_t dictionary_size = 2048;
+static constexpr std::size_t dictionary_size = 2048;
/**
* Dictionary definitions for creating mnemonics.


message:
[Refactor] GetStakeModifier
Extracts some likely reusable code from ZerocoinStake, and moves the
helper functions to the top of the file.

diff:
typedef std::vector<unsigned char> valtype;
+// Use the PoW hash or the PoS hash
+uint256 GetHashFromIndex(const CBlockIndex* pindexSample)
+{
+ if (pindexSample->IsProofOfWork()) {
+ // By using the pindex time and checking it against the PoWUpdateTimestamp we can tell the code to either
+ // set the veildatahash to all zeros if True is passed, or to do nothing if False is passed.
+ // When mining to the local wallet aggressively we have found that occassionaly the memory of the pindex block data
+ // shows that the veildatahash is not zero (0000xxxx). This made the wallet not accept valid PoS blocks from the chain tip
+ // and allowed the wallet to fork off. This fix allows us to pass in the boolean that is used to tell the code
+ // to set the veildatahash to zero manually for us. This can be done only after the PoWUpdateTimestamp as veildatahash isn't used
+ // in the block hash calculation after that timestamp.
+ return pindexSample->GetX16RTPoWHash(pindexSample->nTime >= Params().PowUpdateTimestamp());
+ }
+
+ uint256 hashProof = pindexSample->GetBlockPoSHash();
+ return hashProof;
+}
+
+// As the sampling gets further back into the chain, use more bits of entropy. This prevents the ability to significantly
+// impact the modifier if you create one of the most recent blocks used. For example, the contribution from the first sample
+// (which is 101 blocks from the coin tip) will only be 2 bits, thus only able to modify the end result of the modifier
+// 4 different ways. As the sampling gets further back into the chain (take previous sample height - nSampleCount*6 for the height
+// it will be) it has more entropy that is assigned to that specific sampling. The further back in the chain, the less
+// ability there is to have any influence at all over the modifier calculations going forward from that specific block.
+// The bits taper down as it gets deeper into the chain so that the precomputability is less significant.
+int GetSampleBits(int nSampleCount)
+{
+ switch(nSampleCount) {
+ case 0:
+ return 2;
+ case 1:
+ return 4;
+ case 2:
+ return 8;
+ case 3:
+ return 16;
+ case 4:
+ return 32;
+ case 5:
+ return 64;
+ case 6:
+ return 128;
+ case 7:
+ return 64;
+ case 8:
+ return 32;
+ case 9:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+bool GetStakeModifier(uint64_t& nStakeModifier, const CBlockIndex& pindexChainPrev)
+{
+ uint256 hashModifier;
+ //Use a new modifier that is less able to be "grinded"
+ int nHeightChain = pindexChainPrev.nHeight;
+ int nHeightPrevious = nHeightChain - 100;
+ for (int i = 0; i < 10; i++) {
+ int nHeightSample = nHeightPrevious - (6*i);
+ nHeightPrevious = nHeightSample;
+ auto pindexSample = pindexChainPrev.GetAncestor(nHeightSample);
+
+ if (!pindexSample) return false;
+ //Get a sampling of entropy from this block. Rehash the sample, since PoW hashes may have lots of 0's
+ uint256 hashSample = GetHashFromIndex(pindexSample);
+ hashSample = Hash(hashSample.begin(), hashSample.end());
+
+ //Reduce the size of the sampling
+ int nBitsToUse = GetSampleBits(i);
+ auto arith = UintToArith256(hashSample);
+ arith >>= (256-nBitsToUse);
+ hashSample = ArithToUint256(arith);
+ hashModifier = Hash(hashModifier.begin(), hashModifier.end(), hashSample.begin(), hashSample.end());
+ }
+
+ nStakeModifier = UintToArith256(hashModifier).GetLow64();
+ return true;
+}
+
ZerocoinStake::ZerocoinStake(const libzerocoin::CoinSpend& spend)
{
this->nChecksum = spend.getAccumulatorChecksum();
@@ -91,59 +172,6 @@ int ZerocoinStake::HeightToModifierHeight(int nHeight)
return (nHeight - Params().KernelModulus()) - (nHeight % Params().KernelModulus()) ;
}
-// Use the PoW hash or the PoS hash
-uint256 GetHashFromIndex(const CBlockIndex* pindexSample)
-{
- if (pindexSample->IsProofOfWork()) {
- // By using the pindex time and checking it against the PoWUpdateTimestamp we can tell the code to either
- // set the veildatahash to all zeros if True is passed, or to do nothing if False is passed.
- // When mining to the local wallet aggressively we have found that occassionaly the memory of the pindex block data
- // shows that the veildatahash is not zero (0000xxxx). This made the wallet not accept valid PoS blocks from the chain tip
- // and allowed the wallet to fork off. This fix allows us to pass in the boolean that is used to tell the code
- // to set the veildatahash to zero manually for us. This can be done only after the PoWUpdateTimestamp as veildatahash isn't used
- // in the block hash calculation after that timestamp.
- return pindexSample->GetX16RTPoWHash(pindexSample->nTime >= Params().PowUpdateTimestamp());
- }
-
- uint256 hashProof = pindexSample->GetBlockPoSHash();
- return hashProof;
-}
-
-// As the sampling gets further back into the chain, use more bits of entropy. This prevents the ability to significantly
-// impact the modifier if you create one of the most recent blocks used. For example, the contribution from the first sample
-// (which is 101 blocks from the coin tip) will only be 2 bits, thus only able to modify the end result of the modifier
-// 4 different ways. As the sampling gets further back into the chain (take previous sample height - nSampleCount*6 for the height
-// it will be) it has more entropy that is assigned to that specific sampling. The further back in the chain, the less
-// ability there is to have any influence at all over the modifier calculations going forward from that specific block.
-// The bits taper down as it gets deeper into the chain so that the precomputability is less significant.
-int GetSampleBits(int nSampleCount)
-{
- switch(nSampleCount) {
- case 0:
- return 2;
- case 1:
- return 4;
- case 2:
- return 8;
- case 3:
- return 16;
- case 4:
- return 32;
- case 5:
- return 64;
- case 6:
- return 128;
- case 7:
- return 64;
- case 8:
- return 32;
- case 9:
- return 16;
- default:
- return 0;
- }
-}
-
//Use the first accumulator checkpoint that occurs 60 minutes after the block being staked from
bool ZerocoinStake::GetModifier(uint64_t& nStakeModifier, const CBlockIndex* pindexChainPrev)
{
@@ -153,30 +181,8 @@ bool ZerocoinStake::GetModifier(uint64_t& nStakeModifier, const CBlockIndex* pin
return false;
}
- uint256 hashModifier;
if (pindexChainPrev->nHeight >= Params().HeightLightZerocoin()) {
- //Use a new modifier that is less able to be "grinded"
- int nHeightChain = pindexChainPrev->nHeight;
- int nHeightPrevious = nHeightChain - 100;
- for (int i = 0; i < 10; i++) {
- int nHeightSample = nHeightPrevious - (6*i);
- nHeightPrevious = nHeightSample;
- auto pindexSample = pindexChainPrev->GetAncestor(nHeightSample);
-
- if (!pindexSample) return false;
- //Get a sampling of entropy from this block. Rehash the sample, since PoW hashes may have lots of 0's
- uint256 hashSample = GetHashFromIndex(pindexSample);
- hashSample = Hash(hashSample.begin(), hashSample.end());
-
- //Reduce the size of the sampling
- int nBitsToUse = GetSampleBits(i);
- auto arith = UintToArith256(hashSample);
- arith >>= (256-nBitsToUse);
- hashSample = ArithToUint256(arith);
- hashModifier = Hash(hashModifier.begin(), hashModifier.end(), hashSample.begin(), hashSample.end());
- }
- nStakeModifier = UintToArith256(hashModifier).GetLow64();
- return true;
+ return GetStakeModifier(nStakeModifier, *pindexChainPrev);
}
int nNearest100Block = ZerocoinStake::HeightToModifierHeight(pindex->nHeight);


message:
getblockstats: Consider ct_fee as tx fee if available
Otherwise fall back to subtraction (mainly basecoin-to-basecoin) or skipping.

diff:
@@ -2076,10 +2076,6 @@ static UniValue getblockstats(const JSONRPCRequest& request)
if (tx->IsCoinStake()) {
continue;
}
- if (tx->vin[0].IsAnonInput()) {
- // Can't really do much with a ringCT transaction
- continue;
- }
inputs += tx->vin.size(); // Don't count coinbase's fake input
total_out += tx_total_out; // Don't count coinbase reward
@@ -2110,9 +2106,17 @@ static UniValue getblockstats(const JSONRPCRequest& request)
if (loop_inputs) {
+ CAmount txfee;
+ if (tx->vin[0].IsAnonInput()) {
+ if (!tx->GetCTFee(txfee)) {
+ // Can't really do much with a ringCT transaction with no fee
+ continue;
+ }
+ } else {
if (!g_txindex) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled");
}
+ // Total up the utxo_size_inc even if we have a ct_fee
CAmount tx_total_in = 0;
for (const CTxIn& in : tx->vin) {
if (!in.IsZerocoinSpend()) {
@@ -2132,12 +2136,16 @@ static UniValue getblockstats(const JSONRPCRequest& request)
tx_total_in += in.GetZerocoinSpent();
}
}
-
- CAmount txfee = tx_total_in - tx_total_out;
+ // Prefer the ct_fee over the difference
+ if (!tx->GetCTFee(txfee)) {
+ txfee = tx_total_in - tx_total_out;
if (tx_total_in < tx_total_out) {
// RingCT with hidden inputs, can't count it
continue;
}
+ }
+ }
+
assert(MoneyRange(txfee));
if (do_medianfee) {
fee_array.push_back(txfee);


message: [Refactor] Move parts of AddAnonInputs into helper functions.

diff:
@@ -3122,6 +3122,174 @@ bool AnonWallet::IsMyAnonInput(const CTxIn& txin, COutPoint& myOutpoint)
return false;
}
+bool AnonWallet::ArrangeBlinds(
+ std::vector<CTxIn>& vin,
+ std::vector<ec_point>& vInputBlinds,
+ std::vector<std::vector<std::vector<int64_t>>>& vMI,
+ std::vector<size_t>& vSecretColumns,
+ std::vector<std::pair<MapRecords_t::const_iterator, unsigned int>>& setCoins,
+ bool dummySigs,
+ std::string& sError)
+{
+ std::set<int64_t> setHave; // Anon prev-outputs can only be used once per transaction.
+ size_t nTotalInputs = 0;
+ for (size_t l = 0; l < vin.size(); ++l) { // Must add real outputs to setHave before picking decoys
+ auto &txin = vin[l];
+ uint32_t nSigInputs, nSigRingSize;
+ txin.GetAnonInfo(nSigInputs, nSigRingSize);
+
+ vInputBlinds[l].resize(32 * nSigInputs);
+ std::vector<std::pair<MapRecords_t::const_iterator, unsigned int> >
+ vCoins(setCoins.begin() + nTotalInputs, setCoins.begin() + nTotalInputs + nSigInputs);
+ nTotalInputs += nSigInputs;
+
+ if (!PlaceRealOutputs(vMI[l], vSecretColumns[l], nSigRingSize, setHave, vCoins, vInputBlinds[l], sError)) {
+ return false;
+ }
+ }
+
+ // Fill in dummy signatures for fee calculation.
+ for (size_t l = 0; l < vin.size(); ++l) {
+ auto &txin = vin[l];
+ uint32_t nSigInputs, nSigRingSize;
+ txin.GetAnonInfo(nSigInputs, nSigRingSize);
+
+ if (!PickHidingOutputs(vMI[l], vSecretColumns[l], nSigRingSize, setHave, sError))
+ return false;
+
+ std::vector<uint8_t> vPubkeyMatrixIndices;
+
+ for (size_t k = 0; k < nSigInputs; ++k)
+ for (size_t i = 0; i < nSigRingSize; ++i) {
+ PutVarInt(vPubkeyMatrixIndices, vMI[l][k][i]);
+ }
+
+ txin.scriptWitness.stack.emplace_back(vPubkeyMatrixIndices);
+
+ if (dummySigs) {
+ std::vector<uint8_t> vKeyImages(33 * nSigInputs);
+ txin.scriptData.stack.emplace_back(vKeyImages);
+
+ std::vector<uint8_t> vDL(
+ (1 + (nSigInputs + 1) * nSigRingSize) *
+ 32 // extra element for C, extra row for commitment row
+ + (vin.size() > 1 ? 33 : 0)); // extra commitment for split value if multiple sigs
+ txin.scriptWitness.stack.emplace_back(vDL);
+ }
+ }
+ return true;
+}
+
+bool AnonWallet::GetKeyImage(
+ CTxIn& txin,
+ std::vector<std::vector<int64_t>>& vMI,
+ size_t& secretColumn,
+ std::string& sError)
+{
+ int rv;
+
+ uint32_t nSigInputs, nSigRingSize;
+ txin.GetAnonInfo(nSigInputs, nSigRingSize);
+
+ std::vector<uint8_t> &vKeyImages = txin.scriptData.stack[0];
+ vKeyImages.resize(33 * nSigInputs);
+
+ for (size_t k = 0; k < nSigInputs; ++k) {
+ int64_t nIndex = vMI[k][secretColumn];
+
+ CAnonOutput anonOutput;
+ if (!pblocktree->ReadRCTOutput(nIndex, anonOutput)) {
+ sError = strprintf("Output %d not found in database.", nIndex);
+ return error("%s: %s", __func__, sError);
+ }
+
+ CKeyID idk = anonOutput.pubkey.GetID();
+ CKey key;
+ if (!GetKey(idk, key)) {
+ sError = strprintf("No key for output: %s", HexStr(anonOutput.pubkey.begin(), anonOutput.pubkey.end()));
+ return error("%s: %s", __func__, sError);
+ }
+
+ // Keyimage is required for the tx hash
+ rv = secp256k1_get_keyimage(secp256k1_ctx_blind, &vKeyImages[k * 33], anonOutput.pubkey.begin(), key.begin());
+ if (0 != rv) {
+ sError = strprintf("Failed to get keyimage.");
+ return error("%s: %s", __func__, sError);
+ }
+
+ // Double check key image is not used... todo, this should not be done here and is result of bad state
+ uint256 txhashKI;
+ auto ki = *((CCmpPubKey*)&vKeyImages[k*33]);
+ if (pblocktree->ReadRCTKeyImage(ki, txhashKI)) {
+ AnonWalletDB wdb(*walletDatabase);
+ COutPoint out;
+ bool fErased = false;
+ if (wdb.ReadAnonKeyImage(ki, out)) {
+ MarkOutputSpent(out, true);
+ fErased = true;
+ }
+ sError = strprintf("Bad wallet state trying to spend already spent input, outpoint=%s erased=%s.",
+ out.ToString(), fErased ? "true" : "false");
+ return error("%s: %s", __func__, sError);
+ }
+ }
+ return true;
+}
+
+bool AnonWallet::SetBlinds(
+ size_t nSigRingSize,
+ size_t nSigInputs,
+ std::vector<std::vector<int64_t>>& vMI,
+ std::vector<CKey>& vsk,
+ std::vector<const uint8_t*>& vpsk,
+ std::vector<uint8_t>& vm,
+ std::vector<secp256k1_pedersen_commitment>& vCommitments,
+ std::vector<const uint8_t*>& vpInCommits,
+ std::vector<const uint8_t*>& vpBlinds,
+ ec_point& vInputBlinds,
+ size_t& secretColumn,
+ std::string& sError)
+{
+ size_t nCols = nSigRingSize;
+ size_t nRows = nSigInputs + 1;
+
+ for (size_t k = 0; k < nSigInputs; ++k) {
+ for (size_t i = 0; i < nCols; ++i) {
+ int64_t nIndex = vMI[k][i];
+
+ CAnonOutput ao;
+ if (!pblocktree->ReadRCTOutput(nIndex, ao)) {
+ sError = strprintf("Output %d not found in database.", nIndex);
+ return error("%s: %s", __func__, sError);
+ }
+
+ memcpy(&vm[(i + k * nCols) * 33], ao.pubkey.begin(), 33);
+ vCommitments.push_back(ao.commitment);
+ vpInCommits[i + k * nCols] = vCommitments.back().data;
+
+ if (i == secretColumn) {
+ CKeyID idk = ao.pubkey.GetID();
+ if (!GetKey(idk, vsk[k])) {
+ sError = strprintf("No key for output: %s", HexStr(ao.pubkey.begin(), ao.pubkey.end()));
+ return error("%s: %s", __func__, sError);
+ }
+ vpsk[k] = vsk[k].begin();
+
+ vpBlinds.push_back(&vInputBlinds[k * 32]);
+ /*
+ // Keyimage is required for the tx hash
+ rv = secp256k1_get_keyimage(secp256k1_ctx_blind, &vKeyImages[k * 33], &vm[(i+k*nCols)*33], vpsk[k]);
+ if (0 != rv) {
+ sError = strprintf("Failed to get keyimage.");
+ return error("%s: %s", __func__, sError);
+ }
+ */
+ }
+ }
+ }
+ return true;
+}
+
// Returns bool
bool AnonWallet::AddAnonInputs_Inner(CWalletTx &wtx, CTransactionRecord &rtx, std::vector<CTempRecipient> &vecSend,
bool sign, size_t nRingSize, size_t nInputsPerSig, CAmount &nFeeRet, const CCoinControl *coinControl,
@@ -3331,51 +3499,9 @@ bool AnonWallet::AddAnonInputs_Inner(CWalletTx &wtx, CTransactionRecord &rtx, st
}
if (!fAlreadyHaveInputs) {
- std::set<int64_t> setHave; // Anon prev-outputs can only be used once per transaction.
- size_t nTotalInputs = 0;
- for (size_t l = 0; l < txNew.vin.size(); ++l) { // Must add real outputs to setHave before picking decoys
- auto &txin = txNew.vin[l];
- uint32_t nSigInputs, nSigRingSize;
- txin.GetAnonInfo(nSigInputs, nSigRingSize);
-
- vInputBlinds[l].resize(32 * nSigInputs);
- std::vector<std::pair<MapRecords_t::const_iterator, unsigned int> >
- vCoins(setCoins.begin() + nTotalInputs, setCoins.begin() + nTotalInputs + nSigInputs);
- nTotalInputs += nSigInputs;
-
- if (!PlaceRealOutputs(vMI[l], vSecretColumns[l], nSigRingSize, setHave, vCoins, vInputBlinds[l], sError)) {
+ if (!ArrangeBlinds(txNew.vin, vInputBlinds, vMI, vSecretColumns, setCoins, true, sError))
return false;
}
- }
-
- // Fill in dummy signatures for fee calculation.
- for (size_t l = 0; l < txNew.vin.size(); ++l) {
- auto &txin = txNew.vin[l];
- uint32_t nSigInputs, nSigRingSize;
- txin.GetAnonInfo(nSigInputs, nSigRingSize);
-
- if (!PickHidingOutputs(vMI[l], vSecretColumns[l], nSigRingSize, setHave, sError))
- return false;
-
- std::vector<uint8_t> vPubkeyMatrixIndices;
-
- for (size_t k = 0; k < nSigInputs; ++k)
- for (size_t i = 0; i < nSigRingSize; ++i) {
- PutVarInt(vPubkeyMatrixIndices, vMI[l][k][i]);
- }
-
- std::vector<uint8_t> vKeyImages(33 * nSigInputs);
- txin.scriptData.stack.emplace_back(vKeyImages);
-
- txin.scriptWitness.stack.emplace_back(vPubkeyMatrixIndices);
-
- std::vector<uint8_t> vDL((1 + (nSigInputs + 1) * nSigRingSize) *
- 32 // extra element for C, extra row for commitment row
- + (txNew.vin.size() > 1 ? 33
- : 0)); // extra commitment for split value if multiple sigs
- txin.scriptWitness.stack.emplace_back(vDL);
- }
- }
if (fSkipFee) {
nFeeNeeded = 0;
@@ -3522,57 +3648,9 @@ bool AnonWallet::AddAnonInputs_Inner(CWalletTx &wtx, CTransactionRecord &rtx, st
std::vector<CKey> vSplitCommitBlindingKeys(txNew.vin.size()); // input amount commitment when > 1 mlsag
int rv;
size_t nTotalInputs = 0;
-
- for (size_t l = 0; l < txNew.vin.size(); ++l) {
- auto &txin = txNew.vin[l];
-
- uint32_t nSigInputs, nSigRingSize;
- txin.GetAnonInfo(nSigInputs, nSigRingSize);
-
- std::vector<uint8_t> &vKeyImages = txin.scriptData.stack[0];
- vKeyImages.resize(33 * nSigInputs);
-
- for (size_t k = 0; k < nSigInputs; ++k) {
- size_t i = vSecretColumns[l];
- int64_t nIndex = vMI[l][k][i];
-
- CAnonOutput anonOutput;
- if (!pblocktree->ReadRCTOutput(nIndex, anonOutput)) {
- sError = strprintf("Output %d not found in database.", nIndex);
- return error("%s: %s", __func__, sError);
- }
-
- CKeyID idk = anonOutput.pubkey.GetID();
- CKey key;
- if (!GetKey(idk, key)) {
- sError = strprintf("No key for output: %s", HexStr(anonOutput.pubkey.begin(), anonOutput.pubkey.end()));
- return error("%s: %s", __func__, sError);
- }
-
- // Keyimage is required for the tx hash
- rv = secp256k1_get_keyimage(secp256k1_ctx_blind, &vKeyImages[k * 33], anonOutput.pubkey.begin(), key.begin());
- if (0 != rv) {
- sError = strprintf("Failed to get keyimage.");
- return error("%s: %s", __func__, sError);
- }
-
- // Double check key image is not used... todo, this should not be done here and is result of bad state
- uint256 txhashKI;
- auto ki = *((CCmpPubKey*)&vKeyImages[k*33]);
- if (pblocktree->ReadRCTKeyImage(ki, txhashKI)) {
- AnonWalletDB wdb(*walletDatabase);
- COutPoint out;
- bool fErased = false;
- if (wdb.ReadAnonKeyImage(ki, out)) {
- MarkOutputSpent(out, true);
- fErased = true;
- }
- sError = strprintf("Bad wallet state trying to spend already spent input, outpoint=%s erased=%s.",
- out.ToString(), fErased ? "true" : "false");
- return error("%s: %s", __func__, sError);
- }
- }
- }
+ for (size_t l = 0; l < txNew.vin.size(); ++l)
+ if (!GetKeyImage(txNew.vin[l], vMI[l], vSecretColumns[l], sError))
+ return false;
for (size_t l = 0; l < txNew.vin.size(); ++l) {
auto &txin = txNew.vin[l];
@@ -3583,9 +3661,6 @@ bool AnonWallet::AddAnonInputs_Inner(CWalletTx &wtx, CTransactionRecord &rtx, st
size_t nCols = nSigRingSize;
size_t nRows = nSigInputs + 1;
- uint8_t randSeed[32];
- GetStrongRandBytes(randSeed, 32);
-
std::vector<CKey> vsk(nSigInputs);
std::vector<const uint8_t*> vpsk(nRows);
@@ -3595,42 +3670,12 @@ bool AnonWallet::AddAnonInputs_Inner(CWalletTx &wtx, CTransactionRecord &rtx, st
std::vector<const uint8_t*> vpInCommits(nCols * nSigInputs);
std::vector<const uint8_t*> vpBlinds;
- std::vector<uint8_t> &vKeyImages = txin.scriptData.stack[0];
-
- for (size_t k = 0; k < nSigInputs; ++k) {
- for (size_t i = 0; i < nCols; ++i) {
- int64_t nIndex = vMI[l][k][i];
-
- CAnonOutput ao;
- if (!pblocktree->ReadRCTOutput(nIndex, ao)) {
- sError = strprintf("Output %d not found in database.", nIndex);
- return error("%s: %s", __func__, sError);
- }
-
- memcpy(&vm[(i + k * nCols) * 33], ao.pubkey.begin(), 33);
- vCommitments.push_back(ao.commitment);
- vpInCommits[i + k * nCols] = vCommitments.back().data;
-
- if (i == vSecretColumns[l]) {
- CKeyID idk = ao.pubkey.GetID();
- if (!GetKey(idk, vsk[k])) {
- sError = strprintf("No key for output: %s", HexStr(ao.pubkey.begin(), ao.pubkey.end()));
- return error("%s: %s", __func__, sError);
- }
- vpsk[k] = vsk[k].begin();
+ if (!SetBlinds(nSigRingSize, nSigInputs, vMI[l], vsk, vpsk, vm, vCommitments,
+ vpInCommits, vpBlinds, vInputBlinds[l],
+ vSecretColumns[l], sError))
+ return false;
- vpBlinds.push_back(&vInputBlinds[l][k * 32]);
- /*
- // Keyimage is required for the tx hash
- rv = secp256k1_get_keyimage(secp256k1_ctx_blind, &vKeyImages[k * 33], &vm[(i+k*nCols)*33], vpsk[k]);
- if (0 != rv) {
- sError = strprintf("Failed to get keyimage.");
- return error("%s: %s", __func__, sError);
- }
- */
- }
- }
- }
+ std::vector<uint8_t> &vKeyImages = txin.scriptData.stack[0];
uint8_t blindSum[32];
memset(blindSum, 0, 32);
@@ -3701,6 +3746,9 @@ bool AnonWallet::AddAnonInputs_Inner(CWalletTx &wtx, CTransactionRecord &rtx, st
};
uint256 hashOutputs = txNew.GetOutputsHash();
+
+ uint8_t randSeed[32];
+ GetStrongRandBytes(randSeed, 32);
if (0 != (rv = secp256k1_generate_mlsag(secp256k1_ctx_blind, &vKeyImages[0], &vDL[0], &vDL[32],
randSeed, hashOutputs.begin(), nCols, nRows, vSecretColumns[l],
&vpsk[0], &vm[0]))) {

diff:
@@ -366,6 +366,33 @@ private:
std::string GetDisplayName() const { return "ringctwallet"; }
void ParseAddressForMetaData(const CTxDestination &addr, COutputRecord &rec);
+ bool ArrangeBlinds(
+ std::vector<CTxIn>& vin,
+ std::vector<ec_point>& vInputBlinds,
+ std::vector<std::vector<std::vector<int64_t>>>& vMI,
+ std::vector<size_t>& vSecretColumns,
+ std::vector<std::pair<MapRecords_t::const_iterator, unsigned int>>& setCoins,
+ bool dummySigs,
+ std::string& sError);
+ bool GetKeyImage(
+ CTxIn& txin,
+ std::vector<std::vector<int64_t>>& vMI,
+ size_t& secretColumn,
+ std::string& sError);
+ bool SetBlinds(
+ size_t nSigRingSize,
+ size_t nSigInputs,
+ std::vector<std::vector<int64_t>>& vMI,
+ std::vector<CKey>& vsk,
+ std::vector<const uint8_t*>& vpsk,
+ std::vector<uint8_t>& vm,
+ std::vector<secp256k1_pedersen_commitment>& vCommitments,
+ std::vector<const uint8_t*>& vpInCommits,
+ std::vector<const uint8_t*>& vpBlinds,
+ ec_point& vInputBlinds,
+ size_t& secretColumn,
+ std::string& sError);
+
template<typename... Params>
bool werror(std::string fmt, Params... parameters) const {
return error(("%s " + fmt).c_str(), GetDisplayName(), parameters...);


message: [Logging] Add missing format specifier.

diff:
@@ -3015,7 +3015,7 @@ bool AnonWallet::PickHidingOutputs(std::vector<std::vector<int64_t> > &vMI, size
const static size_t nMaxTries = 1000;
for (j = 0; j < nMaxTries; ++j) {
if (nLastRCTOutIndex <= nMinIndex) {
- sError = strprintf("Not enough anonymous outputs exist, min: last: %d, required: %d.",
+ sError = strprintf("Not enough anonymous outputs exist, min: %d, last: %d, required: %d.",
nMinIndex, nLastRCTOutIndex, nInputs * nRingSize);
return error("%s: %s", __func__, sError);
}

original_message: [Logging] Add missing format specifier.


message:
Refactor ZC-specific staking functionality.
In preparation for defining a RingCTStakeInput type, move more
zerocoin-specific stuff behind a CStakeInput interface.

diff:
#include "util/system.h"
#include "stakeinput.h"
#include "veil/zerocoin/zchain.h"
-#include "libzerocoin/bignum.h"
#include <versionbits.h>
using namespace std;
@@ -47,21 +46,6 @@ bool CheckStake(const CDataStream& ssUniqueID, CAmount nValueIn, const uint64_t
}
-//Sets nValueIn with the weighted amount given a certain zerocoin denomination
-void WeightStake(CAmount& nValueIn, const libzerocoin::CoinDenomination denom)
-{
- if (denom == libzerocoin::CoinDenomination::ZQ_ONE_HUNDRED) {
- //10% reduction
- nValueIn = (nValueIn * 90) / 100;
- } else if (denom == libzerocoin::CoinDenomination::ZQ_ONE_THOUSAND) {
- //20% reduction
- nValueIn = (nValueIn * 80) / 100;
- } else if (denom == libzerocoin::CoinDenomination::ZQ_TEN_THOUSAND) {
- //30% reduction
- nValueIn = (nValueIn * 70) / 100;
- }
-}
-
std::set<uint256> setFoundStakes;
bool Stake(CStakeInput* stakeInput, unsigned int nBits, unsigned int nTimeBlockFrom, unsigned int& nTimeTx, const CBlockIndex* pindexBest, uint256& hashProofOfStake, bool fWeightStake)
{
@@ -84,11 +68,8 @@ bool Stake(CStakeInput* stakeInput, unsigned int nBits, unsigned int nTimeBlockF
int64_t nMaxTime = (int)GetAdjustedTime() + MAX_FUTURE_BLOCK_TIME - 40;
CDataStream ssUniqueID = stakeInput->GetUniqueness();
- CAmount nValueIn = stakeInput->GetValue();
-
- //Adjust stake weights to larger denoms
- if (fWeightStake)
- WeightStake(nValueIn, stakeInput->GetDenomination());
+ // Adjust stake weights
+ CAmount nValueIn = fWeightStake ? stakeInput->GetWeight() : stakeInput->GetValue();
int nBestHeight = pindexBest->nHeight;
uint256 hashBestBlock = pindexBest->GetBlockHash();
@@ -167,11 +148,12 @@ bool CheckProofOfStake(CBlockIndex* pindexCheck, const CTransactionRef txRef, co
unsigned int nBlockFromTime = blockprev.nTime;
unsigned int nTxTime = nTimeBlock;
- CAmount nValue = stake->GetValue();
// Enforce VIP-1 after it was activated
- if ((int)nTxTime > Params().EnforceWeightReductionTime())
- WeightStake(nValue, stake->GetDenomination());
+ CAmount nValue = (int)nTxTime > Params().EnforceWeightReductionTime()
+ ? stake->GetWeight()
+ : stake->GetValue();
+
if (!CheckStake(stake->GetUniqueness(), nValue, nStakeModifier, ArithToUint256(bnTargetPerCoinDay), nBlockFromTime,
nTxTime, hashProofOfStake)) {

diff:
@@ -166,6 +166,21 @@ CAmount ZerocoinStake::GetValue()
return denom * COIN;
}
+CAmount ZerocoinStake::GetWeight()
+{
+ if (denom == libzerocoin::CoinDenomination::ZQ_ONE_HUNDRED) {
+ //10% reduction
+ return (denom * COIN * 9) / 10;
+ } else if (denom == libzerocoin::CoinDenomination::ZQ_ONE_THOUSAND) {
+ //20% reduction
+ return (denom * COIN * 8) / 10;
+ } else if (denom == libzerocoin::CoinDenomination::ZQ_TEN_THOUSAND) {
+ //30% reduction
+ return (denom * COIN * 7) / 10;
+ }
+ return denom * COIN;
+}
+
int ZerocoinStake::HeightToModifierHeight(int nHeight)
{
//Nearest multiple of KernelModulus that is over KernelModulus bocks deep in the chain
@@ -277,6 +292,13 @@ bool ZerocoinStake::CreateTxOuts(CWallet* pwallet, std::vector<CTxOut>& vout, CA
#endif
}
+bool ZerocoinStake::CompleteTx(CWallet* pwallet, CMutableTransaction& txNew)
+{
+ if (!MarkSpent(pwallet, txNew.GetHash()))
+ return error("%s: failed to mark mint as used\n", __func__);
+ return true;
+}
+
bool ZerocoinStake::GetTxFrom(CTransaction& tx)
{
return false;

diff:
// Copyright (c) 2017-2019 The PIVX developers
-// Copyright (c) 2019 The Veil developers
+// Copyright (c) 2019-2022 The Veil developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,14 +25,17 @@ protected:
public:
virtual ~CStakeInput(){};
virtual CBlockIndex* GetIndexFrom() = 0;
- virtual bool CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut = uint256()) = 0;
virtual bool GetTxFrom(CTransaction& tx) = 0;
virtual CAmount GetValue() = 0;
- virtual bool CreateTxOuts(CWallet* pwallet, std::vector<CTxOut>& vout, CAmount nTotal) = 0;
+ virtual CAmount GetWeight() = 0;
virtual bool GetModifier(uint64_t& nStakeModifier, const CBlockIndex* pindexChainPrev) = 0;
virtual bool IsZerocoins() = 0;
virtual CDataStream GetUniqueness() = 0;
libzerocoin::CoinDenomination GetDenomination() {return denom;};
+
+ virtual bool CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut = uint256()) = 0;
+ virtual bool CreateTxOuts(CWallet* pwallet, std::vector<CTxOut>& vout, CAmount nTotal) = 0;
+ virtual bool CompleteTx(CWallet* pwallet, CMutableTransaction& txNew) = 0;
};
@@ -60,12 +63,15 @@ public:
CBlockIndex* GetIndexFrom() override;
bool GetTxFrom(CTransaction& tx) override;
CAmount GetValue() override;
+ CAmount GetWeight() override;
bool GetModifier(uint64_t& nStakeModifier, const CBlockIndex* pindexChainPrev) override;
CDataStream GetUniqueness() override;
bool CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut = uint256()) override;
bool CreateTxOuts(CWallet* pwallet, std::vector<CTxOut>& vout, CAmount nTotal) override;
- bool MarkSpent(CWallet* pwallet, const uint256& txid);
+ bool CompleteTx(CWallet* pwallet, CMutableTransaction& txNew) override;
bool IsZerocoins() override { return true; }
+
+ bool MarkSpent(CWallet* pwallet, const uint256& txid);
int GetChecksumHeightFromMint();
int GetChecksumHeightFromSpend();
uint256 GetChecksum();

diff:
@@ -3884,10 +3884,10 @@ bool CWallet::CreateCoinStake(const CBlockIndex* pindexBest, unsigned int nBits,
if (GetAdjustedTime() - chainActive.Tip()->GetBlockTime() < 1)
UninterruptibleSleep(std::chrono::milliseconds{2500});
- CAmount nCredit = 0;
CScript scriptPubKeyKernel;
bool fKernelFound = false;
for (std::unique_ptr<ZerocoinStake>& stakeInput : listInputs) {
+ CAmount nCredit = 0;
// Make sure the wallet is unlocked and shutdown hasn't been requested
if (IsLocked() || ShutdownRequested())
return false;
@@ -3964,16 +3964,14 @@ bool CWallet::CreateCoinStake(const CBlockIndex* pindexBest, unsigned int nBits,
LogPrintf("%s : failed to create TxIn\n", __func__);
txNew.vin.clear();
txNew.vpout.clear();
- nCredit = 0;
continue;
}
}
txNew.vin.emplace_back(in);
//Mark mints as spent
- auto* z = (ZerocoinStake*)stakeInput.get();
- if (!z->MarkSpent(this, txNew.GetHash()))
- return error("%s: failed to mark mint as used\n", __func__);
+ if (!stakeInput->CompleteTx(this, txNew))
+ return false;
fKernelFound = true;
break;


message:
Correct progress display on searchdeterministiczerocoin
The progress items of the individual threads have already accounted for
their start points, so we don't need to subtract the overall start point
again.

diff:
@@ -392,7 +392,9 @@ bool CzWallet::DeterministicSearch(int nCountStart, int nCountEnd, int* nThreade
}
}
- int percentageDone = std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100)));
+ // items complete = progress_current
+ // items total = progress_end - progress_begin
+ int percentageDone = std::max(1, std::min(99, (int)(progress_current / (progress_end - progress_begin) * 100)));
uiInterface.ShowProgress(_("Searching..."), percentageDone, 0);
}
if (nThreadedProgress == nullptr) {