diff --git a/src/blocksignature.cpp b/src/blocksignature.cpp index 87c0401756e74..c54f20c1c3c41 100644 --- a/src/blocksignature.cpp +++ b/src/blocksignature.cpp @@ -67,7 +67,7 @@ bool CheckBlockSignature(const CBlock& block) * UTXO: The public key that signs must match the public key associated with the first utxo of the coinstake tx. */ CPubKey pubkey; - bool fzPIVStake = block.vtx[1].IsZerocoinSpend(); + bool fzPIVStake = block.vtx[1].vin[0].IsZerocoinSpend(); if (fzPIVStake) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(block.vtx[1].vin[0]); pubkey = spend.getPubKey(); diff --git a/src/bloom.cpp b/src/bloom.cpp index 90ebd12f4a078..7e9eb0d12b7b5 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -219,7 +219,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) opcodetype opcode; if (!txin.scriptSig.GetOp(pc, opcode, data)) break; - if (txin.scriptSig.IsZerocoinSpend()){ + if (txin.IsZerocoinSpend()) { CDataStream s(vector(txin.scriptSig.begin() + 44, txin.scriptSig.end()), SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/coins.cpp b/src/coins.cpp index 81b141f57a3ec..80a6c2586c6af 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -224,7 +224,7 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const return 0; //todo are there any security precautions to take here? - if (tx.IsZerocoinSpend()) + if (tx.HasZerocoinSpendInputs()) return tx.GetZerocoinSpent(); CAmount nResult = 0; @@ -236,7 +236,7 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint& prevout = tx.vin[i].prevout; const CCoins* coins = AccessCoins(prevout.hash); diff --git a/src/coins.h b/src/coins.h index 8b884558c135e..8619ce672102d 100644 --- a/src/coins.h +++ b/src/coins.h @@ -272,7 +272,7 @@ class CCoins //! check whether a particular output is still available bool IsAvailable(unsigned int nPos) const { - return (nPos < vout.size() && !vout[nPos].IsNull() && !vout[nPos].scriptPubKey.IsZerocoinMint()); + return (nPos < vout.size() && !vout[nPos].IsNull() && !vout[nPos].IsZerocoinMint()); } //! check whether the entire CCoins is spent diff --git a/src/kernel.cpp b/src/kernel.cpp index f8cd593e5df2b..3f0dfac78e914 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -361,7 +361,7 @@ bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::uniqu const CTxIn& txin = tx.vin[0]; //Construct the stakeinput object - if (tx.IsZerocoinSpend()) { + if (txin.IsZerocoinSpend()) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin); if (spend.getSpendType() != libzerocoin::SpendType::STAKE) return error("%s: spend is using the wrong SpendType (%d)", __func__, (int)spend.getSpendType()); diff --git a/src/main.cpp b/src/main.cpp index f3c9dd0be1b70..9060eb6c88dd0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -739,7 +739,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) } for (const CTxIn& txin : tx.vin) { - if (txin.scriptSig.IsZerocoinSpend()) + if (txin.IsZerocoinSpend()) continue; // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed // keys. (remember the 520 byte limit on redeemScript size) That works @@ -815,7 +815,7 @@ bool IsFinalTx(const CTransaction& tx, int nBlockHeight, int64_t nBlockTime) */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { - if (tx.IsCoinBase() || tx.IsZerocoinSpend()) + if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs()) return true; // coinbase has no inputs and zerocoinspend has a special input //todo should there be a check for a 'standard' zerocoinspend here? @@ -882,7 +882,8 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx) unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) { - if (tx.IsCoinBase() || tx.IsZerocoinSpend()) + if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs()) + // a tx containing a zc spend can have only zc inputs return 0; unsigned int nSigOps = 0; @@ -1070,7 +1071,7 @@ bool CheckZerocoinSpend(const CTransaction& tx, bool fVerifySignature, CValidati for (const CTxIn& txin : tx.vin) { //only check txin that is a zcspend - if (!txin.scriptSig.IsZerocoinSpend()) + if (!txin.IsZerocoinSpend()) continue; CoinSpend newSpend = TxInToZerocoinSpend(txin); @@ -1141,7 +1142,6 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject // Check for negative or overflow output values CAmount nValueOut = 0; - int nZCSpendCount = 0; BOOST_FOREACH (const CTxOut& txout, tx.vout) { if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake()) return state.DoS(100, error("CheckTransaction(): txout empty for user transaction")); @@ -1160,20 +1160,34 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject if(!CheckZerocoinMint(tx.GetHash(), txout, state, true)) return state.DoS(100, error("CheckTransaction() : invalid zerocoin mint")); } - if (fZerocoinActive && txout.scriptPubKey.IsZerocoinSpend()) + } + + set vInOutPoints; + set vZerocoinSpendSerials; + int nZCSpendCount = 0; + for (const CTxIn& txin : tx.vin) { + // Check for duplicate inputs + if (vInOutPoints.count(txin.prevout)) + return state.DoS(100, error("CheckTransaction() : duplicate inputs"), + REJECT_INVALID, "bad-txns-inputs-duplicate"); + + //duplicate zcspend serials are checked in CheckZerocoinSpend() + if (!txin.IsZerocoinSpend()) { + vInOutPoints.insert(txin.prevout); + } else { nZCSpendCount++; + } } if (fZerocoinActive) { if (nZCSpendCount > Params().Zerocoin_MaxSpendsPerTransaction()) return state.DoS(100, error("CheckTransaction() : there are more zerocoin spends than are allowed in one transaction")); - if (tx.IsZerocoinSpend()) { - //require that a zerocoinspend only has inputs that are zerocoins + //require that a zerocoinspend only has inputs that are zerocoins + if (tx.HasZerocoinSpendInputs()) { for (const CTxIn& in : tx.vin) { - if (!in.scriptSig.IsZerocoinSpend()) - return state.DoS(100, - error("CheckTransaction() : zerocoinspend contains inputs that are not zerocoins")); + if (!in.IsZerocoinSpend()) + return state.DoS(100, error("CheckTransaction() : zerocoinspend contains inputs that are not zerocoins")); } // Do not require signature verification if this is initial sync and a block over 24 hours old @@ -1183,29 +1197,16 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject } } - // Check for duplicate inputs - set vInOutPoints; - set vZerocoinSpendSerials; - for (const CTxIn& txin : tx.vin) { - if (vInOutPoints.count(txin.prevout)) - return state.DoS(100, error("CheckTransaction() : duplicate inputs"), - REJECT_INVALID, "bad-txns-inputs-duplicate"); - - //duplicate zcspend serials are checked in CheckZerocoinSpend() - if (!txin.scriptSig.IsZerocoinSpend()) - vInOutPoints.insert(txin.prevout); - } - if (tx.IsCoinBase()) { if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 150) return state.DoS(100, error("CheckTransaction() : coinbase script size=%d", tx.vin[0].scriptSig.size()), REJECT_INVALID, "bad-cb-length"); - } else if (fZerocoinActive && tx.IsZerocoinSpend()) { + } else if (fZerocoinActive && tx.HasZerocoinSpendInputs()) { if(tx.vin.size() < 1 || static_cast(tx.vin.size()) > Params().Zerocoin_MaxSpendsPerTransaction()) return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has more than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend"); } else { BOOST_FOREACH (const CTxIn& txin, tx.vin) - if (txin.prevout.IsNull() && (fZerocoinActive && !txin.scriptSig.IsZerocoinSpend())) + if (txin.prevout.IsNull() && (fZerocoinActive && !txin.IsZerocoinSpend())) return state.DoS(10, error("CheckTransaction() : prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); } @@ -1328,7 +1329,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa } // Check for conflicts with in-memory transactions - if (!tx.IsZerocoinSpend()) { + if (!tx.HasZerocoinSpendInputs()) { LOCK(pool.cs); // protect pool.mapNextTx for (unsigned int i = 0; i < tx.vin.size(); i++) { COutPoint outpoint = tx.vin[i].prevout; @@ -1345,7 +1346,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa CCoinsViewCache view(&dummy); CAmount nValueIn = 0; - if(tx.IsZerocoinSpend()){ + if (tx.HasZerocoinSpendInputs()) { nValueIn = tx.GetZerocoinSpent(); //Check that txid is not already in the chain @@ -1356,7 +1357,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa //Check for double spending of serial #'s for (const CTxIn& txIn : tx.vin) { - if (!txIn.scriptSig.IsZerocoinSpend()) + if (!txIn.IsZerocoinSpend()) continue; CoinSpend spend = TxInToZerocoinSpend(txIn); if (!ContextualCheckZerocoinSpend(tx, spend, chainActive.Tip(), 0)) @@ -1389,19 +1390,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa } } - // Check that zPIV mints are not already known - if (tx.IsZerocoinMint()) { - for (auto& out : tx.vout) { - if (!out.IsZerocoinMint()) - continue; + // Check that zPIV mints (if included) are not already known + for (auto& out : tx.vout) { + if (!out.IsZerocoinMint()) + continue; - PublicCoin coin(Params().Zerocoin_Params(false)); - if (!TxOutToPublicCoin(out, coin, state)) - return state.Invalid(error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); + PublicCoin coin(Params().Zerocoin_Params(false)); + if (!TxOutToPublicCoin(out, coin, state)) + return state.Invalid(error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); - if (!ContextualCheckZerocoinMint(tx, coin, chainActive.Tip())) - return state.Invalid(error("%s: zerocoin mint failed contextual check", __func__)); - } + if (!ContextualCheckZerocoinMint(tx, coin, chainActive.Tip())) + return state.Invalid(error("%s: zerocoin mint failed contextual check", __func__)); } // are the actual inputs available? @@ -1427,7 +1426,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // itself can contain sigops MAX_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than // merely non-standard transaction. - if (!tx.IsZerocoinSpend()) { + if (!tx.HasZerocoinSpendInputs()) { unsigned int nSigOps = GetLegacySigOpCount(tx); unsigned int nMaxSigOps = MAX_TX_SIGOPS_CURRENT; nSigOps += GetP2SHSigOpCount(tx, view); @@ -1441,7 +1440,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa CAmount nValueOut = tx.GetValueOut(); CAmount nFees = nValueIn - nValueOut; double dPriority = 0; - if (!tx.IsZerocoinSpend()) + if (!tx.HasZerocoinSpendInputs()) view.GetPriority(tx, chainActive.Height()); CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height()); @@ -1453,23 +1452,23 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa mempool.PrioritiseTransaction(hash, hash.ToString(), 1000, 0.1 * COIN); } else if (!ignoreFees) { CAmount txMinFee = GetMinRelayFee(tx, nSize, true); - if (fLimitFree && nFees < txMinFee && !tx.IsZerocoinSpend()) + if (fLimitFree && nFees < txMinFee && !tx.HasZerocoinSpendInputs()) return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d", hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); // Require that free transactions have sufficient priority to be mined in the next block. - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { if(nFees < Params().Zerocoin_MintFee() * tx.GetZerocoinMintCount()) return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee for zerocoinmint"); - } else if (!tx.IsZerocoinSpend() && GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { + } else if (!tx.HasZerocoinSpendInputs() && GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); } // Continuously rate-limit free (really, very-low-fee) transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.IsZerocoinSpend()) { + if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.HasZerocoinSpendInputs()) { static CCriticalSection csFreeLimiter; static double dFreeCount; static int64_t nLastTime; @@ -1530,7 +1529,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa SyncWithWallets(tx, NULL); //Track zerocoinspends and ensure that they are given priority to make it into the blockchain - if (tx.IsZerocoinSpend()) + if (tx.HasZerocoinSpendInputs()) mapZerocoinspends[tx.GetHash()] = GetAdjustedTime(); return true; @@ -1577,7 +1576,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact } // Check for conflicts with in-memory transactions - if (!tx.IsZerocoinSpend()) { + if (!tx.HasZerocoinSpendInputs()) { LOCK(pool.cs); // protect pool.mapNextTx for (unsigned int i = 0; i < tx.vin.size(); i++) { COutPoint outpoint = tx.vin[i].prevout; @@ -1666,9 +1665,8 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact mempool.PrioritiseTransaction(hash, hash.ToString(), 1000, 0.1 * COIN); } else { // same as !ignoreFees for AcceptToMemoryPool CAmount txMinFee = GetMinRelayFee(tx, nSize, true); - if (fLimitFree && nFees < txMinFee && !tx.IsZerocoinSpend()) - return state.DoS(0, error("AcceptableInputs : not enough fees %s, %d < %d", - hash.ToString(), nFees, txMinFee), + if (fLimitFree && nFees < txMinFee && !tx.HasZerocoinSpendInputs()) + return state.DoS(0, error("AcceptableInputs : not enough fees %s, %d < %d", hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); // Require that free transactions have sufficient priority to be mined in the next block. @@ -1679,7 +1677,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // Continuously rate-limit free (really, very-low-fee) transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.IsZerocoinSpend()) { + if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.HasZerocoinSpendInputs()) { static CCriticalSection csFreeLimiter; static double dFreeCount; static int64_t nLastTime; @@ -2345,7 +2343,7 @@ void static InvalidBlockFound(CBlockIndex* pindex, const CValidationState& state void UpdateCoins(const CTransaction& tx, CValidationState& state, CCoinsViewCache& inputs, CTxUndo& txundo, int nHeight) { // mark inputs spent - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { txundo.vprevout.reserve(tx.vin.size()); BOOST_FOREACH (const CTxIn& txin, tx.vin) { txundo.vprevout.push_back(CTxInUndo()); @@ -2380,7 +2378,7 @@ void AddInvalidSpendsToMap(const CBlock& block) //Check all zerocoinspends for bad serials for (const CTxIn& in : tx.vin) { - if (in.scriptSig.IsZerocoinSpend()) { + if (in.IsZerocoinSpend()) { CoinSpend spend = TxInToZerocoinSpend(in); //If serial is not valid, mark all outputs as bad @@ -2442,7 +2440,7 @@ CAmount GetInvalidUTXOValue() bool CheckInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector* pvChecks) { - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { if (pvChecks) pvChecks->reserve(tx.vin.size()); @@ -2569,40 +2567,38 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex * note we only undo zerocoin databasing in the following statement, value to and from PIVX * addresses should still be handled by the typical bitcoin based undo code * */ - if (tx.ContainsZerocoins()) { - if (tx.IsZerocoinSpend()) { - //erase all zerocoinspends in this transaction - for (const CTxIn& txin : tx.vin) { - if (txin.scriptSig.IsZerocoinSpend()) { - CoinSpend spend = TxInToZerocoinSpend(txin); - if (!zerocoinDB->EraseCoinSpend(spend.getCoinSerialNumber())) - return error("failed to erase spent zerocoin in block"); - - //if this was our spend, then mark it unspent now - if (pwalletMain) { - if (pwalletMain->IsMyZerocoinSpend(spend.getCoinSerialNumber())) { - if (!pwalletMain->SetMintUnspent(spend.getCoinSerialNumber())) - LogPrintf("%s: failed to automatically reset mint", __func__); - } + if (tx.HasZerocoinSpendInputs()) { + //erase all zerocoinspends in this transaction + for (const CTxIn& txin : tx.vin) { + if (txin.IsZerocoinSpend()) { + CoinSpend spend = TxInToZerocoinSpend(txin); + if (!zerocoinDB->EraseCoinSpend(spend.getCoinSerialNumber())) + return error("failed to erase spent zerocoin in block"); + + //if this was our spend, then mark it unspent now + if (pwalletMain) { + if (pwalletMain->IsMyZerocoinSpend(spend.getCoinSerialNumber())) { + if (!pwalletMain->SetMintUnspent(spend.getCoinSerialNumber())) + LogPrintf("%s: failed to automatically reset mint", __func__); } } - } + } + } - if (tx.IsZerocoinMint()) { - //erase all zerocoinmints in this transaction - for (const CTxOut& txout : tx.vout) { - if (txout.scriptPubKey.empty() || !txout.scriptPubKey.IsZerocoinMint()) - continue; + if (tx.HasZerocoinMintOutputs()) { + //erase all zerocoinmints in this transaction + for (const CTxOut& txout : tx.vout) { + if (txout.scriptPubKey.empty() || !txout.IsZerocoinMint()) + continue; - PublicCoin pubCoin(Params().Zerocoin_Params(false)); - if (!TxOutToPublicCoin(txout, pubCoin, state)) - return error("DisconnectBlock(): TxOutToPublicCoin() failed"); + PublicCoin pubCoin(Params().Zerocoin_Params(false)); + if (!TxOutToPublicCoin(txout, pubCoin, state)) + return error("DisconnectBlock(): TxOutToPublicCoin() failed"); - if(!zerocoinDB->EraseCoinMint(pubCoin.getValue())) - return error("DisconnectBlock(): Failed to erase coin mint"); - } + if(!zerocoinDB->EraseCoinMint(pubCoin.getValue())) + return error("DisconnectBlock(): Failed to erase coin mint"); } } @@ -2631,7 +2627,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } // restore inputs - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { // not coinbases or zerocoinspend because they dont have traditional inputs + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { // not coinbases or zerocoinspend because they dont have traditional inputs const CTxUndo& txundo = blockUndo.vtxundo[i - 1]; if (txundo.vprevout.size() != tx.vin.size()) return error("DisconnectBlock() : transaction and undo data inconsistent - txundo.vprevout.siz=%d tx.vin.siz=%d", txundo.vprevout.size(), tx.vin.size()); @@ -2849,7 +2845,7 @@ bool RecalculatePIVSupply(int nHeightStart) if (tx.IsCoinBase()) break; - if (tx.vin[i].scriptSig.IsZerocoinSpend()) { + if (tx.vin[i].IsZerocoinSpend()) { nValueIn += tx.vin[i].nSequence * COIN; continue; } @@ -3113,7 +3109,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock() : zerocoin transactions are currently in maintenance mode")); } - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { int nHeightTx = 0; uint256 txid = tx.GetHash(); vSpendsInBlock.emplace_back(txid); @@ -3128,7 +3124,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin //Check for double spending of serial #'s set setSerials; for (const CTxIn& txIn : tx.vin) { - if (!txIn.scriptSig.IsZerocoinSpend()) + if (!txIn.IsZerocoinSpend()) continue; CoinSpend spend = TxInToZerocoinSpend(txIn); nValueIn += spend.getDenomination() * COIN; @@ -3140,7 +3136,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } // Check that zPIV mints are not already known - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { for (auto& out : tx.vout) { if (!out.IsZerocoinMint()) continue; @@ -3169,7 +3165,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } // Check that zPIV mints are not already known - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { for (auto& out : tx.vout) { if (!out.IsZerocoinMint()) continue; @@ -4314,9 +4310,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return error("CheckBlock() : CheckTransaction failed"); // double check that there are no double spent zPIV spends in this block - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { for (const CTxIn& txIn : tx.vin) { - if (txIn.scriptSig.IsZerocoinSpend()) { + if (txIn.IsZerocoinSpend()) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); if (count(vBlockSerials.begin(), vBlockSerials.end(), spend.getCoinSerialNumber())) return state.DoS(100, error("%s : Double spending of zPIV serial %s in block\n Block: %s", @@ -4647,7 +4643,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, std::vector zPIVInputs; for (const CTxIn& stakeIn : stakeTxIn.vin) { - if(stakeIn.scriptSig.IsZerocoinSpend()){ + if(stakeIn.IsZerocoinSpend()){ zPIVInputs.push_back(stakeIn); }else{ pivInputs.push_back(stakeIn); @@ -4663,7 +4659,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, for (const CTransaction& tx : block.vtx) { for (const CTxIn& in: tx.vin) { if(nHeight >= Params().Zerocoin_StartHeight()) { - if (in.scriptSig.IsZerocoinSpend()) { + if (in.IsZerocoinSpend()) { CoinSpend spend = TxInToZerocoinSpend(in); // Check for serials double spending in the same block if (std::find(inBlockSerials.begin(), inBlockSerials.end(), spend.getCoinSerialNumber()) != @@ -4725,7 +4721,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, } // Second, if there is zPoS staking then store the serials for later check - if (in.scriptSig.IsZerocoinSpend()) { + if(in.IsZerocoinSpend()){ vBlockSerials.push_back(TxInToZerocoinSpend(in).getCoinSerialNumber()); } } @@ -4792,7 +4788,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, // If the stake is not a zPoS then let's check if the inputs were spent on the main chain const CCoinsViewCache coins(pcoinsTip); - if(!stakeTxIn.IsZerocoinSpend()) { + if(!stakeTxIn.HasZerocoinSpendInputs()) { for (const CTxIn& in: stakeTxIn.vin) { const CCoins* coin = coins.AccessCoins(in.prevout.hash); @@ -4912,7 +4908,7 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis for (const CTransaction& tx : pblock->vtx) { if (tx.ContainsZerocoins()) { for (const CTxIn& in : tx.vin) { - if (in.scriptSig.IsZerocoinSpend()) + if (in.IsZerocoinSpend()) nSpends++; } for (const CTxOut& out : tx.vout) { @@ -6415,7 +6411,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapAlreadyAskedFor.erase(inv); - if (!tx.IsZerocoinSpend() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, false, ignoreFees)) { + if (!tx.HasZerocoinSpendInputs() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, false, ignoreFees)) { mempool.check(pcoinsTip); RelayTransaction(tx); vWorkQueue.push_back(inv.hash); @@ -6469,7 +6465,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } BOOST_FOREACH (uint256 hash, vEraseQueue)EraseOrphanTx(hash); - } else if (tx.IsZerocoinSpend() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingZerocoinInputs, false, ignoreFees)) { + } else if (tx.HasZerocoinSpendInputs() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingZerocoinInputs, false, ignoreFees)) { //Presstab: ZCoin has a bunch of code commented out here. Is this something that should have more going on? //Also there is nothing that handles fMissingZerocoinInputs. Does there need to be? RelayTransaction(tx); diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index d49156c9ebe5e..e55c932eab4f2 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -544,7 +544,7 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) nMasternode_Drift_Count = mnodeman.size() + Params().MasternodeCountDrift(); } - CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight, nReward, nMasternode_Drift_Count, txNew.IsZerocoinSpend()); + CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight, nReward, nMasternode_Drift_Count, txNew.HasZerocoinSpendInputs()); //require at least 6 signatures BOOST_FOREACH (CMasternodePayee& payee, vecPayments) diff --git a/src/miner.cpp b/src/miner.cpp index c0883c0e6b535..b92a30085c4de 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -219,11 +219,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, CAmount nTotalIn = 0; bool fMissingInputs = false; uint256 txid = tx.GetHash(); + bool hasZerocoinSpends = tx.HasZerocoinSpendInputs(); + if (hasZerocoinSpends) + nTotalIn = tx.GetZerocoinSpent(); + for (const CTxIn& txin : tx.vin) { //zerocoinspend has special vin - if (tx.IsZerocoinSpend()) { - nTotalIn = tx.GetZerocoinSpent(); - + if (hasZerocoinSpends) { //Give a high priority to zerocoinspends to get into the next block //Priority = (age^6+100000)*amount - gives higher priority to zpivs that have been in mempool long //and higher priority to zpivs that are large in value @@ -346,7 +348,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, double dPriorityDelta = 0; CAmount nFeeDelta = 0; mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); - if (!tx.IsZerocoinSpend() && fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + if (!tx.HasZerocoinSpendInputs() && fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritise by fee once past the priority size or we run out of high-priority @@ -362,14 +364,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, continue; // double check that there are no double spent zPIV spends in this block or tx - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { int nHeightTx = 0; if (IsTransactionInChain(tx.GetHash(), nHeightTx)) continue; bool fDoubleSerial = false; for (const CTxIn& txIn : tx.vin) { - if (txIn.scriptSig.IsZerocoinSpend()) { + if (txIn.IsZerocoinSpend()) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); bool fUseV1Params = libzerocoin::ExtractVersionFromSerial(spend.getCoinSerialNumber()) < libzerocoin::PrivateCoin::PUBKEY_VERSION; if (!spend.HasValidSerial(Params().Zerocoin_Params(fUseV1Params))) diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 51f7f74c242cc..5edb9bc9c6d45 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -143,5 +143,5 @@ void CBlock::print() const bool CBlock::IsZerocoinStake() const { - return IsProofOfStake() && vtx[1].IsZerocoinSpend(); -} \ No newline at end of file + return IsProofOfStake() && vtx[1].HasZerocoinSpendInputs(); +} diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 94835fd9b67c6..cf5f58b2df7a4 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -60,13 +60,18 @@ CTxIn::CTxIn(const libzerocoin::CoinSpend& spend, libzerocoin::CoinDenomination nSequence = denom; } +bool CTxIn::IsZerocoinSpend() const +{ + return prevout.hash == 0 && scriptSig.IsZerocoinSpend(); +} + std::string CTxIn::ToString() const { std::string str; str += "CTxIn("; str += prevout.ToString(); if (prevout.IsNull()) - if(scriptSig.IsZerocoinSpend()) + if(IsZerocoinSpend()) str += strprintf(", zerocoinspend %s...", HexStr(scriptSig).substr(0, 25)); else str += strprintf(", coinbase %s", HexStr(scriptSig)); @@ -98,6 +103,19 @@ uint256 CTxOut::GetHash() const return SerializeHash(*this); } +bool CTxOut::IsZerocoinMint() const +{ + return scriptPubKey.IsZerocoinMint(); +} + +CAmount CTxOut::GetZerocoinMinted() const +{ + if (!IsZerocoinMint()) + return CAmount(0); + + return nValue; +} + std::string CTxOut::ToString() const { return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30)); @@ -146,17 +164,35 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) { return *this; } +bool CTransaction::HasZerocoinSpendInputs() const +{ + for (const CTxIn& txin: vin) { + if (txin.IsZerocoinSpend()) + return true; + } + return false; +} + +bool CTransaction::HasZerocoinMintOutputs() const +{ + for(const CTxOut& txout : vout) { + if (txout.IsZerocoinMint()) + return true; + } + return false; +} + bool CTransaction::IsCoinStake() const { if (vin.empty()) return false; // ppcoin: the coin stake transaction is marked with the first output empty - bool fAllowNull = vin[0].scriptSig.IsZerocoinSpend(); + bool fAllowNull = vin[0].IsZerocoinSpend(); if (vin[0].prevout.IsNull() && !fAllowNull) return false; - return (vin.size() > 0 && vout.size() >= 2 && vout[0].IsEmpty()); + return (vout.size() >= 2 && vout[0].IsEmpty()); } CAmount CTransaction::GetValueOut() const @@ -178,14 +214,12 @@ CAmount CTransaction::GetValueOut() const CAmount CTransaction::GetZerocoinMinted() const { + CAmount nValueOut = 0; for (const CTxOut& txOut : vout) { - if(!txOut.scriptPubKey.IsZerocoinMint()) - continue; - - return txOut.nValue; + nValueOut += txOut.GetZerocoinMinted(); } - return CAmount(0); + return nValueOut; } bool CTransaction::UsesUTXO(const COutPoint out) @@ -209,12 +243,9 @@ std::list CTransaction::GetOutPoints() const CAmount CTransaction::GetZerocoinSpent() const { - if(!IsZerocoinSpend()) - return 0; - CAmount nValueOut = 0; for (const CTxIn& txin : vin) { - if(!txin.scriptSig.IsZerocoinSpend()) + if(!txin.IsZerocoinSpend()) continue; nValueOut += txin.nSequence * COIN; @@ -227,7 +258,7 @@ int CTransaction::GetZerocoinMintCount() const { int nCount = 0; for (const CTxOut& out : vout) { - if (out.scriptPubKey.IsZerocoinMint()) + if (out.IsZerocoinMint()) nCount++; } return nCount; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 29d5f300c8752..fceabedf32d04 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -95,6 +95,8 @@ class CTxIn return (nSequence == std::numeric_limits::max()); } + bool IsZerocoinSpend() const; + friend bool operator==(const CTxIn& a, const CTxIn& b) { return (a.prevout == b.prevout && @@ -173,10 +175,8 @@ class CTxOut return (nValue < 3*minRelayTxFee.GetFee(nSize)); } - bool IsZerocoinMint() const - { - return !scriptPubKey.empty() && scriptPubKey.IsZerocoinMint(); - } + bool IsZerocoinMint() const; + CAmount GetZerocoinMinted() const; friend bool operator==(const CTxOut& a, const CTxOut& b) { @@ -259,23 +259,13 @@ class CTransaction // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; - bool IsZerocoinSpend() const - { - return (vin.size() > 0 && vin[0].prevout.hash == 0 && vin[0].scriptSig[0] == OP_ZEROCOINSPEND); - } + bool HasZerocoinSpendInputs() const; - bool IsZerocoinMint() const - { - for(const CTxOut& txout : vout) { - if (txout.scriptPubKey.IsZerocoinMint()) - return true; - } - return false; - } + bool HasZerocoinMintOutputs() const; bool ContainsZerocoins() const { - return IsZerocoinSpend() || IsZerocoinMint(); + return HasZerocoinSpendInputs() || HasZerocoinMintOutputs(); } CAmount GetZerocoinMinted() const; diff --git a/src/qt/privacydialog.cpp b/src/qt/privacydialog.cpp index 789cc72d0bc5d..5510b3cc89610 100644 --- a/src/qt/privacydialog.cpp +++ b/src/qt/privacydialog.cpp @@ -490,7 +490,7 @@ void PrivacyDialog::sendzPIV() strStats += tr("address: "); CTxDestination dest; - if(txout.scriptPubKey.IsZerocoinMint()) + if(txout.IsZerocoinMint()) strStats += tr("zPIV Mint"); else if(ExtractDestination(txout.scriptPubKey, dest)) strStats += tr(CBitcoinAddress(dest).ToString().c_str()); diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 0598e0fb0d1c7..c91ee690e3670 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -42,7 +42,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* std::map mapValue = wtx.mapValue; bool fZSpendFromMe = false; - if (wtx.IsZerocoinSpend()) { + if (wtx.HasZerocoinSpendInputs()) { // a zerocoin spend that was created by this wallet libzerocoin::CoinSpend zcspend = TxInToZerocoinSpend(wtx.vin[0]); fZSpendFromMe = wallet->IsMyZerocoinSpend(zcspend.getCoinSerialNumber()); @@ -51,10 +51,10 @@ QList TransactionRecord::decomposeTransaction(const CWallet* if (wtx.IsCoinStake()) { TransactionRecord sub(hash, nTime); CTxDestination address; - if (!wtx.IsZerocoinSpend() && !ExtractDestination(wtx.vout[1].scriptPubKey, address)) + if (!wtx.HasZerocoinSpendInputs() && !ExtractDestination(wtx.vout[1].scriptPubKey, address)) return parts; - if (wtx.IsZerocoinSpend() && (fZSpendFromMe || wallet->zpivTracker->HasMintTx(hash))) { + if (wtx.HasZerocoinSpendInputs() && (fZSpendFromMe || wallet->zpivTracker->HasMintTx(hash))) { //zPIV stake reward sub.involvesWatchAddress = false; sub.type = TransactionRecord::StakeZPIV; @@ -85,7 +85,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* } parts.append(sub); - } else if (wtx.IsZerocoinSpend()) { + } else if (wtx.HasZerocoinSpendInputs()) { //zerocoin spend outputs bool fFeeAssigned = false; for (const CTxOut& txout : wtx.vout) { @@ -245,7 +245,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* sub.credit = nCredit - nChange; parts.append(sub); parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument - } else if (fAllFromMe || wtx.IsZerocoinMint()) { + } else if (fAllFromMe || wtx.HasZerocoinMintOutputs()) { // // Debit // @@ -267,7 +267,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* if (ExtractDestination(txout.scriptPubKey, address)) { //This is most likely only going to happen when resyncing deterministic wallet without the knowledge of the //private keys that the change was sent to. Do not display a "sent to" here. - if (wtx.IsZerocoinMint()) + if (wtx.HasZerocoinMintOutputs()) continue; // Sent to PIVX Address sub.type = TransactionRecord::SendToAddress; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6fe73895752fd..ce9a0a89b5deb 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1051,7 +1051,7 @@ UniValue getfeeinfo(const UniValue& params, bool fHelp) continue; for (unsigned int j = 0; j < tx.vin.size(); j++) { - if (tx.vin[j].scriptSig.IsZerocoinSpend()) { + if (tx.vin[j].IsZerocoinSpend()) { nValueIn += tx.vin[j].nSequence * COIN; continue; } @@ -1446,7 +1446,7 @@ UniValue getserials(const UniValue& params, bool fHelp) { } // loop through each input for (const CTxIn& txin : tx.vin) { - if (txin.scriptSig.IsZerocoinSpend()) { + if (txin.IsZerocoinSpend()) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin); std::string serial_str = spend.getCoinSerialNumber().ToString(16); if (!fVerbose) { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index bb7ba1d3b1300..69dc2c77ace86 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -901,7 +901,7 @@ UniValue getspentzerocoinamount(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter for transaction input"); const CTxIn& input = tx.vin[inputIndex]; - if (!input.scriptSig.IsZerocoinSpend()) + if (!input.IsZerocoinSpend()) return -1; libzerocoin::CoinSpend spend = TxInToZerocoinSpend(input); diff --git a/src/script/script.cpp b/src/script/script.cpp index 468a0c1d46b01..dbd44486558ba 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -248,19 +248,19 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } +bool CScript::StartsWithOpcode(const opcodetype opcode) const +{ + return (!this->empty() && this->at(0) == opcode); +} + bool CScript::IsZerocoinMint() const { - //fast test for Zerocoin Mint CScripts - return (this->size() > 0 && - this->at(0) == OP_ZEROCOINMINT); + return StartsWithOpcode(OP_ZEROCOINMINT); } bool CScript::IsZerocoinSpend() const { - if (this->empty()) - return false; - - return (this->at(0) == OP_ZEROCOINSPEND); + return StartsWithOpcode(OP_ZEROCOINSPEND); } bool CScript::IsPushOnly(const_iterator pc) const diff --git a/src/script/script.h b/src/script/script.h index d276df42f42ad..801562ebd61eb 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -598,6 +598,7 @@ class CScript : public std::vector bool IsNormalPaymentScript() const; bool IsPayToScriptHash() const; + bool StartsWithOpcode(const opcodetype opcode) const; bool IsZerocoinMint() const; bool IsZerocoinSpend() const; diff --git a/src/script/standard.cpp b/src/script/standard.cpp index b94390573f37e..325c1f2985269 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -66,7 +66,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 150) return false; vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.end()); diff --git a/src/test/zerocoin_implementation_tests.cpp b/src/test/zerocoin_implementation_tests.cpp index 53ac2effd5848..0390f02093e61 100644 --- a/src/test/zerocoin_implementation_tests.cpp +++ b/src/test/zerocoin_implementation_tests.cpp @@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinmint_test) CValidationState state; bool fFoundMint = false; for(unsigned int i = 0; i < tx.vout.size(); i++){ - if(!tx.vout[i].scriptPubKey.empty() && tx.vout[i].scriptPubKey.IsZerocoinMint()) { + if(tx.vout[i].IsZerocoinMint()) { BOOST_CHECK(CheckZerocoinMint(tx.GetHash(), tx.vout[i], state, true)); fFoundMint = true; } @@ -177,7 +177,7 @@ bool CheckZerocoinSpendNoDB(const CTransaction tx, string& strError) BOOST_FOREACH(const CTxIn& txin, tx.vin) { //only check txin that is a zcspend - if (!txin.scriptSig.IsZerocoinSpend()) + if (!txin.IsZerocoinSpend()) continue; // extract the CoinSpend from the txin @@ -271,7 +271,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) BOOST_CHECK_MESSAGE(DecodeHexTx(tx, raw.first), "Failed to deserialize hex transaction"); for(const CTxOut& out : tx.vout){ - if(!out.scriptPubKey.empty() && out.scriptPubKey.IsZerocoinMint()) { + if(out.IsZerocoinMint()) { PublicCoin publicCoin(Params().Zerocoin_Params(true)); BOOST_CHECK_MESSAGE(TxOutToPublicCoin(out, publicCoin, state), "Failed to convert CTxOut " << out.ToString() << " to PublicCoin"); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5c1e3c1b34746..f9a36c12ba083 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -411,7 +411,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry) { mapTx[hash] = entry; const CTransaction& tx = mapTx[hash].GetTx(); - if(!tx.IsZerocoinSpend()) { + if(!tx.HasZerocoinSpendInputs()) { for (unsigned int i = 0; i < tx.vin.size(); i++) mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); } @@ -565,11 +565,11 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const fDependsWait = true; } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); - if(!txin.scriptSig.IsZerocoinSpend()) + if(!txin.IsZerocoinSpend()) assert(coins && coins->IsAvailable(txin.prevout.n)); } // Check whether its inputs are marked in mapNextTx. - if(!txin.scriptSig.IsZerocoinSpend()) { + if(!txin.IsZerocoinSpend()) { std::map::const_iterator it3 = mapNextTx.find(txin.prevout); assert(it3 != mapNextTx.end()); assert(it3->second.ptx == &tx); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 35cae7b3ed9cc..fbd22d46d5706 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3034,7 +3034,7 @@ extern UniValue DoZpivSpend(const CAmount nAmount, bool fMintChange, bool fMinim nValueOut += txout.nValue; CTxDestination dest; - if(txout.scriptPubKey.IsZerocoinMint()) + if(txout.IsZerocoinMint()) out.push_back(Pair("address", "zerocoinmint")); else if(ExtractDestination(txout.scriptPubKey, dest)) out.push_back(Pair("address", CBitcoinAddress(dest).ToString())); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0eb5b659f8f53..50827720fbe6d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -389,7 +389,7 @@ set CWallet::GetConflicts(const uint256& txid) const std::pair range; BOOST_FOREACH (const CTxIn& txin, wtx.vin) { - if (mapTxSpends.count(txin.prevout) <= 1 || wtx.IsZerocoinSpend()) + if (mapTxSpends.count(txin.prevout) <= 1 || wtx.HasZerocoinSpendInputs()) continue; // No conflict if zero or one spends range = mapTxSpends.equal_range(txin.prevout); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) @@ -744,7 +744,7 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) // available of the outputs it spends. So force those to be // recomputed, also: BOOST_FOREACH (const CTxIn& txin, tx.vin) { - if (!tx.IsZerocoinSpend() && mapWallet.count(txin.prevout.hash)) + if (!txin.IsZerocoinSpend() && mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } } @@ -969,7 +969,7 @@ int64_t CWalletTx::GetTxTime() const int64_t CWalletTx::GetComputedTxTime() const { LOCK(cs_main); - if (IsZerocoinSpend() || IsZerocoinMint()) { + if (ContainsZerocoins()) { if (IsInMainChain()) return mapBlockIndex.at(hashBlock)->GetBlockTime(); else @@ -1377,6 +1377,7 @@ void CWalletTx::GetAmounts(list& listReceived, } // Sent/received. + bool hasZerocoinSpends = HasZerocoinSpendInputs(); for (unsigned int i = 0; i < vout.size(); ++i) { const CTxOut& txout = vout[i]; isminetype fIsMine = pwallet->IsMine(txout); @@ -1387,12 +1388,12 @@ void CWalletTx::GetAmounts(list& listReceived, // Don't report 'change' txouts if (pwallet->IsChange(txout)) continue; - } else if (!(fIsMine & filter) && !IsZerocoinSpend()) + } else if (!(fIsMine & filter) && !hasZerocoinSpends) continue; // In either case, we need to get the destination address CTxDestination address; - if (txout.scriptPubKey.IsZerocoinMint()) { + if (txout.IsZerocoinMint()) { address = CNoDestination(); } else if (!ExtractDestination(txout.scriptPubKey, address)) { if (!IsCoinStake() && !IsCoinBase()) { @@ -2126,7 +2127,7 @@ bool CWallet::SelectStakeCoins(std::list >& listInp //if zerocoinspend, then use the block time int64_t nTxTime = out.tx->GetTxTime(); - if (out.tx->IsZerocoinSpend()) { + if (out.tx->vin[0].IsZerocoinSpend()) { if (!out.tx->IsInMainChain()) continue; nTxTime = mapBlockIndex.at(out.tx->hashBlock)->GetBlockTime(); @@ -2200,7 +2201,7 @@ bool CWallet::MintableCoins() for (const COutput& out : vCoins) { int64_t nTxTime = out.tx->GetTxTime(); - if (out.tx->IsZerocoinSpend()) { + if (out.tx->vin[0].IsZerocoinSpend()) { if (!out.tx->IsInMainChain()) continue; nTxTime = mapBlockIndex.at(out.tx->hashBlock)->GetBlockTime(); @@ -3113,7 +3114,7 @@ bool CWallet::CreateCoinStake( // Sign for PIV int nIn = 0; - if (!txNew.vin[0].scriptSig.IsZerocoinSpend()) { + if (!txNew.vin[0].IsZerocoinSpend()) { for (CTxIn txIn : txNew.vin) { const CWalletTx *wtx = GetWalletTx(txIn.prevout.hash); if (!SignSignature(*this, *wtx, txNew, nIn++)) @@ -3168,7 +3169,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std: AddToWallet(wtxNew); // Notify that old coins are spent - if (!wtxNew.IsZerocoinSpend()) { + if (!wtxNew.HasZerocoinSpendInputs()) { set updated_hahes; BOOST_FOREACH (const CTxIn& txin, wtxNew.vin) { // notify only once diff --git a/src/zpiv/zpivwallet.cpp b/src/zpiv/zpivwallet.cpp index 69cdca4d703da..8421d36e356ff 100644 --- a/src/zpiv/zpivwallet.cpp +++ b/src/zpiv/zpivwallet.cpp @@ -229,7 +229,7 @@ void CzPIVWallet::SyncWithChain(bool fGenerateMintPool) bool fFoundMint = false; CBigNum bnValue = 0; for (const CTxOut& out : tx.vout) { - if (!out.scriptPubKey.IsZerocoinMint()) + if (!out.IsZerocoinMint()) continue; PublicCoin pubcoin(Params().Zerocoin_Params(false)); diff --git a/src/zpivchain.cpp b/src/zpivchain.cpp index 2a6132281adb5..ccf78667fc3d2 100644 --- a/src/zpivchain.cpp +++ b/src/zpivchain.cpp @@ -16,11 +16,11 @@ bool BlockToMintValueVector(const CBlock& block, const libzerocoin::CoinDenomination denom, vector& vValues) { for (const CTransaction& tx : block.vtx) { - if(!tx.IsZerocoinMint()) + if(!tx.HasZerocoinMintOutputs()) continue; for (const CTxOut& txOut : tx.vout) { - if(!txOut.scriptPubKey.IsZerocoinMint()) + if(!txOut.IsZerocoinMint()) continue; CValidationState state; @@ -41,7 +41,7 @@ bool BlockToMintValueVector(const CBlock& block, const libzerocoin::CoinDenomina bool BlockToPubcoinList(const CBlock& block, std::list& listPubcoins, bool fFilterInvalid) { for (const CTransaction& tx : block.vtx) { - if(!tx.IsZerocoinMint()) + if(!tx.HasZerocoinMintOutputs()) continue; // Filter out mints that have used invalid outpoints @@ -64,7 +64,7 @@ bool BlockToPubcoinList(const CBlock& block, std::list& break; const CTxOut txOut = tx.vout[i]; - if(!txOut.scriptPubKey.IsZerocoinMint()) + if(!txOut.IsZerocoinMint()) continue; CValidationState state; @@ -83,7 +83,7 @@ bool BlockToPubcoinList(const CBlock& block, std::list& bool BlockToZerocoinMintList(const CBlock& block, std::list& vMints, bool fFilterInvalid) { for (const CTransaction& tx : block.vtx) { - if(!tx.IsZerocoinMint()) + if(!tx.HasZerocoinMintOutputs()) continue; // Filter out mints that have used invalid outpoints @@ -106,7 +106,7 @@ bool BlockToZerocoinMintList(const CBlock& block, std::list& vMin break; const CTxOut txOut = tx.vout[i]; - if(!txOut.scriptPubKey.IsZerocoinMint()) + if(!txOut.IsZerocoinMint()) continue; CValidationState state; @@ -283,9 +283,9 @@ std::string ReindexZerocoinDB() if (tx.ContainsZerocoins()) { uint256 txid = tx.GetHash(); //Record Serials - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { for (auto& in : tx.vin) { - if (!in.scriptSig.IsZerocoinSpend()) + if (!in.IsZerocoinSpend()) continue; libzerocoin::CoinSpend spend = TxInToZerocoinSpend(in); @@ -294,7 +294,7 @@ std::string ReindexZerocoinDB() } //Record mints - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { for (auto& out : tx.vout) { if (!out.IsZerocoinMint()) continue; @@ -372,11 +372,11 @@ std::list ZerocoinSpendListFromBlock(const CBlock { std::list vSpends; for (const CTransaction& tx : block.vtx) { - if (!tx.IsZerocoinSpend()) + if (!tx.HasZerocoinSpendInputs()) continue; for (const CTxIn& txin : tx.vin) { - if (!txin.scriptSig.IsZerocoinSpend()) + if (!txin.IsZerocoinSpend()) continue; if (fFilterInvalid) {